static updated

parent 35cdaf37
......@@ -11,6 +11,8 @@
gadget_klass.declareAcquiredMethod("aq_allDocs", "jio_allDocs").declareAcquiredMethod("pleaseRedirectMyHash", "pleaseRedirectMyHash").declareAcquiredMethod("whoWantsToDisplayThisDocument", "whoWantsToDisplayThisDocument").declareMethod("render", function() {
var gadget = this;
return gadget.aq_allDocs({
include_docs: true,
query: 'type:= "Dream"',
select_list: [ "title", "modified" ]
}).push(function(document_list) {
var result_list = [], doc, i;
......
......@@ -18,8 +18,9 @@
<script id="panel-template" type="text/x-handlebars-template">
<ul data-role="listview">
<li><a class="home_link ui-btn ui-icon-home ui-btn-icon-left" data-icon="home">Documents</a></li>
<li><a class="fast_input_link ui-btn ui-icon-plus ui-btn-icon-left" data-icon="plus">New Document</a></li>
<li><a class="pre_input_link ui-btn ui-icon-grid ui-btn-icon-left" data-icon="grid">Documents</a></li>
<!--li><a class="home_link ui-btn ui-icon-home ui-btn-icon-left" data-icon="home">Documents</a></li-->
<!--li><a class="fast_input_link ui-btn ui-icon-plus ui-btn-icon-left" data-icon="plus">New Document</a></li-->
{{#navigationlist}}
<li><a href="{{link}}">{{title}}</a></li>
{{/navigationlist}}
......
......@@ -14,156 +14,22 @@
/////////////////////////////////////////////////////////////////
// XXX we should use lists instead to keep ordering
var portal_types = {
"Input Module": {
"Pre Input Module": {
view: {
gadget: "InputModule_viewInputList",
type: "object_list",
title: "Document List"
},
view_fast_input: {
gadget: "InputModule_viewAddDocumentDialog",
gadget: "InputModule_viewAddInstanceDefinitionDialog",
type: "object_fast_input",
title: "Create Document"
}
},
Input: {
view: {
gadget: "Input_viewProductionLine",
type: "object_view",
title: "Production Line"
},
view_wip_part_spreadsheet: {
gadget: "Input_viewWipPartSpreadsheet",
type: "object_view",
title: "WIP Part Spreadsheet",
condition: function(gadget) {
return gadget.props.configuration_dict["Dream-Configuration"].gui.wip_part_spreadsheet;
}
},
view_shift_spreadsheet: {
gadget: "Input_viewShiftSpreadsheet",
type: "object_view",
title: "Shift Spreadsheet",
condition: function(gadget) {
return gadget.props.configuration_dict["Dream-Configuration"].gui.shift_spreadsheet;
}
},
view_available_capacity_spreadsheet: {
gadget: "Input_viewAvailableCapacitySpreadsheet",
type: "object_view",
title: "Available Capacity Spreadsheet",
condition: function(gadget) {
return gadget.props.configuration_dict["Dream-Configuration"].gui.capacity_by_project_spreadsheet;
}
},
view_required_capacity_spreadsheet: {
gadget: "Input_viewRequiredCapacitySpreadsheet",
type: "object_view",
title: "Required Capacity Spreadsheet",
condition: function(gadget) {
return gadget.props.configuration_dict["Dream-Configuration"].gui.capacity_by_station_spreadsheet;
}
},
view_dp_capacity_spreadsheet: {
gadget: "Input_viewDemandPlanningCapacitySpreadsheet",
type: "object_view",
title: "Demand Planning Required Capacity Spreadsheet",
condition: function(gadget) {
return gadget.props.configuration_dict["Dream-Configuration"].gui.dp_capacity_spreadsheet;
}
},
view_dp_route_spreadsheet: {
gadget: "Input_viewDemandPlanningRouteSpreadsheet",
type: "object_view",
title: "Demand Planning Route Spreadsheet",
condition: function(gadget) {
return gadget.props.configuration_dict["Dream-Configuration"].gui.dp_route_spreadsheet;
}
},
view_simu: {
gadget: "Input_viewSimulation",
type: "object_view",
title: "Run simulation"
},
view_management: {
gadget: "Input_viewDocumentManagement",
type: "object_view",
title: "Manage document"
},
view_result: {
gadget: "Input_viewResultList",
type: "object_view",
title: "Results"
}
},
Output: {
view: {
gadget: "Output_viewStationUtilisationGraph",
type: "object_view",
title: "Stations Utilization",
condition: function(gadget) {
return gadget.props.configuration_dict["Dream-Configuration"].gui.station_utilisation_graph;
}
},
download_excel_spreadsheet: {
gadget: "Output_viewDownloadExcelSpreadsheet",
type: "object_view",
title: "Download Excel Spreadsheet",
condition: function(gadget) {
return gadget.props.configuration_dict["Dream-Configuration"].gui.download_excel_spreadsheet;
}
},
view_capacity_utilization: {
gadget: "Output_viewCapacityUtilisationGraph",
type: "object_view",
title: "Capacity Utilization",
condition: function(gadget) {
return gadget.props.configuration_dict["Dream-Configuration"].gui.capacity_utilisation_graph;
}
},
view_queue_stat: {
gadget: "Output_viewQueueStatGraph",
type: "object_view",
title: "Queues Statistics",
condition: function(gadget) {
return gadget.props.configuration_dict["Dream-Configuration"].gui.queue_stat;
}
},
view_exit_stat: {
gadget: "Output_viewExitStatistics",
type: "object_view",
title: "Exit Statistics",
condition: function(gadget) {
return gadget.props.configuration_dict["Dream-Configuration"].gui.exit_stat;
}
},
view_gantt: {
gadget: "Output_viewJobGantt",
type: "object_view",
title: "Job Gantt",
condition: function(gadget) {
return gadget.props.configuration_dict["Dream-Configuration"].gui.job_gantt;
}
},
view_schedule: {
gadget: "Output_viewJobScheduleSpreadsheet",
type: "object_view",
title: "Job Schedule",
condition: function(gadget) {
return gadget.props.configuration_dict["Dream-Configuration"].gui.job_schedule_spreadsheet;
}
},
view_debug: {
gadget: "Output_viewDebugJson",
type: "object_view",
title: "Debug JSON",
condition: function(gadget) {
return gadget.props.configuration_dict["Dream-Configuration"].gui.debug_json;
}
title: "Choose Instance Definition"
}
}
}, panel_template, navigation_template, active_navigation_template, error_template, gadget_klass = rJS(window);
function calculateTabHTML(gadget, options, key, title, active) {
/*console.log('________________________');
console.log(key);
console.log(gadget);
console.log(options);
console.log(title);
console.log(active);
console.log('________________________');*/
return new RSVP.Queue().push(function() {
var kw = {
action: key,
......@@ -174,6 +40,14 @@
}
return gadget.aq_pleasePublishMyState(kw);
}).push(function(url) {
/*console.log('<><><><><><><>><><><><><><><calculating tab url:');
console.log(key);
if (url === undefined) {
console.log('tab url:');
console.log(url);
} else {
console.log('undefined url');
}*/
var kw = {
title: title,
link: url
......@@ -207,7 +81,7 @@
forward_kw.result = current + 1;
}
});
} else if (portal_type !== "Input Module") {
} else if (portal_type !== "Pre Input Module") {
throw new Error("Unknown portal type: " + portal_type);
}
return queue.push(function() {
......@@ -216,7 +90,7 @@
}
function getTitle(gadget, portal_type, options) {
var title;
if (portal_type === "Input Module") {
if (portal_type === "Pre Input Module") {
title = "Documents";
} else if (portal_type === "Input") {
title = gadget.getDeclaredGadget("jio").push(function(jio_gadget) {
......@@ -242,6 +116,15 @@
return title;
}
function calculateNavigationHTML(gadget, portal_type, options) {
/*console.log('.............................');
console.log(gadget);
console.log(portal_type);
console.log(options);
console.log(options.action);
console.log(portal_types[portal_type]);
console.log(portal_types[portal_type][options.action]);
console.log(portal_types[portal_type][options.action].type);
console.log('<<<<<<<<<<<<<<<<<<<<<<<<<<<<');*/
var nav_html, action;
if (portal_types[portal_type][options.action].type === "object_view") {
return new RSVP.Queue().push(function() {
......@@ -256,8 +139,13 @@
}
}
}
/*console.log('url_list');
console.log(url_list);
console.log('>>>>>>>>>>>>>>>>>>>>>>>>');*/
return RSVP.all(url_list);
}).push(function(entry_list) {
/*console.log('entry_list');
console.log(entry_list);*/
var i;
nav_html = '<nav data-role="navbar" data-collapsible="true"><ul>';
for (i = 0; i < entry_list.length; i += 1) {
......@@ -269,6 +157,9 @@
}
}
initGadgetMixin(gadget_klass);
/*console.log('AaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAa');
console.log(gadget_klass);
console.log('AaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAa');*/
gadget_klass.declareAcquiredMethod("pleaseRedirectMyHash", "pleaseRedirectMyHash").allowPublicAcquisition("jio_allDocs", function(param_list) {
return this.getDeclaredGadget("jio").push(function(jio_gadget) {
return jio_gadget.allDocs.apply(jio_gadget, param_list);
......@@ -297,6 +188,21 @@
return this.getDeclaredGadget("jio").push(function(jio_gadget) {
return jio_gadget.getAttachment.apply(jio_gadget, param_list);
});
}).allowPublicAcquisition("startListenTo", function(param_list) {
//console.log('arkoudesarkoudesarkoudesarkoudesarkoudes');
var obj, type, fn;
obj = param_list[0];
type = param_list[1];
fn = param_list[2];
if (obj.addEventListener) {
obj.addEventListener(type, fn, false);
} else if (obj.attachEvent) {
obj["e" + type + fn] = fn;
obj[type + fn] = function() {
obj["e" + type + fn](window.event);
};
obj.attachEvent("on" + type, obj[type + fn]);
}
}).allowPublicAcquisition("whoWantsToDisplayHome", function() {
// Hey, I want to display some URL
return this.aq_pleasePublishMyState({});
......@@ -309,6 +215,9 @@
if (param_list[0] !== undefined) {
kw.id = param_list[0];
}
/*console.log(1010101010101);
console.log(kw);
console.log(param_list);*/
return this.aq_pleasePublishMyState(kw);
}).allowPublicAcquisition("whoWantsToDisplayThisResult", function(param_list) {
// Hey, I want to display some jIO document
......@@ -330,73 +239,106 @@
});
}).allowPublicAcquisition("getConfigurationDict", function() {
return this.props.configuration_dict;
}).allowPublicAcquisition("configurationIsSet", function() {
this.props.configSet = true;
}).allowPublicAcquisition("setConfigurationDict", function(conf_dict) {
this.props.configuration_dict = JSON.parse(conf_dict);
}).allowPublicAcquisition("getDefaultConfigurationDict", function() {
var jio_gadget, g = this;
//console.log('@@@@@@@@@@@@@@@getting DeclalredGadget@@@@@@@@@@@@@@@');
//console.log(g);
return g.getDeclaredGadget("jio").push(function(gadget) {
jio_gadget = gadget;
// XXX Hardcoded relative URL
return jio_gadget.ajax({
url: "../../getConfigurationDict"
});
}).push(function(evt) {
g.props.configuration_dict = JSON.parse(evt.target.responseText);
return g.props.configuration_dict;
});
}).ready(function() {
if (panel_template === undefined) {
// XXX Only works as root gadget
panel_template = Handlebars.compile(document.getElementById("panel-template").innerHTML);
//console.log(123123123123123);
//console.log('panel_template');
//console.log(document.getElementById("panel-template").innerHTML);
navigation_template = Handlebars.compile(document.getElementById("navigation-template").innerHTML);
/*console.log(123123123123);
console.log('navigation_template');
console.log(document.getElementById("navigation-template")
.innerHTML);*/
active_navigation_template = Handlebars.compile(document.getElementById("active-navigation-template").innerHTML);
/*console.log(123123123123);
console.log('active_navigation_template');
console.log(
document.getElementById("active-navigation-template").innerHTML
);*/
error_template = Handlebars.compile(document.getElementById("error-template").innerHTML);
}
}).ready(function(g) {
//console.log('ggggggggggggggggggggg');
//console.log(g);
return new RSVP.Queue().push(function() {
return RSVP.all([ g.aq_pleasePublishMyState({}), g.aq_pleasePublishMyState({
action: "view_fast_input"
//console.log('**********************************1');
//console.log(g);
return RSVP.all([ g.aq_pleasePublishMyState({}), //g.aq_pleasePublishMyState({action: "view_fast_input"}),
g.aq_pleasePublishMyState({
action: "view"
}) ]);
}).push(function(link_list) {
//console.log('____________________link_List*********************');
//console.log(link_list);
//console.log('_________________________*************************');
var panel = g.props.element.querySelector("#leftpanel");
panel.innerHTML = panel_template({
navigationlist: []
});
panel.getElementsByClassName("home_link")[0].href = link_list[0];
panel.getElementsByClassName("fast_input_link")[0].href = link_list[1];
panel.getElementsByClassName("pre_input_link")[0].href = link_list[0];
//panel.getElementsByClassName("home_link")[0].href = link_list[0];
//panel.getElementsByClassName("fast_input_link")[0].href =
// link_list[1];
// XXX JQuery mobile
$(panel).trigger("create");
});
}).ready(function(g) {
var jio_gadget;
//console.log('@@@@@@@@@@@@@@@getting DeclalredGadget@@@@@@@@@@@@@@@');
//console.log(g);
return g.getDeclaredGadget("jio").push(function(gadget) {
jio_gadget = gadget;
//console.log("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
//console.log(jio_gadget);
//console.log("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
return jio_gadget.createJio({
type: "local",
username: "dream",
applicationname: "dream"
});
}).push(function() {
g.props.configuration_dict = {
"Dream-Configuration": {
_class: "Dream.Configuration",
gui: {
debug_json: 1,
download_excel_spreadsheet: 0,
exit_stat: 1,
job_gantt: 0,
job_schedule_spreadsheet: 0,
queue_stat: 1,
shift_spreadsheet: 0,
station_utilisation_graph: 1,
wip_part_spreadsheet: 0,
wip_spreadsheet: 0
},
property_list: [ {
_class: "Dream.Property",
_default: 10,
id: "numberOfReplications",
name: "Number of replications",
type: "number"
} ]
}
};
});
}).declareMethod("render", function(options) {
var gadget = this, back_kw = {
action: "view"
}, page_gadget, portal_type = "Input Module", nav_element = gadget.props.element.getElementsByClassName("nav_container")[0], element = gadget.props.element.getElementsByClassName("gadget_container")[0];
}, page_gadget, portal_type = "Pre Input Module", nav_element = gadget.props.element.getElementsByClassName("nav_container")[0], element = gadget.props.element.getElementsByClassName("gadget_container")[0];
console.log("!!!!!!!!!!!!!!!!!!!!!!options!!!!!!!!!!!!!!!!!!!!!!!");
console.log(options);
console.log("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
if (options.action === undefined) {
// Redirect to the view action
options.action = "view";
return gadget.aq_pleasePublishMyState(options).push(gadget.pleaseRedirectMyHash.bind(gadget));
}
/*// if configuration_dict is defined
// then Pre Input Module should not be loaded
if (gadget.props.configSet === true) {
portal_type = "Input Module";
$('.pre_input_link').hide();
}*/
if (gadget.props.configSet === true) {
portal_types.Input = gadget.props.configuration_dict.application_configuration.Input;
portal_types.Output = gadget.props.configuration_dict.application_configuration.Output;
}
// Detect what is the kind of document displayed
if (options.id !== undefined) {
if (options.result === undefined) {
......@@ -407,6 +349,11 @@
back_kw.id = options.id;
}
}
console.log("__________________portal_types__________________");
console.log(portal_types);
console.log(portal_type);
console.log(options);
console.log(portal_types[portal_type]);
// Get the action information
return gadget.declareGadget(portal_types[portal_type][options.action].gadget + ".html").push(function(g) {
page_gadget = g;
......@@ -416,6 +363,9 @@
}).push(function() {
return RSVP.all([ page_gadget.getElement(), calculateNavigationHTML(gadget, portal_type, options), gadget.aq_pleasePublishMyState(back_kw), getTitle(gadget, portal_type, options), getNextLink(gadget, portal_type, options) ]);
}).push(function(result_list) {
console.log("????????????????????????????????????????????");
console.log(result_list);
console.log("????????????????????????????????????????????");
var nav_html = result_list[1], page_element = result_list[0];
// Update title
gadget.props.element.querySelector("header h1").textContent = result_list[3];
......
/* ====================== listview checkbox ======================== */
/* allow checkbox and radio in split listview */
html body .ui-listview li.ui-li-has-checkbox {
padding-right: 2.25em;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
-webkit-border-top-right-radius: 0;
-webkit-border-bottom-right-radius: 0;
}
html body .ui-listview li.ui-li-has-checkbox label {
border-left-width: 0px;
-moz-box-sizing: border-box;
}
html .ui-listview li.ui-li-has-alt a.ui-btn.ui-icon-caret-right:after,
html .ui-listview li.ui-li-has-alt a.ui-btn.ui-icon-carat-r:after {
content: "";
}
html .ui-listview li div.ui-radio,
html .ui-listview li div.ui-checkbox {
height: 100%;
margin: 0;
padding: 0;
position: absolute;
right: 0;
top: 0;
width: 2.5em;
z-index: 2;
}
html body .ui-listview li div.ui-radio label.ui-btn,
html body .ui-listview li div.ui-checkbox label.ui-btn {
border-radius: .375em;
height: 100%;
min-height: 1em;
padding: 0;
width: auto;
}
html body .ui-listview li div.ui-radio,
html body .ui-listview li div.ui-radio label.ui-btn,
html body .ui-listview li div.ui-checkbox,
html body .ui-listview li div.ui-checkbox label.ui-btn {
box-shadow: 0;
-webkit-box-shadow: 0;
border-radius: 0;
-webkit-border-radius: 0;
}
html body .ui-listview li.ui-first-child div.ui-radio,
html body .ui-listview li.ui-first-child div.ui-radio label.ui-btn,
html body .ui-listview li.ui-first-child div.ui-checkbox,
html body .ui-listview li.ui-first-child div.ui-checkbox label.ui-btn {
border-top-right-radius: .375em;
-webkit-border-top-right-radius: .375em;
}
html body .ui-listview li.ui-last-child div.ui-radio,
html body .ui-listview li.ui-last-child div.ui-radio label,
html body .ui-listview li.ui-last-child div.ui-checkbox,
html body .ui-listview li.ui-last-child div.ui-checkbox label {
border-bottom-right-radius: .375em;
-webkit-border-bottom-right-radius: .375em;
border-bottom-width: 1px;
margin-bottom: -1px;
}
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Choose Instance</title>
<link rel="stylesheet" href="inputModule_viewAddInstanceDefinitionDialog.css" />
<script src="../lib/rsvp.min.js" type="text/javascript"></script>
<script src="../lib/handlebars.min.js" type="text/javascript"></script>
<script src="../lib/renderjs.min.js" type="text/javascript"></script>
<script src="mixin_gadget.js" type="text/javascript"></script>
<script src="mixin_promise.js" type="text/javascript"></script>
<script src="InputModule_viewAddInstanceDefinitionDialog.js" type="text/javascript"></script>
<script id="table-template" type="text/x-handlebars-template">
<ul data-role="listview" data-inset="true" class="document-listview">
{{#documentlist}}
<li>
<div>
<!--div class="ui-btn ui-input-btn">{{title}} -->
<input type="submit" value="{{title}}" name= "{{name}}">
</div>
<div class="ui-checkbox">
<label class="ui-corner-all ui-btn-inherit ui-btn-icon-left ui-icon-checkbox-off ui-checkbox-off">
<!--label class="ui-corner-all ui-btn-inherit"-->
<input type="checkbox" value="" name="{{name}}">
</label>
</div>
</li>
{{/documentlist}}
</ul>
</script>
</head>
<body>
<div class="ui-grid-a ui-responsive">
<div class="ui-block-a">
<form class="new_form">
<button type="submit" class="ui-btn ui-btn ui-btn-inline ui-icon-plus ui-btn-icon-right">Default</button>
</form>
<form class="import_form">
<input id="dream_import" type="file" required=""
name="dream_import" class="ui-btn ui-btn-b ui-btn-inline">
<button type="submit" class="ui-btn ui-btn ui-btn-inline ui-icon-plus ui-btn-icon-right">Import</button>
</form>
</div>
<div class="ui-block-b">
<form method="post" action="#">
<input type="hidden" name="method" value="delete_status" ></input>
<section class="document_list"></section>
<!--ul data-role="listview" class="document-list" data-inset="true"></ul-->
<div class="ui-input-btn ui-btn ui-icon-delete ui-btn-inline ui-btn-icon-left">
Delete
<input type="submit" data-enhanced="true" value="Delete">
</div>
</form>
</div>
</div>
</body>
</html>
/*global $, rJS, RSVP, promiseEventListener, promiseReadAsText,
initGadgetMixin, Handlebars, console */
(function(window, rJS, RSVP, promiseEventListener, promiseReadAsText, initGadgetMixin, Handlebars) {
/* Handlebars*/
"use strict";
// delete last session document
function removeLastSession(gadget, name) {
var now = new Date(), documents, element_list, element, i, len, promise_list;
promise_list = [];
gadget.aq_allDocs({
include_docs: true,
query: 'type:= "DreamLastInstance"',
select_list: [ "title", "modified" ]
}).push(function(docs) {
documents = docs;
if (documents.data.total_rows === undefined) {
console.log("Last instance data is undefined");
} else if (documents.data.total_rows === 0) {
console.log("There is no record of DreamLastInstance type");
} else if (documents.data.total_rows > 0) {
//aq_remove should be performed here
element_list = documents.data.rows;
for (i = 0, len = element_list.length; i < len; i += 1) {
element = element_list[i];
//.nextSibling;
promise_list[i] = gadget.aq_remove({
_id: element.id
});
}
}
});
// create last instance jIO document
promise_list[promise_list.length] = gadget.aq_post({
title: name,
type: "DreamLastInstance",
format: "application/json",
modified: now.toUTCString(),
date: now.getFullYear() + "-" + (now.getMonth() + 1) + "-" + now.getDate()
});
return RSVP.all(promise_list);
}
// create a jIO document
function createDocument(gadget, name) {
var now = new Date(), documents, element_list, element, i, len, promise_list;
promise_list = [];
gadget.aq_allDocs({
include_docs: true,
query: 'type:= "DreamLastInstance"',
select_list: [ "title", "modified" ]
}).push(function(docs) {
documents = docs;
if (documents.data.total_rows === undefined) {
console.log("Last instance data is undefined");
} else if (documents.data.total_rows === 0) {
console.log("There is no record in the last", "instance list, can proceed without deleting");
} else if (documents.data.total_rows > 0) {
//aq_remove should be performed here
element_list = documents.data.rows;
for (i = 0, len = element_list.length; i < len; i += 1) {
element = element_list[i];
//.nextSibling;
promise_list[i] = gadget.aq_remove({
_id: element.id
});
}
}
});
// Create jIO document
promise_list[promise_list.length] = gadget.aq_post({
title: name,
type: "DreamInstance",
format: "application/json",
modified: now.toUTCString(),
date: now.getFullYear() + "-" + (now.getMonth() + 1) + "-" + now.getDate()
});
// create last instance jIO document
promise_list[promise_list.length] = gadget.aq_post({
title: name,
type: "DreamLastInstance",
format: "application/json",
modified: now.toUTCString(),
date: now.getFullYear() + "-" + (now.getMonth() + 1) + "-" + now.getDate()
});
return RSVP.all(promise_list);
}
function waitForImport(gadget) {
// here import definition dict from a local file
var json_data, name;
return new RSVP.Queue().push(function() {
return promiseEventListener(gadget.props.element.getElementsByClassName("import_form")[0], "submit", false);
}).push(function(evt) {
// Prevent double click
evt.target.getElementsByClassName("ui-btn")[0].disabled = true;
var file = evt.target.dream_import.files[0];
name = file.name;
return promiseReadAsText(file);
}).push(function(json) {
json_data = json;
gadget.configurationIsSet(true);
gadget.setConfigurationDict(json_data);
return createDocument(gadget, name);
}).push(function(jio_document_list) {
// Add JSON as attachment
return RSVP.all([ gadget.aq_putAttachment({
_id: jio_document_list[0].id,
_attachment: "body.json",
_data: json_data,
_mimetype: "application/json"
}), gadget.aq_putAttachment({
_id: jio_document_list[1].id,
_attachment: "body.json",
_data: json_data,
_mimetype: "application/json"
}) ]);
});
}
function waitForDefault(gadget) {
var name = "DefaultInstance", json_data = {};
return new RSVP.Queue().push(function() {
return promiseEventListener(gadget.props.element.getElementsByClassName("new_form")[0], "submit", false);
}).push(function(evt) {
// Prevent double click
evt.target.getElementsByClassName("ui-btn")[0].disabled = true;
}).push(function() {
//return gadget.getConfigurationDict();
return gadget.getDefaultConfigurationDict();
}).push(function(data) {
json_data = data || {};
gadget.configurationIsSet(true);
return createDocument(gadget, name);
}).push(function(jio_document_list) {
// Add JSON as attachment
return RSVP.all([ gadget.aq_putAttachment({
_id: jio_document_list[0].id,
_attachment: "body.json",
_data: JSON.stringify(json_data),
_mimetype: "application/json"
}), gadget.aq_putAttachment({
_id: jio_document_list[1].id,
_attachment: "body.json",
_data: JSON.stringify(json_data),
_mimetype: "application/json"
}) ]);
});
}
var gadget_klass = rJS(window), source = gadget_klass.__template_element.getElementById("table-template").innerHTML, table_template = Handlebars.compile(source);
initGadgetMixin(gadget_klass);
gadget_klass.declareAcquiredMethod("aq_post", "jio_post").declareAcquiredMethod("aq_allDocs", "jio_allDocs").declareAcquiredMethod("aq_putAttachment", "jio_putAttachment").declareAcquiredMethod("aq_getAttachment", "jio_getAttachment").declareAcquiredMethod("aq_remove", "jio_remove").declareAcquiredMethod("whoWantsToDisplayHome", "whoWantsToDisplayHome").declareAcquiredMethod("pleaseRedirectMyHash", "pleaseRedirectMyHash").declareAcquiredMethod("whoWantsToDisplayThisDocument", "whoWantsToDisplayThisDocument").declareAcquiredMethod("aq_startListenTo", "startListenTo").declareAcquiredMethod("getConfigurationDict", "getConfigurationDict").declareAcquiredMethod("getDefaultConfigurationDict", "getDefaultConfigurationDict").declareAcquiredMethod("configurationIsSet", "configurationIsSet").declareAcquiredMethod("setConfigurationDict", "setConfigurationDict").ready(function(gadget) {
gadget.state_parameter_dict = {};
}).declareMethod("render", function() {
console.log("VIEWADDINSTANCE RENDER 1");
var gadget, doc_list, innerHTML;
gadget = this;
doc_list = gadget.props.element.querySelector(".document_list");
console.log("list created? 1");
console.log(doc_list);
// helper: add options to selects
function makeListItems(row_list) {
console.log("MAKEDOCUMENTLIST 1");
var i, len, record, item, //button, box, label, fragment
param_list;
//test;
param_list = [];
//fragment = document.createDocumentFragment();
len = row_list.length;
if (len === 1) {
if (row_list[0].doc === "none") {
item = document.createElement("div");
item.innerHTML = "no records";
doc_list.appendChild(item);
} else {
record = row_list[0].doc;
param_list[0] = {
title: record.title + " (" + record.date + ")",
name: "record_" + record._id,
date: new Date(record.date)
};
}
} else {
for (i = 0; i < len; i += 1) {
record = row_list[i].doc;
param_list[i] = {
title: record.title + " (" + record.date + ")",
name: "record_" + record._id,
date: new Date(record.date)
};
}
param_list.sort(function(a, b) {
return b.date - a.date;
});
}
innerHTML = table_template({
documentlist: param_list
});
console.log("MAKEDOCUMENTLIST 2");
}
// helper: select a configuration dictionary from a doc
function handleDictSelect(e) {
var form, element, id, json_data;
//prevent default
e.preventDefault();
form = e.target;
element = form.querySelector("div.ui-focus");
if (element === null || element === "undefined") {
console.log(0);
element = form.querySelector("input.ui-state-focus");
console.log(element);
id = element.name.replace("record_", "");
} else {
id = element.childNodes[1].name.replace("record_", "");
}
return gadget.aq_getAttachment({
_id: id,
_attachment: "body.json"
}).push(function(json) {
json_data = json;
gadget.configurationIsSet(true);
gadget.setConfigurationDict(json_data);
}).push(function() {
console.log("to remove last session");
return removeLastSession(gadget);
}).push(function(jio_document_list) {
// receive jio_document_list
return gadget.aq_putAttachment({
_id: jio_document_list[0].id,
_attachment: "body.json",
_data: JSON.stringify(json_data),
_mimetype: "application/json"
});
}).push(function() {
return gadget.whoWantsToDisplayThisDocument(id);
}).push(function(url) {
return gadget.pleaseRedirectMyHash(url);
});
}
// helper: delete a doc
function handleDelete(e) {
var form, element_list, promise_list, i, len, element, list_element, id, fragment, $doc;
//prevent default
console.log("HANDLING DELETE 1");
e.preventDefault();
form = e.target;
promise_list = [];
element_list = form.querySelectorAll("label.ui-checkbox-on");
console.log(element_list);
if (element_list) {
for (i = 0, len = element_list.length; i < len; i += 1) {
element = element_list[i].nextSibling;
id = element.name.replace("record_", "");
console.log(id);
list_element = element.parentNode.parentNode.parentNode;
console.log(list_element);
list_element.parentNode.removeChild(list_element);
if (form.querySelector("ul").children.length === 0) {
fragment = document.createElement("li");
fragment.innerHTML = "No records";
form.querySelector("ul").appendChild(fragment);
}
promise_list[i] = gadget.aq_remove({
_id: id
});
}
// enhance/refresh
$doc = $(doc_list);
if ($doc.listview("instance")) {
$doc.listview("refresh");
}
}
console.log("HANDLING DELETE 2");
console.log("list created? 1");
console.log(doc_list);
return RSVP.all(promise_list);
}
return gadget.aq_allDocs({
include_docs: true,
query: 'type:= "DreamInstance"',
select_list: [ "title", "modified" ]
}).push(function(document_list) {
var len, data, $doc;
data = document_list.data;
len = data.total_rows;
if (len > 0) {
makeListItems(data.rows);
} else {
makeListItems([ {
doc: "none"
} ]);
}
// append
while (doc_list.firstChild) {
doc_list.removeChild(doc_list.firstChild);
}
console.log("list created? last");
console.log(doc_list);
doc_list.innerHTML = innerHTML;
// enhance/refresh
$doc = $(doc_list);
if ($doc.listview("instance")) {
$doc.listview("refresh");
}
}).push(function() {
console.log("VIEWADDINSTANCE RENDER 3");
if (!gadget.state_parameter_dict.bound) {
gadget.state_parameter_dict.bound = true;
return RSVP.all([ gadget.aq_startListenTo(gadget.props.element.getElementsByTagName("FORM")[2], "submit", handleDelete), // XXXXXXXXXXXXXXXXXXXXX
gadget.aq_startListenTo(gadget.props.element.getElementsByTagName("FORM")[2], "submit", handleDictSelect) ]);
}
});
}).declareMethod("startService", function() {
console.log("VIEWADDINSTANCE STARTSERVICE 1");
var gadget = this;
return new RSVP.Queue().push(function() {
console.log("VIEWADDINSTANCE STARTSERVICE 2");
return RSVP.any([ waitForImport(gadget), waitForDefault(gadget) ]);
}).push(function(result) {
console.log("VIEWADDINSTANCE STARTSERVICE 3");
return gadget.whoWantsToDisplayThisDocument(result[0].id);
}).push(function(url) {
console.log("VIEWADDINSTANCE STARTSERVICE 4");
return gadget.pleaseRedirectMyHash(url);
});
});
})(window, rJS, RSVP, promiseEventListener, promiseReadAsText, initGadgetMixin, Handlebars);
\ No newline at end of file
......@@ -3,6 +3,7 @@
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="../lib/jquery-ui.css">
<link rel="stylesheet" href="../lib/jquerymobile.css">
<link rel="stylesheet" href="jsplumb.css">
<script src="../lib/jquery.js"></script>
......
......@@ -17,27 +17,11 @@
* along with DREAM. If not, see <http://www.gnu.org/licenses/>.
* ==========================================================================*/
/*global RSVP, rJS, $, jsPlumb, Handlebars, initGadgetMixin,
loopEventListener, promiseEventListener, DOMParser, confirm */
loopEventListener, promiseEventListener, DOMParser, confirm, console*/
/*jslint unparam: true todo: true */
(function(RSVP, rJS, $, jsPlumb, Handlebars, initGadgetMixin, loopEventListener, promiseEventListener, DOMParser) {
"use strict";
/*jslint nomen: true */
/* TODO:
* - make node edition popup a gadget ?
* - add function to turn event handlers in promise ?
*
* tests:
* - loading & saving DONE
* - dropping a new node from palette DONE
* - dragging a node
* - editing node properties with popup (make sure we can display after
* edit)
* - connecting two nodes
* - removing a connection
* - removing a node ( make sure connections are removed )
* - changing a node id ( make sure connections are updated ) ( make sure
* we can display after edit )
*/
var gadget_klass = rJS(window), node_template_source = gadget_klass.__template_element.getElementById("node-template").innerHTML, node_template = Handlebars.compile(node_template_source), popup_edit_template = gadget_klass.__template_element.getElementById("popup-edit-template"), domParser = new DOMParser();
function loopJsplumbBind(gadget, type, callback) {
//////////////////////////
......@@ -74,22 +58,31 @@
return new RSVP.Promise(resolver, canceller);
}
function getNodeId(gadget, element_id) {
console.log("getNODEID 1");
// returns the ID of the node in the graph from its DOM element id
var node_id;
$.each(gadget.props.node_id_to_dom_element_id, function(k, v) {
console.log(k);
console.log(v);
console.log(element_id);
if (v === element_id) {
node_id = k;
return false;
}
});
console.log("getNODEID 2");
console.log(node_id);
console.log(gadget.props.data.graph.main_graph.node);
return node_id;
}
function generateNodeId(gadget, element) {
console.log("generateNODEID 1");
// Generate a node id
var n = 1, class_def = gadget.props.data.class_definition[element._class], id = class_def.short_id || element._class;
while (gadget.props.data.graph.node[id + n] !== undefined) {
var n = 1, class_def = gadget.props.data.class_definition[element._class], id = class_def.allOf[1].properties.id._default || element._class;
while (gadget.props.data.graph.main_graph.node[id + n] !== undefined) {
n += 1;
}
console.log("generateNODEID 2");
return id + n;
}
function generateDomElementId(gadget_element) {
......@@ -102,14 +95,14 @@
}
function updateConnectionData(gadget, connection, remove, edge_data) {
if (remove) {
delete gadget.props.data.graph.edge[connection.id];
delete gadget.props.data.graph.main_graph.edge[connection.id];
} else {
edge_data = edge_data || {
_class: "Dream.Edge"
};
edge_data.source = getNodeId(gadget, connection.sourceId);
edge_data.destination = getNodeId(gadget, connection.targetId);
gadget.props.data.graph.edge[connection.id] = edge_data;
gadget.props.data.graph.main_graph.edge[connection.id] = edge_data;
}
gadget.notifyDataChanged();
}
......@@ -142,17 +135,22 @@
return [ left, top ];
}
function updateElementCoordinate(gadget, node_id, coordinate) {
console.log("updateELEMENTCOORDINATE 1");
var element_id = gadget.props.node_id_to_dom_element_id[node_id], element, relative_position;
console.log("updateELEMENTCOORDINATE 2");
if (coordinate === undefined) {
element = $(gadget.props.element).find("#" + element_id);
console.log("updateELEMENTCOORDINATE 3");
relative_position = convertToRelativePosition(gadget, element.css("left"), element.css("top"));
coordinate = {
left: relative_position[0],
top: relative_position[1]
};
console.log("updateELEMENTCOORDINATE 4");
}
gadget.props.data.graph.node[node_id].coordinate = coordinate;
gadget.props.data.graph.main_graph.node[node_id].coordinate = coordinate;
gadget.notifyDataChanged();
console.log("updateELEMENTCOORDINATE 5");
return coordinate;
}
function draggable(gadget) {
......@@ -269,32 +267,41 @@
// );
// }
function removeElement(gadget, node_id) {
console.log("removeELEMENT 1");
var element_id = gadget.props.node_id_to_dom_element_id[node_id];
gadget.props.jsplumb_instance.removeAllEndpoints($(gadget.props.element).find("#" + element_id));
console.log("removeELEMENT 2");
$(gadget.props.element).find("#" + element_id).remove();
delete gadget.props.data.graph.node[node_id];
$.each(gadget.props.data.graph.edge, function(k, v) {
delete gadget.props.data.graph.main_graph.node[node_id];
delete gadget.props.node_id_to_dom_element_id[node_id];
console.log("removeELEMENT 3");
$.each(gadget.props.data.graph.main_graph.edge, function(k, v) {
if (node_id === v.source || node_id === v.destination) {
delete gadget.props.data.graph.edge[k];
delete gadget.props.data.graph.main_graph.edge[k];
}
});
gadget.notifyDataChanged();
console.log("removeELEMENT 4");
}
function updateElementData(gadget, node_id, data) {
console.log("updateELEMENTDATA 1");
var element_id = gadget.props.node_id_to_dom_element_id[node_id], new_id = data.id;
if (data.data.name) {
$(gadget.props.element).find("#" + element_id).text(data.data.name).append('<div class="ep"></div></div>');
gadget.props.data.graph.node[node_id].name = data.data.name;
$(gadget.props.element).find("#" + element_id).text(data.data.name).attr("title", data.data.name).append('<div class="ep"></div></div>');
gadget.props.data.graph.main_graph.node[node_id].name = data.data.name;
}
console.log("updateELEMENTDATA 2");
delete data.id;
$.extend(gadget.props.data.graph.node[node_id], data.data);
$.extend(gadget.props.data.graph.main_graph.node[node_id], data.data);
console.log("updateELEMENTDATA 3");
if (new_id && new_id !== node_id) {
gadget.props.data.graph.node[new_id] = gadget.props.data.graph.node[node_id];
delete gadget.props.data.graph.node[node_id];
gadget.props.data.graph.main_graph.node[new_id] = gadget.props.data.graph.main_graph.node[node_id];
delete gadget.props.data.graph.main_graph.node[node_id];
gadget.props.node_id_to_dom_element_id[new_id] = gadget.props.node_id_to_dom_element_id[node_id];
delete gadget.props.node_id_to_dom_element_id[node_id];
delete gadget.props.data.graph.node[new_id].id;
$.each(gadget.props.data.graph.edge, function(k, v) {
console.log("updateELEMENTDATA 5");
delete gadget.props.data.graph.main_graph.node[new_id].id;
$.each(gadget.props.data.graph.main_graph.edge, function(k, v) {
if (v.source === node_id) {
v.source = new_id;
}
......@@ -302,7 +309,9 @@
v.destination = new_id;
}
});
console.log("updateELEMENTDATA 6");
}
console.log("updateELEMENTDATA 7");
gadget.notifyDataChanged();
}
function addEdge(gadget, edge_id, edge_data) {
......@@ -328,14 +337,17 @@
// minimal expanding of json schema, supports merging allOf and $ref
// references
// TODO: check for a library with full support
console.log("expandSCHEMA 1");
var property, referenced, i, expanded_class_definition = {
properties: class_definition.properties || {}
};
}, ref_word_list, ref_word;
if (class_definition.allOf) {
for (i = 0; i < class_definition.allOf.length; i += 1) {
referenced = class_definition.allOf[i];
if (referenced.$ref) {
referenced = expandSchema(full_schema.class_definition[referenced.$ref.substr(1, referenced.$ref.length)], full_schema);
ref_word_list = referenced.$ref.split("/");
ref_word = ref_word_list[ref_word_list.length - 1];
referenced = expandSchema(full_schema.class_definition[ref_word], full_schema);
}
if (referenced.properties) {
for (property in referenced.properties) {
......@@ -348,22 +360,38 @@
}
}
}
console.log("expandSCHEMA 1");
return expanded_class_definition;
}
// TODO: remove class_definition from this function and callees signature
function openNodeDialog(gadget, element, class_definition) {
var node_id = getNodeId(gadget, element.id), node_data = gadget.props.data.graph.node[node_id], node_edit_popup = $(gadget.props.element).find("#popup-edit-template"), schema = expandSchema(class_definition, gadget.props.data), fieldset_element, delete_promise;
console.log("openNODEDIALOG 1");
console.log(class_definition);
var node_id = getNodeId(gadget, element.id), node_data = gadget.props.data.graph.main_graph.node[node_id], node_edit_popup = $(gadget.props.element).find("#popup-edit-template"), schema = expandSchema(class_definition, gadget.props.data), fieldset_element, delete_promise;
console.log("openNODEDIALOG 1.1");
if (node_edit_popup.length !== 0) {
node_edit_popup.remove();
}
console.log("openNODEDIALOG 1.2");
gadget.props.element.appendChild(document.importNode(popup_edit_template.content, true).children[0]);
console.log("openNODEDIALOG 1.3");
node_edit_popup = $(gadget.props.element).find("#node-edit-popup");
console.log("openNODEDIALOG 1.35");
console.log(node_edit_popup);
console.log(node_edit_popup.find(".node_class"));
console.log(gadget.props.data.graph.main_graph.node);
console.log(node_data);
console.log(node_edit_popup.find(".node_class").text(node_data._class));
// Set the name of the popup to the node class
node_edit_popup.find(".node_class").text(node_data._class);
console.log("openNODEDIALOG 1.4");
fieldset_element = node_edit_popup.find("fieldset")[0];
console.log("openNODEDIALOG 1.5");
node_edit_popup.popup();
console.log("openNODEDIALOG 1.6");
node_data.id = node_id;
// XXX
console.log("openNODEDIALOG 2");
function save_promise(fieldset_gadget, node_id) {
return RSVP.Queue().push(function() {
return promiseEventListener(node_edit_popup.find("form")[0], "submit", false);
......@@ -379,12 +407,13 @@
});
});
}
console.log("openNODEDIALOG 3");
delete_promise = new RSVP.Queue().push(function() {
return promiseEventListener(node_edit_popup.find("form [type='button']")[0], "click", false);
}).push(function() {
return removeElement(gadget, node_id);
});
// XXX the gadget to use on node click should be an option
console.log("openNODEDIALOG 4");
return gadget.declareGadget("../fieldset/index.html", {
element: fieldset_element,
scope: "fieldset"
......@@ -398,27 +427,43 @@
node_edit_popup.popup("open");
return fieldset_gadget[0];
}).push(function(fieldset_gadget) {
return RSVP.any([ save_promise(fieldset_gadget, node_id), delete_promise ]);
// Expose the dialog handling promise so that we can wait for it in
// test.
gadget.props.dialog_promise = RSVP.any([ // TODO: why different signature ?
save_promise(fieldset_gadget, node_id), delete_promise ]);
return gadget.props.dialog_promise;
}).push(function() {
node_edit_popup.popup("close");
node_edit_popup.remove();
delete gadget.props.dialog_promise;
});
}
function waitForNodeClick(gadget, node, config_dict) {
console.log("waitFORNODEclick 1");
gadget.props.nodes_click_monitor.monitor(loopEventListener(node, "dblclick", false, openNodeDialog.bind(null, gadget, node, config_dict)));
}
function addNode(gadget, node_id, node_data) {
console.log("addNODE 0");
console.log(node_data);
var render_element = $(gadget.props.element).find("#main"), class_definition = gadget.props.data.class_definition[node_data._class], coordinate = node_data.coordinate, dom_element_id, box, absolute_position, domElement;
console.log("addNODE 1");
dom_element_id = generateDomElementId(gadget.props.element);
gadget.props.node_id_to_dom_element_id[node_id] = dom_element_id;
console.log("addNODE 2");
node_data.name = node_data.name || class_definition.name;
gadget.props.data.graph.node[node_id] = node_data;
console.log("addNODE 2.5");
gadget.props.data.graph.main_graph.node[node_id] = node_data;
console.log("addNODE 3");
if (coordinate === undefined) {
coordinate = {
top: 0,
left: 0
};
}
console.log("addNODE 4");
node_data.coordinate = updateElementCoordinate(gadget, node_id, coordinate);
console.log("addNODE 4.5");
console.log(node_data);
// XXX make node template an option, or use CSS from class_definition
/*jslint nomen: true*/
domElement = domParser.parseFromString(node_template({
......@@ -428,27 +473,40 @@
name: node_data.name || node_data.id
}), "text/html").querySelector(".window");
render_element.append(domElement);
console.log("addNODE 5");
waitForNodeClick(gadget, domElement, class_definition);
box = $(gadget.props.element).find("#" + dom_element_id);
absolute_position = convertToAbsolutePosition(gadget, coordinate.left, coordinate.top);
console.log("addNODE 6");
box.css("top", absolute_position[1]);
box.css("left", absolute_position[0]);
updateNodeStyle(gadget, dom_element_id);
draggable(gadget);
gadget.notifyDataChanged();
console.log("addNODE 7");
}
function waitForDrop(gadget) {
console.log("wait for DROP 1");
var callback;
function canceller() {
console.log("wait for DROP canceler1");
if (callback !== undefined) {
console.log("wait for DROP canceller2");
gadget.props.main.removeEventListener("drop", callback, false);
}
}
/*jslint unparam: true*/
function resolver(resolve, reject) {
console.log("wait for DROP resolver1");
callback = function(evt) {
console.log("wait for DROP resolver2");
try {
console.log("wait for DROP resolver3");
var class_name = JSON.parse(evt.dataTransfer.getData("application/json")), offset = $(gadget.props.main).offset(), relative_position = convertToRelativePosition(gadget, evt.clientX - offset.left + "px", evt.clientY - offset.top + "px");
console.log("wait for DROP resolver4");
console.log(class_name);
console.log(offset);
console.log(relative_position);
addNode(gadget, generateNodeId(gadget, {
_class: class_name
}), {
......@@ -458,12 +516,15 @@
},
_class: class_name
});
console.log("wait for DROP resolver5");
} catch (e) {
console.log("wait for DROP resolver100");
reject(e);
}
};
gadget.props.main.addEventListener("drop", callback, false);
}
console.log("wait for DROP 2");
return new RSVP.all([ // loopEventListener adds an event listener that will prevent default for
// dragover
loopEventListener(gadget.props.main, "dragover", false, function() {
......@@ -476,21 +537,25 @@
g.props.zoom_level = 1;
g.props.style_attr_list = [ "width", "height", "padding-top", "line-height" ];
}).declareMethod("render", function(data) {
console.log("RENDEERING WORKFLOW EDITOR1");
this.props.data = JSON.parse(data);
this.props.jsplumb_instance = jsPlumb.getInstance();
console.log("RENDEERING WORKFLOW EDITOR3");
}).declareMethod("getContent", function() {
return JSON.stringify(this.props.data);
}).declareMethod("startService", function() {
console.log("startservice WORKFLOW EDITOR1");
var gadget = this;
this.props.main = this.props.element.querySelector("#main");
initJsPlumb(this);
this.props.nodes_click_monitor = RSVP.Monitor();
$.each(this.props.data.graph.node, function(key, value) {
$.each(this.props.data.graph.main_graph.node, function(key, value) {
addNode(gadget, key, value);
});
$.each(this.props.data.graph.edge, function(key, value) {
$.each(this.props.data.graph.main_graph.edge, function(key, value) {
addEdge(gadget, key, value);
});
console.log("startservice WORKFLOW EDITOR2");
return RSVP.all([ waitForDrop(gadget), waitForConnection(gadget), waitForConnectionDetached(gadget), waitForConnectionClick(gadget), gadget.props.nodes_click_monitor ]);
});
})(RSVP, rJS, $, jsPlumb, Handlebars, initGadgetMixin, loopEventListener, promiseEventListener, DOMParser);
\ No newline at end of file
/*global rJS, JSON, QUnit, jQuery, RSVP, console*/
/*global rJS, JSON, QUnit, jQuery, RSVP, console, setTimeout*/
(function(rJS, JSON, QUnit, RSVP, $) {
"use strict";
var start = QUnit.start, stop = QUnit.stop, test = QUnit.test, equal = QUnit.equal, ok = QUnit.ok, sample_class_definition = {
var start = QUnit.start, stop = QUnit.stop, test = QUnit.test, equal = QUnit.equal, ok = QUnit.ok, error_handler = function(e) {
console.error(e);
ok(false, e);
}, sample_class_definition = {
edge: {
description: "Base definition for edge",
properties: {
......@@ -133,7 +136,7 @@
return jsplumb_gadget.getContent();
}).then(function(content) {
equal(content, sample_data_graph);
}).fail(console.error.bind(this)).always(start);
}).fail(error_handler).always(start);
});
test("New node can be drag & dropped", function() {
var jsplumb_gadget;
......@@ -147,7 +150,7 @@
e.dataTransfer = {
getData: function(type) {
// make sure we are called properly
equal(type, "application/json");
equal("application/json", type, "The drag&dropped element must have data type application/json");
return JSON.stringify("Example.Node");
}
};
......@@ -168,7 +171,7 @@
jsplumb_gadget.render(sample_data_empty_graph);
}).then(function() {
return RSVP.any([ jsplumb_gadget.startService(), runTest() ]);
}).fail(console.error.bind(this)).always(start);
}).fail(error_handler).always(start);
});
test("Node can be dragged", function() {
var jsplumb_gadget;
......@@ -198,22 +201,49 @@
jsplumb_gadget.render(sample_data_graph);
}).then(function() {
return RSVP.any([ jsplumb_gadget.startService(), runTest() ]);
}).fail(console.error.bind(this)).always(start);
}).fail(error_handler).always(start);
});
test("Node properties can be edited", function() {
var jsplumb_gadget;
stop();
function runTest() {
return jsplumb_gadget.getContent().then(function() {
// click on a node to see display the popup
$("div[title='Node 1']").simulate("dblclick");
// XXX popup not displayed
$("input[name='name']").val("Modified Name");
$("input[value='Validate']").click();
}).then(function() {
return jsplumb_gadget.getContent();
}).then(function(content) {
var graph = JSON.parse(content).graph, node = graph.node.N1;
equal(node.name, "Modified Name");
// Promises that handle the dialog actions are not available
// immediately after clicking.
var promise = RSVP.Promise(function(resolve) {
var fillDialog = function() {
if (!jsplumb_gadget.props.dialog_promise) {
// Dialog not ready. Let's retry later.
// XXX this condition is actually incorrect. We need to wait
// for the event listener to have been registered for the
// dialog buttons. This setTimeout is good enough for now.
return setTimeout(fillDialog, 1e3);
}
// check displayed values
equal($("input[name='id']").val(), "N1");
equal($("input[name='name']").val(), "Node 1");
equal($("input[name='shape']").val(), "square");
// change the name
$("input[name='name']").val("Modified Name");
equal(1, $("input[value='Validate']").length, "There should be one validate button");
// and save
$("input[value='Validate']").click();
// resolve our test promise once the dialog handling promise is
// finished.
jsplumb_gadget.props.dialog_promise.then(resolve);
};
fillDialog();
});
return promise.then(function() {
return jsplumb_gadget.getContent().then(function(content) {
var graph = JSON.parse(content).graph, node = graph.node.N1;
equal("Modified Name", node.name, "Data is modified");
equal("Modified Name", $("div#" + jsplumb_gadget.props.node_id_to_dom_element_id.N1).text(), "DOM is modified");
equal(1, $("div[title='Modified Name']").length, "DOM title attribute is modified");
});
});
});
}
g.declareGadget("./index.html", {
......@@ -223,7 +253,7 @@
jsplumb_gadget.render(sample_data_graph);
}).then(function() {
return RSVP.any([ jsplumb_gadget.startService(), runTest() ]);
}).fail(console.error.bind(this)).always(start);
}).fail(error_handler).always(start);
});
test("Node can be connected", function() {
var jsplumb_gadget;
......@@ -231,8 +261,7 @@
function runTest() {
return jsplumb_gadget.getContent().then(function(content) {
var node1 = jsplumb_gadget.props.main.querySelector("div[title='Node 1']"), node2 = jsplumb_gadget.props.main.querySelector("div[title='Node 2']");
// At this point we have no edge
equal(Object.keys(JSON.parse(content).graph.edge).length, 0);
equal(0, Object.keys(JSON.parse(content).graph.edge).length, "There are no edge at the beginning");
jsplumb_gadget.props.jsplumb_instance.connect({
source: node1.id,
target: node2.id
......@@ -241,13 +270,13 @@
return jsplumb_gadget.getContent();
}).then(function(content) {
var edge, graph = JSON.parse(content).graph;
equal(Object.keys(graph.node).length, 2);
equal(Object.keys(graph.edge).length, 1);
equal(2, Object.keys(graph.node).length, "We still have 2 nodes");
equal(1, Object.keys(graph.edge).length, "We have 1 edge");
edge = graph.edge[Object.keys(graph.edge)[0]];
// XXX how edge class would be set ? the first one from schema ?
//equal(edge._class, "Example.Edge");
equal(edge.source, "N1");
equal(edge.destination, "N2");
//equal("Example.Edge", edge._class, "Edge class is correct");
equal("N1", edge.source, "edge source is correct");
equal("N2", edge.destination, "edge destination is correct");
});
}
g.declareGadget("./index.html", {
......@@ -257,31 +286,245 @@
jsplumb_gadget.render(sample_data_graph_not_connected);
}).then(function() {
return RSVP.any([ jsplumb_gadget.startService(), runTest() ]);
}).fail(console.error.bind(this)).always(start);
}).fail(error_handler).always(start);
});
test("Node can be deleted", function() {
var jsplumb_gadget;
stop();
function runTest() {
return jsplumb_gadget.getContent().then(function() {
equal(1, $("div[title='Node 1']").length, "node 1 is visible");
equal(1, $("._jsPlumb_connector").length, "there is 1 connection");
// click on node 1 to see display the popup
$("div[title='Node 1']").simulate("dblclick");
// Promises that handle the dialog actions are not available
// immediately after clicking.
var promise = RSVP.Promise(function(resolve) {
var waitForDialogAndDelete = function() {
if (!jsplumb_gadget.props.dialog_promise) {
// Dialog not ready. Let's retry later.
// XXX this condition is actually incorrect. We need to wait
// for the event listener to have been registered for the
// dialog buttons. This setTimeout is good enough for now.
return setTimeout(waitForDialogAndDelete, 1e3);
}
equal(1, $("input[value='Delete']").length, "There should be one delete button");
$("input[value='Delete']").click();
// resolve our test promise once the dialog handling promise is
// finished.
jsplumb_gadget.props.dialog_promise.then(resolve);
};
waitForDialogAndDelete();
});
return promise.then(function() {
return jsplumb_gadget.getContent().then(function(content) {
var graph = JSON.parse(content).graph;
equal(1, Object.keys(graph.node).length, "node is removed from data");
equal(0, Object.keys(graph.edge).length, "edge referencing this node is also removed");
equal(0, $("div[title='Node 1']").length, "DOM element for node is removed");
equal(0, $("._jsPlumb_connector").length, "DOM element for edge is removed");
});
});
});
}
g.declareGadget("./index.html", {
element: document.querySelector("#qunit-fixture")
}).then(function(new_gadget) {
jsplumb_gadget = new_gadget;
jsplumb_gadget.render(sample_data_graph);
}).then(function() {
return RSVP.any([ jsplumb_gadget.startService(), runTest() ]);
}).fail(error_handler).always(start);
});
test("Node id can be changed (connections are updated and node" + " can be edited afterwards)", function() {
var jsplumb_gadget;
stop();
function runTest() {
return jsplumb_gadget.getContent().then(function() {
// click on a node to see display the popup
$("div[title='Node 1']").simulate("dblclick");
// XXX popup not displayed
$("input[value='Delete']").click();
// Promises that handle the dialog actions are not available
// immediately after clicking.
var promise = RSVP.Promise(function(resolve) {
var fillDialog = function() {
if (!jsplumb_gadget.props.dialog_promise) {
// Dialog not ready. Let's retry later.
// XXX this condition is actually incorrect. We need to wait
// for the event listener to have been registered for the
// dialog buttons. This setTimeout is good enough for now.
return setTimeout(fillDialog, 1e3);
}
equal($("input[name='id']").val(), "N1");
// change the id
$("input[name='id']").val("N1b");
equal(1, $("input[value='Validate']").length, "There should be one validate button");
$("input[value='Validate']").click();
// resolve our test promise once the dialog handling promise is
// finished.
jsplumb_gadget.props.dialog_promise.then(resolve);
};
fillDialog();
});
return promise.then(function() {
return jsplumb_gadget.getContent().then(function(content) {
var graph = JSON.parse(content).graph;
equal(2, Object.keys(graph.node).length, "We still have two nodes");
ok(graph.node.N1b !== undefined, "Node Id changed");
equal(1, Object.keys(graph.edge).length, "We still have one connection");
equal("N1b", graph.edge.edge1.source, "Connection source has been updated");
});
});
});
}
g.declareGadget("./index.html", {
element: document.querySelector("#qunit-fixture")
}).then(function(new_gadget) {
jsplumb_gadget = new_gadget;
jsplumb_gadget.render(sample_data_graph);
}).then(function() {
return RSVP.any([ jsplumb_gadget.startService(), runTest() ]);
}).fail(error_handler).always(start);
});
test("New node can be edited", function() {
var jsplumb_gadget, node_id;
stop();
function runTest() {
// XXX here I used getContent to have a promise, but there must be a
// more elegant way.
return jsplumb_gadget.getContent().then(function() {
// fake a drop event
var e = new Event("drop");
e.dataTransfer = {
getData: function(type) {
// make sure we are called properly
equal("application/json", type, "The drag&dropped element must have data type application/json");
return JSON.stringify("Example.Node");
}
};
jsplumb_gadget.props.main.dispatchEvent(e);
}).then(function() {
return jsplumb_gadget.getContent();
}).then(function(content) {
var graph = JSON.parse(content).graph;
var node, graph = JSON.parse(content).graph;
equal(1, Object.keys(graph.node).length);
node_id = Object.keys(graph.node)[0];
node = graph.node[node_id];
equal("Example.Node", node._class);
}).then(function() {
// click the new node to see display the popup
// XXX at the moment nodes have class window
equal(1, $("div.window").length, "We have a new node");
$("div.window").simulate("dblclick");
// Promises that handle the dialog actions are not available
// immediately after clicking.
var promise = RSVP.Promise(function(resolve) {
var fillDialog = function() {
if (!jsplumb_gadget.props.dialog_promise) {
// Dialog not ready. Let's retry later.
// XXX this condition is actually incorrect. We need to wait
// for the event listener to have been registered for the
// dialog buttons. This setTimeout is good enough for now.
return setTimeout(fillDialog, 1e3);
}
// check displayed values
equal($("input[name='id']").val(), node_id);
equal($("input[name='name']").val(), "");
equal($("input[name='shape']").val(), "");
// change the name
$("input[name='name']").val("Modified Name");
equal(1, $("input[value='Validate']").length, "There should be one validate button");
// and save
$("input[value='Validate']").click();
// resolve our test promise once the dialog handling promise is
// finished.
jsplumb_gadget.props.dialog_promise.then(resolve);
};
fillDialog();
});
return promise.then(function() {
return jsplumb_gadget.getContent().then(function(content) {
var graph = JSON.parse(content).graph, node = graph.node[node_id];
equal("Modified Name", node.name, "Data is modified");
equal("Modified Name", $("div.window").text(), "DOM is modified");
});
});
});
}
g.declareGadget("./index.html", {
element: document.querySelector("#qunit-fixture")
}).then(function(new_gadget) {
jsplumb_gadget = new_gadget;
jsplumb_gadget.render(sample_data_graph);
jsplumb_gadget.render(sample_data_empty_graph);
}).then(function() {
return RSVP.any([ jsplumb_gadget.startService(), runTest() ]);
}).fail(error_handler).always(start);
});
test("New node can be deleted", function() {
var jsplumb_gadget, node_id;
stop();
function runTest() {
// XXX here I used getContent to have a promise, but there must be a
// more elegant way.
return jsplumb_gadget.getContent().then(function() {
// fake a drop event
var e = new Event("drop");
e.dataTransfer = {
getData: function(type) {
// make sure we are called properly
equal("application/json", type, "The drag&dropped element must have data type application/json");
return JSON.stringify("Example.Node");
}
};
jsplumb_gadget.props.main.dispatchEvent(e);
}).then(function() {
return jsplumb_gadget.getContent();
}).then(function(content) {
var node, graph = JSON.parse(content).graph;
equal(1, Object.keys(graph.node).length);
node_id = Object.keys(graph.node)[0];
node = graph.node[node_id];
equal("Example.Node", node._class);
}).then(function() {
// click the new node to see display the popup
// XXX at the moment nodes have class window
equal(1, $("div.window").length, "We have a new node");
$("div.window").simulate("dblclick");
// Promises that handle the dialog actions are not available
// immediately after clicking.
var promise = RSVP.Promise(function(resolve) {
var waitForDialogAndDelete = function() {
if (!jsplumb_gadget.props.dialog_promise) {
// Dialog not ready. Let's retry later.
// XXX this condition is actually incorrect. We need to wait
// for the event listener to have been registered for the
// dialog buttons. This setTimeout is good enough for now.
return setTimeout(waitForDialogAndDelete, 1e3);
}
equal(1, $("input[value='Delete']").length, "There should be one delete button");
$("input[value='Delete']").click();
// resolve our test promise once the dialog handling promise is
// finished.
jsplumb_gadget.props.dialog_promise.then(resolve);
};
waitForDialogAndDelete();
});
return promise.then(function() {
return jsplumb_gadget.getContent().then(function(content) {
var graph = JSON.parse(content).graph;
equal(0, Object.keys(graph.node).length, "node is removed from data");
equal(0, $("div.window").length, "DOM is modified");
});
});
});
}
g.declareGadget("./index.html", {
element: document.querySelector("#qunit-fixture")
}).then(function(new_gadget) {
jsplumb_gadget = new_gadget;
jsplumb_gadget.render(sample_data_empty_graph);
}).then(function() {
return RSVP.any([ jsplumb_gadget.startService(), runTest() ]);
}).fail(console.error.bind(this)).always(start);
}).fail(error_handler).always(start);
});
});
})(rJS, JSON, QUnit, RSVP, jQuery);
\ No newline at end of file
/*!
handlebars v2.0.0-alpha.4
handlebars v2.0.0
Copyright (C) 2011-2014 by Yehuda Katz
......@@ -24,5 +24,5 @@ THE SOFTWARE.
@license
*/
this.Handlebars=function(){var a=function(){"use strict";function a(a){this.string=a}var b;return a.prototype.toString=function(){return""+this.string},b=a}(),b=function(a){"use strict";function b(a){return i[a]||"&amp;"}function c(a){for(var b=1;b<arguments.length;b++)for(var c in arguments[b])Object.prototype.hasOwnProperty.call(arguments[b],c)&&(a[c]=arguments[b][c]);return a}function d(a){return a instanceof h?a.toString():a||0===a?(a=""+a,k.test(a)?a.replace(j,b):a):""}function e(a){return a||0===a?n(a)&&0===a.length?!0:!1:!0}function f(a,b){return(a?a+".":"")+b}var g={},h=a,i={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;","`":"&#x60;"},j=/[&<>"'`]/g,k=/[&<>"'`]/;g.extend=c;var l=Object.prototype.toString;g.toString=l;var m=function(a){return"function"==typeof a};m(/x/)&&(m=function(a){return"function"==typeof a&&"[object Function]"===l.call(a)});var m;g.isFunction=m;var n=Array.isArray||function(a){return a&&"object"==typeof a?"[object Array]"===l.call(a):!1};return g.isArray=n,g.escapeExpression=d,g.isEmpty=e,g.appendContextPath=f,g}(a),c=function(){"use strict";function a(a,b){var d;b&&b.firstLine&&(d=b.firstLine,a+=" - "+d+":"+b.firstColumn);for(var e=Error.prototype.constructor.call(this,a),f=0;f<c.length;f++)this[c[f]]=e[c[f]];d&&(this.lineNumber=d,this.column=b.firstColumn)}var b,c=["description","fileName","lineNumber","message","name","number","stack"];return a.prototype=new Error,b=a}(),d=function(a,b){"use strict";function c(a,b){this.helpers=a||{},this.partials=b||{},d(this)}function d(a){a.registerHelper("helperMissing",function(){if(1===arguments.length)return void 0;throw new h("Missing helper: '"+arguments[arguments.length-1].name+"'")}),a.registerHelper("blockHelperMissing",function(b,c){var d=c.inverse||function(){},e=c.fn;if(m(b)&&(b=b.call(this)),b===!0)return e(this);if(b===!1||null==b)return d(this);if(l(b))return b.length>0?(c.ids&&(c.ids=[c.name]),a.helpers.each(b,c)):d(this);if(c.data&&c.ids){var f=q(c.data);f.contextPath=g.appendContextPath(c.data.contextPath,c.name),c={data:f}}return e(b,c)}),a.registerHelper("each",function(a,b){b||(b=a,a=this);var c,d,e=b.fn,f=b.inverse,h=0,i="";if(b.data&&b.ids&&(d=g.appendContextPath(b.data.contextPath,b.ids[0])+"."),m(a)&&(a=a.call(this)),b.data&&(c=q(b.data)),a&&"object"==typeof a)if(l(a))for(var j=a.length;j>h;h++)c&&(c.index=h,c.first=0===h,c.last=h===a.length-1,d&&(c.contextPath=d+h)),i+=e(a[h],{data:c});else for(var k in a)a.hasOwnProperty(k)&&(c&&(c.key=k,c.index=h,c.first=0===h,d&&(c.contextPath=d+k)),i+=e(a[k],{data:c}),h++);return 0===h&&(i=f(this)),i}),a.registerHelper("if",function(a,b){return m(a)&&(a=a.call(this)),!b.hash.includeZero&&!a||g.isEmpty(a)?b.inverse(this):b.fn(this)}),a.registerHelper("unless",function(b,c){return a.helpers["if"].call(this,b,{fn:c.inverse,inverse:c.fn,hash:c.hash})}),a.registerHelper("with",function(a,b){m(a)&&(a=a.call(this));var c=b.fn;if(!g.isEmpty(a)){if(b.data&&b.ids){var d=q(b.data);d.contextPath=g.appendContextPath(b.data.contextPath,b.ids[0]),b={data:d}}return c(a,b)}}),a.registerHelper("log",function(b,c){var d=c.data&&null!=c.data.level?parseInt(c.data.level,10):1;a.log(d,b)}),a.registerHelper("lookup",function(a,b){return a&&a[b]})}function e(a,b){p.log(a,b)}var f={},g=a,h=b,i="2.0.0-alpha.4";f.VERSION=i;var j=5;f.COMPILER_REVISION=j;var k={1:"<= 1.0.rc.2",2:"== 1.0.0-rc.3",3:"== 1.0.0-rc.4",4:"== 1.x.x",5:">= 2.0.0"};f.REVISION_CHANGES=k;var l=g.isArray,m=g.isFunction,n=g.toString,o="[object Object]";f.HandlebarsEnvironment=c,c.prototype={constructor:c,logger:p,log:e,registerHelper:function(a,b,c){if(n.call(a)===o){if(c||b)throw new h("Arg not supported with multiple helpers");g.extend(this.helpers,a)}else c&&(b.not=c),this.helpers[a]=b},unregisterHelper:function(a){delete this.helpers[a]},registerPartial:function(a,b){n.call(a)===o?g.extend(this.partials,a):this.partials[a]=b},unregisterPartial:function(a){delete this.partials[a]}};var p={methodMap:{0:"debug",1:"info",2:"warn",3:"error"},DEBUG:0,INFO:1,WARN:2,ERROR:3,level:3,log:function(a,b){if(p.level<=a){var c=p.methodMap[a];"undefined"!=typeof console&&console[c]&&console[c].call(console,b)}}};f.logger=p,f.log=e;var q=function(a){var b=g.extend({},a);return b._parent=a,b};return f.createFrame=q,f}(b,c),e=function(a,b,c){"use strict";function d(a){var b=a&&a[0]||1,c=n;if(b!==c){if(c>b){var d=o[c],e=o[b];throw new m("Template was precompiled with an older version of Handlebars than the current runtime. Please update your precompiler to a newer version ("+d+") or downgrade your runtime to an older version ("+e+").")}throw new m("Template was precompiled with a newer version of Handlebars than the current runtime. Please update your runtime to a newer version ("+a[1]+").")}}function e(a,b){if(!b)throw new m("No environment passed to template");b.VM.checkRevision(a.compiler);var c=function(a,c,d,e,f,g,h){e&&(d=l.extend({},d,e));var i=b.VM.invokePartial.call(this,a,c,d,f,g,h);if(null!=i)return i;if(b.compile){var j={helpers:f,partials:g,data:h};return g[c]=b.compile(a,{data:void 0!==h},b),g[c](d,j)}throw new m("The partial "+c+" could not be compiled when running in runtime-only mode")},d={escapeExpression:l.escapeExpression,invokePartial:c,fn:function(b){return a[b]},programs:[],program:function(a,b){var c=this.programs[a],d=this.fn(a);return b?c=g(this,a,d,b):c||(c=this.programs[a]=g(this,a,d)),c},programWithDepth:b.VM.programWithDepth,data:function(a,b){for(;a&&b--;)a=a._parent;return a},merge:function(a,b){var c=a||b;return a&&b&&a!==b&&(c=l.extend({},b,a)),c},noop:b.VM.noop,compilerInfo:a.compiler},e=function(b,c){c=c||{};var f=c.data;return e._setup(c),!c.partial&&a.useData&&(f=j(b,f)),a.main.call(d,b,d.helpers,d.partials,f)};return e._setup=function(c){c.partial?(d.helpers=c.helpers,d.partials=c.partials):(d.helpers=d.merge(c.helpers,b.helpers),a.usePartial&&(d.partials=d.merge(c.partials,b.partials)))},e._child=function(a){return d.programWithDepth(a)},e}function f(a,b){var c=Array.prototype.slice.call(arguments,2),d=this,e=d.fn(a),f=function(a,f){return f=f||{},e.apply(d,[a,d.helpers,d.partials,f.data||b].concat(c))};return f.program=a,f.depth=c.length,f}function g(a,b,c,d){var e=function(b,e){return e=e||{},c.call(a,b,a.helpers,a.partials,e.data||d)};return e.program=b,e.depth=0,e}function h(a,b,c,d,e,f){var g={partial:!0,helpers:d,partials:e,data:f};if(void 0===a)throw new m("The partial "+b+" could not be found");return a instanceof Function?a(c,g):void 0}function i(){return""}function j(a,b){return b&&"root"in b||(b=b?p(b):{},b.root=a),b}var k={},l=a,m=b,n=c.COMPILER_REVISION,o=c.REVISION_CHANGES,p=c.createFrame;return k.checkRevision=d,k.template=e,k.programWithDepth=f,k.program=g,k.invokePartial=h,k.noop=i,k}(b,c,d),f=function(a,b,c,d,e){"use strict";var f,g=a,h=b,i=c,j=d,k=e,l=function(){var a=new g.HandlebarsEnvironment;return j.extend(a,g),a.SafeString=h,a.Exception=i,a.Utils=j,a.VM=k,a.template=function(b){return k.template(b,a)},a},m=l();return m.create=l,f=m}(d,a,c,b,e),g=function(a){"use strict";function b(a){a=a||{},this.firstLine=a.first_line,this.firstColumn=a.first_column,this.lastColumn=a.last_column,this.lastLine=a.last_line}var c,d=a,e={ProgramNode:function(a,c,d,f){var g,h;3===arguments.length?(f=d,d=null):2===arguments.length&&(f=c,c=null),b.call(this,f),this.type="program",this.statements=a,this.strip={},d?(h=d[0],h?(g={first_line:h.firstLine,last_line:h.lastLine,last_column:h.lastColumn,first_column:h.firstColumn},this.inverse=new e.ProgramNode(d,c,g)):this.inverse=new e.ProgramNode(d,c),this.strip.right=c.left):c&&(this.strip.left=c.right)},MustacheNode:function(a,c,d,f,g){if(b.call(this,g),this.type="mustache",this.strip=f,null!=d&&d.charAt){var h=d.charAt(3)||d.charAt(2);this.escaped="{"!==h&&"&"!==h}else this.escaped=!!d;this.sexpr=a instanceof e.SexprNode?a:new e.SexprNode(a,c),this.sexpr.isRoot=!0,this.id=this.sexpr.id,this.params=this.sexpr.params,this.hash=this.sexpr.hash,this.eligibleHelper=this.sexpr.eligibleHelper,this.isHelper=this.sexpr.isHelper},SexprNode:function(a,c,d){b.call(this,d),this.type="sexpr",this.hash=c;var e=this.id=a[0],f=this.params=a.slice(1);this.isHelper=!(!f.length&&!c),this.eligibleHelper=this.isHelper||e.isSimple},PartialNode:function(a,c,d,e,f){b.call(this,f),this.type="partial",this.partialName=a,this.context=c,this.hash=d,this.strip=e},BlockNode:function(a,c,e,f,g){if(b.call(this,g),a.sexpr.id.original!==f.path.original)throw new d(a.sexpr.id.original+" doesn't match "+f.path.original,this);this.type="block",this.mustache=a,this.program=c,this.inverse=e,this.strip={left:a.strip.left,right:f.strip.right},(c||e).strip.left=a.strip.right,(e||c).strip.right=f.strip.left,e&&!c&&(this.isInverse=!0)},RawBlockNode:function(a,c,f,g){if(b.call(this,g),a.sexpr.id.original!==f)throw new d(a.sexpr.id.original+" doesn't match "+f,this);c=new e.ContentNode(c,g),this.type="block",this.mustache=a,this.program=new e.ProgramNode([c],g)},ContentNode:function(a,c){b.call(this,c),this.type="content",this.string=a},HashNode:function(a,c){b.call(this,c),this.type="hash",this.pairs=a},IdNode:function(a,c){b.call(this,c),this.type="ID";for(var e="",f=[],g=0,h="",i=0,j=a.length;j>i;i++){var k=a[i].part;if(e+=(a[i].separator||"")+k,".."===k||"."===k||"this"===k){if(f.length>0)throw new d("Invalid path: "+e,this);".."===k?(g++,h+="../"):this.isScoped=!0}else f.push(k)}this.original=e,this.parts=f,this.string=f.join("."),this.depth=g,this.idName=h+this.string,this.isSimple=1===a.length&&!this.isScoped&&0===g,this.stringModeValue=this.string},PartialNameNode:function(a,c){b.call(this,c),this.type="PARTIAL_NAME",this.name=a.original},DataNode:function(a,c){b.call(this,c),this.type="DATA",this.id=a,this.stringModeValue=a.stringModeValue,this.idName="@"+a.stringModeValue},StringNode:function(a,c){b.call(this,c),this.type="STRING",this.original=this.string=this.stringModeValue=a},NumberNode:function(a,c){b.call(this,c),this.type="NUMBER",this.original=this.number=a,this.stringModeValue=Number(a)},BooleanNode:function(a,c){b.call(this,c),this.type="BOOLEAN",this.bool=a,this.stringModeValue="true"===a},CommentNode:function(a,c){b.call(this,c),this.type="comment",this.comment=a}};return c=e}(c),h=function(){"use strict";var a,b=function(){function a(a,b){return{left:"~"===a.charAt(2),right:"~"===b.charAt(0)||"~"===b.charAt(1)}}function b(){this.yy={}}var c={trace:function(){},yy:{},symbols_:{error:2,root:3,statements:4,EOF:5,program:6,simpleInverse:7,statement:8,openRawBlock:9,CONTENT:10,END_RAW_BLOCK:11,openInverse:12,closeBlock:13,openBlock:14,mustache:15,partial:16,COMMENT:17,OPEN_RAW_BLOCK:18,sexpr:19,CLOSE_RAW_BLOCK:20,OPEN_BLOCK:21,CLOSE:22,OPEN_INVERSE:23,OPEN_ENDBLOCK:24,path:25,OPEN:26,OPEN_UNESCAPED:27,CLOSE_UNESCAPED:28,OPEN_PARTIAL:29,partialName:30,param:31,partial_option0:32,partial_option1:33,sexpr_repetition0:34,sexpr_option0:35,dataName:36,STRING:37,NUMBER:38,BOOLEAN:39,OPEN_SEXPR:40,CLOSE_SEXPR:41,hash:42,hash_repetition_plus0:43,hashSegment:44,ID:45,EQUALS:46,DATA:47,pathSegments:48,SEP:49,$accept:0,$end:1},terminals_:{2:"error",5:"EOF",10:"CONTENT",11:"END_RAW_BLOCK",17:"COMMENT",18:"OPEN_RAW_BLOCK",20:"CLOSE_RAW_BLOCK",21:"OPEN_BLOCK",22:"CLOSE",23:"OPEN_INVERSE",24:"OPEN_ENDBLOCK",26:"OPEN",27:"OPEN_UNESCAPED",28:"CLOSE_UNESCAPED",29:"OPEN_PARTIAL",37:"STRING",38:"NUMBER",39:"BOOLEAN",40:"OPEN_SEXPR",41:"CLOSE_SEXPR",45:"ID",46:"EQUALS",47:"DATA",49:"SEP"},productions_:[0,[3,2],[3,1],[6,2],[6,3],[6,2],[6,1],[6,1],[6,0],[4,1],[4,2],[8,3],[8,3],[8,3],[8,1],[8,1],[8,1],[8,1],[9,3],[14,3],[12,3],[13,3],[15,3],[15,3],[16,5],[16,4],[7,2],[19,3],[19,1],[31,1],[31,1],[31,1],[31,1],[31,1],[31,3],[42,1],[44,3],[30,1],[30,1],[30,1],[36,2],[25,1],[48,3],[48,1],[32,0],[32,1],[33,0],[33,1],[34,0],[34,2],[35,0],[35,1],[43,1],[43,2]],performAction:function(b,c,d,e,f,g){var h=g.length-1;switch(f){case 1:return new e.ProgramNode(g[h-1],this._$);case 2:return new e.ProgramNode([],this._$);case 3:this.$=new e.ProgramNode([],g[h-1],g[h],this._$);break;case 4:this.$=new e.ProgramNode(g[h-2],g[h-1],g[h],this._$);break;case 5:this.$=new e.ProgramNode(g[h-1],g[h],[],this._$);break;case 6:this.$=new e.ProgramNode(g[h],this._$);break;case 7:this.$=new e.ProgramNode([],this._$);break;case 8:this.$=new e.ProgramNode([],this._$);break;case 9:this.$=[g[h]];break;case 10:g[h-1].push(g[h]),this.$=g[h-1];break;case 11:this.$=new e.RawBlockNode(g[h-2],g[h-1],g[h],this._$);break;case 12:this.$=new e.BlockNode(g[h-2],g[h-1].inverse,g[h-1],g[h],this._$);break;case 13:this.$=new e.BlockNode(g[h-2],g[h-1],g[h-1].inverse,g[h],this._$);break;case 14:this.$=g[h];break;case 15:this.$=g[h];break;case 16:this.$=new e.ContentNode(g[h],this._$);break;case 17:this.$=new e.CommentNode(g[h],this._$);break;case 18:this.$=new e.MustacheNode(g[h-1],null,"","",this._$);break;case 19:this.$=new e.MustacheNode(g[h-1],null,g[h-2],a(g[h-2],g[h]),this._$);break;case 20:this.$=new e.MustacheNode(g[h-1],null,g[h-2],a(g[h-2],g[h]),this._$);break;case 21:this.$={path:g[h-1],strip:a(g[h-2],g[h])};break;case 22:this.$=new e.MustacheNode(g[h-1],null,g[h-2],a(g[h-2],g[h]),this._$);break;case 23:this.$=new e.MustacheNode(g[h-1],null,g[h-2],a(g[h-2],g[h]),this._$);break;case 24:this.$=new e.PartialNode(g[h-3],g[h-2],g[h-1],a(g[h-4],g[h]),this._$);break;case 25:this.$=new e.PartialNode(g[h-2],void 0,g[h-1],a(g[h-3],g[h]),this._$);break;case 26:this.$=a(g[h-1],g[h]);break;case 27:this.$=new e.SexprNode([g[h-2]].concat(g[h-1]),g[h],this._$);break;case 28:this.$=new e.SexprNode([g[h]],null,this._$);break;case 29:this.$=g[h];break;case 30:this.$=new e.StringNode(g[h],this._$);break;case 31:this.$=new e.NumberNode(g[h],this._$);break;case 32:this.$=new e.BooleanNode(g[h],this._$);break;case 33:this.$=g[h];break;case 34:g[h-1].isHelper=!0,this.$=g[h-1];break;case 35:this.$=new e.HashNode(g[h],this._$);break;case 36:this.$=[g[h-2],g[h]];break;case 37:this.$=new e.PartialNameNode(g[h],this._$);break;case 38:this.$=new e.PartialNameNode(new e.StringNode(g[h],this._$),this._$);break;case 39:this.$=new e.PartialNameNode(new e.NumberNode(g[h],this._$));break;case 40:this.$=new e.DataNode(g[h],this._$);break;case 41:this.$=new e.IdNode(g[h],this._$);break;case 42:g[h-2].push({part:g[h],separator:g[h-1]}),this.$=g[h-2];break;case 43:this.$=[{part:g[h]}];break;case 48:this.$=[];break;case 49:g[h-1].push(g[h]);break;case 52:this.$=[g[h]];break;case 53:g[h-1].push(g[h])}},table:[{3:1,4:2,5:[1,3],8:4,9:5,10:[1,10],12:6,14:7,15:8,16:9,17:[1,11],18:[1,12],21:[1,14],23:[1,13],26:[1,15],27:[1,16],29:[1,17]},{1:[3]},{5:[1,18],8:19,9:5,10:[1,10],12:6,14:7,15:8,16:9,17:[1,11],18:[1,12],21:[1,14],23:[1,13],26:[1,15],27:[1,16],29:[1,17]},{1:[2,2]},{5:[2,9],10:[2,9],17:[2,9],18:[2,9],21:[2,9],23:[2,9],24:[2,9],26:[2,9],27:[2,9],29:[2,9]},{10:[1,20]},{4:23,6:21,7:22,8:4,9:5,10:[1,10],12:6,14:7,15:8,16:9,17:[1,11],18:[1,12],21:[1,14],23:[1,24],24:[2,8],26:[1,15],27:[1,16],29:[1,17]},{4:23,6:25,7:22,8:4,9:5,10:[1,10],12:6,14:7,15:8,16:9,17:[1,11],18:[1,12],21:[1,14],23:[1,24],24:[2,8],26:[1,15],27:[1,16],29:[1,17]},{5:[2,14],10:[2,14],17:[2,14],18:[2,14],21:[2,14],23:[2,14],24:[2,14],26:[2,14],27:[2,14],29:[2,14]},{5:[2,15],10:[2,15],17:[2,15],18:[2,15],21:[2,15],23:[2,15],24:[2,15],26:[2,15],27:[2,15],29:[2,15]},{5:[2,16],10:[2,16],17:[2,16],18:[2,16],21:[2,16],23:[2,16],24:[2,16],26:[2,16],27:[2,16],29:[2,16]},{5:[2,17],10:[2,17],17:[2,17],18:[2,17],21:[2,17],23:[2,17],24:[2,17],26:[2,17],27:[2,17],29:[2,17]},{19:26,25:27,36:28,45:[1,31],47:[1,30],48:29},{19:32,25:27,36:28,45:[1,31],47:[1,30],48:29},{19:33,25:27,36:28,45:[1,31],47:[1,30],48:29},{19:34,25:27,36:28,45:[1,31],47:[1,30],48:29},{19:35,25:27,36:28,45:[1,31],47:[1,30],48:29},{25:37,30:36,37:[1,38],38:[1,39],45:[1,31],48:29},{1:[2,1]},{5:[2,10],10:[2,10],17:[2,10],18:[2,10],21:[2,10],23:[2,10],24:[2,10],26:[2,10],27:[2,10],29:[2,10]},{11:[1,40]},{13:41,24:[1,42]},{4:43,8:4,9:5,10:[1,10],12:6,14:7,15:8,16:9,17:[1,11],18:[1,12],21:[1,14],23:[1,13],24:[2,7],26:[1,15],27:[1,16],29:[1,17]},{7:44,8:19,9:5,10:[1,10],12:6,14:7,15:8,16:9,17:[1,11],18:[1,12],21:[1,14],23:[1,24],24:[2,6],26:[1,15],27:[1,16],29:[1,17]},{19:32,22:[1,45],25:27,36:28,45:[1,31],47:[1,30],48:29},{13:46,24:[1,42]},{20:[1,47]},{20:[2,48],22:[2,48],28:[2,48],34:48,37:[2,48],38:[2,48],39:[2,48],40:[2,48],41:[2,48],45:[2,48],47:[2,48]},{20:[2,28],22:[2,28],28:[2,28],41:[2,28]},{20:[2,41],22:[2,41],28:[2,41],37:[2,41],38:[2,41],39:[2,41],40:[2,41],41:[2,41],45:[2,41],47:[2,41],49:[1,49]},{25:50,45:[1,31],48:29},{20:[2,43],22:[2,43],28:[2,43],37:[2,43],38:[2,43],39:[2,43],40:[2,43],41:[2,43],45:[2,43],47:[2,43],49:[2,43]},{22:[1,51]},{22:[1,52]},{22:[1,53]},{28:[1,54]},{22:[2,46],25:57,31:55,33:56,36:61,37:[1,58],38:[1,59],39:[1,60],40:[1,62],42:63,43:64,44:66,45:[1,65],47:[1,30],48:29},{22:[2,37],37:[2,37],38:[2,37],39:[2,37],40:[2,37],45:[2,37],47:[2,37]},{22:[2,38],37:[2,38],38:[2,38],39:[2,38],40:[2,38],45:[2,38],47:[2,38]},{22:[2,39],37:[2,39],38:[2,39],39:[2,39],40:[2,39],45:[2,39],47:[2,39]},{5:[2,11],10:[2,11],17:[2,11],18:[2,11],21:[2,11],23:[2,11],24:[2,11],26:[2,11],27:[2,11],29:[2,11]},{5:[2,12],10:[2,12],17:[2,12],18:[2,12],21:[2,12],23:[2,12],24:[2,12],26:[2,12],27:[2,12],29:[2,12]},{25:67,45:[1,31],48:29},{8:19,9:5,10:[1,10],12:6,14:7,15:8,16:9,17:[1,11],18:[1,12],21:[1,14],23:[1,13],24:[2,3],26:[1,15],27:[1,16],29:[1,17]},{4:68,8:4,9:5,10:[1,10],12:6,14:7,15:8,16:9,17:[1,11],18:[1,12],21:[1,14],23:[1,13],24:[2,5],26:[1,15],27:[1,16],29:[1,17]},{10:[2,26],17:[2,26],18:[2,26],21:[2,26],23:[2,26],24:[2,26],26:[2,26],27:[2,26],29:[2,26]},{5:[2,13],10:[2,13],17:[2,13],18:[2,13],21:[2,13],23:[2,13],24:[2,13],26:[2,13],27:[2,13],29:[2,13]},{10:[2,18]},{20:[2,50],22:[2,50],25:57,28:[2,50],31:70,35:69,36:61,37:[1,58],38:[1,59],39:[1,60],40:[1,62],41:[2,50],42:71,43:64,44:66,45:[1,65],47:[1,30],48:29},{45:[1,72]},{20:[2,40],22:[2,40],28:[2,40],37:[2,40],38:[2,40],39:[2,40],40:[2,40],41:[2,40],45:[2,40],47:[2,40]},{10:[2,20],17:[2,20],18:[2,20],21:[2,20],23:[2,20],24:[2,20],26:[2,20],27:[2,20],29:[2,20]},{10:[2,19],17:[2,19],18:[2,19],21:[2,19],23:[2,19],24:[2,19],26:[2,19],27:[2,19],29:[2,19]},{5:[2,22],10:[2,22],17:[2,22],18:[2,22],21:[2,22],23:[2,22],24:[2,22],26:[2,22],27:[2,22],29:[2,22]},{5:[2,23],10:[2,23],17:[2,23],18:[2,23],21:[2,23],23:[2,23],24:[2,23],26:[2,23],27:[2,23],29:[2,23]},{22:[2,44],32:73,42:74,43:64,44:66,45:[1,75]},{22:[1,76]},{20:[2,29],22:[2,29],28:[2,29],37:[2,29],38:[2,29],39:[2,29],40:[2,29],41:[2,29],45:[2,29],47:[2,29]},{20:[2,30],22:[2,30],28:[2,30],37:[2,30],38:[2,30],39:[2,30],40:[2,30],41:[2,30],45:[2,30],47:[2,30]},{20:[2,31],22:[2,31],28:[2,31],37:[2,31],38:[2,31],39:[2,31],40:[2,31],41:[2,31],45:[2,31],47:[2,31]},{20:[2,32],22:[2,32],28:[2,32],37:[2,32],38:[2,32],39:[2,32],40:[2,32],41:[2,32],45:[2,32],47:[2,32]},{20:[2,33],22:[2,33],28:[2,33],37:[2,33],38:[2,33],39:[2,33],40:[2,33],41:[2,33],45:[2,33],47:[2,33]},{19:77,25:27,36:28,45:[1,31],47:[1,30],48:29},{22:[2,47]},{20:[2,35],22:[2,35],28:[2,35],41:[2,35],44:78,45:[1,75]},{20:[2,43],22:[2,43],28:[2,43],37:[2,43],38:[2,43],39:[2,43],40:[2,43],41:[2,43],45:[2,43],46:[1,79],47:[2,43],49:[2,43]},{20:[2,52],22:[2,52],28:[2,52],41:[2,52],45:[2,52]},{22:[1,80]},{8:19,9:5,10:[1,10],12:6,14:7,15:8,16:9,17:[1,11],18:[1,12],21:[1,14],23:[1,13],24:[2,4],26:[1,15],27:[1,16],29:[1,17]},{20:[2,27],22:[2,27],28:[2,27],41:[2,27]},{20:[2,49],22:[2,49],28:[2,49],37:[2,49],38:[2,49],39:[2,49],40:[2,49],41:[2,49],45:[2,49],47:[2,49]},{20:[2,51],22:[2,51],28:[2,51],41:[2,51]},{20:[2,42],22:[2,42],28:[2,42],37:[2,42],38:[2,42],39:[2,42],40:[2,42],41:[2,42],45:[2,42],47:[2,42],49:[2,42]},{22:[1,81]},{22:[2,45]},{46:[1,79]},{5:[2,25],10:[2,25],17:[2,25],18:[2,25],21:[2,25],23:[2,25],24:[2,25],26:[2,25],27:[2,25],29:[2,25]},{41:[1,82]},{20:[2,53],22:[2,53],28:[2,53],41:[2,53],45:[2,53]},{25:57,31:83,36:61,37:[1,58],38:[1,59],39:[1,60],40:[1,62],45:[1,31],47:[1,30],48:29},{5:[2,21],10:[2,21],17:[2,21],18:[2,21],21:[2,21],23:[2,21],24:[2,21],26:[2,21],27:[2,21],29:[2,21]},{5:[2,24],10:[2,24],17:[2,24],18:[2,24],21:[2,24],23:[2,24],24:[2,24],26:[2,24],27:[2,24],29:[2,24]},{20:[2,34],22:[2,34],28:[2,34],37:[2,34],38:[2,34],39:[2,34],40:[2,34],41:[2,34],45:[2,34],47:[2,34]},{20:[2,36],22:[2,36],28:[2,36],41:[2,36],45:[2,36]}],defaultActions:{3:[2,2],18:[2,1],47:[2,18],63:[2,47],74:[2,45]},parseError:function(a){throw new Error(a)},parse:function(a){function b(){var a;return a=c.lexer.lex()||1,"number"!=typeof a&&(a=c.symbols_[a]||a),a}var c=this,d=[0],e=[null],f=[],g=this.table,h="",i=0,j=0,k=0;this.lexer.setInput(a),this.lexer.yy=this.yy,this.yy.lexer=this.lexer,this.yy.parser=this,"undefined"==typeof this.lexer.yylloc&&(this.lexer.yylloc={});var l=this.lexer.yylloc;f.push(l);var m=this.lexer.options&&this.lexer.options.ranges;"function"==typeof this.yy.parseError&&(this.parseError=this.yy.parseError);for(var n,o,p,q,r,s,t,u,v,w={};;){if(p=d[d.length-1],this.defaultActions[p]?q=this.defaultActions[p]:((null===n||"undefined"==typeof n)&&(n=b()),q=g[p]&&g[p][n]),"undefined"==typeof q||!q.length||!q[0]){var x="";if(!k){v=[];for(s in g[p])this.terminals_[s]&&s>2&&v.push("'"+this.terminals_[s]+"'");x=this.lexer.showPosition?"Parse error on line "+(i+1)+":\n"+this.lexer.showPosition()+"\nExpecting "+v.join(", ")+", got '"+(this.terminals_[n]||n)+"'":"Parse error on line "+(i+1)+": Unexpected "+(1==n?"end of input":"'"+(this.terminals_[n]||n)+"'"),this.parseError(x,{text:this.lexer.match,token:this.terminals_[n]||n,line:this.lexer.yylineno,loc:l,expected:v})}}if(q[0]instanceof Array&&q.length>1)throw new Error("Parse Error: multiple actions possible at state: "+p+", token: "+n);switch(q[0]){case 1:d.push(n),e.push(this.lexer.yytext),f.push(this.lexer.yylloc),d.push(q[1]),n=null,o?(n=o,o=null):(j=this.lexer.yyleng,h=this.lexer.yytext,i=this.lexer.yylineno,l=this.lexer.yylloc,k>0&&k--);break;case 2:if(t=this.productions_[q[1]][1],w.$=e[e.length-t],w._$={first_line:f[f.length-(t||1)].first_line,last_line:f[f.length-1].last_line,first_column:f[f.length-(t||1)].first_column,last_column:f[f.length-1].last_column},m&&(w._$.range=[f[f.length-(t||1)].range[0],f[f.length-1].range[1]]),r=this.performAction.call(w,h,j,i,this.yy,q[1],e,f),"undefined"!=typeof r)return r;t&&(d=d.slice(0,-1*t*2),e=e.slice(0,-1*t),f=f.slice(0,-1*t)),d.push(this.productions_[q[1]][0]),e.push(w.$),f.push(w._$),u=g[d[d.length-2]][d[d.length-1]],d.push(u);break;case 3:return!0}}return!0}},d=function(){var a={EOF:1,parseError:function(a,b){if(!this.yy.parser)throw new Error(a);this.yy.parser.parseError(a,b)},setInput:function(a){return this._input=a,this._more=this._less=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var a=this._input[0];this.yytext+=a,this.yyleng++,this.offset++,this.match+=a,this.matched+=a;var b=a.match(/(?:\r\n?|\n).*/g);return b?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),a},unput:function(a){var b=a.length,c=a.split(/(?:\r\n?|\n)/g);this._input=a+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-b-1),this.offset-=b;var d=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),c.length-1&&(this.yylineno-=c.length-1);var e=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:c?(c.length===d.length?this.yylloc.first_column:0)+d[d.length-c.length].length-c[0].length:this.yylloc.first_column-b},this.options.ranges&&(this.yylloc.range=[e[0],e[0]+this.yyleng-b]),this},more:function(){return this._more=!0,this},less:function(a){this.unput(this.match.slice(a))},pastInput:function(){var a=this.matched.substr(0,this.matched.length-this.match.length);return(a.length>20?"...":"")+a.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var a=this.match;return a.length<20&&(a+=this._input.substr(0,20-a.length)),(a.substr(0,20)+(a.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var a=this.pastInput(),b=new Array(a.length+1).join("-");return a+this.upcomingInput()+"\n"+b+"^"},next:function(){if(this.done)return this.EOF;this._input||(this.done=!0);var a,b,c,d,e;this._more||(this.yytext="",this.match="");for(var f=this._currentRules(),g=0;g<f.length&&(c=this._input.match(this.rules[f[g]]),!c||b&&!(c[0].length>b[0].length)||(b=c,d=g,this.options.flex));g++);return b?(e=b[0].match(/(?:\r\n?|\n).*/g),e&&(this.yylineno+=e.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:e?e[e.length-1].length-e[e.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+b[0].length},this.yytext+=b[0],this.match+=b[0],this.matches=b,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._input=this._input.slice(b[0].length),this.matched+=b[0],a=this.performAction.call(this,this.yy,this,f[d],this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),a?a:void 0):""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){var a=this.next();return"undefined"!=typeof a?a:this.lex()},begin:function(a){this.conditionStack.push(a)},popState:function(){return this.conditionStack.pop()},_currentRules:function(){return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules},topState:function(){return this.conditionStack[this.conditionStack.length-2]},pushState:function(a){this.begin(a)}};return a.options={},a.performAction=function(a,b,c,d){function e(a,c){return b.yytext=b.yytext.substr(a,b.yyleng-c)}switch(c){case 0:if("\\\\"===b.yytext.slice(-2)?(e(0,1),this.begin("mu")):"\\"===b.yytext.slice(-1)?(e(0,1),this.begin("emu")):this.begin("mu"),b.yytext)return 10;break;case 1:return 10;case 2:return this.popState(),10;case 3:return b.yytext=b.yytext.substr(5,b.yyleng-9),this.popState(),11;case 4:return 10;case 5:return e(0,4),this.popState(),17;case 6:return 40;case 7:return 41;case 8:return 18;case 9:return this.popState(),this.begin("raw"),20;case 10:return b.yytext=b.yytext.substr(4,b.yyleng-8),this.popState(),"RAW_BLOCK";case 11:return 29;case 12:return 21;case 13:return 24;case 14:return 23;case 15:return 23;case 16:return 27;case 17:return 26;case 18:this.popState(),this.begin("com");break;case 19:return e(3,5),this.popState(),17;case 20:return 26;case 21:return 46;case 22:return 45;case 23:return 45;case 24:return 49;case 25:break;case 26:return this.popState(),28;case 27:return this.popState(),22;case 28:return b.yytext=e(1,2).replace(/\\"/g,'"'),37;case 29:return b.yytext=e(1,2).replace(/\\'/g,"'"),37;case 30:return 47;case 31:return 39;case 32:return 39;case 33:return 38;case 34:return 45;case 35:return b.yytext=e(1,2),45;case 36:return"INVALID";case 37:return 5}},a.rules=[/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|\\\{\{|\\\\\{\{|$)))/,/^(?:\{\{\{\{\/[^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=[=}\s\/.])\}\}\}\})/,/^(?:[^\x00]*?(?=(\{\{\{\{\/)))/,/^(?:[\s\S]*?--\}\})/,/^(?:\()/,/^(?:\))/,/^(?:\{\{\{\{)/,/^(?:\}\}\}\})/,/^(?:\{\{\{\{[^\x00]*\}\}\}\})/,/^(?:\{\{(~)?>)/,/^(?:\{\{(~)?#)/,/^(?:\{\{(~)?\/)/,/^(?:\{\{(~)?\^)/,/^(?:\{\{(~)?\s*else\b)/,/^(?:\{\{(~)?\{)/,/^(?:\{\{(~)?&)/,/^(?:\{\{!--)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{(~)?)/,/^(?:=)/,/^(?:\.\.)/,/^(?:\.(?=([=~}\s\/.)])))/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}(~)?\}\})/,/^(?:(~)?\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@)/,/^(?:true(?=([~}\s)])))/,/^(?:false(?=([~}\s)])))/,/^(?:-?[0-9]+(?:\.[0-9]+)?(?=([~}\s)])))/,/^(?:([^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=([=~}\s\/.)]))))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:$)/],a.conditions={mu:{rules:[6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37],inclusive:!1},emu:{rules:[2],inclusive:!1},com:{rules:[5],inclusive:!1},raw:{rules:[3,4],inclusive:!1},INITIAL:{rules:[0,1,37],inclusive:!0}},a}();return c.lexer=d,b.prototype=c,c.Parser=b,new b}();return a=b}(),i=function(a,b){"use strict";function c(a){return a.constructor===f.ProgramNode?a:(e.yy=f,e.parse(a))}var d={},e=a,f=b;return d.parser=e,d.parse=c,d}(h,g),j=function(a){"use strict";function b(){}function c(a,b,c){if(null==a||"string"!=typeof a&&a.constructor!==c.AST.ProgramNode)throw new f("You must pass a string or Handlebars AST to Handlebars.precompile. You passed "+a);b=b||{},"data"in b||(b.data=!0);var d=c.parse(a),e=(new c.Compiler).compile(d,b);return(new c.JavaScriptCompiler).compile(e,b)}function d(a,b,c){function d(){var d=c.parse(a),e=(new c.Compiler).compile(d,b),f=(new c.JavaScriptCompiler).compile(e,b,void 0,!0);return c.template(f)}if(null==a||"string"!=typeof a&&a.constructor!==c.AST.ProgramNode)throw new f("You must pass a string or Handlebars AST to Handlebars.compile. You passed "+a);b=b||{},"data"in b||(b.data=!0);var e,g=function(a,b){return e||(e=d()),e.call(this,a,b)};return g._setup=function(a){return e||(e=d()),e._setup(a)},g._child=function(a){return e||(e=d()),e._child(a)},g}var e={},f=a;return e.Compiler=b,b.prototype={compiler:b,disassemble:function(){for(var a,b,c,d=this.opcodes,e=[],f=0,g=d.length;g>f;f++)if(a=d[f],"DECLARE"===a.opcode)e.push("DECLARE "+a.name+"="+a.value);else{b=[];for(var h=0;h<a.args.length;h++)c=a.args[h],"string"==typeof c&&(c='"'+c.replace("\n","\\n")+'"'),b.push(c);e.push(a.opcode+" "+b.join(" "))}return e.join("\n")},equals:function(a){var b=this.opcodes.length;if(a.opcodes.length!==b)return!1;for(var c=0;b>c;c++){var d=this.opcodes[c],e=a.opcodes[c];if(d.opcode!==e.opcode||d.args.length!==e.args.length)return!1;for(var f=0;f<d.args.length;f++)if(d.args[f]!==e.args[f])return!1}if(b=this.children.length,a.children.length!==b)return!1;for(c=0;b>c;c++)if(!this.children[c].equals(a.children[c]))return!1;return!0},guid:0,compile:function(a,b){this.opcodes=[],this.children=[],this.depths={list:[]},this.options=b,this.stringParams=b.stringParams,this.trackIds=b.trackIds;var c=this.options.knownHelpers;if(this.options.knownHelpers={helperMissing:!0,blockHelperMissing:!0,each:!0,"if":!0,unless:!0,"with":!0,log:!0,lookup:!0},c)for(var d in c)this.options.knownHelpers[d]=c[d];return this.accept(a)},accept:function(a){var b,c=a.strip||{};return c.left&&this.opcode("strip"),b=this[a.type](a),c.right&&this.opcode("strip"),b},program:function(a){for(var b=a.statements,c=0,d=b.length;d>c;c++)this.accept(b[c]);return this.isSimple=1===d,this.depths.list=this.depths.list.sort(function(a,b){return a-b}),this},compileProgram:function(a){var b,c=(new this.compiler).compile(a,this.options),d=this.guid++;this.usePartial=this.usePartial||c.usePartial,this.children[d]=c;for(var e=0,f=c.depths.list.length;f>e;e++)b=c.depths.list[e],2>b||this.addDepth(b-1);return d},block:function(a){var b=a.mustache,c=a.program,d=a.inverse;c&&(c=this.compileProgram(c)),d&&(d=this.compileProgram(d));var e=b.sexpr,f=this.classifySexpr(e);"helper"===f?this.helperSexpr(e,c,d):"simple"===f?(this.simpleSexpr(e),this.opcode("pushProgram",c),this.opcode("pushProgram",d),this.opcode("emptyHash"),this.opcode("blockValue",e.id.original)):(this.ambiguousSexpr(e,c,d),this.opcode("pushProgram",c),this.opcode("pushProgram",d),this.opcode("emptyHash"),this.opcode("ambiguousBlockValue")),this.opcode("append")},hash:function(a){var b,c,d=a.pairs;for(this.opcode("pushHash"),b=0,c=d.length;c>b;b++)this.pushParam(d[b][1]);for(;b--;)this.opcode("assignToHash",d[b][0]);this.opcode("popHash")},partial:function(a){var b=a.partialName;this.usePartial=!0,a.hash?this.accept(a.hash):this.opcode("push","undefined"),a.context?this.accept(a.context):this.opcode("push","depth0"),this.opcode("invokePartial",b.name),this.opcode("append")
},content:function(a){this.opcode("appendContent",a.string)},mustache:function(a){this.sexpr(a.sexpr),a.escaped&&!this.options.noEscape?this.opcode("appendEscaped"):this.opcode("append")},ambiguousSexpr:function(a,b,c){var d=a.id,e=d.parts[0],f=null!=b||null!=c;this.opcode("getContext",d.depth),this.opcode("pushProgram",b),this.opcode("pushProgram",c),this.opcode("invokeAmbiguous",e,f)},simpleSexpr:function(a){var b=a.id;"DATA"===b.type?this.DATA(b):b.parts.length?this.ID(b):(this.addDepth(b.depth),this.opcode("getContext",b.depth),this.opcode("pushContext")),this.opcode("resolvePossibleLambda")},helperSexpr:function(a,b,c){var d=this.setupFullMustacheParams(a,b,c),e=a.id,g=e.parts[0];if(this.options.knownHelpers[g])this.opcode("invokeKnownHelper",d.length,g);else{if(this.options.knownHelpersOnly)throw new f("You specified knownHelpersOnly, but used the unknown helper "+g,a);this.ID(e),this.opcode("invokeHelper",d.length,e.original,a.isRoot)}},sexpr:function(a){var b=this.classifySexpr(a);"simple"===b?this.simpleSexpr(a):"helper"===b?this.helperSexpr(a):this.ambiguousSexpr(a)},ID:function(a){this.addDepth(a.depth),this.opcode("getContext",a.depth);var b=a.parts[0];b?this.opcode("lookupOnContext",a.parts[0]):this.opcode("pushContext");for(var c=1,d=a.parts.length;d>c;c++)this.opcode("lookup",a.parts[c])},DATA:function(a){this.options.data=!0,this.opcode("lookupData",a.id.depth);for(var b=a.id.parts,c=0,d=b.length;d>c;c++)this.opcode("lookup",b[c])},STRING:function(a){this.opcode("pushString",a.string)},NUMBER:function(a){this.opcode("pushLiteral",a.number)},BOOLEAN:function(a){this.opcode("pushLiteral",a.bool)},comment:function(){},opcode:function(a){this.opcodes.push({opcode:a,args:[].slice.call(arguments,1)})},declare:function(a,b){this.opcodes.push({opcode:"DECLARE",name:a,value:b})},addDepth:function(a){0!==a&&(this.depths[a]||(this.depths[a]=!0,this.depths.list.push(a)))},classifySexpr:function(a){var b=a.isHelper,c=a.eligibleHelper,d=this.options;if(c&&!b){var e=a.id.parts[0];d.knownHelpers[e]?b=!0:d.knownHelpersOnly&&(c=!1)}return b?"helper":c?"ambiguous":"simple"},pushParams:function(a){for(var b=0,c=a.length;c>b;b++)this.pushParam(a[b])},pushParam:function(a){this.stringParams?(a.depth&&this.addDepth(a.depth),this.opcode("getContext",a.depth||0),this.opcode("pushStringParam",a.stringModeValue,a.type),"sexpr"===a.type&&this.sexpr(a)):(this.trackIds&&this.opcode("pushId",a.type,a.idName||a.stringModeValue),this.accept(a))},setupFullMustacheParams:function(a,b,c){var d=a.params;return this.pushParams(d),this.opcode("pushProgram",b),this.opcode("pushProgram",c),a.hash?this.hash(a.hash):this.opcode("emptyHash"),d}},e.precompile=c,e.compile=d,e}(c),k=function(a,b){"use strict";function c(a){this.value=a}function d(){}var e,f=a.COMPILER_REVISION,g=a.REVISION_CHANGES,h=a.log,i=b;d.prototype={nameLookup:function(a,b){var c,e;return 0===a.indexOf("depth")&&(c=!0),e=d.isValidJavaScriptVariableName(b)?a+"."+b:a+"['"+b+"']",c?"("+a+" && "+e+")":e},compilerInfo:function(){var a=f,b=g[a];return[a,b]},appendToBuffer:function(a){return this.environment.isSimple?"return "+a+";":{appendToBuffer:!0,content:a,toString:function(){return"buffer += "+a+";"}}},initializeBuffer:function(){return this.quotedString("")},namespace:"Handlebars",compile:function(a,b,c,d){this.environment=a,this.options=b||{},this.stringParams=this.options.stringParams,this.trackIds=this.options.trackIds,this.precompile=!d,h("debug",this.environment.disassemble()+"\n\n"),this.name=this.environment.name,this.isChild=!!c,this.context=c||{programs:[],environments:[]},this.preamble(),this.stackSlot=0,this.stackVars=[],this.aliases={},this.registers={list:[]},this.hashes=[],this.compileStack=[],this.inlineStack=[],this.compileChildren(a,b);var e,f,g,j=a.opcodes;for(f=0,g=j.length;g>f;f++)e=j[f],"DECLARE"===e.opcode?this[e.name]=e.value:this[e.opcode].apply(this,e.args),e.opcode!==this.stripNext&&(this.stripNext=!1);if(this.pushSource(""),this.stackSlot||this.inlineStack.length||this.compileStack.length)throw new i("Compile completed with content left on stack");var k=this.createFunctionContext(d);if(this.isChild)return k;var l={compiler:this.compilerInfo(),main:k},m=this.context.programs;for(f=0,g=m.length;g>f;f++)m[f]&&(l[f]=m[f]);return this.environment.usePartial&&(l.usePartial=!0),this.options.data&&(l.useData=!0),d||(l.compiler=JSON.stringify(l.compiler),l=this.objectLiteral(l)),l},preamble:function(){this.lastContext=0,this.source=[]},createFunctionContext:function(a){var b="",c=this.stackVars.concat(this.registers.list);c.length>0&&(b+=", "+c.join(", "));for(var d in this.aliases)this.aliases.hasOwnProperty(d)&&(b+=", "+d+"="+this.aliases[d]);for(var e=["depth0","helpers","partials","data"],f=0,g=this.environment.depths.list.length;g>f;f++)e.push("depth"+this.environment.depths.list[f]);var h=this.mergeSource(b);return a?(e.push(h),Function.apply(this,e)):"function("+e.join(",")+") {\n "+h+"}"},mergeSource:function(a){for(var b,c,d="",e=!this.forceBuffer,f=0,g=this.source.length;g>f;f++){var h=this.source[f];h.appendToBuffer?b=b?b+"\n + "+h.content:h.content:(b&&(d?d+="buffer += "+b+";\n ":(c=!0,d=b+";\n "),b=void 0),d+=h+"\n ",this.environment.isSimple||(e=!1))}return e?(b||!d)&&(d+="return "+(b||'""')+";\n"):(a+=", buffer = "+(c?"":this.initializeBuffer()),d+=b?"return buffer + "+b+";\n":"return buffer;\n"),a&&(d="var "+a.substring(2)+(c?"":";\n ")+d),d},blockValue:function(a){this.aliases.blockHelperMissing="helpers.blockHelperMissing";var b=["depth0"];this.setupParams(a,0,b),this.replaceStack(function(a){return b.splice(1,0,a),"blockHelperMissing.call("+b.join(", ")+")"})},ambiguousBlockValue:function(){this.aliases.blockHelperMissing="helpers.blockHelperMissing";var a=["depth0"];this.setupParams("",0,a,!0),this.flushInline();var b=this.topStack();a.splice(1,0,b),this.pushSource("if (!"+this.lastHelper+") { "+b+" = blockHelperMissing.call("+a.join(", ")+"); }")},appendContent:function(a){this.pendingContent&&(a=this.pendingContent+a),this.stripNext&&(a=a.replace(/^\s+/,"")),this.pendingContent=a},strip:function(){this.pendingContent&&(this.pendingContent=this.pendingContent.replace(/\s+$/,"")),this.stripNext="strip"},append:function(){this.flushInline();var a=this.popStack();this.pushSource("if("+a+" || "+a+" === 0) { "+this.appendToBuffer(a)+" }"),this.environment.isSimple&&this.pushSource("else { "+this.appendToBuffer("''")+" }")},appendEscaped:function(){this.aliases.escapeExpression="this.escapeExpression",this.pushSource(this.appendToBuffer("escapeExpression("+this.popStack()+")"))},getContext:function(a){this.lastContext!==a&&(this.lastContext=a)},lookupOnContext:function(a){this.push(this.nameLookup("depth"+this.lastContext,a,"context"))},pushContext:function(){this.pushStackLiteral("depth"+this.lastContext)},resolvePossibleLambda:function(){this.aliases.functionType='"function"',this.replaceStack(function(a){return"typeof "+a+" === functionType ? "+a+".apply(depth0) : "+a})},lookup:function(a){this.replaceStack(function(b){return b+" == null || "+b+" === false ? "+b+" : "+this.nameLookup(b,a,"context")})},lookupData:function(a){a?this.pushStackLiteral("this.data(data, "+a+")"):this.pushStackLiteral("data")},pushStringParam:function(a,b){this.pushStackLiteral("depth"+this.lastContext),this.pushString(b),"sexpr"!==b&&("string"==typeof a?this.pushString(a):this.pushStackLiteral(a))},emptyHash:function(){this.pushStackLiteral("{}"),this.trackIds&&this.push("{}"),this.stringParams&&(this.push("{}"),this.push("{}"))},pushHash:function(){this.hash&&this.hashes.push(this.hash),this.hash={values:[],types:[],contexts:[],ids:[]}},popHash:function(){var a=this.hash;this.hash=this.hashes.pop(),this.trackIds&&this.push("{"+a.ids.join(",")+"}"),this.stringParams&&(this.push("{"+a.contexts.join(",")+"}"),this.push("{"+a.types.join(",")+"}")),this.push("{\n "+a.values.join(",\n ")+"\n }")},pushString:function(a){this.pushStackLiteral(this.quotedString(a))},push:function(a){return this.inlineStack.push(a),a},pushLiteral:function(a){this.pushStackLiteral(a)},pushProgram:function(a){null!=a?this.pushStackLiteral(this.programExpression(a)):this.pushStackLiteral(null)},invokeHelper:function(a,b,c){this.aliases.helperMissing="helpers.helperMissing",this.useRegister("helper");var d=this.popStack(),e=this.setupHelper(a,b),f="helper = "+e.name+" || "+d+" || helperMissing";e.paramsInit&&(f+=","+e.paramsInit),this.push("("+f+",helper.call("+e.callParams+"))"),c||this.flushInline()},invokeKnownHelper:function(a,b){var c=this.setupHelper(a,b);this.push(c.name+".call("+c.callParams+")")},invokeAmbiguous:function(a,b){this.aliases.functionType='"function"',this.useRegister("helper"),this.emptyHash();var c=this.setupHelper(0,a,b),d=this.lastHelper=this.nameLookup("helpers",a,"helper"),e=this.nameLookup("depth"+this.lastContext,a,"context");this.push("((helper = "+d+" || "+e+(c.paramsInit?"),("+c.paramsInit:"")+"),(typeof helper === functionType ? helper.call("+c.callParams+") : helper))")},invokePartial:function(a){var b=[this.nameLookup("partials",a,"partial"),"'"+a+"'",this.popStack(),this.popStack(),"helpers","partials"];this.options.data&&b.push("data"),this.push("this.invokePartial("+b.join(", ")+")")},assignToHash:function(a){var b,c,d,e=this.popStack();this.trackIds&&(d=this.popStack()),this.stringParams&&(c=this.popStack(),b=this.popStack());var f=this.hash;b&&f.contexts.push("'"+a+"': "+b),c&&f.types.push("'"+a+"': "+c),d&&f.ids.push("'"+a+"': "+d),f.values.push("'"+a+"': ("+e+")")},pushId:function(a,b){"ID"===a||"DATA"===a?this.pushString(b):"sexpr"===a?this.pushStackLiteral("true"):this.pushStackLiteral("null")},compiler:d,compileChildren:function(a,b){for(var c,d,e=a.children,f=0,g=e.length;g>f;f++){c=e[f],d=new this.compiler;var h=this.matchExistingProgram(c);null==h?(this.context.programs.push(""),h=this.context.programs.length,c.index=h,c.name="program"+h,this.context.programs[h]=d.compile(c,b,this.context,!this.precompile),this.context.environments[h]=c):(c.index=h,c.name="program"+h)}},matchExistingProgram:function(a){for(var b=0,c=this.context.environments.length;c>b;b++){var d=this.context.environments[b];if(d&&d.equals(a))return b}},programExpression:function(a){if(null==a)return"this.noop";for(var b,c=this.environment.children[a],d=c.depths.list,e=[c.index,"data"],f=0,g=d.length;g>f;f++)b=d[f],e.push("depth"+(b-1));return(0===d.length?"this.program(":"this.programWithDepth(")+e.join(", ")+")"},register:function(a,b){this.useRegister(a),this.pushSource(a+" = "+b+";")},useRegister:function(a){this.registers[a]||(this.registers[a]=!0,this.registers.list.push(a))},pushStackLiteral:function(a){return this.push(new c(a))},pushSource:function(a){this.pendingContent&&(this.source.push(this.appendToBuffer(this.quotedString(this.pendingContent))),this.pendingContent=void 0),a&&this.source.push(a)},pushStack:function(a){this.flushInline();var b=this.incrStack();return a&&this.pushSource(b+" = "+a+";"),this.compileStack.push(b),b},replaceStack:function(a){var b,d,e,f="",g=this.isInline();if(g){var h=this.popStack(!0);if(h instanceof c)b=h.value,e=!0;else{d=!this.stackSlot;var i=d?this.incrStack():this.topStackName();f="("+this.push(i)+" = "+h+"),",b=this.topStack()}}else b=this.topStack();var j=a.call(this,b);return g?(e||this.popStack(),d&&this.stackSlot--,this.push("("+f+j+")")):(/^stack/.test(b)||(b=this.nextStack()),this.pushSource(b+" = ("+f+j+");")),b},nextStack:function(){return this.pushStack()},incrStack:function(){return this.stackSlot++,this.stackSlot>this.stackVars.length&&this.stackVars.push("stack"+this.stackSlot),this.topStackName()},topStackName:function(){return"stack"+this.stackSlot},flushInline:function(){var a=this.inlineStack;if(a.length){this.inlineStack=[];for(var b=0,d=a.length;d>b;b++){var e=a[b];e instanceof c?this.compileStack.push(e):this.pushStack(e)}}},isInline:function(){return this.inlineStack.length},popStack:function(a){var b=this.isInline(),d=(b?this.inlineStack:this.compileStack).pop();if(!a&&d instanceof c)return d.value;if(!b){if(!this.stackSlot)throw new i("Invalid stack pop");this.stackSlot--}return d},topStack:function(a){var b=this.isInline()?this.inlineStack:this.compileStack,d=b[b.length-1];return!a&&d instanceof c?d.value:d},quotedString:function(a){return'"'+a.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/\u2028/g,"\\u2028").replace(/\u2029/g,"\\u2029")+'"'},objectLiteral:function(a){var b=[];for(var c in a)a.hasOwnProperty(c)&&b.push(this.quotedString(c)+":"+a[c]);return"{"+b.join(",")+"}"},setupHelper:function(a,b,c){var d=[],e=this.setupParams(b,a,d,c),f=this.nameLookup("helpers",b,"helper");return{params:d,paramsInit:e,name:f,callParams:["depth0"].concat(d).join(", ")}},setupOptions:function(a,b,c){var d,e,f,g={},h=[],i=[],j=[];g.name=this.quotedString(a),g.hash=this.popStack(),this.trackIds&&(g.hashIds=this.popStack()),this.stringParams&&(g.hashTypes=this.popStack(),g.hashContexts=this.popStack()),e=this.popStack(),f=this.popStack(),(f||e)&&(f||(f="this.noop"),e||(e="this.noop"),g.fn=f,g.inverse=e);for(var k=b;k--;)d=this.popStack(),c[k]=d,this.trackIds&&(j[k]=this.popStack()),this.stringParams&&(i[k]=this.popStack(),h[k]=this.popStack());return this.trackIds&&(g.ids="["+j.join(",")+"]"),this.stringParams&&(g.types="["+i.join(",")+"]",g.contexts="["+h.join(",")+"]"),this.options.data&&(g.data="data"),g},setupParams:function(a,b,c,d){var e=this.objectLiteral(this.setupOptions(a,b,c));return d?(this.useRegister("options"),c.push("options"),"options="+e):(c.push(e),"")}};for(var j="break else new var case finally return void catch for switch while continue function this with default if throw delete in try do instanceof typeof abstract enum int short boolean export interface static byte extends long super char final native synchronized class float package throws const goto private transient debugger implements protected volatile double import public let yield".split(" "),k=d.RESERVED_WORDS={},l=0,m=j.length;m>l;l++)k[j[l]]=!0;return d.isValidJavaScriptVariableName=function(a){return!d.RESERVED_WORDS[a]&&/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(a)},e=d}(d,c),l=function(a,b,c,d,e){"use strict";var f,g=a,h=b,i=c.parser,j=c.parse,k=d.Compiler,l=d.compile,m=d.precompile,n=e,o=g.create,p=function(){var a=o();return a.compile=function(b,c){return l(b,c,a)},a.precompile=function(b,c){return m(b,c,a)},a.AST=h,a.Compiler=k,a.JavaScriptCompiler=n,a.Parser=i,a.parse=j,a};return g=p(),g.create=p,f=g}(f,g,i,j,k);return l}();
\ No newline at end of file
!function(a,b){"function"==typeof define&&define.amd?define([],b):"object"==typeof exports?module.exports=b():a.Handlebars=a.Handlebars||b()}(this,function(){var a=function(){"use strict";function a(a){this.string=a}var b;return a.prototype.toString=function(){return""+this.string},b=a}(),b=function(a){"use strict";function b(a){return i[a]}function c(a){for(var b=1;b<arguments.length;b++)for(var c in arguments[b])Object.prototype.hasOwnProperty.call(arguments[b],c)&&(a[c]=arguments[b][c]);return a}function d(a){return a instanceof h?a.toString():null==a?"":a?(a=""+a,k.test(a)?a.replace(j,b):a):a+""}function e(a){return a||0===a?n(a)&&0===a.length?!0:!1:!0}function f(a,b){return(a?a+".":"")+b}var g={},h=a,i={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;","`":"&#x60;"},j=/[&<>"'`]/g,k=/[&<>"'`]/;g.extend=c;var l=Object.prototype.toString;g.toString=l;var m=function(a){return"function"==typeof a};m(/x/)&&(m=function(a){return"function"==typeof a&&"[object Function]"===l.call(a)});var m;g.isFunction=m;var n=Array.isArray||function(a){return a&&"object"==typeof a?"[object Array]"===l.call(a):!1};return g.isArray=n,g.escapeExpression=d,g.isEmpty=e,g.appendContextPath=f,g}(a),c=function(){"use strict";function a(a,b){var d;b&&b.firstLine&&(d=b.firstLine,a+=" - "+d+":"+b.firstColumn);for(var e=Error.prototype.constructor.call(this,a),f=0;f<c.length;f++)this[c[f]]=e[c[f]];d&&(this.lineNumber=d,this.column=b.firstColumn)}var b,c=["description","fileName","lineNumber","message","name","number","stack"];return a.prototype=new Error,b=a}(),d=function(a,b){"use strict";function c(a,b){this.helpers=a||{},this.partials=b||{},d(this)}function d(a){a.registerHelper("helperMissing",function(){if(1===arguments.length)return void 0;throw new g("Missing helper: '"+arguments[arguments.length-1].name+"'")}),a.registerHelper("blockHelperMissing",function(b,c){var d=c.inverse,e=c.fn;if(b===!0)return e(this);if(b===!1||null==b)return d(this);if(k(b))return b.length>0?(c.ids&&(c.ids=[c.name]),a.helpers.each(b,c)):d(this);if(c.data&&c.ids){var g=q(c.data);g.contextPath=f.appendContextPath(c.data.contextPath,c.name),c={data:g}}return e(b,c)}),a.registerHelper("each",function(a,b){if(!b)throw new g("Must pass iterator to #each");var c,d,e=b.fn,h=b.inverse,i=0,j="";if(b.data&&b.ids&&(d=f.appendContextPath(b.data.contextPath,b.ids[0])+"."),l(a)&&(a=a.call(this)),b.data&&(c=q(b.data)),a&&"object"==typeof a)if(k(a))for(var m=a.length;m>i;i++)c&&(c.index=i,c.first=0===i,c.last=i===a.length-1,d&&(c.contextPath=d+i)),j+=e(a[i],{data:c});else for(var n in a)a.hasOwnProperty(n)&&(c&&(c.key=n,c.index=i,c.first=0===i,d&&(c.contextPath=d+n)),j+=e(a[n],{data:c}),i++);return 0===i&&(j=h(this)),j}),a.registerHelper("if",function(a,b){return l(a)&&(a=a.call(this)),!b.hash.includeZero&&!a||f.isEmpty(a)?b.inverse(this):b.fn(this)}),a.registerHelper("unless",function(b,c){return a.helpers["if"].call(this,b,{fn:c.inverse,inverse:c.fn,hash:c.hash})}),a.registerHelper("with",function(a,b){l(a)&&(a=a.call(this));var c=b.fn;if(f.isEmpty(a))return b.inverse(this);if(b.data&&b.ids){var d=q(b.data);d.contextPath=f.appendContextPath(b.data.contextPath,b.ids[0]),b={data:d}}return c(a,b)}),a.registerHelper("log",function(b,c){var d=c.data&&null!=c.data.level?parseInt(c.data.level,10):1;a.log(d,b)}),a.registerHelper("lookup",function(a,b){return a&&a[b]})}var e={},f=a,g=b,h="2.0.0";e.VERSION=h;var i=6;e.COMPILER_REVISION=i;var j={1:"<= 1.0.rc.2",2:"== 1.0.0-rc.3",3:"== 1.0.0-rc.4",4:"== 1.x.x",5:"== 2.0.0-alpha.x",6:">= 2.0.0-beta.1"};e.REVISION_CHANGES=j;var k=f.isArray,l=f.isFunction,m=f.toString,n="[object Object]";e.HandlebarsEnvironment=c,c.prototype={constructor:c,logger:o,log:p,registerHelper:function(a,b){if(m.call(a)===n){if(b)throw new g("Arg not supported with multiple helpers");f.extend(this.helpers,a)}else this.helpers[a]=b},unregisterHelper:function(a){delete this.helpers[a]},registerPartial:function(a,b){m.call(a)===n?f.extend(this.partials,a):this.partials[a]=b},unregisterPartial:function(a){delete this.partials[a]}};var o={methodMap:{0:"debug",1:"info",2:"warn",3:"error"},DEBUG:0,INFO:1,WARN:2,ERROR:3,level:3,log:function(a,b){if(o.level<=a){var c=o.methodMap[a];"undefined"!=typeof console&&console[c]&&console[c].call(console,b)}}};e.logger=o;var p=o.log;e.log=p;var q=function(a){var b=f.extend({},a);return b._parent=a,b};return e.createFrame=q,e}(b,c),e=function(a,b,c){"use strict";function d(a){var b=a&&a[0]||1,c=m;if(b!==c){if(c>b){var d=n[c],e=n[b];throw new l("Template was precompiled with an older version of Handlebars than the current runtime. Please update your precompiler to a newer version ("+d+") or downgrade your runtime to an older version ("+e+").")}throw new l("Template was precompiled with a newer version of Handlebars than the current runtime. Please update your runtime to a newer version ("+a[1]+").")}}function e(a,b){if(!b)throw new l("No environment passed to template");if(!a||!a.main)throw new l("Unknown template object: "+typeof a);b.VM.checkRevision(a.compiler);var c=function(c,d,e,f,g,h,i,j,m){g&&(f=k.extend({},f,g));var n=b.VM.invokePartial.call(this,c,e,f,h,i,j,m);if(null==n&&b.compile){var o={helpers:h,partials:i,data:j,depths:m};i[e]=b.compile(c,{data:void 0!==j,compat:a.compat},b),n=i[e](f,o)}if(null!=n){if(d){for(var p=n.split("\n"),q=0,r=p.length;r>q&&(p[q]||q+1!==r);q++)p[q]=d+p[q];n=p.join("\n")}return n}throw new l("The partial "+e+" could not be compiled when running in runtime-only mode")},d={lookup:function(a,b){for(var c=a.length,d=0;c>d;d++)if(a[d]&&null!=a[d][b])return a[d][b]},lambda:function(a,b){return"function"==typeof a?a.call(b):a},escapeExpression:k.escapeExpression,invokePartial:c,fn:function(b){return a[b]},programs:[],program:function(a,b,c){var d=this.programs[a],e=this.fn(a);return b||c?d=f(this,a,e,b,c):d||(d=this.programs[a]=f(this,a,e)),d},data:function(a,b){for(;a&&b--;)a=a._parent;return a},merge:function(a,b){var c=a||b;return a&&b&&a!==b&&(c=k.extend({},b,a)),c},noop:b.VM.noop,compilerInfo:a.compiler},e=function(b,c){c=c||{};var f=c.data;e._setup(c),!c.partial&&a.useData&&(f=i(b,f));var g;return a.useDepths&&(g=c.depths?[b].concat(c.depths):[b]),a.main.call(d,b,d.helpers,d.partials,f,g)};return e.isTop=!0,e._setup=function(c){c.partial?(d.helpers=c.helpers,d.partials=c.partials):(d.helpers=d.merge(c.helpers,b.helpers),a.usePartial&&(d.partials=d.merge(c.partials,b.partials)))},e._child=function(b,c,e){if(a.useDepths&&!e)throw new l("must pass parent depths");return f(d,b,a[b],c,e)},e}function f(a,b,c,d,e){var f=function(b,f){return f=f||{},c.call(a,b,a.helpers,a.partials,f.data||d,e&&[b].concat(e))};return f.program=b,f.depth=e?e.length:0,f}function g(a,b,c,d,e,f,g){var h={partial:!0,helpers:d,partials:e,data:f,depths:g};if(void 0===a)throw new l("The partial "+b+" could not be found");return a instanceof Function?a(c,h):void 0}function h(){return""}function i(a,b){return b&&"root"in b||(b=b?o(b):{},b.root=a),b}var j={},k=a,l=b,m=c.COMPILER_REVISION,n=c.REVISION_CHANGES,o=c.createFrame;return j.checkRevision=d,j.template=e,j.program=f,j.invokePartial=g,j.noop=h,j}(b,c,d),f=function(a,b,c,d,e){"use strict";var f,g=a,h=b,i=c,j=d,k=e,l=function(){var a=new g.HandlebarsEnvironment;return j.extend(a,g),a.SafeString=h,a.Exception=i,a.Utils=j,a.escapeExpression=j.escapeExpression,a.VM=k,a.template=function(b){return k.template(b,a)},a},m=l();return m.create=l,m["default"]=m,f=m}(d,a,c,b,e),g=function(a){"use strict";function b(a){a=a||{},this.firstLine=a.first_line,this.firstColumn=a.first_column,this.lastColumn=a.last_column,this.lastLine=a.last_line}var c,d=a,e={ProgramNode:function(a,c,d){b.call(this,d),this.type="program",this.statements=a,this.strip=c},MustacheNode:function(a,c,d,f,g){if(b.call(this,g),this.type="mustache",this.strip=f,null!=d&&d.charAt){var h=d.charAt(3)||d.charAt(2);this.escaped="{"!==h&&"&"!==h}else this.escaped=!!d;this.sexpr=a instanceof e.SexprNode?a:new e.SexprNode(a,c),this.id=this.sexpr.id,this.params=this.sexpr.params,this.hash=this.sexpr.hash,this.eligibleHelper=this.sexpr.eligibleHelper,this.isHelper=this.sexpr.isHelper},SexprNode:function(a,c,d){b.call(this,d),this.type="sexpr",this.hash=c;var e=this.id=a[0],f=this.params=a.slice(1);this.isHelper=!(!f.length&&!c),this.eligibleHelper=this.isHelper||e.isSimple},PartialNode:function(a,c,d,e,f){b.call(this,f),this.type="partial",this.partialName=a,this.context=c,this.hash=d,this.strip=e,this.strip.inlineStandalone=!0},BlockNode:function(a,c,d,e,f){b.call(this,f),this.type="block",this.mustache=a,this.program=c,this.inverse=d,this.strip=e,d&&!c&&(this.isInverse=!0)},RawBlockNode:function(a,c,f,g){if(b.call(this,g),a.sexpr.id.original!==f)throw new d(a.sexpr.id.original+" doesn't match "+f,this);c=new e.ContentNode(c,g),this.type="block",this.mustache=a,this.program=new e.ProgramNode([c],{},g)},ContentNode:function(a,c){b.call(this,c),this.type="content",this.original=this.string=a},HashNode:function(a,c){b.call(this,c),this.type="hash",this.pairs=a},IdNode:function(a,c){b.call(this,c),this.type="ID";for(var e="",f=[],g=0,h="",i=0,j=a.length;j>i;i++){var k=a[i].part;if(e+=(a[i].separator||"")+k,".."===k||"."===k||"this"===k){if(f.length>0)throw new d("Invalid path: "+e,this);".."===k?(g++,h+="../"):this.isScoped=!0}else f.push(k)}this.original=e,this.parts=f,this.string=f.join("."),this.depth=g,this.idName=h+this.string,this.isSimple=1===a.length&&!this.isScoped&&0===g,this.stringModeValue=this.string},PartialNameNode:function(a,c){b.call(this,c),this.type="PARTIAL_NAME",this.name=a.original},DataNode:function(a,c){b.call(this,c),this.type="DATA",this.id=a,this.stringModeValue=a.stringModeValue,this.idName="@"+a.stringModeValue},StringNode:function(a,c){b.call(this,c),this.type="STRING",this.original=this.string=this.stringModeValue=a},NumberNode:function(a,c){b.call(this,c),this.type="NUMBER",this.original=this.number=a,this.stringModeValue=Number(a)},BooleanNode:function(a,c){b.call(this,c),this.type="BOOLEAN",this.bool=a,this.stringModeValue="true"===a},CommentNode:function(a,c){b.call(this,c),this.type="comment",this.comment=a,this.strip={inlineStandalone:!0}}};return c=e}(c),h=function(){"use strict";var a,b=function(){function a(){this.yy={}}var b={trace:function(){},yy:{},symbols_:{error:2,root:3,program:4,EOF:5,program_repetition0:6,statement:7,mustache:8,block:9,rawBlock:10,partial:11,CONTENT:12,COMMENT:13,openRawBlock:14,END_RAW_BLOCK:15,OPEN_RAW_BLOCK:16,sexpr:17,CLOSE_RAW_BLOCK:18,openBlock:19,block_option0:20,closeBlock:21,openInverse:22,block_option1:23,OPEN_BLOCK:24,CLOSE:25,OPEN_INVERSE:26,inverseAndProgram:27,INVERSE:28,OPEN_ENDBLOCK:29,path:30,OPEN:31,OPEN_UNESCAPED:32,CLOSE_UNESCAPED:33,OPEN_PARTIAL:34,partialName:35,param:36,partial_option0:37,partial_option1:38,sexpr_repetition0:39,sexpr_option0:40,dataName:41,STRING:42,NUMBER:43,BOOLEAN:44,OPEN_SEXPR:45,CLOSE_SEXPR:46,hash:47,hash_repetition_plus0:48,hashSegment:49,ID:50,EQUALS:51,DATA:52,pathSegments:53,SEP:54,$accept:0,$end:1},terminals_:{2:"error",5:"EOF",12:"CONTENT",13:"COMMENT",15:"END_RAW_BLOCK",16:"OPEN_RAW_BLOCK",18:"CLOSE_RAW_BLOCK",24:"OPEN_BLOCK",25:"CLOSE",26:"OPEN_INVERSE",28:"INVERSE",29:"OPEN_ENDBLOCK",31:"OPEN",32:"OPEN_UNESCAPED",33:"CLOSE_UNESCAPED",34:"OPEN_PARTIAL",42:"STRING",43:"NUMBER",44:"BOOLEAN",45:"OPEN_SEXPR",46:"CLOSE_SEXPR",50:"ID",51:"EQUALS",52:"DATA",54:"SEP"},productions_:[0,[3,2],[4,1],[7,1],[7,1],[7,1],[7,1],[7,1],[7,1],[10,3],[14,3],[9,4],[9,4],[19,3],[22,3],[27,2],[21,3],[8,3],[8,3],[11,5],[11,4],[17,3],[17,1],[36,1],[36,1],[36,1],[36,1],[36,1],[36,3],[47,1],[49,3],[35,1],[35,1],[35,1],[41,2],[30,1],[53,3],[53,1],[6,0],[6,2],[20,0],[20,1],[23,0],[23,1],[37,0],[37,1],[38,0],[38,1],[39,0],[39,2],[40,0],[40,1],[48,1],[48,2]],performAction:function(a,b,c,d,e,f){var g=f.length-1;switch(e){case 1:return d.prepareProgram(f[g-1].statements,!0),f[g-1];case 2:this.$=new d.ProgramNode(d.prepareProgram(f[g]),{},this._$);break;case 3:this.$=f[g];break;case 4:this.$=f[g];break;case 5:this.$=f[g];break;case 6:this.$=f[g];break;case 7:this.$=new d.ContentNode(f[g],this._$);break;case 8:this.$=new d.CommentNode(f[g],this._$);break;case 9:this.$=new d.RawBlockNode(f[g-2],f[g-1],f[g],this._$);break;case 10:this.$=new d.MustacheNode(f[g-1],null,"","",this._$);break;case 11:this.$=d.prepareBlock(f[g-3],f[g-2],f[g-1],f[g],!1,this._$);break;case 12:this.$=d.prepareBlock(f[g-3],f[g-2],f[g-1],f[g],!0,this._$);break;case 13:this.$=new d.MustacheNode(f[g-1],null,f[g-2],d.stripFlags(f[g-2],f[g]),this._$);break;case 14:this.$=new d.MustacheNode(f[g-1],null,f[g-2],d.stripFlags(f[g-2],f[g]),this._$);break;case 15:this.$={strip:d.stripFlags(f[g-1],f[g-1]),program:f[g]};break;case 16:this.$={path:f[g-1],strip:d.stripFlags(f[g-2],f[g])};break;case 17:this.$=new d.MustacheNode(f[g-1],null,f[g-2],d.stripFlags(f[g-2],f[g]),this._$);break;case 18:this.$=new d.MustacheNode(f[g-1],null,f[g-2],d.stripFlags(f[g-2],f[g]),this._$);break;case 19:this.$=new d.PartialNode(f[g-3],f[g-2],f[g-1],d.stripFlags(f[g-4],f[g]),this._$);break;case 20:this.$=new d.PartialNode(f[g-2],void 0,f[g-1],d.stripFlags(f[g-3],f[g]),this._$);break;case 21:this.$=new d.SexprNode([f[g-2]].concat(f[g-1]),f[g],this._$);break;case 22:this.$=new d.SexprNode([f[g]],null,this._$);break;case 23:this.$=f[g];break;case 24:this.$=new d.StringNode(f[g],this._$);break;case 25:this.$=new d.NumberNode(f[g],this._$);break;case 26:this.$=new d.BooleanNode(f[g],this._$);break;case 27:this.$=f[g];break;case 28:f[g-1].isHelper=!0,this.$=f[g-1];break;case 29:this.$=new d.HashNode(f[g],this._$);break;case 30:this.$=[f[g-2],f[g]];break;case 31:this.$=new d.PartialNameNode(f[g],this._$);break;case 32:this.$=new d.PartialNameNode(new d.StringNode(f[g],this._$),this._$);break;case 33:this.$=new d.PartialNameNode(new d.NumberNode(f[g],this._$));break;case 34:this.$=new d.DataNode(f[g],this._$);break;case 35:this.$=new d.IdNode(f[g],this._$);break;case 36:f[g-2].push({part:f[g],separator:f[g-1]}),this.$=f[g-2];break;case 37:this.$=[{part:f[g]}];break;case 38:this.$=[];break;case 39:f[g-1].push(f[g]);break;case 48:this.$=[];break;case 49:f[g-1].push(f[g]);break;case 52:this.$=[f[g]];break;case 53:f[g-1].push(f[g])}},table:[{3:1,4:2,5:[2,38],6:3,12:[2,38],13:[2,38],16:[2,38],24:[2,38],26:[2,38],31:[2,38],32:[2,38],34:[2,38]},{1:[3]},{5:[1,4]},{5:[2,2],7:5,8:6,9:7,10:8,11:9,12:[1,10],13:[1,11],14:16,16:[1,20],19:14,22:15,24:[1,18],26:[1,19],28:[2,2],29:[2,2],31:[1,12],32:[1,13],34:[1,17]},{1:[2,1]},{5:[2,39],12:[2,39],13:[2,39],16:[2,39],24:[2,39],26:[2,39],28:[2,39],29:[2,39],31:[2,39],32:[2,39],34:[2,39]},{5:[2,3],12:[2,3],13:[2,3],16:[2,3],24:[2,3],26:[2,3],28:[2,3],29:[2,3],31:[2,3],32:[2,3],34:[2,3]},{5:[2,4],12:[2,4],13:[2,4],16:[2,4],24:[2,4],26:[2,4],28:[2,4],29:[2,4],31:[2,4],32:[2,4],34:[2,4]},{5:[2,5],12:[2,5],13:[2,5],16:[2,5],24:[2,5],26:[2,5],28:[2,5],29:[2,5],31:[2,5],32:[2,5],34:[2,5]},{5:[2,6],12:[2,6],13:[2,6],16:[2,6],24:[2,6],26:[2,6],28:[2,6],29:[2,6],31:[2,6],32:[2,6],34:[2,6]},{5:[2,7],12:[2,7],13:[2,7],16:[2,7],24:[2,7],26:[2,7],28:[2,7],29:[2,7],31:[2,7],32:[2,7],34:[2,7]},{5:[2,8],12:[2,8],13:[2,8],16:[2,8],24:[2,8],26:[2,8],28:[2,8],29:[2,8],31:[2,8],32:[2,8],34:[2,8]},{17:21,30:22,41:23,50:[1,26],52:[1,25],53:24},{17:27,30:22,41:23,50:[1,26],52:[1,25],53:24},{4:28,6:3,12:[2,38],13:[2,38],16:[2,38],24:[2,38],26:[2,38],28:[2,38],29:[2,38],31:[2,38],32:[2,38],34:[2,38]},{4:29,6:3,12:[2,38],13:[2,38],16:[2,38],24:[2,38],26:[2,38],28:[2,38],29:[2,38],31:[2,38],32:[2,38],34:[2,38]},{12:[1,30]},{30:32,35:31,42:[1,33],43:[1,34],50:[1,26],53:24},{17:35,30:22,41:23,50:[1,26],52:[1,25],53:24},{17:36,30:22,41:23,50:[1,26],52:[1,25],53:24},{17:37,30:22,41:23,50:[1,26],52:[1,25],53:24},{25:[1,38]},{18:[2,48],25:[2,48],33:[2,48],39:39,42:[2,48],43:[2,48],44:[2,48],45:[2,48],46:[2,48],50:[2,48],52:[2,48]},{18:[2,22],25:[2,22],33:[2,22],46:[2,22]},{18:[2,35],25:[2,35],33:[2,35],42:[2,35],43:[2,35],44:[2,35],45:[2,35],46:[2,35],50:[2,35],52:[2,35],54:[1,40]},{30:41,50:[1,26],53:24},{18:[2,37],25:[2,37],33:[2,37],42:[2,37],43:[2,37],44:[2,37],45:[2,37],46:[2,37],50:[2,37],52:[2,37],54:[2,37]},{33:[1,42]},{20:43,27:44,28:[1,45],29:[2,40]},{23:46,27:47,28:[1,45],29:[2,42]},{15:[1,48]},{25:[2,46],30:51,36:49,38:50,41:55,42:[1,52],43:[1,53],44:[1,54],45:[1,56],47:57,48:58,49:60,50:[1,59],52:[1,25],53:24},{25:[2,31],42:[2,31],43:[2,31],44:[2,31],45:[2,31],50:[2,31],52:[2,31]},{25:[2,32],42:[2,32],43:[2,32],44:[2,32],45:[2,32],50:[2,32],52:[2,32]},{25:[2,33],42:[2,33],43:[2,33],44:[2,33],45:[2,33],50:[2,33],52:[2,33]},{25:[1,61]},{25:[1,62]},{18:[1,63]},{5:[2,17],12:[2,17],13:[2,17],16:[2,17],24:[2,17],26:[2,17],28:[2,17],29:[2,17],31:[2,17],32:[2,17],34:[2,17]},{18:[2,50],25:[2,50],30:51,33:[2,50],36:65,40:64,41:55,42:[1,52],43:[1,53],44:[1,54],45:[1,56],46:[2,50],47:66,48:58,49:60,50:[1,59],52:[1,25],53:24},{50:[1,67]},{18:[2,34],25:[2,34],33:[2,34],42:[2,34],43:[2,34],44:[2,34],45:[2,34],46:[2,34],50:[2,34],52:[2,34]},{5:[2,18],12:[2,18],13:[2,18],16:[2,18],24:[2,18],26:[2,18],28:[2,18],29:[2,18],31:[2,18],32:[2,18],34:[2,18]},{21:68,29:[1,69]},{29:[2,41]},{4:70,6:3,12:[2,38],13:[2,38],16:[2,38],24:[2,38],26:[2,38],29:[2,38],31:[2,38],32:[2,38],34:[2,38]},{21:71,29:[1,69]},{29:[2,43]},{5:[2,9],12:[2,9],13:[2,9],16:[2,9],24:[2,9],26:[2,9],28:[2,9],29:[2,9],31:[2,9],32:[2,9],34:[2,9]},{25:[2,44],37:72,47:73,48:58,49:60,50:[1,74]},{25:[1,75]},{18:[2,23],25:[2,23],33:[2,23],42:[2,23],43:[2,23],44:[2,23],45:[2,23],46:[2,23],50:[2,23],52:[2,23]},{18:[2,24],25:[2,24],33:[2,24],42:[2,24],43:[2,24],44:[2,24],45:[2,24],46:[2,24],50:[2,24],52:[2,24]},{18:[2,25],25:[2,25],33:[2,25],42:[2,25],43:[2,25],44:[2,25],45:[2,25],46:[2,25],50:[2,25],52:[2,25]},{18:[2,26],25:[2,26],33:[2,26],42:[2,26],43:[2,26],44:[2,26],45:[2,26],46:[2,26],50:[2,26],52:[2,26]},{18:[2,27],25:[2,27],33:[2,27],42:[2,27],43:[2,27],44:[2,27],45:[2,27],46:[2,27],50:[2,27],52:[2,27]},{17:76,30:22,41:23,50:[1,26],52:[1,25],53:24},{25:[2,47]},{18:[2,29],25:[2,29],33:[2,29],46:[2,29],49:77,50:[1,74]},{18:[2,37],25:[2,37],33:[2,37],42:[2,37],43:[2,37],44:[2,37],45:[2,37],46:[2,37],50:[2,37],51:[1,78],52:[2,37],54:[2,37]},{18:[2,52],25:[2,52],33:[2,52],46:[2,52],50:[2,52]},{12:[2,13],13:[2,13],16:[2,13],24:[2,13],26:[2,13],28:[2,13],29:[2,13],31:[2,13],32:[2,13],34:[2,13]},{12:[2,14],13:[2,14],16:[2,14],24:[2,14],26:[2,14],28:[2,14],29:[2,14],31:[2,14],32:[2,14],34:[2,14]},{12:[2,10]},{18:[2,21],25:[2,21],33:[2,21],46:[2,21]},{18:[2,49],25:[2,49],33:[2,49],42:[2,49],43:[2,49],44:[2,49],45:[2,49],46:[2,49],50:[2,49],52:[2,49]},{18:[2,51],25:[2,51],33:[2,51],46:[2,51]},{18:[2,36],25:[2,36],33:[2,36],42:[2,36],43:[2,36],44:[2,36],45:[2,36],46:[2,36],50:[2,36],52:[2,36],54:[2,36]},{5:[2,11],12:[2,11],13:[2,11],16:[2,11],24:[2,11],26:[2,11],28:[2,11],29:[2,11],31:[2,11],32:[2,11],34:[2,11]},{30:79,50:[1,26],53:24},{29:[2,15]},{5:[2,12],12:[2,12],13:[2,12],16:[2,12],24:[2,12],26:[2,12],28:[2,12],29:[2,12],31:[2,12],32:[2,12],34:[2,12]},{25:[1,80]},{25:[2,45]},{51:[1,78]},{5:[2,20],12:[2,20],13:[2,20],16:[2,20],24:[2,20],26:[2,20],28:[2,20],29:[2,20],31:[2,20],32:[2,20],34:[2,20]},{46:[1,81]},{18:[2,53],25:[2,53],33:[2,53],46:[2,53],50:[2,53]},{30:51,36:82,41:55,42:[1,52],43:[1,53],44:[1,54],45:[1,56],50:[1,26],52:[1,25],53:24},{25:[1,83]},{5:[2,19],12:[2,19],13:[2,19],16:[2,19],24:[2,19],26:[2,19],28:[2,19],29:[2,19],31:[2,19],32:[2,19],34:[2,19]},{18:[2,28],25:[2,28],33:[2,28],42:[2,28],43:[2,28],44:[2,28],45:[2,28],46:[2,28],50:[2,28],52:[2,28]},{18:[2,30],25:[2,30],33:[2,30],46:[2,30],50:[2,30]},{5:[2,16],12:[2,16],13:[2,16],16:[2,16],24:[2,16],26:[2,16],28:[2,16],29:[2,16],31:[2,16],32:[2,16],34:[2,16]}],defaultActions:{4:[2,1],44:[2,41],47:[2,43],57:[2,47],63:[2,10],70:[2,15],73:[2,45]},parseError:function(a){throw new Error(a)},parse:function(a){function b(){var a;return a=c.lexer.lex()||1,"number"!=typeof a&&(a=c.symbols_[a]||a),a}var c=this,d=[0],e=[null],f=[],g=this.table,h="",i=0,j=0,k=0;this.lexer.setInput(a),this.lexer.yy=this.yy,this.yy.lexer=this.lexer,this.yy.parser=this,"undefined"==typeof this.lexer.yylloc&&(this.lexer.yylloc={});var l=this.lexer.yylloc;f.push(l);var m=this.lexer.options&&this.lexer.options.ranges;"function"==typeof this.yy.parseError&&(this.parseError=this.yy.parseError);for(var n,o,p,q,r,s,t,u,v,w={};;){if(p=d[d.length-1],this.defaultActions[p]?q=this.defaultActions[p]:((null===n||"undefined"==typeof n)&&(n=b()),q=g[p]&&g[p][n]),"undefined"==typeof q||!q.length||!q[0]){var x="";if(!k){v=[];for(s in g[p])this.terminals_[s]&&s>2&&v.push("'"+this.terminals_[s]+"'");x=this.lexer.showPosition?"Parse error on line "+(i+1)+":\n"+this.lexer.showPosition()+"\nExpecting "+v.join(", ")+", got '"+(this.terminals_[n]||n)+"'":"Parse error on line "+(i+1)+": Unexpected "+(1==n?"end of input":"'"+(this.terminals_[n]||n)+"'"),this.parseError(x,{text:this.lexer.match,token:this.terminals_[n]||n,line:this.lexer.yylineno,loc:l,expected:v})}}if(q[0]instanceof Array&&q.length>1)throw new Error("Parse Error: multiple actions possible at state: "+p+", token: "+n);switch(q[0]){case 1:d.push(n),e.push(this.lexer.yytext),f.push(this.lexer.yylloc),d.push(q[1]),n=null,o?(n=o,o=null):(j=this.lexer.yyleng,h=this.lexer.yytext,i=this.lexer.yylineno,l=this.lexer.yylloc,k>0&&k--);break;case 2:if(t=this.productions_[q[1]][1],w.$=e[e.length-t],w._$={first_line:f[f.length-(t||1)].first_line,last_line:f[f.length-1].last_line,first_column:f[f.length-(t||1)].first_column,last_column:f[f.length-1].last_column},m&&(w._$.range=[f[f.length-(t||1)].range[0],f[f.length-1].range[1]]),r=this.performAction.call(w,h,j,i,this.yy,q[1],e,f),"undefined"!=typeof r)return r;t&&(d=d.slice(0,-1*t*2),e=e.slice(0,-1*t),f=f.slice(0,-1*t)),d.push(this.productions_[q[1]][0]),e.push(w.$),f.push(w._$),u=g[d[d.length-2]][d[d.length-1]],d.push(u);break;case 3:return!0}}return!0}},c=function(){var a={EOF:1,parseError:function(a,b){if(!this.yy.parser)throw new Error(a);this.yy.parser.parseError(a,b)},setInput:function(a){return this._input=a,this._more=this._less=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var a=this._input[0];this.yytext+=a,this.yyleng++,this.offset++,this.match+=a,this.matched+=a;var b=a.match(/(?:\r\n?|\n).*/g);return b?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),a},unput:function(a){var b=a.length,c=a.split(/(?:\r\n?|\n)/g);this._input=a+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-b-1),this.offset-=b;var d=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),c.length-1&&(this.yylineno-=c.length-1);var e=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:c?(c.length===d.length?this.yylloc.first_column:0)+d[d.length-c.length].length-c[0].length:this.yylloc.first_column-b},this.options.ranges&&(this.yylloc.range=[e[0],e[0]+this.yyleng-b]),this},more:function(){return this._more=!0,this},less:function(a){this.unput(this.match.slice(a))},pastInput:function(){var a=this.matched.substr(0,this.matched.length-this.match.length);return(a.length>20?"...":"")+a.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var a=this.match;return a.length<20&&(a+=this._input.substr(0,20-a.length)),(a.substr(0,20)+(a.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var a=this.pastInput(),b=new Array(a.length+1).join("-");return a+this.upcomingInput()+"\n"+b+"^"},next:function(){if(this.done)return this.EOF;this._input||(this.done=!0);var a,b,c,d,e;this._more||(this.yytext="",this.match="");for(var f=this._currentRules(),g=0;g<f.length&&(c=this._input.match(this.rules[f[g]]),!c||b&&!(c[0].length>b[0].length)||(b=c,d=g,this.options.flex));g++);return b?(e=b[0].match(/(?:\r\n?|\n).*/g),e&&(this.yylineno+=e.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:e?e[e.length-1].length-e[e.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+b[0].length},this.yytext+=b[0],this.match+=b[0],this.matches=b,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._input=this._input.slice(b[0].length),this.matched+=b[0],a=this.performAction.call(this,this.yy,this,f[d],this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),a?a:void 0):""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){var a=this.next();return"undefined"!=typeof a?a:this.lex()},begin:function(a){this.conditionStack.push(a)},popState:function(){return this.conditionStack.pop()},_currentRules:function(){return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules},topState:function(){return this.conditionStack[this.conditionStack.length-2]},pushState:function(a){this.begin(a)}};return a.options={},a.performAction=function(a,b,c,d){function e(a,c){return b.yytext=b.yytext.substr(a,b.yyleng-c)}switch(c){case 0:if("\\\\"===b.yytext.slice(-2)?(e(0,1),this.begin("mu")):"\\"===b.yytext.slice(-1)?(e(0,1),this.begin("emu")):this.begin("mu"),b.yytext)return 12;break;case 1:return 12;case 2:return this.popState(),12;case 3:return b.yytext=b.yytext.substr(5,b.yyleng-9),this.popState(),15;case 4:return 12;case 5:return e(0,4),this.popState(),13;case 6:return 45;case 7:return 46;case 8:return 16;case 9:return this.popState(),this.begin("raw"),18;case 10:return 34;case 11:return 24;case 12:return 29;case 13:return this.popState(),28;case 14:return this.popState(),28;case 15:return 26;case 16:return 26;case 17:return 32;case 18:return 31;case 19:this.popState(),this.begin("com");break;case 20:return e(3,5),this.popState(),13;case 21:return 31;case 22:return 51;case 23:return 50;case 24:return 50;case 25:return 54;case 26:break;case 27:return this.popState(),33;case 28:return this.popState(),25;case 29:return b.yytext=e(1,2).replace(/\\"/g,'"'),42;case 30:return b.yytext=e(1,2).replace(/\\'/g,"'"),42;case 31:return 52;case 32:return 44;case 33:return 44;case 34:return 43;case 35:return 50;case 36:return b.yytext=e(1,2),50;case 37:return"INVALID";case 38:return 5}},a.rules=[/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|\\\{\{|\\\\\{\{|$)))/,/^(?:\{\{\{\{\/[^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=[=}\s\/.])\}\}\}\})/,/^(?:[^\x00]*?(?=(\{\{\{\{\/)))/,/^(?:[\s\S]*?--\}\})/,/^(?:\()/,/^(?:\))/,/^(?:\{\{\{\{)/,/^(?:\}\}\}\})/,/^(?:\{\{(~)?>)/,/^(?:\{\{(~)?#)/,/^(?:\{\{(~)?\/)/,/^(?:\{\{(~)?\^\s*(~)?\}\})/,/^(?:\{\{(~)?\s*else\s*(~)?\}\})/,/^(?:\{\{(~)?\^)/,/^(?:\{\{(~)?\s*else\b)/,/^(?:\{\{(~)?\{)/,/^(?:\{\{(~)?&)/,/^(?:\{\{!--)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{(~)?)/,/^(?:=)/,/^(?:\.\.)/,/^(?:\.(?=([=~}\s\/.)])))/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}(~)?\}\})/,/^(?:(~)?\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@)/,/^(?:true(?=([~}\s)])))/,/^(?:false(?=([~}\s)])))/,/^(?:-?[0-9]+(?:\.[0-9]+)?(?=([~}\s)])))/,/^(?:([^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=([=~}\s\/.)]))))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:$)/],a.conditions={mu:{rules:[6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38],inclusive:!1},emu:{rules:[2],inclusive:!1},com:{rules:[5],inclusive:!1},raw:{rules:[3,4],inclusive:!1},INITIAL:{rules:[0,1,38],inclusive:!0}},a}();return b.lexer=c,a.prototype=b,b.Parser=a,new a}();return a=b}(),i=function(a){"use strict";function b(a,b){return{left:"~"===a.charAt(2),right:"~"===b.charAt(b.length-3)}}function c(a,b,c,d,i,k){if(a.sexpr.id.original!==d.path.original)throw new j(a.sexpr.id.original+" doesn't match "+d.path.original,a);var l=c&&c.program,m={left:a.strip.left,right:d.strip.right,openStandalone:f(b.statements),closeStandalone:e((l||b).statements)};if(a.strip.right&&g(b.statements,null,!0),l){var n=c.strip;n.left&&h(b.statements,null,!0),n.right&&g(l.statements,null,!0),d.strip.left&&h(l.statements,null,!0),e(b.statements)&&f(l.statements)&&(h(b.statements),g(l.statements))}else d.strip.left&&h(b.statements,null,!0);return i?new this.BlockNode(a,l,b,m,k):new this.BlockNode(a,b,l,m,k)}function d(a,b){for(var c=0,d=a.length;d>c;c++){var i=a[c],j=i.strip;if(j){var k=e(a,c,b,"partial"===i.type),l=f(a,c,b),m=j.openStandalone&&k,n=j.closeStandalone&&l,o=j.inlineStandalone&&k&&l;j.right&&g(a,c,!0),j.left&&h(a,c,!0),o&&(g(a,c),h(a,c)&&"partial"===i.type&&(i.indent=/([ \t]+$)/.exec(a[c-1].original)?RegExp.$1:"")),m&&(g((i.program||i.inverse).statements),h(a,c)),n&&(g(a,c),h((i.inverse||i.program).statements))}}return a}function e(a,b,c){void 0===b&&(b=a.length);var d=a[b-1],e=a[b-2];return d?"content"===d.type?(e||!c?/\r?\n\s*?$/:/(^|\r?\n)\s*?$/).test(d.original):void 0:c}function f(a,b,c){void 0===b&&(b=-1);var d=a[b+1],e=a[b+2];return d?"content"===d.type?(e||!c?/^\s*?\r?\n/:/^\s*?(\r?\n|$)/).test(d.original):void 0:c}function g(a,b,c){var d=a[null==b?0:b+1];if(d&&"content"===d.type&&(c||!d.rightStripped)){var e=d.string;d.string=d.string.replace(c?/^\s+/:/^[ \t]*\r?\n?/,""),d.rightStripped=d.string!==e}}function h(a,b,c){var d=a[null==b?a.length-1:b-1];if(d&&"content"===d.type&&(c||!d.leftStripped)){var e=d.string;return d.string=d.string.replace(c?/\s+$/:/[ \t]+$/,""),d.leftStripped=d.string!==e,d.leftStripped}}var i={},j=a;return i.stripFlags=b,i.prepareBlock=c,i.prepareProgram=d,i}(c),j=function(a,b,c,d){"use strict";function e(a){return a.constructor===h.ProgramNode?a:(g.yy=k,g.parse(a))}var f={},g=a,h=b,i=c,j=d.extend;f.parser=g;var k={};return j(k,i,h),f.parse=e,f}(h,g,i,b),k=function(a,b){"use strict";function c(){}function d(a,b,c){if(null==a||"string"!=typeof a&&a.constructor!==c.AST.ProgramNode)throw new h("You must pass a string or Handlebars AST to Handlebars.precompile. You passed "+a);b=b||{},"data"in b||(b.data=!0),b.compat&&(b.useDepths=!0);var d=c.parse(a),e=(new c.Compiler).compile(d,b);return(new c.JavaScriptCompiler).compile(e,b)}function e(a,b,c){function d(){var d=c.parse(a),e=(new c.Compiler).compile(d,b),f=(new c.JavaScriptCompiler).compile(e,b,void 0,!0);return c.template(f)}if(null==a||"string"!=typeof a&&a.constructor!==c.AST.ProgramNode)throw new h("You must pass a string or Handlebars AST to Handlebars.compile. You passed "+a);b=b||{},"data"in b||(b.data=!0),b.compat&&(b.useDepths=!0);var e,f=function(a,b){return e||(e=d()),e.call(this,a,b)};return f._setup=function(a){return e||(e=d()),e._setup(a)},f._child=function(a,b,c){return e||(e=d()),e._child(a,b,c)},f}function f(a,b){if(a===b)return!0;if(i(a)&&i(b)&&a.length===b.length){for(var c=0;c<a.length;c++)if(!f(a[c],b[c]))return!1;return!0}}var g={},h=a,i=b.isArray,j=[].slice;return g.Compiler=c,c.prototype={compiler:c,equals:function(a){var b=this.opcodes.length;if(a.opcodes.length!==b)return!1;for(var c=0;b>c;c++){var d=this.opcodes[c],e=a.opcodes[c];if(d.opcode!==e.opcode||!f(d.args,e.args))return!1}for(b=this.children.length,c=0;b>c;c++)if(!this.children[c].equals(a.children[c]))return!1;return!0},guid:0,compile:function(a,b){this.opcodes=[],this.children=[],this.depths={list:[]},this.options=b,this.stringParams=b.stringParams,this.trackIds=b.trackIds;var c=this.options.knownHelpers;if(this.options.knownHelpers={helperMissing:!0,blockHelperMissing:!0,each:!0,"if":!0,unless:!0,"with":!0,log:!0,lookup:!0},c)for(var d in c)this.options.knownHelpers[d]=c[d];return this.accept(a)},accept:function(a){return this[a.type](a)},program:function(a){for(var b=a.statements,c=0,d=b.length;d>c;c++)this.accept(b[c]);return this.isSimple=1===d,this.depths.list=this.depths.list.sort(function(a,b){return a-b}),this},compileProgram:function(a){var b,c=(new this.compiler).compile(a,this.options),d=this.guid++;
this.usePartial=this.usePartial||c.usePartial,this.children[d]=c;for(var e=0,f=c.depths.list.length;f>e;e++)b=c.depths.list[e],2>b||this.addDepth(b-1);return d},block:function(a){var b=a.mustache,c=a.program,d=a.inverse;c&&(c=this.compileProgram(c)),d&&(d=this.compileProgram(d));var e=b.sexpr,f=this.classifySexpr(e);"helper"===f?this.helperSexpr(e,c,d):"simple"===f?(this.simpleSexpr(e),this.opcode("pushProgram",c),this.opcode("pushProgram",d),this.opcode("emptyHash"),this.opcode("blockValue",e.id.original)):(this.ambiguousSexpr(e,c,d),this.opcode("pushProgram",c),this.opcode("pushProgram",d),this.opcode("emptyHash"),this.opcode("ambiguousBlockValue")),this.opcode("append")},hash:function(a){var b,c,d=a.pairs;for(this.opcode("pushHash"),b=0,c=d.length;c>b;b++)this.pushParam(d[b][1]);for(;b--;)this.opcode("assignToHash",d[b][0]);this.opcode("popHash")},partial:function(a){var b=a.partialName;this.usePartial=!0,a.hash?this.accept(a.hash):this.opcode("push","undefined"),a.context?this.accept(a.context):(this.opcode("getContext",0),this.opcode("pushContext")),this.opcode("invokePartial",b.name,a.indent||""),this.opcode("append")},content:function(a){a.string&&this.opcode("appendContent",a.string)},mustache:function(a){this.sexpr(a.sexpr),a.escaped&&!this.options.noEscape?this.opcode("appendEscaped"):this.opcode("append")},ambiguousSexpr:function(a,b,c){var d=a.id,e=d.parts[0],f=null!=b||null!=c;this.opcode("getContext",d.depth),this.opcode("pushProgram",b),this.opcode("pushProgram",c),this.ID(d),this.opcode("invokeAmbiguous",e,f)},simpleSexpr:function(a){var b=a.id;"DATA"===b.type?this.DATA(b):b.parts.length?this.ID(b):(this.addDepth(b.depth),this.opcode("getContext",b.depth),this.opcode("pushContext")),this.opcode("resolvePossibleLambda")},helperSexpr:function(a,b,c){var d=this.setupFullMustacheParams(a,b,c),e=a.id,f=e.parts[0];if(this.options.knownHelpers[f])this.opcode("invokeKnownHelper",d.length,f);else{if(this.options.knownHelpersOnly)throw new h("You specified knownHelpersOnly, but used the unknown helper "+f,a);e.falsy=!0,this.ID(e),this.opcode("invokeHelper",d.length,e.original,e.isSimple)}},sexpr:function(a){var b=this.classifySexpr(a);"simple"===b?this.simpleSexpr(a):"helper"===b?this.helperSexpr(a):this.ambiguousSexpr(a)},ID:function(a){this.addDepth(a.depth),this.opcode("getContext",a.depth);var b=a.parts[0];b?this.opcode("lookupOnContext",a.parts,a.falsy,a.isScoped):this.opcode("pushContext")},DATA:function(a){this.options.data=!0,this.opcode("lookupData",a.id.depth,a.id.parts)},STRING:function(a){this.opcode("pushString",a.string)},NUMBER:function(a){this.opcode("pushLiteral",a.number)},BOOLEAN:function(a){this.opcode("pushLiteral",a.bool)},comment:function(){},opcode:function(a){this.opcodes.push({opcode:a,args:j.call(arguments,1)})},addDepth:function(a){0!==a&&(this.depths[a]||(this.depths[a]=!0,this.depths.list.push(a)))},classifySexpr:function(a){var b=a.isHelper,c=a.eligibleHelper,d=this.options;if(c&&!b){var e=a.id.parts[0];d.knownHelpers[e]?b=!0:d.knownHelpersOnly&&(c=!1)}return b?"helper":c?"ambiguous":"simple"},pushParams:function(a){for(var b=0,c=a.length;c>b;b++)this.pushParam(a[b])},pushParam:function(a){this.stringParams?(a.depth&&this.addDepth(a.depth),this.opcode("getContext",a.depth||0),this.opcode("pushStringParam",a.stringModeValue,a.type),"sexpr"===a.type&&this.sexpr(a)):(this.trackIds&&this.opcode("pushId",a.type,a.idName||a.stringModeValue),this.accept(a))},setupFullMustacheParams:function(a,b,c){var d=a.params;return this.pushParams(d),this.opcode("pushProgram",b),this.opcode("pushProgram",c),a.hash?this.hash(a.hash):this.opcode("emptyHash"),d}},g.precompile=d,g.compile=e,g}(c,b),l=function(a,b){"use strict";function c(a){this.value=a}function d(){}var e,f=a.COMPILER_REVISION,g=a.REVISION_CHANGES,h=b;d.prototype={nameLookup:function(a,b){return d.isValidJavaScriptVariableName(b)?a+"."+b:a+"['"+b+"']"},depthedLookup:function(a){return this.aliases.lookup="this.lookup",'lookup(depths, "'+a+'")'},compilerInfo:function(){var a=f,b=g[a];return[a,b]},appendToBuffer:function(a){return this.environment.isSimple?"return "+a+";":{appendToBuffer:!0,content:a,toString:function(){return"buffer += "+a+";"}}},initializeBuffer:function(){return this.quotedString("")},namespace:"Handlebars",compile:function(a,b,c,d){this.environment=a,this.options=b,this.stringParams=this.options.stringParams,this.trackIds=this.options.trackIds,this.precompile=!d,this.name=this.environment.name,this.isChild=!!c,this.context=c||{programs:[],environments:[]},this.preamble(),this.stackSlot=0,this.stackVars=[],this.aliases={},this.registers={list:[]},this.hashes=[],this.compileStack=[],this.inlineStack=[],this.compileChildren(a,b),this.useDepths=this.useDepths||a.depths.list.length||this.options.compat;var e,f,g,i=a.opcodes;for(f=0,g=i.length;g>f;f++)e=i[f],this[e.opcode].apply(this,e.args);if(this.pushSource(""),this.stackSlot||this.inlineStack.length||this.compileStack.length)throw new h("Compile completed with content left on stack");var j=this.createFunctionContext(d);if(this.isChild)return j;var k={compiler:this.compilerInfo(),main:j},l=this.context.programs;for(f=0,g=l.length;g>f;f++)l[f]&&(k[f]=l[f]);return this.environment.usePartial&&(k.usePartial=!0),this.options.data&&(k.useData=!0),this.useDepths&&(k.useDepths=!0),this.options.compat&&(k.compat=!0),d||(k.compiler=JSON.stringify(k.compiler),k=this.objectLiteral(k)),k},preamble:function(){this.lastContext=0,this.source=[]},createFunctionContext:function(a){var b="",c=this.stackVars.concat(this.registers.list);c.length>0&&(b+=", "+c.join(", "));for(var d in this.aliases)this.aliases.hasOwnProperty(d)&&(b+=", "+d+"="+this.aliases[d]);var e=["depth0","helpers","partials","data"];this.useDepths&&e.push("depths");var f=this.mergeSource(b);return a?(e.push(f),Function.apply(this,e)):"function("+e.join(",")+") {\n "+f+"}"},mergeSource:function(a){for(var b,c,d="",e=!this.forceBuffer,f=0,g=this.source.length;g>f;f++){var h=this.source[f];h.appendToBuffer?b=b?b+"\n + "+h.content:h.content:(b&&(d?d+="buffer += "+b+";\n ":(c=!0,d=b+";\n "),b=void 0),d+=h+"\n ",this.environment.isSimple||(e=!1))}return e?(b||!d)&&(d+="return "+(b||'""')+";\n"):(a+=", buffer = "+(c?"":this.initializeBuffer()),d+=b?"return buffer + "+b+";\n":"return buffer;\n"),a&&(d="var "+a.substring(2)+(c?"":";\n ")+d),d},blockValue:function(a){this.aliases.blockHelperMissing="helpers.blockHelperMissing";var b=[this.contextName(0)];this.setupParams(a,0,b);var c=this.popStack();b.splice(1,0,c),this.push("blockHelperMissing.call("+b.join(", ")+")")},ambiguousBlockValue:function(){this.aliases.blockHelperMissing="helpers.blockHelperMissing";var a=[this.contextName(0)];this.setupParams("",0,a,!0),this.flushInline();var b=this.topStack();a.splice(1,0,b),this.pushSource("if (!"+this.lastHelper+") { "+b+" = blockHelperMissing.call("+a.join(", ")+"); }")},appendContent:function(a){this.pendingContent&&(a=this.pendingContent+a),this.pendingContent=a},append:function(){this.flushInline();var a=this.popStack();this.pushSource("if ("+a+" != null) { "+this.appendToBuffer(a)+" }"),this.environment.isSimple&&this.pushSource("else { "+this.appendToBuffer("''")+" }")},appendEscaped:function(){this.aliases.escapeExpression="this.escapeExpression",this.pushSource(this.appendToBuffer("escapeExpression("+this.popStack()+")"))},getContext:function(a){this.lastContext=a},pushContext:function(){this.pushStackLiteral(this.contextName(this.lastContext))},lookupOnContext:function(a,b,c){var d=0,e=a.length;for(c||!this.options.compat||this.lastContext?this.pushContext():this.push(this.depthedLookup(a[d++]));e>d;d++)this.replaceStack(function(c){var e=this.nameLookup(c,a[d],"context");return b?" && "+e:" != null ? "+e+" : "+c})},lookupData:function(a,b){a?this.pushStackLiteral("this.data(data, "+a+")"):this.pushStackLiteral("data");for(var c=b.length,d=0;c>d;d++)this.replaceStack(function(a){return" && "+this.nameLookup(a,b[d],"data")})},resolvePossibleLambda:function(){this.aliases.lambda="this.lambda",this.push("lambda("+this.popStack()+", "+this.contextName(0)+")")},pushStringParam:function(a,b){this.pushContext(),this.pushString(b),"sexpr"!==b&&("string"==typeof a?this.pushString(a):this.pushStackLiteral(a))},emptyHash:function(){this.pushStackLiteral("{}"),this.trackIds&&this.push("{}"),this.stringParams&&(this.push("{}"),this.push("{}"))},pushHash:function(){this.hash&&this.hashes.push(this.hash),this.hash={values:[],types:[],contexts:[],ids:[]}},popHash:function(){var a=this.hash;this.hash=this.hashes.pop(),this.trackIds&&this.push("{"+a.ids.join(",")+"}"),this.stringParams&&(this.push("{"+a.contexts.join(",")+"}"),this.push("{"+a.types.join(",")+"}")),this.push("{\n "+a.values.join(",\n ")+"\n }")},pushString:function(a){this.pushStackLiteral(this.quotedString(a))},push:function(a){return this.inlineStack.push(a),a},pushLiteral:function(a){this.pushStackLiteral(a)},pushProgram:function(a){null!=a?this.pushStackLiteral(this.programExpression(a)):this.pushStackLiteral(null)},invokeHelper:function(a,b,c){this.aliases.helperMissing="helpers.helperMissing";var d=this.popStack(),e=this.setupHelper(a,b),f=(c?e.name+" || ":"")+d+" || helperMissing";this.push("(("+f+").call("+e.callParams+"))")},invokeKnownHelper:function(a,b){var c=this.setupHelper(a,b);this.push(c.name+".call("+c.callParams+")")},invokeAmbiguous:function(a,b){this.aliases.functionType='"function"',this.aliases.helperMissing="helpers.helperMissing",this.useRegister("helper");var c=this.popStack();this.emptyHash();var d=this.setupHelper(0,a,b),e=this.lastHelper=this.nameLookup("helpers",a,"helper");this.push("((helper = (helper = "+e+" || "+c+") != null ? helper : helperMissing"+(d.paramsInit?"),("+d.paramsInit:"")+"),(typeof helper === functionType ? helper.call("+d.callParams+") : helper))")},invokePartial:function(a,b){var c=[this.nameLookup("partials",a,"partial"),"'"+b+"'","'"+a+"'",this.popStack(),this.popStack(),"helpers","partials"];this.options.data?c.push("data"):this.options.compat&&c.push("undefined"),this.options.compat&&c.push("depths"),this.push("this.invokePartial("+c.join(", ")+")")},assignToHash:function(a){var b,c,d,e=this.popStack();this.trackIds&&(d=this.popStack()),this.stringParams&&(c=this.popStack(),b=this.popStack());var f=this.hash;b&&f.contexts.push("'"+a+"': "+b),c&&f.types.push("'"+a+"': "+c),d&&f.ids.push("'"+a+"': "+d),f.values.push("'"+a+"': ("+e+")")},pushId:function(a,b){"ID"===a||"DATA"===a?this.pushString(b):"sexpr"===a?this.pushStackLiteral("true"):this.pushStackLiteral("null")},compiler:d,compileChildren:function(a,b){for(var c,d,e=a.children,f=0,g=e.length;g>f;f++){c=e[f],d=new this.compiler;var h=this.matchExistingProgram(c);null==h?(this.context.programs.push(""),h=this.context.programs.length,c.index=h,c.name="program"+h,this.context.programs[h]=d.compile(c,b,this.context,!this.precompile),this.context.environments[h]=c,this.useDepths=this.useDepths||d.useDepths):(c.index=h,c.name="program"+h)}},matchExistingProgram:function(a){for(var b=0,c=this.context.environments.length;c>b;b++){var d=this.context.environments[b];if(d&&d.equals(a))return b}},programExpression:function(a){var b=this.environment.children[a],c=(b.depths.list,this.useDepths),d=[b.index,"data"];return c&&d.push("depths"),"this.program("+d.join(", ")+")"},useRegister:function(a){this.registers[a]||(this.registers[a]=!0,this.registers.list.push(a))},pushStackLiteral:function(a){return this.push(new c(a))},pushSource:function(a){this.pendingContent&&(this.source.push(this.appendToBuffer(this.quotedString(this.pendingContent))),this.pendingContent=void 0),a&&this.source.push(a)},pushStack:function(a){this.flushInline();var b=this.incrStack();return this.pushSource(b+" = "+a+";"),this.compileStack.push(b),b},replaceStack:function(a){{var b,d,e,f="";this.isInline()}if(!this.isInline())throw new h("replaceStack on non-inline");var g=this.popStack(!0);if(g instanceof c)f=b=g.value,e=!0;else{d=!this.stackSlot;var i=d?this.incrStack():this.topStackName();f="("+this.push(i)+" = "+g+")",b=this.topStack()}var j=a.call(this,b);e||this.popStack(),d&&this.stackSlot--,this.push("("+f+j+")")},incrStack:function(){return this.stackSlot++,this.stackSlot>this.stackVars.length&&this.stackVars.push("stack"+this.stackSlot),this.topStackName()},topStackName:function(){return"stack"+this.stackSlot},flushInline:function(){var a=this.inlineStack;if(a.length){this.inlineStack=[];for(var b=0,d=a.length;d>b;b++){var e=a[b];e instanceof c?this.compileStack.push(e):this.pushStack(e)}}},isInline:function(){return this.inlineStack.length},popStack:function(a){var b=this.isInline(),d=(b?this.inlineStack:this.compileStack).pop();if(!a&&d instanceof c)return d.value;if(!b){if(!this.stackSlot)throw new h("Invalid stack pop");this.stackSlot--}return d},topStack:function(){var a=this.isInline()?this.inlineStack:this.compileStack,b=a[a.length-1];return b instanceof c?b.value:b},contextName:function(a){return this.useDepths&&a?"depths["+a+"]":"depth"+a},quotedString:function(a){return'"'+a.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/\u2028/g,"\\u2028").replace(/\u2029/g,"\\u2029")+'"'},objectLiteral:function(a){var b=[];for(var c in a)a.hasOwnProperty(c)&&b.push(this.quotedString(c)+":"+a[c]);return"{"+b.join(",")+"}"},setupHelper:function(a,b,c){var d=[],e=this.setupParams(b,a,d,c),f=this.nameLookup("helpers",b,"helper");return{params:d,paramsInit:e,name:f,callParams:[this.contextName(0)].concat(d).join(", ")}},setupOptions:function(a,b,c){var d,e,f,g={},h=[],i=[],j=[];g.name=this.quotedString(a),g.hash=this.popStack(),this.trackIds&&(g.hashIds=this.popStack()),this.stringParams&&(g.hashTypes=this.popStack(),g.hashContexts=this.popStack()),e=this.popStack(),f=this.popStack(),(f||e)&&(f||(f="this.noop"),e||(e="this.noop"),g.fn=f,g.inverse=e);for(var k=b;k--;)d=this.popStack(),c[k]=d,this.trackIds&&(j[k]=this.popStack()),this.stringParams&&(i[k]=this.popStack(),h[k]=this.popStack());return this.trackIds&&(g.ids="["+j.join(",")+"]"),this.stringParams&&(g.types="["+i.join(",")+"]",g.contexts="["+h.join(",")+"]"),this.options.data&&(g.data="data"),g},setupParams:function(a,b,c,d){var e=this.objectLiteral(this.setupOptions(a,b,c));return d?(this.useRegister("options"),c.push("options"),"options="+e):(c.push(e),"")}};for(var i="break else new var case finally return void catch for switch while continue function this with default if throw delete in try do instanceof typeof abstract enum int short boolean export interface static byte extends long super char final native synchronized class float package throws const goto private transient debugger implements protected volatile double import public let yield".split(" "),j=d.RESERVED_WORDS={},k=0,l=i.length;l>k;k++)j[i[k]]=!0;return d.isValidJavaScriptVariableName=function(a){return!d.RESERVED_WORDS[a]&&/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(a)},e=d}(d,c),m=function(a,b,c,d,e){"use strict";var f,g=a,h=b,i=c.parser,j=c.parse,k=d.Compiler,l=d.compile,m=d.precompile,n=e,o=g.create,p=function(){var a=o();return a.compile=function(b,c){return l(b,c,a)},a.precompile=function(b,c){return m(b,c,a)},a.AST=h,a.Compiler=k,a.JavaScriptCompiler=n,a.Parser=i,a.parse=j,a};return g=p(),g.create=p,g["default"]=g,f=g}(f,g,j,k,l);return m});
\ No newline at end of file
......@@ -2915,6 +2915,9 @@ function restCommandRejecter(param, args) {
if (arg.columnNumber !== undefined && arg.columnNumber !== null) {
current_priority.columnNumber = arg.columnNumber;
}
if (arg.fileName !== undefined && arg.fileName !== null) {
current_priority.fileName = arg.fileName;
}
if (arg.filename !== undefined && arg.filename !== null) {
current_priority.filename = arg.filename;
}
......@@ -4147,7 +4150,7 @@ function enableRestParamChecker(jio, shared) {
}
});
["getAttachment", "removeAttachment"].forEach(function (method) {
["removeAttachment"].forEach(function (method) {
shared.on(method, function (param) {
if (!checkId(param)) {
checkAttachmentId(param);
......@@ -4155,6 +4158,26 @@ function enableRestParamChecker(jio, shared) {
});
});
["getAttachment"].forEach(function (method) {
shared.on(method, function (param) {
if (param.storage_spec.type !== "indexeddb" &&
param.storage_spec.type !== "dav" &&
(param.kwargs._start !== undefined
|| param.kwargs._end !== undefined)) {
restCommandRejecter(param, [
'bad_request',
'unsupport',
'_start, _end not support'
]);
return false;
}
if (!checkId(param)) {
checkAttachmentId(param);
}
});
});
["check", "repair"].forEach(function (method) {
shared.on(method, function (param) {
if (param.kwargs._id !== undefined) {
......
/*!
* QUnit 1.14.0
* QUnit 1.15.0
* http://qunitjs.com/
*
* Copyright 2013 jQuery Foundation and other contributors
* Copyright 2014 jQuery Foundation and other contributors
* Released under the MIT license
* http://jquery.org/license
*
* Date: 2014-01-31T16:40Z
* Date: 2014-08-08T16:00Z
*/
/** Font Family and Sizes */
......@@ -62,14 +62,14 @@
}
#qunit-testrunner-toolbar {
padding: 0.5em 0 0.5em 2em;
padding: 0.5em 1em 0.5em 1em;
color: #5E740B;
background-color: #EEE;
overflow: hidden;
}
#qunit-userAgent {
padding: 0.5em 0 0.5em 2.5em;
padding: 0.5em 1em 0.5em 1em;
background-color: #2B81AF;
color: #FFF;
text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
......@@ -86,7 +86,7 @@
}
#qunit-tests li {
padding: 0.4em 0.5em 0.4em 2.5em;
padding: 0.4em 1em 0.4em 1em;
border-bottom: 1px solid #FFF;
list-style-position: inside;
}
......@@ -215,7 +215,7 @@
/** Result */
#qunit-testresult {
padding: 0.5em 0.5em 0.5em 2.5em;
padding: 0.5em 1em 0.5em 1em;
color: #2B81AF;
background-color: #D2E0E6;
......
/*!
* QUnit 1.14.0
* QUnit 1.15.0
* http://qunitjs.com/
*
* Copyright 2013 jQuery Foundation and other contributors
* Copyright 2014 jQuery Foundation and other contributors
* Released under the MIT license
* http://jquery.org/license
*
* Date: 2014-01-31T16:40Z
* Date: 2014-08-08T16:00Z
*/
(function( window ) {
var QUnit,
assert,
config,
onErrorFnPrev,
testId = 0,
fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
fileName = ( sourceFromStacktrace( 0 ) || "" ).replace( /(:\d+)+\)?/, "" ).replace( /.+\//, "" ),
toString = Object.prototype.toString,
hasOwn = Object.prototype.hasOwnProperty,
// Keep a local reference to Date (GH-283)
Date = window.Date,
now = Date.now || function() {
return new Date().getTime();
},
setTimeout = window.setTimeout,
clearTimeout = window.clearTimeout,
defined = {
......@@ -32,7 +33,7 @@ var QUnit,
sessionStorage.setItem( x, x );
sessionStorage.removeItem( x );
return true;
} catch( e ) {
} catch ( e ) {
return false;
}
}())
......@@ -74,20 +75,17 @@ var QUnit,
* @return {Object} New object with only the own properties (recursively).
*/
objectValues = function( obj ) {
// Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
/*jshint newcap: false */
var key, val,
vals = QUnit.is( "array", obj ) ? [] : {};
for ( key in obj ) {
if ( hasOwn.call( obj, key ) ) {
val = obj[key];
vals[key] = val === Object(val) ? objectValues(val) : val;
val = obj[ key ];
vals[ key ] = val === Object( val ) ? objectValues( val ) : val;
}
}
return vals;
};
// Root QUnit object.
// `QUnit` initialized at top of scope
QUnit = {
......@@ -96,7 +94,7 @@ QUnit = {
module: function( name, testEnvironment ) {
config.currentModule = name;
config.currentModuleTestEnvironment = testEnvironment;
config.modules[name] = true;
config.modules[ name ] = true;
},
asyncTest: function( testName, expected, callback ) {
......@@ -109,20 +107,14 @@ QUnit = {
},
test: function( testName, expected, callback, async ) {
var test,
nameHtml = "<span class='test-name'>" + escapeText( testName ) + "</span>";
var test;
if ( arguments.length === 2 ) {
callback = expected;
expected = null;
}
if ( config.currentModule ) {
nameHtml = "<span class='module-name'>" + escapeText( config.currentModule ) + "</span>: " + nameHtml;
}
test = new Test({
nameHtml: nameHtml,
testName: testName,
expected: expected,
async: async,
......@@ -139,16 +131,9 @@ QUnit = {
test.queue();
},
// Specify the number of expected assertions to guarantee that failed test (no assertions are run at all) don't slip through.
expect: function( asserts ) {
if (arguments.length === 1) {
config.current.expected = asserts;
} else {
return config.current.expected;
}
},
start: function( count ) {
var message;
// QUnit hasn't been initialized yet.
// Note: RequireJS (et al) may delay onLoad
if ( config.semaphore === undefined ) {
......@@ -166,10 +151,21 @@ QUnit = {
if ( config.semaphore > 0 ) {
return;
}
// Set the starting time when the first test is run
QUnit.config.started = QUnit.config.started || now();
// ignore if start is called more often then stop
if ( config.semaphore < 0 ) {
config.semaphore = 0;
QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
message = "Called start() while already started (QUnit.config.semaphore was 0 already)";
if ( config.current ) {
QUnit.pushFailure( message, sourceFromStacktrace( 2 ) );
} else {
throw new Error( message );
}
return;
}
// A slight delay, to avoid any current callbacks
......@@ -184,7 +180,7 @@ QUnit = {
config.blocking = false;
process( true );
}, 13);
}, 13 );
} else {
config.blocking = false;
process( true );
......@@ -212,6 +208,7 @@ QUnit = {
function F() {}
F.prototype = QUnit;
QUnit = new F();
// Make F QUnit's constructor so that we can add to the prototype later
QUnit.constructor = F;
}());
......@@ -263,14 +260,7 @@ config = {
// Set of all modules.
modules: {},
// logging callback queues
begin: [],
done: [],
log: [],
testStart: [],
testDone: [],
moduleStart: [],
moduleDone: []
callbacks: {}
};
// Initialize more QUnit.config and QUnit.urlParams
......@@ -323,71 +313,6 @@ extend( QUnit, {
config: config,
// Initialize the configuration options
init: function() {
extend( config, {
stats: { all: 0, bad: 0 },
moduleStats: { all: 0, bad: 0 },
started: +new Date(),
updateRate: 1000,
blocking: false,
autostart: true,
autorun: false,
filter: "",
queue: [],
semaphore: 1
});
var tests, banner, result,
qunit = id( "qunit" );
if ( qunit ) {
qunit.innerHTML =
"<h1 id='qunit-header'>" + escapeText( document.title ) + "</h1>" +
"<h2 id='qunit-banner'></h2>" +
"<div id='qunit-testrunner-toolbar'></div>" +
"<h2 id='qunit-userAgent'></h2>" +
"<ol id='qunit-tests'></ol>";
}
tests = id( "qunit-tests" );
banner = id( "qunit-banner" );
result = id( "qunit-testresult" );
if ( tests ) {
tests.innerHTML = "";
}
if ( banner ) {
banner.className = "";
}
if ( result ) {
result.parentNode.removeChild( result );
}
if ( tests ) {
result = document.createElement( "p" );
result.id = "qunit-testresult";
result.className = "result";
tests.parentNode.insertBefore( result, tests );
result.innerHTML = "Running...<br/>&nbsp;";
}
},
// Resets the test setup. Useful for tests that modify the DOM.
/*
DEPRECATED: Use multiple tests instead of resetting inside a test.
Use testStart or testDone for custom cleanup.
This method will throw an error in 2.0, and will be removed in 2.1
*/
reset: function() {
var fixture = id( "qunit-fixture" );
if ( fixture ) {
fixture.innerHTML = config.fixture;
}
},
// Safe object type checking
is: function( type, obj ) {
return QUnit.objectType( obj ) === type;
......@@ -403,12 +328,12 @@ extend( QUnit, {
return "null";
}
var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
type = match && match[1] || "";
var match = toString.call( obj ).match( /^\[object\s(.*)\]$/ ),
type = match && match[ 1 ] || "";
switch ( type ) {
case "Number":
if ( isNaN(obj) ) {
if ( isNaN( obj ) ) {
return "nan";
}
return "number";
......@@ -426,91 +351,6 @@ extend( QUnit, {
return undefined;
},
push: function( result, actual, expected, message ) {
if ( !config.current ) {
throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
}
var output, source,
details = {
module: config.current.module,
name: config.current.testName,
result: result,
message: message,
actual: actual,
expected: expected
};
message = escapeText( message ) || ( result ? "okay" : "failed" );
message = "<span class='test-message'>" + message + "</span>";
output = message;
if ( !result ) {
expected = escapeText( QUnit.jsDump.parse(expected) );
actual = escapeText( QUnit.jsDump.parse(actual) );
output += "<table><tr class='test-expected'><th>Expected: </th><td><pre>" + expected + "</pre></td></tr>";
if ( actual !== expected ) {
output += "<tr class='test-actual'><th>Result: </th><td><pre>" + actual + "</pre></td></tr>";
output += "<tr class='test-diff'><th>Diff: </th><td><pre>" + QUnit.diff( expected, actual ) + "</pre></td></tr>";
}
source = sourceFromStacktrace();
if ( source ) {
details.source = source;
output += "<tr class='test-source'><th>Source: </th><td><pre>" + escapeText( source ) + "</pre></td></tr>";
}
output += "</table>";
}
runLoggingCallbacks( "log", QUnit, details );
config.current.assertions.push({
result: !!result,
message: output
});
},
pushFailure: function( message, source, actual ) {
if ( !config.current ) {
throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
}
var output,
details = {
module: config.current.module,
name: config.current.testName,
result: false,
message: message
};
message = escapeText( message ) || "error";
message = "<span class='test-message'>" + message + "</span>";
output = message;
output += "<table>";
if ( actual ) {
output += "<tr class='test-actual'><th>Result: </th><td><pre>" + escapeText( actual ) + "</pre></td></tr>";
}
if ( source ) {
details.source = source;
output += "<tr class='test-source'><th>Source: </th><td><pre>" + escapeText( source ) + "</pre></td></tr>";
}
output += "</table>";
runLoggingCallbacks( "log", QUnit, details );
config.current.assertions.push({
result: false,
message: output
});
},
url: function( params ) {
params = extend( extend( {}, QUnit.urlParams ), params );
var key,
......@@ -526,13 +366,7 @@ extend( QUnit, {
window.location.pathname + querystring.slice( 0, -1 );
},
extend: extend,
id: id,
addEvent: addEvent,
addClass: addClass,
hasClass: hasClass,
removeClass: removeClass
// load, equiv, jsDump, diff: Attached later
extend: extend
});
/**
......@@ -567,215 +401,29 @@ extend( QUnit.constructor.prototype, {
moduleDone: registerLoggingCallback( "moduleDone" )
});
if ( !defined.document || document.readyState === "complete" ) {
config.autorun = true;
}
QUnit.load = function() {
runLoggingCallbacks( "begin", QUnit, {} );
// Initialize the config, saving the execution queue
var banner, filter, i, j, label, len, main, ol, toolbar, val, selection,
urlConfigContainer, moduleFilter, userAgent,
numModules = 0,
moduleNames = [],
moduleFilterHtml = "",
urlConfigHtml = "",
oldconfig = extend( {}, config );
QUnit.init();
extend(config, oldconfig);
config.blocking = false;
len = config.urlConfig.length;
for ( i = 0; i < len; i++ ) {
val = config.urlConfig[i];
if ( typeof val === "string" ) {
val = {
id: val,
label: val
};
}
config[ val.id ] = QUnit.urlParams[ val.id ];
if ( !val.value || typeof val.value === "string" ) {
urlConfigHtml += "<input id='qunit-urlconfig-" + escapeText( val.id ) +
"' name='" + escapeText( val.id ) +
"' type='checkbox'" +
( val.value ? " value='" + escapeText( val.value ) + "'" : "" ) +
( config[ val.id ] ? " checked='checked'" : "" ) +
" title='" + escapeText( val.tooltip ) +
"'><label for='qunit-urlconfig-" + escapeText( val.id ) +
"' title='" + escapeText( val.tooltip ) + "'>" + val.label + "</label>";
} else {
urlConfigHtml += "<label for='qunit-urlconfig-" + escapeText( val.id ) +
"' title='" + escapeText( val.tooltip ) +
"'>" + val.label +
": </label><select id='qunit-urlconfig-" + escapeText( val.id ) +
"' name='" + escapeText( val.id ) +
"' title='" + escapeText( val.tooltip ) +
"'><option></option>";
selection = false;
if ( QUnit.is( "array", val.value ) ) {
for ( j = 0; j < val.value.length; j++ ) {
urlConfigHtml += "<option value='" + escapeText( val.value[j] ) + "'" +
( config[ val.id ] === val.value[j] ?
(selection = true) && " selected='selected'" :
"" ) +
">" + escapeText( val.value[j] ) + "</option>";
}
} else {
for ( j in val.value ) {
if ( hasOwn.call( val.value, j ) ) {
urlConfigHtml += "<option value='" + escapeText( j ) + "'" +
( config[ val.id ] === j ?
(selection = true) && " selected='selected'" :
"" ) +
">" + escapeText( val.value[j] ) + "</option>";
}
}
}
if ( config[ val.id ] && !selection ) {
urlConfigHtml += "<option value='" + escapeText( config[ val.id ] ) +
"' selected='selected' disabled='disabled'>" +
escapeText( config[ val.id ] ) +
"</option>";
}
urlConfigHtml += "</select>";
}
}
for ( i in config.modules ) {
if ( config.modules.hasOwnProperty( i ) ) {
moduleNames.push(i);
}
}
numModules = moduleNames.length;
moduleNames.sort( function( a, b ) {
return a.localeCompare( b );
runLoggingCallbacks( "begin", {
totalTests: Test.count
});
moduleFilterHtml += "<label for='qunit-modulefilter'>Module: </label><select id='qunit-modulefilter' name='modulefilter'><option value='' " +
( config.module === undefined ? "selected='selected'" : "" ) +
">< All Modules ></option>";
for ( i = 0; i < numModules; i++) {
moduleFilterHtml += "<option value='" + escapeText( encodeURIComponent(moduleNames[i]) ) + "' " +
( config.module === moduleNames[i] ? "selected='selected'" : "" ) +
">" + escapeText(moduleNames[i]) + "</option>";
}
moduleFilterHtml += "</select>";
// `userAgent` initialized at top of scope
userAgent = id( "qunit-userAgent" );
if ( userAgent ) {
userAgent.innerHTML = navigator.userAgent;
}
// `banner` initialized at top of scope
banner = id( "qunit-header" );
if ( banner ) {
banner.innerHTML = "<a href='" + QUnit.url({ filter: undefined, module: undefined, testNumber: undefined }) + "'>" + banner.innerHTML + "</a> ";
}
// `toolbar` initialized at top of scope
toolbar = id( "qunit-testrunner-toolbar" );
if ( toolbar ) {
// `filter` initialized at top of scope
filter = document.createElement( "input" );
filter.type = "checkbox";
filter.id = "qunit-filter-pass";
addEvent( filter, "click", function() {
var tmp,
ol = id( "qunit-tests" );
if ( filter.checked ) {
ol.className = ol.className + " hidepass";
} else {
tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
ol.className = tmp.replace( / hidepass /, " " );
}
if ( defined.sessionStorage ) {
if (filter.checked) {
sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
} else {
sessionStorage.removeItem( "qunit-filter-passed-tests" );
}
}
});
if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
filter.checked = true;
// `ol` initialized at top of scope
ol = id( "qunit-tests" );
ol.className = ol.className + " hidepass";
}
toolbar.appendChild( filter );
// `label` initialized at top of scope
label = document.createElement( "label" );
label.setAttribute( "for", "qunit-filter-pass" );
label.setAttribute( "title", "Only show tests and assertions that fail. Stored in sessionStorage." );
label.innerHTML = "Hide passed tests";
toolbar.appendChild( label );
urlConfigContainer = document.createElement("span");
urlConfigContainer.innerHTML = urlConfigHtml;
// For oldIE support:
// * Add handlers to the individual elements instead of the container
// * Use "click" instead of "change" for checkboxes
// * Fallback from event.target to event.srcElement
addEvents( urlConfigContainer.getElementsByTagName("input"), "click", function( event ) {
var params = {},
target = event.target || event.srcElement;
params[ target.name ] = target.checked ?
target.defaultValue || true :
undefined;
window.location = QUnit.url( params );
});
addEvents( urlConfigContainer.getElementsByTagName("select"), "change", function( event ) {
var params = {},
target = event.target || event.srcElement;
params[ target.name ] = target.options[ target.selectedIndex ].value || undefined;
window.location = QUnit.url( params );
});
toolbar.appendChild( urlConfigContainer );
if (numModules > 1) {
moduleFilter = document.createElement( "span" );
moduleFilter.setAttribute( "id", "qunit-modulefilter-container" );
moduleFilter.innerHTML = moduleFilterHtml;
addEvent( moduleFilter.lastChild, "change", function() {
var selectBox = moduleFilter.getElementsByTagName("select")[0],
selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
window.location = QUnit.url({
module: ( selectedModule === "" ) ? undefined : selectedModule,
// Remove any existing filters
filter: undefined,
testNumber: undefined
});
});
toolbar.appendChild(moduleFilter);
}
}
// Initialize the configuration options
extend( config, {
stats: { all: 0, bad: 0 },
moduleStats: { all: 0, bad: 0 },
started: 0,
updateRate: 1000,
autostart: true,
filter: "",
semaphore: 1
}, true );
// `main` initialized at top of scope
main = id( "qunit-fixture" );
if ( main ) {
config.fixture = main.innerHTML;
}
config.blocking = false;
if ( config.autostart ) {
QUnit.start();
}
};
if ( defined.document ) {
addEvent( window, "load", QUnit.load );
}
// `onErrorFnPrev` initialized at top of scope
// Preserve other handlers
onErrorFnPrev = window.onerror;
......@@ -783,7 +431,7 @@ onErrorFnPrev = window.onerror;
// Cover uncaught exceptions
// Returning true will suppress the default browser handler,
// returning false will let it run.
window.onerror = function ( error, filePath, linerNr ) {
window.onerror = function( error, filePath, linerNr ) {
var ret = false;
if ( onErrorFnPrev ) {
ret = onErrorFnPrev( error, filePath, linerNr );
......@@ -798,7 +446,7 @@ window.onerror = function ( error, filePath, linerNr ) {
}
QUnit.pushFailure( error, filePath + ":" + linerNr );
} else {
QUnit.test( "global failure", extend( function() {
QUnit.test( "global failure", extend(function() {
QUnit.pushFailure( error, filePath + ":" + linerNr );
}, { validTest: validTest } ) );
}
......@@ -813,7 +461,7 @@ function done() {
// Log the last module results
if ( config.previousModule ) {
runLoggingCallbacks( "moduleDone", QUnit, {
runLoggingCallbacks( "moduleDone", {
name: config.previousModule,
failed: config.moduleStats.bad,
passed: config.moduleStats.all - config.moduleStats.bad,
......@@ -822,58 +470,10 @@ function done() {
}
delete config.previousModule;
var i, key,
banner = id( "qunit-banner" ),
tests = id( "qunit-tests" ),
runtime = +new Date() - config.started,
passed = config.stats.all - config.stats.bad,
html = [
"Tests completed in ",
runtime,
" milliseconds.<br/>",
"<span class='passed'>",
passed,
"</span> assertions of <span class='total'>",
config.stats.all,
"</span> passed, <span class='failed'>",
config.stats.bad,
"</span> failed."
].join( "" );
if ( banner ) {
banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
}
if ( tests ) {
id( "qunit-testresult" ).innerHTML = html;
}
if ( config.altertitle && defined.document && document.title ) {
// show ✖ for good, ✔ for bad suite result in title
// use escape sequences in case file gets loaded with non-utf-8-charset
document.title = [
( config.stats.bad ? "\u2716" : "\u2714" ),
document.title.replace( /^[\u2714\u2716] /i, "" )
].join( " " );
}
// clear own sessionStorage items if all tests passed
if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
// `key` & `i` initialized at top of scope
for ( i = 0; i < sessionStorage.length; i++ ) {
key = sessionStorage.key( i++ );
if ( key.indexOf( "qunit-test-" ) === 0 ) {
sessionStorage.removeItem( key );
}
}
}
// scroll back to top to show results
if ( config.scrolltop && window.scrollTo ) {
window.scrollTo(0, 0);
}
var runtime = now() - config.started,
passed = config.stats.all - config.stats.bad;
runLoggingCallbacks( "done", QUnit, {
runLoggingCallbacks( "done", {
failed: config.stats.bad,
passed: passed,
total: config.stats.all,
......@@ -922,21 +522,22 @@ function validTest( test ) {
return !include;
}
// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
// Later Safari and IE10 are supposed to support error.stack as well
// Doesn't support IE6 to IE9
// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
function extractStacktrace( e, offset ) {
offset = offset === undefined ? 3 : offset;
offset = offset === undefined ? 4 : offset;
var stack, include, i;
if ( e.stacktrace ) {
// Opera
// Opera 12.x
return e.stacktrace.split( "\n" )[ offset + 3 ];
} else if ( e.stack ) {
// Firefox, Chrome
// Firefox, Chrome, Safari 6+, IE10+, PhantomJS and Node
stack = e.stack.split( "\n" );
if (/^error$/i.test( stack[0] ) ) {
if ( /^error$/i.test( stack[ 0 ] ) ) {
stack.shift();
}
if ( fileName ) {
......@@ -953,12 +554,13 @@ function extractStacktrace( e, offset ) {
}
return stack[ offset ];
} else if ( e.sourceURL ) {
// Safari, PhantomJS
// hopefully one day Safari provides actual stacktraces
// Safari < 6
// exclude useless self-reference for generated Error objects
if ( /qunit.js$/.test( e.sourceURL ) ) {
return;
}
// for actual exceptions, this is useful
return e.sourceURL + ":" + e.line;
}
......@@ -971,31 +573,6 @@ function sourceFromStacktrace( offset ) {
}
}
/**
* Escape text for attribute or text content.
*/
function escapeText( s ) {
if ( !s ) {
return "";
}
s = s + "";
// Both single quotes and double quotes (for attributes)
return s.replace( /['"<>&]/g, function( s ) {
switch( s ) {
case "'":
return "&#039;";
case "\"":
return "&quot;";
case "<":
return "&lt;";
case ">":
return "&gt;";
case "&":
return "&amp;";
}
});
}
function synchronize( callback, last ) {
config.queue.push( callback );
......@@ -1008,11 +585,11 @@ function process( last ) {
function next() {
process( last );
}
var start = new Date().getTime();
var start = now();
config.depth = config.depth ? config.depth + 1 : 1;
while ( config.queue.length && !config.blocking ) {
if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
if ( !defined.setTimeout || config.updateRate <= 0 || ( ( now() - start ) < config.updateRate ) ) {
config.queue.shift()();
} else {
setTimeout( next, 13 );
......@@ -1050,12 +627,12 @@ function checkPollution() {
newGlobals = diff( config.pollution, old );
if ( newGlobals.length > 0 ) {
QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join( ", " ) );
}
deletedGlobals = diff( old, config.pollution );
if ( deletedGlobals.length > 0 ) {
QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join( ", " ) );
}
}
......@@ -1066,7 +643,7 @@ function diff( a, b ) {
for ( i = 0; i < result.length; i++ ) {
for ( j = 0; j < b.length; j++ ) {
if ( result[i] === b[j] ) {
if ( result[ i ] === b[ j ] ) {
result.splice( i, 1 );
i--;
break;
......@@ -1076,14 +653,15 @@ function diff( a, b ) {
return result;
}
function extend( a, b ) {
function extend( a, b, undefOnly ) {
for ( var prop in b ) {
if ( hasOwn.call( b, prop ) ) {
// Avoid "Member not found" error in IE8 caused by messing with window.constructor
if ( !( prop === "constructor" && a === window ) ) {
if ( b[ prop ] === undefined ) {
delete a[ prop ];
} else {
} else if ( !( undefOnly && typeof a[ prop ] !== "undefined" ) ) {
a[ prop ] = b[ prop ];
}
}
......@@ -1093,79 +671,24 @@ function extend( a, b ) {
return a;
}
/**
* @param {HTMLElement} elem
* @param {string} type
* @param {Function} fn
*/
function addEvent( elem, type, fn ) {
if ( elem.addEventListener ) {
// Standards-based browsers
elem.addEventListener( type, fn, false );
} else if ( elem.attachEvent ) {
// support: IE <9
elem.attachEvent( "on" + type, fn );
} else {
function registerLoggingCallback( key ) {
// Caller must ensure support for event listeners is present
throw new Error( "addEvent() was called in a context without event listener support" );
// Initialize key collection of logging callback
if ( QUnit.objectType( config.callbacks[ key ] ) === "undefined" ) {
config.callbacks[ key ] = [];
}
return function( callback ) {
config.callbacks[ key ].push( callback );
};
}
/**
* @param {Array|NodeList} elems
* @param {string} type
* @param {Function} fn
*/
function addEvents( elems, type, fn ) {
var i = elems.length;
while ( i-- ) {
addEvent( elems[i], type, fn );
}
}
function hasClass( elem, name ) {
return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
}
function addClass( elem, name ) {
if ( !hasClass( elem, name ) ) {
elem.className += (elem.className ? " " : "") + name;
}
}
function removeClass( elem, name ) {
var set = " " + elem.className + " ";
// Class name may appear multiple times
while ( set.indexOf(" " + name + " ") > -1 ) {
set = set.replace(" " + name + " " , " ");
}
// If possible, trim it for prettiness, but not necessarily
elem.className = typeof set.trim === "function" ? set.trim() : set.replace(/^\s+|\s+$/g, "");
}
function id( name ) {
return defined.document && document.getElementById && document.getElementById( name );
}
function registerLoggingCallback( key ) {
return function( callback ) {
config[key].push( callback );
};
}
// Supports deprecated method of completely overwriting logging callbacks
function runLoggingCallbacks( key, scope, args ) {
var i, callbacks;
if ( QUnit.hasOwnProperty( key ) ) {
QUnit[ key ].call(scope, args );
} else {
callbacks = config[ key ];
for ( i = 0; i < callbacks.length; i++ ) {
callbacks[ i ].call( scope, args );
}
function runLoggingCallbacks( key, args ) {
var i, l, callbacks;
callbacks = config.callbacks[ key ];
for ( i = 0, l = callbacks.length; i < l; i++ ) {
callbacks[ i ]( args );
}
}
......@@ -1186,6 +709,7 @@ function inArray( elem, array ) {
function Test( settings ) {
extend( this, settings );
this.assert = new Assert( this );
this.assertions = [];
this.testNumber = ++Test.count;
}
......@@ -1193,32 +717,12 @@ function Test( settings ) {
Test.count = 0;
Test.prototype = {
init: function() {
var a, b, li,
tests = id( "qunit-tests" );
if ( tests ) {
b = document.createElement( "strong" );
b.innerHTML = this.nameHtml;
// `a` initialized at top of scope
a = document.createElement( "a" );
a.innerHTML = "Rerun";
a.href = QUnit.url({ testNumber: this.testNumber });
li = document.createElement( "li" );
li.appendChild( b );
li.appendChild( a );
li.className = "running";
li.id = this.id = "qunit-test-output" + testId++;
tests.appendChild( li );
}
},
setup: function() {
if (
// Emit moduleStart when we're switching from one module to another
this.module !== config.previousModule ||
// They could be equal (both undefined) but if the previousModule property doesn't
// yet exist it means this is the first test in a suite that isn't wrapped in a
// module, in which case we'll just emit a moduleStart event for 'undefined'.
......@@ -1226,7 +730,7 @@ Test.prototype = {
!hasOwn.call( config, "previousModule" )
) {
if ( hasOwn.call( config, "previousModule" ) ) {
runLoggingCallbacks( "moduleDone", QUnit, {
runLoggingCallbacks( "moduleDone", {
name: config.previousModule,
failed: config.moduleStats.bad,
passed: config.moduleStats.all - config.moduleStats.bad,
......@@ -1235,7 +739,7 @@ Test.prototype = {
}
config.previousModule = this.module;
config.moduleStats = { all: 0, bad: 0 };
runLoggingCallbacks( "moduleStart", QUnit, {
runLoggingCallbacks( "moduleStart", {
name: this.module
});
}
......@@ -1247,65 +751,49 @@ Test.prototype = {
teardown: function() {}
}, this.moduleTestEnvironment );
this.started = +new Date();
runLoggingCallbacks( "testStart", QUnit, {
this.started = now();
runLoggingCallbacks( "testStart", {
name: this.testName,
module: this.module
module: this.module,
testNumber: this.testNumber
});
/*jshint camelcase:false */
/**
* Expose the current test environment.
*
* @deprecated since 1.12.0: Use QUnit.config.current.testEnvironment instead.
*/
QUnit.current_testEnvironment = this.testEnvironment;
/*jshint camelcase:true */
if ( !config.pollution ) {
saveGlobal();
}
if ( config.notrycatch ) {
this.testEnvironment.setup.call( this.testEnvironment, QUnit.assert );
this.testEnvironment.setup.call( this.testEnvironment, this.assert );
return;
}
try {
this.testEnvironment.setup.call( this.testEnvironment, QUnit.assert );
} catch( e ) {
QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
this.testEnvironment.setup.call( this.testEnvironment, this.assert );
} catch ( e ) {
this.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
}
},
run: function() {
config.current = this;
var running = id( "qunit-testresult" );
if ( running ) {
running.innerHTML = "Running: <br/>" + this.nameHtml;
}
if ( this.async ) {
QUnit.stop();
}
this.callbackStarted = +new Date();
this.callbackStarted = now();
if ( config.notrycatch ) {
this.callback.call( this.testEnvironment, QUnit.assert );
this.callbackRuntime = +new Date() - this.callbackStarted;
this.callback.call( this.testEnvironment, this.assert );
this.callbackRuntime = now() - this.callbackStarted;
return;
}
try {
this.callback.call( this.testEnvironment, QUnit.assert );
this.callbackRuntime = +new Date() - this.callbackStarted;
} catch( e ) {
this.callbackRuntime = +new Date() - this.callbackStarted;
this.callback.call( this.testEnvironment, this.assert );
this.callbackRuntime = now() - this.callbackStarted;
} catch ( e ) {
this.callbackRuntime = now() - this.callbackStarted;
this.pushFailure( "Died on test #" + ( this.assertions.length + 1 ) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
// else next test will carry the responsibility
saveGlobal();
......@@ -1319,15 +807,15 @@ Test.prototype = {
config.current = this;
if ( config.notrycatch ) {
if ( typeof this.callbackRuntime === "undefined" ) {
this.callbackRuntime = +new Date() - this.callbackStarted;
this.callbackRuntime = now() - this.callbackStarted;
}
this.testEnvironment.teardown.call( this.testEnvironment, QUnit.assert );
this.testEnvironment.teardown.call( this.testEnvironment, this.assert );
return;
} else {
try {
this.testEnvironment.teardown.call( this.testEnvironment, QUnit.assert );
} catch( e ) {
QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
this.testEnvironment.teardown.call( this.testEnvironment, this.assert );
} catch ( e ) {
this.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
}
}
checkPollution();
......@@ -1335,115 +823,44 @@ Test.prototype = {
finish: function() {
config.current = this;
if ( config.requireExpects && this.expected === null ) {
QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
this.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
} else if ( this.expected !== null && this.expected !== this.assertions.length ) {
QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
this.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
} else if ( this.expected === null && !this.assertions.length ) {
QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
this.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
}
var i, assertion, a, b, time, li, ol,
test = this,
good = 0,
bad = 0,
tests = id( "qunit-tests" );
var i,
bad = 0;
this.runtime = +new Date() - this.started;
this.runtime = now() - this.started;
config.stats.all += this.assertions.length;
config.moduleStats.all += this.assertions.length;
if ( tests ) {
ol = document.createElement( "ol" );
ol.className = "qunit-assert-list";
for ( i = 0; i < this.assertions.length; i++ ) {
assertion = this.assertions[i];
li = document.createElement( "li" );
li.className = assertion.result ? "pass" : "fail";
li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
ol.appendChild( li );
if ( assertion.result ) {
good++;
} else {
bad++;
config.stats.bad++;
config.moduleStats.bad++;
}
}
// store result when possible
if ( QUnit.config.reorder && defined.sessionStorage ) {
if ( bad ) {
sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
} else {
sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
}
}
if ( bad === 0 ) {
addClass( ol, "qunit-collapsed" );
}
// `b` initialized at top of scope
b = document.createElement( "strong" );
b.innerHTML = this.nameHtml + " <b class='counts'>(<b class='failed'>" + bad + "</b>, <b class='passed'>" + good + "</b>, " + this.assertions.length + ")</b>";
addEvent(b, "click", function() {
var next = b.parentNode.lastChild,
collapsed = hasClass( next, "qunit-collapsed" );
( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
});
addEvent(b, "dblclick", function( e ) {
var target = e && e.target ? e.target : window.event.srcElement;
if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
target = target.parentNode;
}
if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
window.location = QUnit.url({ testNumber: test.testNumber });
}
});
// `time` initialized at top of scope
time = document.createElement( "span" );
time.className = "runtime";
time.innerHTML = this.runtime + " ms";
// `li` initialized at top of scope
li = id( this.id );
li.className = bad ? "fail" : "pass";
li.removeChild( li.firstChild );
a = li.firstChild;
li.appendChild( b );
li.appendChild( a );
li.appendChild( time );
li.appendChild( ol );
} else {
for ( i = 0; i < this.assertions.length; i++ ) {
if ( !this.assertions[i].result ) {
bad++;
config.stats.bad++;
config.moduleStats.bad++;
}
for ( i = 0; i < this.assertions.length; i++ ) {
if ( !this.assertions[ i ].result ) {
bad++;
config.stats.bad++;
config.moduleStats.bad++;
}
}
runLoggingCallbacks( "testDone", QUnit, {
runLoggingCallbacks( "testDone", {
name: this.testName,
module: this.module,
failed: bad,
passed: this.assertions.length - bad,
total: this.assertions.length,
runtime: this.runtime,
// HTML Reporter use
assertions: this.assertions,
testNumber: this.testNumber,
// DEPRECATED: this property will be removed in 2.0.0, use runtime instead
duration: this.runtime
});
QUnit.reset();
config.current = undefined;
},
......@@ -1451,9 +868,6 @@ Test.prototype = {
var bad,
test = this;
synchronize(function() {
test.init();
});
function run() {
// each of these can by async
synchronize(function() {
......@@ -1473,59 +887,129 @@ Test.prototype = {
// `bad` initialized at top of scope
// defer when previous test run passed, if storage is available
bad = QUnit.config.reorder && defined.sessionStorage &&
+sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
+sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
if ( bad ) {
run();
} else {
synchronize( run, true );
}
}
};
// `assert` initialized at top of scope
// Assert helpers
// All of these must either call QUnit.push() or manually do:
// - runLoggingCallbacks( "log", .. );
// - config.current.assertions.push({ .. });
assert = QUnit.assert = {
/**
* Asserts rough true-ish result.
* @name ok
* @function
* @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
*/
ok: function( result, msg ) {
if ( !config.current ) {
throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
}
result = !!result;
msg = msg || ( result ? "okay" : "failed" );
},
push: function( result, actual, expected, message ) {
var source,
details = {
module: config.current.module,
name: config.current.testName,
module: this.module,
name: this.testName,
result: result,
message: msg
message: message,
actual: actual,
expected: expected,
testNumber: this.testNumber
};
msg = "<span class='test-message'>" + escapeText( msg ) + "</span>";
if ( !result ) {
source = sourceFromStacktrace( 2 );
source = sourceFromStacktrace();
if ( source ) {
details.source = source;
msg += "<table><tr class='test-source'><th>Source: </th><td><pre>" +
escapeText( source ) +
"</pre></td></tr></table>";
}
}
runLoggingCallbacks( "log", QUnit, details );
config.current.assertions.push({
result: result,
message: msg
runLoggingCallbacks( "log", details );
this.assertions.push({
result: !!result,
message: message
});
},
pushFailure: function( message, source, actual ) {
if ( !this instanceof Test ) {
throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace( 2 ) );
}
var details = {
module: this.module,
name: this.testName,
result: false,
message: message || "error",
actual: actual || null,
testNumber: this.testNumber
};
if ( source ) {
details.source = source;
}
runLoggingCallbacks( "log", details );
this.assertions.push({
result: false,
message: message
});
}
};
QUnit.pushFailure = function() {
if ( !QUnit.config.current ) {
throw new Error( "pushFailure() assertion outside test context, in " + sourceFromStacktrace( 2 ) );
}
// Gets current test obj
var currentTest = QUnit.config.current.assert.test;
return currentTest.pushFailure.apply( currentTest, arguments );
};
function Assert( testContext ) {
this.test = testContext;
}
// Assert helpers
QUnit.assert = Assert.prototype = {
// Specify the number of expected assertions to guarantee that failed test (no assertions are run at all) don't slip through.
expect: function( asserts ) {
if ( arguments.length === 1 ) {
this.test.expected = asserts;
} else {
return this.test.expected;
}
},
// Exports test.push() to the user API
push: function() {
var assert = this;
// Backwards compatibility fix.
// Allows the direct use of global exported assertions and QUnit.assert.*
// Although, it's use is not recommended as it can leak assertions
// to other tests from async tests, because we only get a reference to the current test,
// not exactly the test where assertion were intended to be called.
if ( !QUnit.config.current ) {
throw new Error( "assertion outside test context, in " + sourceFromStacktrace( 2 ) );
}
if ( !( assert instanceof Assert ) ) {
assert = QUnit.config.current.assert;
}
return assert.test.push.apply( assert.test, arguments );
},
/**
* Asserts rough true-ish result.
* @name ok
* @function
* @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
*/
ok: function( result, message ) {
message = message || ( result ? "okay" : "failed, expected argument to be truthy, was: " +
QUnit.dump.parse( result ) );
if ( !!result ) {
this.push( true, result, true, message );
} else {
this.test.pushFailure( message, null, result );
}
},
/**
......@@ -1537,7 +1021,7 @@ assert = QUnit.assert = {
*/
equal: function( actual, expected, message ) {
/*jshint eqeqeq:false */
QUnit.push( expected == actual, actual, expected, message );
this.push( expected == actual, actual, expected, message );
},
/**
......@@ -1546,7 +1030,7 @@ assert = QUnit.assert = {
*/
notEqual: function( actual, expected, message ) {
/*jshint eqeqeq:false */
QUnit.push( expected != actual, actual, expected, message );
this.push( expected != actual, actual, expected, message );
},
/**
......@@ -1554,9 +1038,9 @@ assert = QUnit.assert = {
* @function
*/
propEqual: function( actual, expected, message ) {
actual = objectValues(actual);
expected = objectValues(expected);
QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
actual = objectValues( actual );
expected = objectValues( expected );
this.push( QUnit.equiv( actual, expected ), actual, expected, message );
},
/**
......@@ -1564,9 +1048,9 @@ assert = QUnit.assert = {
* @function
*/
notPropEqual: function( actual, expected, message ) {
actual = objectValues(actual);
expected = objectValues(expected);
QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
actual = objectValues( actual );
expected = objectValues( expected );
this.push( !QUnit.equiv( actual, expected ), actual, expected, message );
},
/**
......@@ -1574,7 +1058,7 @@ assert = QUnit.assert = {
* @function
*/
deepEqual: function( actual, expected, message ) {
QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
this.push( QUnit.equiv( actual, expected ), actual, expected, message );
},
/**
......@@ -1582,7 +1066,7 @@ assert = QUnit.assert = {
* @function
*/
notDeepEqual: function( actual, expected, message ) {
QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
this.push( !QUnit.equiv( actual, expected ), actual, expected, message );
},
/**
......@@ -1590,7 +1074,7 @@ assert = QUnit.assert = {
* @function
*/
strictEqual: function( actual, expected, message ) {
QUnit.push( expected === actual, actual, expected, message );
this.push( expected === actual, actual, expected, message );
},
/**
......@@ -1598,91 +1082,67 @@ assert = QUnit.assert = {
* @function
*/
notStrictEqual: function( actual, expected, message ) {
QUnit.push( expected !== actual, actual, expected, message );
this.push( expected !== actual, actual, expected, message );
},
"throws": function( block, expected, message ) {
var actual,
var actual, expectedType,
expectedOutput = expected,
ok = false;
// 'expected' is optional
if ( !message && typeof expected === "string" ) {
// 'expected' is optional unless doing string comparison
if ( message == null && typeof expected === "string" ) {
message = expected;
expected = null;
}
config.current.ignoreGlobalErrors = true;
this.test.ignoreGlobalErrors = true;
try {
block.call( config.current.testEnvironment );
block.call( this.test.testEnvironment );
} catch (e) {
actual = e;
}
config.current.ignoreGlobalErrors = false;
this.test.ignoreGlobalErrors = false;
if ( actual ) {
expectedType = QUnit.objectType( expected );
// we don't want to validate thrown error
if ( !expected ) {
ok = true;
expectedOutput = null;
// expected is an Error object
} else if ( expected instanceof Error ) {
ok = actual instanceof Error &&
actual.name === expected.name &&
actual.message === expected.message;
// expected is a regexp
} else if ( QUnit.objectType( expected ) === "regexp" ) {
} else if ( expectedType === "regexp" ) {
ok = expected.test( errorString( actual ) );
// expected is a string
} else if ( QUnit.objectType( expected ) === "string" ) {
} else if ( expectedType === "string" ) {
ok = expected === errorString( actual );
// expected is a constructor
} else if ( actual instanceof expected ) {
// expected is a constructor, maybe an Error constructor
} else if ( expectedType === "function" && actual instanceof expected ) {
ok = true;
// expected is a validation function which returns true is validation passed
} else if ( expected.call( {}, actual ) === true ) {
// expected is an Error object
} else if ( expectedType === "object" ) {
ok = actual instanceof expected.constructor &&
actual.name === expected.name &&
actual.message === expected.message;
// expected is a validation function which returns true if validation passed
} else if ( expectedType === "function" && expected.call( {}, actual ) === true ) {
expectedOutput = null;
ok = true;
}
QUnit.push( ok, actual, expectedOutput, message );
this.push( ok, actual, expectedOutput, message );
} else {
QUnit.pushFailure( message, null, "No exception was thrown." );
this.test.pushFailure( message, null, "No exception was thrown." );
}
}
};
/**
* @deprecated since 1.8.0
* Kept assertion helpers in root for backwards compatibility.
*/
extend( QUnit.constructor.prototype, assert );
/**
* @deprecated since 1.9.0
* Kept to avoid TypeErrors for undefined methods.
*/
QUnit.constructor.prototype.raises = function() {
QUnit.push( false, false, false, "QUnit.raises has been deprecated since 2012 (fad3c1ea), use QUnit.throws instead" );
};
/**
* @deprecated since 1.0.0, replaced with error pushes since 1.3.0
* Kept to avoid TypeErrors for undefined methods.
*/
QUnit.constructor.prototype.equals = function() {
QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
};
QUnit.constructor.prototype.same = function() {
QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
};
// Test for equality any JavaScript type.
// Author: Philippe Rathé <prathe@gmail.com>
QUnit.equiv = (function() {
......@@ -1701,22 +1161,26 @@ QUnit.equiv = (function() {
// the real equiv function
var innerEquiv,
// stack to decide between skip/abort functions
callers = [],
// stack to avoiding loops from circular referencing
parents = [],
parentsB = [],
getProto = Object.getPrototypeOf || function ( obj ) {
/*jshint camelcase:false */
getProto = Object.getPrototypeOf || function( obj ) {
/* jshint camelcase: false, proto: true */
return obj.__proto__;
},
callbacks = (function () {
callbacks = (function() {
// for string, boolean, number and null
function useStrictEquality( b, a ) {
/*jshint eqeqeq:false */
if ( b instanceof a.constructor || a instanceof b.constructor ) {
// to catch short annotation VS 'new' annotation of a
// declaration
// e.g. var i = 1;
......@@ -1744,10 +1208,13 @@ QUnit.equiv = (function() {
"regexp": function( b, a ) {
return QUnit.objectType( b ) === "regexp" &&
// the regex itself
a.source === b.source &&
// and its modifiers
a.global === b.global &&
// (gmi) ...
a.ignoreCase === b.ignoreCase &&
a.multiline === b.multiline &&
......@@ -1758,7 +1225,7 @@ QUnit.equiv = (function() {
// - abort otherwise,
// initial === would have catch identical references anyway
"function": function() {
var caller = callers[callers.length - 1];
var caller = callers[ callers.length - 1 ];
return caller !== Object && typeof caller !== "undefined";
},
......@@ -1782,10 +1249,10 @@ QUnit.equiv = (function() {
for ( i = 0; i < len; i++ ) {
loop = false;
for ( j = 0; j < parents.length; j++ ) {
aCircular = parents[j] === a[i];
bCircular = parentsB[j] === b[i];
aCircular = parents[ j ] === a[ i ];
bCircular = parentsB[ j ] === b[ i ];
if ( aCircular || bCircular ) {
if ( a[i] === b[i] || aCircular && bCircular ) {
if ( a[ i ] === b[ i ] || aCircular && bCircular ) {
loop = true;
} else {
parents.pop();
......@@ -1794,7 +1261,7 @@ QUnit.equiv = (function() {
}
}
}
if ( !loop && !innerEquiv(a[i], b[i]) ) {
if ( !loop && !innerEquiv( a[ i ], b[ i ] ) ) {
parents.pop();
parentsB.pop();
return false;
......@@ -1806,6 +1273,7 @@ QUnit.equiv = (function() {
},
"object": function( b, a ) {
/*jshint forin:false */
var i, j, loop, aCircular, bCircular,
// Default to true
......@@ -1816,11 +1284,12 @@ QUnit.equiv = (function() {
// comparing constructors is more strict than using
// instanceof
if ( a.constructor !== b.constructor ) {
// Allow objects with no prototype to be equivalent to
// objects with Object as their constructor.
if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
return false;
if ( !( ( getProto( a ) === null && getProto( b ) === Object.prototype ) ||
( getProto( b ) === null && getProto( a ) === Object.prototype ) ) ) {
return false;
}
}
......@@ -1835,10 +1304,10 @@ QUnit.equiv = (function() {
for ( i in a ) {
loop = false;
for ( j = 0; j < parents.length; j++ ) {
aCircular = parents[j] === a[i];
bCircular = parentsB[j] === b[i];
aCircular = parents[ j ] === a[ i ];
bCircular = parentsB[ j ] === b[ i ];
if ( aCircular || bCircular ) {
if ( a[i] === b[i] || aCircular && bCircular ) {
if ( a[ i ] === b[ i ] || aCircular && bCircular ) {
loop = true;
} else {
eq = false;
......@@ -1846,8 +1315,8 @@ QUnit.equiv = (function() {
}
}
}
aProperties.push(i);
if ( !loop && !innerEquiv(a[i], b[i]) ) {
aProperties.push( i );
if ( !loop && !innerEquiv( a[ i ], b[ i ] ) ) {
eq = false;
break;
}
......@@ -1873,35 +1342,29 @@ QUnit.equiv = (function() {
return true; // end transition
}
return (function( a, b ) {
return ( (function( a, b ) {
if ( a === b ) {
return true; // catch the most you can
} else if ( a === null || b === null || typeof a === "undefined" ||
typeof b === "undefined" ||
QUnit.objectType(a) !== QUnit.objectType(b) ) {
return false; // don't lose time with error prone cases
QUnit.objectType( a ) !== QUnit.objectType( b ) ) {
// don't lose time with error prone cases
return false;
} else {
return bindCallbacks(a, callbacks, [ b, a ]);
return bindCallbacks( a, callbacks, [ b, a ] );
}
// apply transition with (1..n) arguments
}( args[0], args[1] ) && innerEquiv.apply( this, args.splice(1, args.length - 1 )) );
}( args[ 0 ], args[ 1 ] ) ) && innerEquiv.apply( this, args.splice( 1, args.length - 1 ) ) );
};
return innerEquiv;
}());
/**
* jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
* http://flesler.blogspot.com Licensed under BSD
* (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
*
* @projectDescription Advanced and extensible data dumping for Javascript.
* @version 1.0.0
* @author Ariel Flesler
* @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
*/
QUnit.jsDump = (function() {
// Based on jsDump by Ariel Flesler
// http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html
QUnit.dump = (function() {
function quote( str ) {
return "\"" + str.toString().replace( /"/g, "\\\"" ) + "\"";
}
......@@ -1909,42 +1372,43 @@ QUnit.jsDump = (function() {
return o + "";
}
function join( pre, arr, post ) {
var s = jsDump.separator(),
base = jsDump.indent(),
inner = jsDump.indent(1);
var s = dump.separator(),
base = dump.indent(),
inner = dump.indent( 1 );
if ( arr.join ) {
arr = arr.join( "," + s + inner );
}
if ( !arr ) {
return pre + post;
}
return [ pre, inner + arr, base + post ].join(s);
return [ pre, inner + arr, base + post ].join( s );
}
function array( arr, stack ) {
var i = arr.length, ret = new Array(i);
var i = arr.length,
ret = new Array( i );
this.up();
while ( i-- ) {
ret[i] = this.parse( arr[i] , undefined , stack);
ret[ i ] = this.parse( arr[ i ], undefined, stack );
}
this.down();
return join( "[", ret, "]" );
}
var reName = /^function (\w+)/,
jsDump = {
dump = {
// type is used mostly internally, you can fix a (custom)type in advance
parse: function( obj, type, stack ) {
stack = stack || [ ];
stack = stack || [];
var inStack, res,
parser = this.parsers[ type || this.typeOf(obj) ];
parser = this.parsers[ type || this.typeOf( obj ) ];
type = typeof parser;
inStack = inArray( obj, stack );
if ( inStack !== -1 ) {
return "recursion(" + (inStack - stack.length) + ")";
return "recursion(" + ( inStack - stack.length ) + ")";
}
if ( type === "function" ) {
if ( type === "function" ) {
stack.push( obj );
res = parser.call( this, obj, stack );
stack.pop();
......@@ -1958,11 +1422,11 @@ QUnit.jsDump = (function() {
type = "null";
} else if ( typeof obj === "undefined" ) {
type = "undefined";
} else if ( QUnit.is( "regexp", obj) ) {
} else if ( QUnit.is( "regexp", obj ) ) {
type = "regexp";
} else if ( QUnit.is( "date", obj) ) {
} else if ( QUnit.is( "date", obj ) ) {
type = "date";
} else if ( QUnit.is( "function", obj) ) {
} else if ( QUnit.is( "function", obj ) ) {
type = "function";
} else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
type = "window";
......@@ -1971,10 +1435,12 @@ QUnit.jsDump = (function() {
} else if ( obj.nodeType ) {
type = "node";
} else if (
// native arrays
toString.call( obj ) === "[object Array]" ||
// NodeList objects
( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item( 0 ) === obj[ 0 ] : ( obj.item( 0 ) === null && typeof obj[ 0 ] === "undefined" ) ) )
) {
type = "array";
} else if ( obj.constructor === Error.prototype.constructor ) {
......@@ -1985,7 +1451,7 @@ QUnit.jsDump = (function() {
return type;
},
separator: function() {
return this.multiline ? this.HTML ? "<br />" : "\n" : this.HTML ? "&nbsp;" : " ";
return this.multiline ? this.HTML ? "<br />" : "\n" : this.HTML ? "&nbsp;" : " ";
},
// extra can be a number, shortcut for increasing-calling-decreasing
indent: function( extra ) {
......@@ -1996,7 +1462,7 @@ QUnit.jsDump = (function() {
if ( this.HTML ) {
chr = chr.replace( /\t/g, " " ).replace( / /g, "&nbsp;" );
}
return new Array( this.depth + ( extra || 0 ) ).join(chr);
return new Array( this.depth + ( extra || 0 ) ).join( chr );
},
up: function( a ) {
this.depth += a || 1;
......@@ -2005,7 +1471,7 @@ QUnit.jsDump = (function() {
this.depth -= a || 1;
},
setParser: function( name, parser ) {
this.parsers[name] = parser;
this.parsers[ name ] = parser;
},
// The next 3 are exposed so you can use them
quote: quote,
......@@ -2013,11 +1479,11 @@ QUnit.jsDump = (function() {
join: join,
//
depth: 1,
// This is the list of parsers, to modify them, use jsDump.setParser
// This is the list of parsers, to modify them, use dump.setParser
parsers: {
window: "[Window]",
document: "[Document]",
error: function(error) {
error: function( error ) {
return "Error(\"" + error.message + "\")";
},
unknown: "[Unknown]",
......@@ -2026,51 +1492,61 @@ QUnit.jsDump = (function() {
"function": function( fn ) {
var ret = "function",
// functions never have name in IE
name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
name = "name" in fn ? fn.name : ( reName.exec( fn ) || [] )[ 1 ];
if ( name ) {
ret += " " + name;
}
ret += "( ";
ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
ret = [ ret, dump.parse( fn, "functionArgs" ), "){" ].join( "" );
return join( ret, dump.parse( fn, "functionCode" ), "}" );
},
array: array,
nodelist: array,
"arguments": array,
object: function( map, stack ) {
/*jshint forin:false */
var ret = [ ], keys, key, val, i;
QUnit.jsDump.up();
var ret = [], keys, key, val, i, nonEnumerableProperties;
dump.up();
keys = [];
for ( key in map ) {
keys.push( key );
}
// Some properties are not always enumerable on Error objects.
nonEnumerableProperties = [ "message", "name" ];
for ( i in nonEnumerableProperties ) {
key = nonEnumerableProperties[ i ];
if ( key in map && !( key in keys ) ) {
keys.push( key );
}
}
keys.sort();
for ( i = 0; i < keys.length; i++ ) {
key = keys[ i ];
val = map[ key ];
ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
ret.push( dump.parse( key, "key" ) + ": " + dump.parse( val, undefined, stack ) );
}
QUnit.jsDump.down();
dump.down();
return join( "{", ret, "}" );
},
node: function( node ) {
var len, i, val,
open = QUnit.jsDump.HTML ? "&lt;" : "<",
close = QUnit.jsDump.HTML ? "&gt;" : ">",
open = dump.HTML ? "&lt;" : "<",
close = dump.HTML ? "&gt;" : ">",
tag = node.nodeName.toLowerCase(),
ret = open + tag,
attrs = node.attributes;
if ( attrs ) {
for ( i = 0, len = attrs.length; i < len; i++ ) {
val = attrs[i].nodeValue;
val = attrs[ i ].nodeValue;
// IE6 includes all attributes in .attributes, even ones not explicitly set.
// Those have values like undefined, null, 0, false, "" or "inherit".
if ( val && val !== "inherit" ) {
ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
ret += " " + attrs[ i ].nodeName + "=" + dump.parse( val, "attribute" );
}
}
}
......@@ -2083,6 +1559,7 @@ QUnit.jsDump = (function() {
return ret + open + "/" + tag + close;
},
// function calls it internally, it's the arguments part of the function
functionArgs: function( fn ) {
var args,
......@@ -2092,10 +1569,11 @@ QUnit.jsDump = (function() {
return "";
}
args = new Array(l);
args = new Array( l );
while ( l-- ) {
// 97 is 'a'
args[l] = String.fromCharCode(97+l);
args[ l ] = String.fromCharCode( 97 + l );
}
return " " + args.join( ", " ) + " ";
},
......@@ -2119,9 +1597,73 @@ QUnit.jsDump = (function() {
multiline: true
};
return jsDump;
return dump;
}());
// back compat
QUnit.jsDump = QUnit.dump;
// For browser, export only select globals
if ( typeof window !== "undefined" ) {
// Deprecated
// Extend assert methods to QUnit and Global scope through Backwards compatibility
(function() {
var i,
assertions = Assert.prototype;
function applyCurrent( current ) {
return function() {
var assert = new Assert( QUnit.config.current );
current.apply( assert, arguments );
};
}
for ( i in assertions ) {
QUnit[ i ] = applyCurrent( assertions[ i ] );
}
})();
(function() {
var i, l,
keys = [
"test",
"module",
"expect",
"asyncTest",
"start",
"stop",
"ok",
"equal",
"notEqual",
"propEqual",
"notPropEqual",
"deepEqual",
"notDeepEqual",
"strictEqual",
"notStrictEqual",
"throws"
];
for ( i = 0, l = keys.length; i < l; i++ ) {
window[ keys[ i ] ] = QUnit[ keys[ i ] ];
}
})();
window.QUnit = QUnit;
}
// For CommonJS environments, export everything
if ( typeof module !== "undefined" && module.exports ) {
module.exports = QUnit;
}
// Get a reference to the global object, like window in browsers
}( (function() {
return this;
})() ));
/*istanbul ignore next */
/*
* Javascript Diff Algorithm
* By John Resig (http://ejohn.org/)
......@@ -2137,6 +1679,8 @@ QUnit.jsDump = (function() {
* QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick <del>brown </del> fox <del>jumped </del><ins>jumps </ins> over"
*/
QUnit.diff = (function() {
var hasOwn = Object.prototype.hasOwnProperty;
/*jshint eqeqeq:false, eqnull:true */
function diff( o, n ) {
var i,
......@@ -2144,65 +1688,65 @@ QUnit.diff = (function() {
os = {};
for ( i = 0; i < n.length; i++ ) {
if ( !hasOwn.call( ns, n[i] ) ) {
ns[ n[i] ] = {
if ( !hasOwn.call( ns, n[ i ] ) ) {
ns[ n[ i ] ] = {
rows: [],
o: null
};
}
ns[ n[i] ].rows.push( i );
ns[ n[ i ] ].rows.push( i );
}
for ( i = 0; i < o.length; i++ ) {
if ( !hasOwn.call( os, o[i] ) ) {
os[ o[i] ] = {
if ( !hasOwn.call( os, o[ i ] ) ) {
os[ o[ i ] ] = {
rows: [],
n: null
};
}
os[ o[i] ].rows.push( i );
os[ o[ i ] ].rows.push( i );
}
for ( i in ns ) {
if ( hasOwn.call( ns, i ) ) {
if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
n[ ns[i].rows[0] ] = {
text: n[ ns[i].rows[0] ],
row: os[i].rows[0]
if ( ns[ i ].rows.length === 1 && hasOwn.call( os, i ) && os[ i ].rows.length === 1 ) {
n[ ns[ i ].rows[ 0 ] ] = {
text: n[ ns[ i ].rows[ 0 ] ],
row: os[ i ].rows[ 0 ]
};
o[ os[i].rows[0] ] = {
text: o[ os[i].rows[0] ],
row: ns[i].rows[0]
o[ os[ i ].rows[ 0 ] ] = {
text: o[ os[ i ].rows[ 0 ] ],
row: ns[ i ].rows[ 0 ]
};
}
}
}
for ( i = 0; i < n.length - 1; i++ ) {
if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
n[ i + 1 ] == o[ n[i].row + 1 ] ) {
if ( n[ i ].text != null && n[ i + 1 ].text == null && n[ i ].row + 1 < o.length && o[ n[ i ].row + 1 ].text == null &&
n[ i + 1 ] == o[ n[ i ].row + 1 ] ) {
n[ i + 1 ] = {
text: n[ i + 1 ],
row: n[i].row + 1
row: n[ i ].row + 1
};
o[ n[i].row + 1 ] = {
text: o[ n[i].row + 1 ],
o[ n[ i ].row + 1 ] = {
text: o[ n[ i ].row + 1 ],
row: i + 1
};
}
}
for ( i = n.length - 1; i > 0; i-- ) {
if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
n[ i - 1 ] == o[ n[i].row - 1 ]) {
if ( n[ i ].text != null && n[ i - 1 ].text == null && n[ i ].row > 0 && o[ n[ i ].row - 1 ].text == null &&
n[ i - 1 ] == o[ n[ i ].row - 1 ] ) {
n[ i - 1 ] = {
text: n[ i - 1 ],
row: n[i].row - 1
row: n[ i ].row - 1
};
o[ n[i].row - 1 ] = {
text: o[ n[i].row - 1 ],
o[ n[ i ].row - 1 ] = {
text: o[ n[ i ].row - 1 ],
row: i - 1
};
}
......@@ -2220,48 +1764,45 @@ QUnit.diff = (function() {
var i, pre,
str = "",
out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
oSpace = o.match(/\s+/g),
nSpace = n.match(/\s+/g);
out = diff( o === "" ? [] : o.split( /\s+/ ), n === "" ? [] : n.split( /\s+/ ) ),
oSpace = o.match( /\s+/g ),
nSpace = n.match( /\s+/g );
if ( oSpace == null ) {
oSpace = [ " " ];
}
else {
} else {
oSpace.push( " " );
}
if ( nSpace == null ) {
nSpace = [ " " ];
}
else {
} else {
nSpace.push( " " );
}
if ( out.n.length === 0 ) {
for ( i = 0; i < out.o.length; i++ ) {
str += "<del>" + out.o[i] + oSpace[i] + "</del>";
str += "<del>" + out.o[ i ] + oSpace[ i ] + "</del>";
}
}
else {
if ( out.n[0].text == null ) {
for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
str += "<del>" + out.o[n] + oSpace[n] + "</del>";
} else {
if ( out.n[ 0 ].text == null ) {
for ( n = 0; n < out.o.length && out.o[ n ].text == null; n++ ) {
str += "<del>" + out.o[ n ] + oSpace[ n ] + "</del>";
}
}
for ( i = 0; i < out.n.length; i++ ) {
if (out.n[i].text == null) {
str += "<ins>" + out.n[i] + nSpace[i] + "</ins>";
}
else {
if ( out.n[ i ].text == null ) {
str += "<ins>" + out.n[ i ] + nSpace[ i ] + "</ins>";
} else {
// `pre` initialized at top of scope
pre = "";
for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
pre += "<del>" + out.o[n] + oSpace[n] + "</del>";
for ( n = out.n[ i ].row + 1; n < out.o.length && out.o[ n ].text == null; n++ ) {
pre += "<del>" + out.o[ n ] + oSpace[ n ] + "</del>";
}
str += " " + out.n[i].text + nSpace[i] + pre;
str += " " + out.n[ i ].text + nSpace[ i ] + pre;
}
}
}
......@@ -2270,19 +1811,685 @@ QUnit.diff = (function() {
};
}());
// For browser, export only select globals
if ( typeof window !== "undefined" ) {
extend( window, QUnit.constructor.prototype );
window.QUnit = QUnit;
}
(function() {
// For CommonJS environments, export everything
if ( typeof module !== "undefined" && module.exports ) {
module.exports = QUnit;
// Deprecated QUnit.init - Ref #530
// Re-initialize the configuration options
QUnit.init = function() {
var tests, banner, result, qunit,
config = QUnit.config;
config.stats = { all: 0, bad: 0 };
config.moduleStats = { all: 0, bad: 0 };
config.started = 0;
config.updateRate = 1000;
config.blocking = false;
config.autostart = true;
config.autorun = false;
config.filter = "";
config.queue = [];
config.semaphore = 1;
// Return on non-browser environments
// This is necessary to not break on node tests
if ( typeof window === "undefined" ) {
return;
}
qunit = id( "qunit" );
if ( qunit ) {
qunit.innerHTML =
"<h1 id='qunit-header'>" + escapeText( document.title ) + "</h1>" +
"<h2 id='qunit-banner'></h2>" +
"<div id='qunit-testrunner-toolbar'></div>" +
"<h2 id='qunit-userAgent'></h2>" +
"<ol id='qunit-tests'></ol>";
}
tests = id( "qunit-tests" );
banner = id( "qunit-banner" );
result = id( "qunit-testresult" );
if ( tests ) {
tests.innerHTML = "";
}
if ( banner ) {
banner.className = "";
}
if ( result ) {
result.parentNode.removeChild( result );
}
if ( tests ) {
result = document.createElement( "p" );
result.id = "qunit-testresult";
result.className = "result";
tests.parentNode.insertBefore( result, tests );
result.innerHTML = "Running...<br/>&nbsp;";
}
};
// Resets the test setup. Useful for tests that modify the DOM.
/*
DEPRECATED: Use multiple tests instead of resetting inside a test.
Use testStart or testDone for custom cleanup.
This method will throw an error in 2.0, and will be removed in 2.1
*/
QUnit.reset = function() {
// Return on non-browser environments
// This is necessary to not break on node tests
if ( typeof window === "undefined" ) {
return;
}
var fixture = id( "qunit-fixture" );
if ( fixture ) {
fixture.innerHTML = config.fixture;
}
};
// Don't load the HTML Reporter on non-Browser environments
if ( typeof window === "undefined" ) {
return;
}
var config = QUnit.config,
hasOwn = Object.prototype.hasOwnProperty,
defined = {
document: typeof window.document !== "undefined",
sessionStorage: (function() {
var x = "qunit-test-string";
try {
sessionStorage.setItem( x, x );
sessionStorage.removeItem( x );
return true;
} catch ( e ) {
return false;
}
}())
};
// Get a reference to the global object, like window in browsers
}( (function() {
return this;
})() ));
/**
* Escape text for attribute or text content.
*/
function escapeText( s ) {
if ( !s ) {
return "";
}
s = s + "";
// Both single quotes and double quotes (for attributes)
return s.replace( /['"<>&]/g, function( s ) {
switch ( s ) {
case "'":
return "&#039;";
case "\"":
return "&quot;";
case "<":
return "&lt;";
case ">":
return "&gt;";
case "&":
return "&amp;";
}
});
}
/**
* @param {HTMLElement} elem
* @param {string} type
* @param {Function} fn
*/
function addEvent( elem, type, fn ) {
if ( elem.addEventListener ) {
// Standards-based browsers
elem.addEventListener( type, fn, false );
} else if ( elem.attachEvent ) {
// support: IE <9
elem.attachEvent( "on" + type, fn );
}
}
/**
* @param {Array|NodeList} elems
* @param {string} type
* @param {Function} fn
*/
function addEvents( elems, type, fn ) {
var i = elems.length;
while ( i-- ) {
addEvent( elems[ i ], type, fn );
}
}
function hasClass( elem, name ) {
return ( " " + elem.className + " " ).indexOf( " " + name + " " ) >= 0;
}
function addClass( elem, name ) {
if ( !hasClass( elem, name ) ) {
elem.className += ( elem.className ? " " : "" ) + name;
}
}
function toggleClass( elem, name ) {
if ( hasClass( elem, name ) ) {
removeClass( elem, name );
} else {
addClass( elem, name );
}
}
function removeClass( elem, name ) {
var set = " " + elem.className + " ";
// Class name may appear multiple times
while ( set.indexOf( " " + name + " " ) >= 0 ) {
set = set.replace( " " + name + " ", " " );
}
// trim for prettiness
elem.className = typeof set.trim === "function" ? set.trim() : set.replace( /^\s+|\s+$/g, "" );
}
function id( name ) {
return defined.document && document.getElementById && document.getElementById( name );
}
function getUrlConfigHtml() {
var i, j, val,
escaped, escapedTooltip,
selection = false,
len = config.urlConfig.length,
urlConfigHtml = "";
for ( i = 0; i < len; i++ ) {
val = config.urlConfig[ i ];
if ( typeof val === "string" ) {
val = {
id: val,
label: val
};
}
escaped = escapeText( val.id );
escapedTooltip = escapeText( val.tooltip );
config[ val.id ] = QUnit.urlParams[ val.id ];
if ( !val.value || typeof val.value === "string" ) {
urlConfigHtml += "<input id='qunit-urlconfig-" + escaped +
"' name='" + escaped + "' type='checkbox'" +
( val.value ? " value='" + escapeText( val.value ) + "'" : "" ) +
( config[ val.id ] ? " checked='checked'" : "" ) +
" title='" + escapedTooltip + "'><label for='qunit-urlconfig-" + escaped +
"' title='" + escapedTooltip + "'>" + val.label + "</label>";
} else {
urlConfigHtml += "<label for='qunit-urlconfig-" + escaped +
"' title='" + escapedTooltip + "'>" + val.label +
": </label><select id='qunit-urlconfig-" + escaped +
"' name='" + escaped + "' title='" + escapedTooltip + "'><option></option>";
if ( QUnit.is( "array", val.value ) ) {
for ( j = 0; j < val.value.length; j++ ) {
escaped = escapeText( val.value[ j ] );
urlConfigHtml += "<option value='" + escaped + "'" +
( config[ val.id ] === val.value[ j ] ?
( selection = true ) && " selected='selected'" : "" ) +
">" + escaped + "</option>";
}
} else {
for ( j in val.value ) {
if ( hasOwn.call( val.value, j ) ) {
urlConfigHtml += "<option value='" + escapeText( j ) + "'" +
( config[ val.id ] === j ?
( selection = true ) && " selected='selected'" : "" ) +
">" + escapeText( val.value[ j ] ) + "</option>";
}
}
}
if ( config[ val.id ] && !selection ) {
escaped = escapeText( config[ val.id ] );
urlConfigHtml += "<option value='" + escaped +
"' selected='selected' disabled='disabled'>" + escaped + "</option>";
}
urlConfigHtml += "</select>";
}
}
return urlConfigHtml;
}
function toolbarUrlConfigContainer() {
var urlConfigContainer = document.createElement( "span" );
urlConfigContainer.innerHTML = getUrlConfigHtml();
// For oldIE support:
// * Add handlers to the individual elements instead of the container
// * Use "click" instead of "change" for checkboxes
// * Fallback from event.target to event.srcElement
addEvents( urlConfigContainer.getElementsByTagName( "input" ), "click", function( event ) {
var params = {},
target = event.target || event.srcElement;
params[ target.name ] = target.checked ?
target.defaultValue || true :
undefined;
window.location = QUnit.url( params );
});
addEvents( urlConfigContainer.getElementsByTagName( "select" ), "change", function( event ) {
var params = {},
target = event.target || event.srcElement;
params[ target.name ] = target.options[ target.selectedIndex ].value || undefined;
window.location = QUnit.url( params );
});
return urlConfigContainer;
}
function getModuleNames() {
var i,
moduleNames = [];
for ( i in config.modules ) {
if ( config.modules.hasOwnProperty( i ) ) {
moduleNames.push( i );
}
}
moduleNames.sort(function( a, b ) {
return a.localeCompare( b );
});
return moduleNames;
}
function toolbarModuleFilterHtml() {
var i,
moduleFilterHtml = "",
moduleNames = getModuleNames();
if ( moduleNames.length <= 1 ) {
return false;
}
moduleFilterHtml += "<label for='qunit-modulefilter'>Module: </label>" +
"<select id='qunit-modulefilter' name='modulefilter'><option value='' " +
( config.module === undefined ? "selected='selected'" : "" ) +
">< All Modules ></option>";
for ( i = 0; i < moduleNames.length; i++ ) {
moduleFilterHtml += "<option value='" +
escapeText( encodeURIComponent( moduleNames[ i ] ) ) + "' " +
( config.module === moduleNames[ i ] ? "selected='selected'" : "" ) +
">" + escapeText( moduleNames[ i ] ) + "</option>";
}
moduleFilterHtml += "</select>";
return moduleFilterHtml;
}
function toolbarModuleFilter() {
var moduleFilter = document.createElement( "span" ),
moduleFilterHtml = toolbarModuleFilterHtml();
if ( !moduleFilterHtml ) {
return false;
}
moduleFilter.setAttribute( "id", "qunit-modulefilter-container" );
moduleFilter.innerHTML = moduleFilterHtml;
addEvent( moduleFilter.lastChild, "change", function() {
var selectBox = moduleFilter.getElementsByTagName( "select" )[ 0 ],
selectedModule = decodeURIComponent( selectBox.options[ selectBox.selectedIndex ].value );
window.location = QUnit.url({
module: ( selectedModule === "" ) ? undefined : selectedModule,
// Remove any existing filters
filter: undefined,
testNumber: undefined
});
});
return moduleFilter;
}
function toolbarFilter() {
var testList = id( "qunit-tests" ),
filter = document.createElement( "input" );
filter.type = "checkbox";
filter.id = "qunit-filter-pass";
addEvent( filter, "click", function() {
if ( filter.checked ) {
addClass( testList, "hidepass" );
if ( defined.sessionStorage ) {
sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
}
} else {
removeClass( testList, "hidepass" );
if ( defined.sessionStorage ) {
sessionStorage.removeItem( "qunit-filter-passed-tests" );
}
}
});
if ( config.hidepassed || defined.sessionStorage &&
sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
filter.checked = true;
addClass( testList, "hidepass" );
}
return filter;
}
function toolbarLabel() {
var label = document.createElement( "label" );
label.setAttribute( "for", "qunit-filter-pass" );
label.setAttribute( "title", "Only show tests and assertions that fail. Stored in sessionStorage." );
label.innerHTML = "Hide passed tests";
return label;
}
function appendToolbar() {
var moduleFilter,
toolbar = id( "qunit-testrunner-toolbar" );
if ( toolbar ) {
toolbar.appendChild( toolbarFilter() );
toolbar.appendChild( toolbarLabel() );
toolbar.appendChild( toolbarUrlConfigContainer() );
moduleFilter = toolbarModuleFilter();
if ( moduleFilter ) {
toolbar.appendChild( moduleFilter );
}
}
}
function appendBanner() {
var banner = id( "qunit-banner" );
if ( banner ) {
banner.className = "";
banner.innerHTML = "<a href='" +
QUnit.url({ filter: undefined, module: undefined, testNumber: undefined }) +
"'>" + banner.innerHTML + "</a> ";
}
}
function appendTestResults() {
var tests = id( "qunit-tests" ),
result = id( "qunit-testresult" );
if ( result ) {
result.parentNode.removeChild( result );
}
if ( tests ) {
tests.innerHTML = "";
result = document.createElement( "p" );
result.id = "qunit-testresult";
result.className = "result";
tests.parentNode.insertBefore( result, tests );
result.innerHTML = "Running...<br>&nbsp;";
}
}
function storeFixture() {
var fixture = id( "qunit-fixture" );
if ( fixture ) {
config.fixture = fixture.innerHTML;
}
}
function appendUserAgent() {
var userAgent = id( "qunit-userAgent" );
if ( userAgent ) {
userAgent.innerHTML = navigator.userAgent;
}
}
// HTML Reporter initialization and load
QUnit.begin(function() {
var qunit = id( "qunit" );
if ( qunit ) {
qunit.innerHTML =
"<h1 id='qunit-header'>" + escapeText( document.title ) + "</h1>" +
"<h2 id='qunit-banner'></h2>" +
"<div id='qunit-testrunner-toolbar'></div>" +
"<h2 id='qunit-userAgent'></h2>" +
"<ol id='qunit-tests'></ol>";
}
appendBanner();
appendTestResults();
appendUserAgent();
appendToolbar();
storeFixture();
});
QUnit.done(function( details ) {
var i, key,
banner = id( "qunit-banner" ),
tests = id( "qunit-tests" ),
html = [
"Tests completed in ",
details.runtime,
" milliseconds.<br>",
"<span class='passed'>",
details.passed,
"</span> assertions of <span class='total'>",
details.total,
"</span> passed, <span class='failed'>",
details.failed,
"</span> failed."
].join( "" );
if ( banner ) {
banner.className = details.failed ? "qunit-fail" : "qunit-pass";
}
if ( tests ) {
id( "qunit-testresult" ).innerHTML = html;
}
if ( config.altertitle && defined.document && document.title ) {
// show ✖ for good, ✔ for bad suite result in title
// use escape sequences in case file gets loaded with non-utf-8-charset
document.title = [
( details.failed ? "\u2716" : "\u2714" ),
document.title.replace( /^[\u2714\u2716] /i, "" )
].join( " " );
}
// clear own sessionStorage items if all tests passed
if ( config.reorder && defined.sessionStorage && details.failed === 0 ) {
for ( i = 0; i < sessionStorage.length; i++ ) {
key = sessionStorage.key( i++ );
if ( key.indexOf( "qunit-test-" ) === 0 ) {
sessionStorage.removeItem( key );
}
}
}
// scroll back to top to show results
if ( config.scrolltop && window.scrollTo ) {
window.scrollTo( 0, 0 );
}
});
function getNameHtml( name, module ) {
var nameHtml = "";
if ( module ) {
nameHtml = "<span class='module-name'>" + escapeText( module ) + "</span>: ";
}
nameHtml += "<span class='test-name'>" + escapeText( name ) + "</span>";
return nameHtml;
}
QUnit.testStart(function( details ) {
var a, b, li, running, assertList,
name = getNameHtml( details.name, details.module ),
tests = id( "qunit-tests" );
if ( tests ) {
b = document.createElement( "strong" );
b.innerHTML = name;
a = document.createElement( "a" );
a.innerHTML = "Rerun";
a.href = QUnit.url({ testNumber: details.testNumber });
li = document.createElement( "li" );
li.appendChild( b );
li.appendChild( a );
li.className = "running";
li.id = "qunit-test-output" + details.testNumber;
assertList = document.createElement( "ol" );
assertList.className = "qunit-assert-list";
li.appendChild( assertList );
tests.appendChild( li );
}
running = id( "qunit-testresult" );
if ( running ) {
running.innerHTML = "Running: <br>" + name;
}
});
QUnit.log(function( details ) {
var assertList, assertLi,
message, expected, actual,
testItem = id( "qunit-test-output" + details.testNumber );
if ( !testItem ) {
return;
}
message = escapeText( details.message ) || ( details.result ? "okay" : "failed" );
message = "<span class='test-message'>" + message + "</span>";
// pushFailure doesn't provide details.expected
// when it calls, it's implicit to also not show expected and diff stuff
// Also, we need to check details.expected existence, as it can exist and be undefined
if ( !details.result && hasOwn.call( details, "expected" ) ) {
expected = escapeText( QUnit.dump.parse( details.expected ) );
actual = escapeText( QUnit.dump.parse( details.actual ) );
message += "<table><tr class='test-expected'><th>Expected: </th><td><pre>" +
expected +
"</pre></td></tr>";
if ( actual !== expected ) {
message += "<tr class='test-actual'><th>Result: </th><td><pre>" +
actual + "</pre></td></tr>" +
"<tr class='test-diff'><th>Diff: </th><td><pre>" +
QUnit.diff( expected, actual ) + "</pre></td></tr>";
}
if ( details.source ) {
message += "<tr class='test-source'><th>Source: </th><td><pre>" +
escapeText( details.source ) + "</pre></td></tr>";
}
message += "</table>";
// this occours when pushFailure is set and we have an extracted stack trace
} else if ( !details.result && details.source ) {
message += "<table>" +
"<tr class='test-source'><th>Source: </th><td><pre>" +
escapeText( details.source ) + "</pre></td></tr>" +
"</table>";
}
assertList = testItem.getElementsByTagName( "ol" )[ 0 ];
assertLi = document.createElement( "li" );
assertLi.className = details.result ? "pass" : "fail";
assertLi.innerHTML = message;
assertList.appendChild( assertLi );
});
QUnit.testDone(function( details ) {
var testTitle, time, testItem, assertList,
good, bad, testCounts,
tests = id( "qunit-tests" );
// QUnit.reset() is deprecated and will be replaced for a new
// fixture reset function on QUnit 2.0/2.1.
// It's still called here for backwards compatibility handling
QUnit.reset();
if ( !tests ) {
return;
}
testItem = id( "qunit-test-output" + details.testNumber );
assertList = testItem.getElementsByTagName( "ol" )[ 0 ];
good = details.passed;
bad = details.failed;
// store result when possible
if ( config.reorder && defined.sessionStorage ) {
if ( bad ) {
sessionStorage.setItem( "qunit-test-" + details.module + "-" + details.name, bad );
} else {
sessionStorage.removeItem( "qunit-test-" + details.module + "-" + details.name );
}
}
if ( bad === 0 ) {
addClass( assertList, "qunit-collapsed" );
}
// testItem.firstChild is the test name
testTitle = testItem.firstChild;
testCounts = bad ?
"<b class='failed'>" + bad + "</b>, " + "<b class='passed'>" + good + "</b>, " :
"";
testTitle.innerHTML += " <b class='counts'>(" + testCounts +
details.assertions.length + ")</b>";
addEvent( testTitle, "click", function() {
toggleClass( assertList, "qunit-collapsed" );
});
time = document.createElement( "span" );
time.className = "runtime";
time.innerHTML = details.runtime + " ms";
testItem.className = bad ? "fail" : "pass";
testItem.insertBefore( time, assertList );
});
if ( !defined.document || document.readyState === "complete" ) {
config.autorun = true;
}
if ( defined.document ) {
addEvent( window, "load", QUnit.load );
}
})();
......@@ -30,19 +30,21 @@
*/
tools_container.className = "tools-container";
Object.keys(data.class_definition).forEach(function(key) {
var _class = data.class_definition[key], tool;
var _class_object = data.class_definition[key], tool;
// XXX "expand" the json schema "allOF" etc
if (_class._class === "node") {
tool = document.createElement("div");
// XXX maybe allow to configure the class name ?
tool.className = "tool " + key;
tool.textContent = _class.name || key;
tool.draggable = true;
tool.dataset.class_name = JSON.stringify(key);
Object.keys(_class.css || {}).forEach(function(k) {
tool.style[k] = _class.css[k];
});
tools_container.appendChild(tool);
if (_class_object.allOf) {
if (_class_object.allOf[0].$ref === "#/class_definition/node") {
tool = document.createElement("div");
// XXX maybe allow to configure the class name ?
tool.className = "tool " + key;
tool.textContent = _class_object.name || key;
tool.draggable = true;
tool.dataset.class_name = JSON.stringify(key);
Object.keys(_class_object.css || {}).forEach(function(k) {
tool.style[k] = _class_object.css[k];
});
tools_container.appendChild(tool);
}
}
});
this.props.element.querySelector(".tools").appendChild(tools_container);
......
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