summaryrefslogtreecommitdiffstats
path: root/sca-cpp/branches/lightweight-sca/modules/js/htdocs
diff options
context:
space:
mode:
Diffstat (limited to 'sca-cpp/branches/lightweight-sca/modules/js/htdocs')
-rw-r--r--sca-cpp/branches/lightweight-sca/modules/js/htdocs/atomutil.js184
-rw-r--r--sca-cpp/branches/lightweight-sca/modules/js/htdocs/component.js637
-rw-r--r--sca-cpp/branches/lightweight-sca/modules/js/htdocs/elemutil.js236
-rw-r--r--sca-cpp/branches/lightweight-sca/modules/js/htdocs/jsonutil.js261
-rw-r--r--sca-cpp/branches/lightweight-sca/modules/js/htdocs/scdl.js250
-rw-r--r--sca-cpp/branches/lightweight-sca/modules/js/htdocs/ui.css709
-rw-r--r--sca-cpp/branches/lightweight-sca/modules/js/htdocs/ui.js409
-rw-r--r--sca-cpp/branches/lightweight-sca/modules/js/htdocs/util.js471
-rw-r--r--sca-cpp/branches/lightweight-sca/modules/js/htdocs/xmlutil.js256
9 files changed, 3413 insertions, 0 deletions
diff --git a/sca-cpp/branches/lightweight-sca/modules/js/htdocs/atomutil.js b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/atomutil.js
new file mode 100644
index 0000000000..068b5de2fd
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/atomutil.js
@@ -0,0 +1,184 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * ATOM data conversion functions.
+ */
+var atom = {};
+
+/**
+ * Convert a list of elements to a list of values representing an ATOM entry.
+ */
+atom.entryElementValues = function(e) {
+ var lt = filter(selector(mklist(element, "'title")), e);
+ var t = mklist(element, "'title", isNil(lt)? '' : elementValue(car(lt)));
+
+ var li = filter(selector(mklist(element, "'id")), e);
+ var i = mklist(element, "'id", isNil(li)? '' : elementValue(car(li)));
+
+ var la = filter(selector(mklist(element, "'author")), e);
+ var lan = isNil(la)? mklist() : filter(selector(mklist(element, "'name")), car(la));
+ var lae = isNil(la)? mklist() : filter(selector(mklist(element, "'email")), car(la));
+ var laa = isNil(lan)? lae : lan;
+ var a = isNil(laa)? mklist() : mklist(mklist(element, "'author", elementValue(car(laa))));
+
+ var lu = filter(selector(mklist(element, "'updated")), e);
+ var u = isNil(lu)? mklist() : mklist(mklist(element, "'updated", elementValue(car(lu))));
+
+ var lc = filter(selector(mklist(element, "'content")), e);
+ var c = isNil(lc)? mklist() : mklist(mklist(element, "'content", elementValue(car(lc))));
+
+ return append(append(append(mklist(element, "'entry", t, i), a), u), c);
+};
+
+/**
+ * Convert a list of elements to a list of values representing ATOM entries.
+ */
+atom.entriesElementValues = function(e) {
+ if (isNil(e))
+ return e;
+ return cons(atom.entryElementValues(car(e)), atom.entriesElementValues(cdr(e)));
+};
+
+/**
+ * Return true if a list of strings represents an ATOM entry.
+ */
+atom.isATOMEntry = function(l) {
+ if (!isXML(l))
+ return false;
+ return car(l).match('<entry') != null && car(l).match('<feed') == null && car(l).match('="http://www.w3.org/2005/Atom"') != null;
+};
+
+/**
+ * Convert a DOM Document to a list of values representing an ATOM entry.
+ */
+atom.readATOMEntryDocument = function(doc) {
+ var e = readXMLDocument(doc);
+ if (isNil(e))
+ return mklist();
+ return mklist(atom.entryElementValues(car(e)));
+};
+
+/**
+ * Convert a list of strings to a list of values representing an ATOM entry.
+ */
+atom.readATOMEntry = function(l) {
+ return atom.readATOMEntryDocument(parseXML(l));
+};
+
+/**
+ * Return true if a list of strings represents an ATOM feed.
+ */
+atom.isATOMFeed = function(l) {
+ if (!isXML(l))
+ return false;
+ return car(l).match('<feed') != null && car(l).match('="http://www.w3.org/2005/Atom"') != null;
+};
+
+/**
+ * Convert a DOM document to a list of values representing an ATOM feed.
+ */
+atom.readATOMFeedDocument = function(doc) {
+ var f = readXMLDocument(doc);
+ if (isNil(f))
+ return mklist();
+ var t = filter(selector(mklist(element, "'title")), car(f));
+ var i = filter(selector(mklist(element, "'id")), car(f));
+ var e = filter(selector(mklist(element, "'entry")), car(f));
+ return mklist(append(
+ mklist(element, "'feed", mklist(element, "'title", elementValue(car(t))), mklist(element, "'id", elementValue(car(i)))),
+ atom.entriesElementValues(e)));
+};
+
+/**
+ * Convert a list of strings to a list of values representing an ATOM feed.
+ */
+atom.readATOMFeed = function(l) {
+ return atom.readATOMFeedDocument(parseXML(l));
+};
+
+/**
+ * Convert a list of values representy an ATOM entry to a list of elements.
+ */
+atom.entryElement = function(l) {
+ var title = elementValue(namedElementChild("'title", l));
+ var id = elementValue(namedElementChild("'id", l));
+ var author = namedElementChild("'author", l);
+ var email = isNil(author)? false : (elementValue(author).indexOf('@') != -1);
+ var updated = namedElementChild("'updated", l);
+ var content = namedElementChild("'content", l);
+ var text = isNil(content)? false : elementHasValue(content);
+ return append(append(append(append(
+ mklist(element, "'entry", mklist(attribute, "'xmlns", "http://www.w3.org/2005/Atom"),
+ mklist(element, "'title", mklist(attribute, "'type", "text"), title), mklist(element, "'id", id)),
+ isNil(author)? mklist() : mklist(element, "'author",
+ (email? mklist(element, "'email", elementValue(author)) : mklist(element, "'name", elementValue(author))))),
+ isNil(updated)? mklist() : mklist(element, "'updated", elementValue(updated))),
+ isNil(content)? mklist() :
+ mklist(append(mklist(element, "'content", mklist(attribute, "'type", text? "text" : "application/xml")),
+ text? mklist(elementValue(content)) : elementChildren(content)))),
+ mklist(mklist(element, "'link", mklist(attribute, "'href", id))));
+};
+
+/**
+ * Convert a list of values representing ATOM entries to a list of elements.
+ */
+atom.entriesElements = function(l) {
+ if (isNil(l))
+ return l;
+ return cons(atom.entryElement(car(l)), atom.entriesElements(cdr(l)));
+};
+
+/**
+ * Convert a list of values representing an ATOM entry to an ATOM entry.
+ */
+atom.writeATOMEntry = function(ll) {
+ var l = isNil(ll)? ll : car(ll);
+ return writeXML(mklist(atom.entryElement(l)), true);
+};
+
+/**
+ * Convert a list of values representing an ATOM feed to an ATOM feed.
+ */
+atom.writeATOMFeed = function(ll) {
+ var l = isNil(ll)? ll : car(ll);
+ var lt = filter(selector(mklist(element, "'title")), l);
+ var t = isNil(lt)? '' : elementValue(car(lt));
+ var li = filter(selector(mklist(element, "'id")), l);
+ var i = isNil(li)? '' : elementValue(car(li));
+ var f = mklist(element, "'feed", mklist(attribute, "'xmlns", "http://www.w3.org/2005/Atom"),
+ mklist(element, "'title", mklist(attribute, "'type", "text"), car(l)),
+ mklist(element, "'id", cadr(l)));
+
+ // Write ATOM entries
+ var le = filter(selector(mklist(element, "'entry")), l);
+ if (isNil(le))
+ return writeXML(mklist(f), true);
+
+ // Write a single ATOM entry element with a list of values
+ if (!isNil(le) && !isNil(car(le)) && isList(car(caddr(car(le))))) {
+ var fe = append(f, atom.entriesElements(caddr(car(le))));
+ return writeXML(mklist(fe), true);
+ }
+
+ // Write separate ATOM entry elements
+ var fe = append(f, atom.entriesElements(le));
+ return writeXML(mklist(fe), true);
+};
+
diff --git a/sca-cpp/branches/lightweight-sca/modules/js/htdocs/component.js b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/component.js
new file mode 100644
index 0000000000..c3799ef708
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/component.js
@@ -0,0 +1,637 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ * The JSON-RPC client code is based on Jan-Klaas' JavaScript
+ * o lait library (jsolait).
+ *
+ * $Id: jsonrpc.js,v 1.36.2.3 2006/03/08 15:09:37 mclark Exp $
+ *
+ * Copyright (c) 2003-2004 Jan-Klaas Kollhof
+ * Copyright (c) 2005 Michael Clark, Metaparadigm Pte Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ */
+
+/**
+ * Client component wiring API, supporting JSON and ATOM bindings.
+ */
+
+var JSONClient = {};
+
+/**
+ * Escape a character.
+ */
+JSONClient.escapeJSONChar = function(c) {
+ if(c == "\"" || c == "\\") return "\\" + c;
+ if (c == "\b") return "\\b";
+ if (c == "\f") return "\\f";
+ if (c == "\n") return "\\n";
+ if (c == "\r") return "\\r";
+ if (c == "\t") return "\\t";
+ var hex = c.charCodeAt(0).toString(16);
+ if(hex.length == 1) return "\\u000" + hex;
+ if(hex.length == 2) return "\\u00" + hex;
+ if(hex.length == 3) return "\\u0" + hex;
+ return "\\u" + hex;
+};
+
+/**
+ * Encode a string into JSON format.
+ */
+JSONClient.escapeJSONString = function(s) {
+ // The following should suffice but Safari's regex is broken (doesn't support callback substitutions)
+ // return "\"" + s.replace(/([^\u0020-\u007f]|[\\\"])/g, JSONClient.escapeJSONChar) + "\"";
+
+ // Rather inefficient way to do it
+ var parts = s.split("");
+ for(var i = 0; i < parts.length; i++) {
+ var c = parts[i];
+ if(c == '"' || c == '\\' || c.charCodeAt(0) < 32 || c.charCodeAt(0) >= 128)
+ parts[i] = JSONClient.escapeJSONChar(parts[i]);
+ }
+ return "\"" + parts.join("") + "\"";
+};
+
+/**
+ * Marshall objects to JSON format.
+ */
+JSONClient.toJSON = function(o) {
+ if(o == null)
+ return "null";
+ if(o.constructor == String)
+ return JSONClient.escapeJSONString(o);
+ if(o.constructor == Number)
+ return o.toString();
+ if(o.constructor == Boolean)
+ return o.toString();
+ if(o.constructor == Date)
+ return '{javaClass: "java.util.Date", time: ' + o.valueOf() +'}';
+ if(o.constructor == Array) {
+ var v = [];
+ for(var i = 0; i < o.length; i++)
+ v.push(JSONClient.toJSON(o[i]));
+ return "[" + v.join(", ") + "]";
+ }
+ var v = [];
+ for(attr in o) {
+ if(o[attr] == null)
+ v.push("\"" + attr + "\": null");
+ else if(typeof o[attr] == "function")
+ ; // Skip
+ else
+ v.push(JSONClient.escapeJSONString(attr) + ": " + JSONClient.toJSON(o[attr]));
+ }
+ return "{" + v.join(", ") + "}";
+};
+
+/**
+ * Construct an HTTPBindingClient.
+ */
+function HTTPBindingClient(name, uri, domain) {
+ this.name = name;
+ this.domain = domain;
+ this.uri = uri;
+ this.apply = this.createApplyMethod();
+}
+
+/**
+ * JSON-RPC request counter.
+ */
+HTTPBindingClient.jsonrpcID = 1;
+
+/**
+ * HTTPBindingClient implementation
+ */
+
+/**
+ * Generate client proxy apply method.
+ */
+HTTPBindingClient.prototype.createApplyMethod = function() {
+ var fn = function() {
+ var methodName = arguments[0];
+ var args = [];
+ for(var i = 1; i < arguments.length; i++)
+ args.push(arguments[i]);
+
+ var cb = null;
+ if (typeof args[args.length - 1] == "function")
+ cb = args.pop();
+
+ var req = HTTPBindingClient.makeJSONRequest(methodName, args, cb);
+ return fn.client.jsonApply(req);
+ };
+ fn.client = this;
+ return fn;
+};
+
+/**
+ * Make a JSON-RPC request.
+ */
+HTTPBindingClient.makeJSONRequest = function(methodName, args, cb) {
+ var req = {};
+ req.id = HTTPBindingClient.jsonrpcID++;
+ if (cb)
+ req.cb = cb;
+ var obj = {};
+ obj.id = req.id;
+ obj.method = methodName;
+ obj.params = args;
+ req.data = JSONClient.toJSON(obj);
+ return req;
+};
+
+/**
+ * Return the JSON result from an XMLHttpRequest.
+ */
+HTTPBindingClient.jsonResult = function(http) {
+ // Get the charset
+ function httpCharset(http) {
+ try {
+ var contentType = http.getResponseHeader("Content-Type");
+ var parts = contentType.split(/\s*;\s*/);
+ for (var i = 0; i < parts.length; i++) {
+ if (parts[i].substring(0, 8) == "charset=")
+ return parts[i].substring(8, parts[i].length);
+ }
+ } catch (e) {}
+ return "UTF-8";
+ }
+ if(!HTTPBindingClient.charset)
+ HTTPBindingClient.charset = httpCharset(http);
+
+ // Unmarshall the JSON response
+ var obj;
+ eval("obj = " + http.responseText);
+ if(obj.error)
+ throw new HTTPBindingClient.Exception(obj.error.code, obj.error.msg);
+ var res = obj.result;
+ return res;
+};
+
+/**
+ * Apply a function remotely using JSON-RPC.
+ */
+HTTPBindingClient.prototype.jsonApply = function(req) {
+ // Connect to the service
+ var http = HTTPBindingClient.getHTTPRequest();
+ var hascb = req.cb? true : false;
+ http.open("POST", this.uri, hascb);
+ http.setRequestHeader("Accept", "*/*");
+ http.setRequestHeader("Content-Type", "application/json-rpc");
+
+ // Construct call back if we have one
+ if(hascb) {
+ http.onreadystatechange = function() {
+ if(http.readyState == 4) {
+ // Pass the result or exception
+ if(http.status == 200) {
+ var res = null;
+ try {
+ res = HTTPBindingClient.jsonResult(http);
+ try {
+ req.cb(res);
+ } catch(cbe) {}
+ } catch(e) {
+ try {
+ req.cb(null, e);
+ } catch(cbe) {}
+ }
+ } else
+ try {
+ req.cb(null, HTTPBindingClient.Exception(http.status, http.statusText));
+ } catch(cbe) {}
+ }
+ };
+
+ // Send the request
+ http.send(req.data);
+ return req.id;
+ }
+
+ // Send the request and return the result or exception
+ http.send(req.data);
+ if (http.status == 200)
+ return HTTPBindingClient.jsonResult(http);
+ throw new HTTPBindingClient.Exception(http.status, http.statusText);
+};
+
+
+/**
+ * REST GET method.
+ */
+HTTPBindingClient.prototype.get = function(id, cb) {
+ var u = id? (this.uri? this.uri + '/' + id : id) : this.uri;
+ var hascb = cb? true : false;
+
+ // Get from local storage first
+ var ls = window.lstorage || localStorage;
+ var item = null;
+ try { item = ls.getItem(u); } catch(e) {}
+ //log('localStorage.getItem', u, item);
+ if (item != null && item != '') {
+ if (!hascb)
+ return item;
+
+ // Pass local result to callback
+ try {
+ cb(item);
+ } catch (cbe) {}
+ }
+
+ // Connect to the service
+ var http = HTTPBindingClient.getHTTPRequest();
+ http.open("GET", u, hascb);
+ http.setRequestHeader("Accept", "*/*");
+
+ // Construct call back if we have one
+ if (hascb) {
+ http.onreadystatechange = function() {
+ //log('readystate', http.readyState, 'status', http.status, 'headers', http.getAllResponseHeaders());
+ if (http.readyState == 4) {
+ // Pass result if different from local result
+ if (http.status == 200) {
+
+ if (http.getResponseHeader("X-Login") != null) {
+ // Detect redirect to a login page
+ try {
+ var le = new HTTPBindingClient.Exception(403, 'X-Login');
+ if (window.onloginredirect)
+ window.onloginredirect(le);
+ return cb(null, le);
+ } catch(cbe) {}
+
+ } else if (http.responseText == '' || http.getResponseHeader("Content-Type") == null) {
+ // Report empty response
+ try {
+ return cb(null, new HTTPBindingClient.Exception(403, 'No-Content'));
+ } catch(cbe) {}
+
+ } else {
+ if (item == null || http.responseText != item) {
+ // Store retrieved entry in local storage
+ if (http.responseText != null) {
+ //log('localStorage.setItem', u, http.responseText);
+ try { ls.setItem(u, http.responseText); } catch(e) {}
+ }
+ try {
+ return cb(http.responseText);
+ } catch(cbe) {}
+ }
+ }
+ }
+ else {
+ // Pass exception if we didn't have a local result
+ if (item == null) {
+ try {
+ return cb(null, new HTTPBindingClient.Exception(http.status, http.statusText));
+ } catch(cbe) {}
+ }
+ }
+ }
+ };
+
+ // Send the request
+ http.send(null);
+ return true;
+ }
+
+ // Send the request and return the result or exception
+ http.send(null);
+ if (http.status == 200) {
+ if (http.getResponseHeader("X-Login") != null) {
+
+ // Detect redirect to a login page
+ var le = new HTTPBindingClient.Exception(403, 'X-Login');
+ if (window.onloginredirect)
+ window.onloginredirect(le);
+ throw le;
+
+ } else if (http.responseText == '' || http.getResponseHeader("Content-Type") == null) {
+
+ // Report empty response
+ throw new HTTPBindingClient.Exception(403, 'No-Content');
+ }
+ return http.responseText;
+ }
+ throw new HTTPBindingClient.Exception(http.status, http.statusText);
+};
+
+/**
+ * REST GET method, does not use the local cache.
+ */
+HTTPBindingClient.prototype.getnocache = function(id, cb) {
+ var u = id? (this.uri? this.uri + '/' + id : id) : this.uri;
+ var hascb = cb? true : false;
+
+ // Connect to the service
+ var http = HTTPBindingClient.getHTTPRequest();
+ http.open("GET", u, hascb);
+ http.setRequestHeader("Accept", "*/*");
+
+ // Construct call back if we have one
+ if (hascb) {
+ http.onreadystatechange = function() {
+ if (http.readyState == 4) {
+ if (http.status == 200) {
+
+ if (http.getResponseHeader("X-Login") != null) {
+ // Detect redirect to a login page
+ try {
+ var le = new HTTPBindingClient.Exception(403, 'X-Login');
+ if (window.onloginredirect)
+ window.onloginredirect(le);
+ return cb(null, le);
+ } catch(cbe) {}
+
+ } else if (http.responseText == '' || http.getResponseHeader("Content-Type") == null) {
+ // Report empty response
+ try {
+ return cb(null, new HTTPBindingClient.Exception(403, 'No-Content'));
+ } catch(cbe) {}
+
+ } else {
+ try {
+ return cb(http.responseText);
+ } catch(cbe) {}
+ }
+ } else {
+ try {
+ return cb(null, new HTTPBindingClient.Exception(http.status, http.statusText));
+ } catch(cbe) {}
+ }
+ }
+ };
+
+ // Send the request
+ http.send(null);
+ return true;
+ }
+
+ // Send the request and return the result or exception
+ http.send(null);
+ if (http.status == 200) {
+ if (http.getResponseHeader("X-Login") != null) {
+
+ // Detect redirect to a login page
+ var le = new HTTPBindingClient.Exception(403, 'X-Login');
+ if (window.onloginredirect)
+ window.onloginredirect(le);
+ throw le;
+
+ } else if (http.responseText == '' || http.getResponseHeader("Content-Type") == null) {
+
+ // Report empty response
+ throw new HTTPBindingClient.Exception(403, 'No-Content');
+ }
+ return http.responseText;
+ }
+ throw new HTTPBindingClient.Exception(http.status, http.statusText);
+};
+
+/**
+ * REST POST method.
+ */
+HTTPBindingClient.prototype.post = function (entry, cb) {
+
+ // Connect to the service
+ var http = HTTPBindingClient.getHTTPRequest();
+ var hascb = cb? true : false;
+ http.open("POST", this.uri, hascb);
+ http.setRequestHeader("Accept", "*/*");
+ http.setRequestHeader("Content-Type", "application/atom+xml");
+
+ // Construct call back if we have one
+ if (hascb) {
+ http.onreadystatechange = function() {
+ // Pass the result or exception
+ if (http.readyState == 4) {
+ if (http.status == 201) {
+ try {
+ cb(http.responseText);
+ } catch(cbe) {}
+ }
+ else {
+ try {
+ cb(null, new HTTPBindingClient.Exception(http.status, http.statusText));
+ } catch(cbe) {}
+ }
+ }
+ };
+ // Send the request
+ http.send(entry);
+ return true;
+ }
+
+ // Send the request and return the result or exception
+ http.send(entry);
+ if (http.status == 201)
+ return http.responseText;
+ throw new HTTPBindingClient.Exception(http.status, http.statusText);
+};
+
+/**
+ * REST PUT method.
+ */
+HTTPBindingClient.prototype.put = function (id, entry, cb) {
+ var u = this.uri + '/' + id;
+
+ // Update local storage
+ var ls = window.lstorage || localStorage;
+ try { ls.setItem(u, entry); } catch(e) {}
+ //log('localStorage.setItem', u, entry);
+
+ // Connect to the service
+ var http = HTTPBindingClient.getHTTPRequest();
+ var hascb = cb? true : false;
+ http.open("PUT", u, hascb);
+ http.setRequestHeader("Accept", "*/*");
+ http.setRequestHeader("Content-Type", "application/atom+xml");
+
+ // Construct call back if we have one
+ if (hascb) {
+ http.onreadystatechange = function() {
+ if (http.readyState == 4) {
+ // Pass any exception
+ if (http.status == 200) {
+ try {
+ cb();
+ } catch(cbe) {}
+ } else {
+ try {
+ cb(new HTTPBindingClient.Exception(http.status, http.statusText));
+ } catch(cbe) {}
+ }
+ }
+ };
+ // Send the request
+ http.send(entry);
+ return true;
+ }
+
+ // Send the request and return any exception
+ http.send(entry);
+ if (http.status == 200)
+ return true;
+ throw new HTTPBindingClient.Exception(http.status, http.statusText);
+};
+
+/**
+ * REST DELETE method.
+ */
+HTTPBindingClient.prototype.del = function (id, cb) {
+ var u = this.uri + '/' + id;
+
+ // Update local storage
+ var ls = window.lstorage || localStorage;
+ try { ls.removeItem(u); } catch(e) {}
+ //log('localStorage.removeItem', u);
+
+ // Connect to the service
+ var http = HTTPBindingClient.getHTTPRequest();
+ var hascb = cb? true : false;
+ http.open("DELETE", u, hascb);
+ http.setRequestHeader("Accept", "*/*");
+
+ // Construct call back if we have one
+ if (cb) {
+ http.onreadystatechange = function() {
+ if (http.readyState == 4) {
+ // Pass any exception
+ if (http.status == 200) {
+ try {
+ cb();
+ } catch(cbe) {}
+ }
+ else {
+ try {
+ cb(new HTTPBindingClient.Exception(http.status, http.statusText));
+ } catch(cbe) {}
+ }
+ }
+ };
+ // Send the request
+ http.send(null);
+ return true;
+ }
+
+ // Send the request and return any exception
+ http.send(null);
+ if (http.status == 200)
+ return true;
+ throw new HTTPBindingClient.Exception(http.status, http.statusText);
+};
+
+/**
+ * HTTPBindingClient exceptions.
+ */
+HTTPBindingClient.Exception = function(code, message) {
+ this.name = "HTTPBindingClientException";
+ this.code = code;
+ this.message = message;
+};
+
+HTTPBindingClient.Exception.prototype = new Error();
+
+HTTPBindingClient.Exception.prototype.toString = function() {
+ return this.name + ": " + this.message;
+};
+
+/**
+ * XMLHttpRequest wrapper.
+ */
+HTTPBindingClient.msxmlNames = [ "MSXML2.XMLHTTP.5.0", "MSXML2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP" ];
+
+HTTPBindingClient.getHTTPRequest = function() {
+ if (HTTPBindingClient.httpFactory)
+ return HTTPBindingClient.httpFactory();
+
+ // Mozilla XMLHttpRequest
+ try {
+ HTTPBindingClient.httpFactory = function() {
+ return new XMLHttpRequest();
+ };
+ return HTTPBindingClient.httpFactory();
+ } catch(e) {}
+
+ // Microsoft MSXML ActiveX
+ for (var i = 0; i < HTTPBindingClient.msxmlNames.length; i++) {
+ try {
+ HTTPBindingClient.httpFactory = function() {
+ return new ActiveXObject(HTTPBindingClient.msxmlNames[i]);
+ };
+ return HTTPBindingClient.httpFactory();
+ } catch (e) {}
+ }
+
+ // Can't create XMLHttpRequest
+ HTTPBindingClient.httpFactory = null;
+ throw new HTTPBindingClient.Exception(0, "Can't create XMLHttpRequest object");
+};
+
+/**
+ * Public API.
+ */
+
+var sca = {};
+
+/**
+ * Return an HTTP client proxy.
+ */
+sca.httpclient = function(name, uri, domain) {
+ return new HTTPBindingClient(name, uri, domain);
+};
+
+/**
+ * Return a component proxy.
+ */
+sca.component = function(name, domain) {
+ if (!domain)
+ return new HTTPBindingClient(name, '/c/' + name, domain);
+ return new HTTPBindingClient(name, '/' + domain + '/c/' + name, domain);
+};
+
+/**
+ * Return a reference proxy.
+ */
+sca.reference = function(comp, rname) {
+ if (!comp.domain)
+ return new HTTPBindingClient(comp.name + '/' + rname, '/r/' + comp.name + '/' + rname, comp.domain);
+ return new HTTPBindingClient(comp.name + '/' + rname, '/' + comp.domain + '/r/' + comp.name + '/' + rname, comp.domain);
+};
+
+/**
+ * Add proxy functions to a reference proxy.
+ */
+sca.defun = function(ref) {
+ function defapply(name) {
+ return function() {
+ var args = new Array();
+ args[0] = name;
+ for (i = 0, n = arguments.length; i < n; i++)
+ args[i + 1] = arguments[i];
+ return this.apply.apply(this, args);
+ };
+ }
+
+ for (f = 1; f < arguments.length; f++) {
+ var fn = arguments[f];
+ ref[fn]= defapply(fn);
+ }
+ return ref;
+};
+
diff --git a/sca-cpp/branches/lightweight-sca/modules/js/htdocs/elemutil.js b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/elemutil.js
new file mode 100644
index 0000000000..37d641f7b3
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/elemutil.js
@@ -0,0 +1,236 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * Functions to help represent data as lists of elements and attributes.
+ */
+
+var element = "'element"
+var attribute = "'attribute"
+var atsign = "'@"
+
+/**
+ * Return true if a value is an element.
+ */
+function isElement(v) {
+ return (!(!isList(v) || isNil(v) || car(v) != element));
+}
+
+/**
+ * Return true if a value is an attribute.
+ */
+function isAttribute(v) {
+ return (!(!isList(v) || isNil(v) || car(v) != attribute));
+}
+
+/**
+ * Return the name of an attribute.
+ */
+attributeName = cadr;
+
+/**
+ * Return the value of an attribute.
+ */
+attributeValue = caddr;
+
+/**
+ * Return the name of an element.
+ */
+elementName = cadr;
+
+/**
+ * Return true if an element has children.
+ */
+function elementHasChildren(l) {
+ return !isNil(cddr(l));
+}
+
+/**
+ * Return the children of an element.
+ */
+elementChildren = cddr;
+
+/**
+ * Return true if an element has a value.
+ */
+function elementHasValue(l) {
+ var r = reverse(l);
+ if (isSymbol(car(r)))
+ return false;
+ return (!(isList(car(r)) && !isNil(car(r)) && isSymbol(car(car(r)))))
+}
+
+/**
+ * Return the value of an element.
+ */
+function elementValue(l) {
+ return car(reverse(l));
+}
+
+/**
+ * Convert an element to a value.
+ */
+function elementToValueIsList(v) {
+ if (!isList(v))
+ return false;
+ return isNil(v) || !isSymbol(car(v));
+}
+
+function elementToValue(t) {
+ if (isTaggedList(t, attribute))
+ return mklist(atsign + attributeName(t).substring(1), attributeValue(t));
+ if (isTaggedList(t, element)) {
+ if (elementHasValue(t)) {
+ if (!elementToValueIsList(elementValue(t)))
+ return mklist(elementName(t), elementValue(t));
+ return cons(elementName(t), mklist(elementsToValues(elementValue(t))));
+ }
+ return cons(elementName(t), elementsToValues(elementChildren(t)));
+ }
+ if (!isList(t))
+ return t;
+ return elementsToValues(t);
+}
+
+/**
+ * Convert a list of elements to a list of values.
+ */
+function elementToValueIsSymbol(v) {
+ return (!(!isList(v)) || isNil(v) || !isSymbol(car(v)));
+}
+
+function elementToValueGroupValues(v, l) {
+ if (isNil(l) || !elementToValueIsSymbol(v) || !elementToValueIsSymbol(car(l)))
+ return cons(v, l);
+ if (car(car(l)) != car(v))
+ return cons(v, l);
+ if (!elementToValueIsList(cadr(car(l)))) {
+ var g = mklist(car(v), mklist(cdr(v), cdr(car(l))));
+ return elementToValueGroupValues(g, cdr(l));
+ }
+ var g = mklist(car(v), cons(cdr(v), cadr(car(l))));
+ return elementToValueGroupValues(g, cdr(l));
+}
+
+function elementsToValues(e) {
+ if (isNil(e))
+ return e;
+ return elementToValueGroupValues(elementToValue(car(e)), elementsToValues(cdr(e)));
+}
+
+/**
+ * Convert a value to an element.
+ */
+function valueToElement(t) {
+ if (isList(t) && !isNil(t) && isSymbol(car(t))) {
+ var n = car(t);
+ var v = isNil(cdr(t))? mklist() : cadr(t);
+ if (!isList(v)) {
+ if (n.substring(0, 2) == atsign)
+ return mklist(attribute, "'" + n.substring(2), v);
+ return mklist(element, n, v);
+ }
+ if (isNil(v) || !isSymbol(car(v)))
+ return cons(element, cons(n, mklist(valuesToElements(v))));
+ return cons(element, cons(n, valuesToElements(cdr(t))));
+ }
+ if (!isList(t))
+ return t;
+ return valuesToElements(t);
+}
+
+/**
+ * Convert a list of values to a list of elements.
+ */
+function valuesToElements(l) {
+ if (isNil(l))
+ return l;
+ return cons(valueToElement(car(l)), valuesToElements(cdr(l)));
+}
+
+/**
+ * Return a selector lambda function which can be used to filter elements.
+ */
+function selector(s) {
+ function evalSelect(s, v) {
+ if (isNil(s))
+ return true;
+ if (isNil(v))
+ return false;
+ if (car(s) != car(v))
+ return false;
+ return evalSelect(cdr(s), cdr(v));
+ }
+
+ return function(v) { return evalSelect(s, v); };
+}
+
+/**
+ * Return the attribute with the given name.
+ */
+function namedAttribute(name, l) {
+ return memo(l, name, function() {
+ var f = filter(function(v) { return isAttribute(v) && attributeName(v) == name; }, l);
+ if (isNil(f))
+ return null;
+ return car(f);
+ });
+}
+
+/**
+ * Return the value of the attribute with the given name.
+ */
+function namedAttributeValue(name, l) {
+ var a = namedAttribute(name, l);
+ if (a == null)
+ return null
+ return attributeValue(a);
+}
+
+/**
+ * Return child elements with the given name.
+ */
+function namedElementChildren(name, l) {
+ return memo(l, name, function() {
+ return filter(function(v) { return isElement(v) && elementName(v) == name; }, l);
+ });
+}
+
+/**
+ * Return the child element with the given name.
+ */
+function namedElementChild(name, l) {
+ var f = namedElementChildren(name, l);
+ if (isNil(f))
+ return null;
+ return car(f);
+}
+
+/**
+ * Side effect functions. Use with moderation.
+ */
+
+/**
+ * Set the contents of an element.
+ */
+function setElement(l, e) {
+ setlist(l, e);
+ l.memo = {};
+}
+
diff --git a/sca-cpp/branches/lightweight-sca/modules/js/htdocs/jsonutil.js b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/jsonutil.js
new file mode 100644
index 0000000000..8aa291bc89
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/jsonutil.js
@@ -0,0 +1,261 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * JSON data conversion functions.
+ */
+var json = {};
+
+/**
+ * JSON exceptions.
+ */
+json.Exception = function(code, message) {
+ this.name = "JSONException";
+ this.code = code;
+ this.message = message;
+};
+
+json.Exception.prototype = new Error();
+
+json.Exception.prototype.toString = function() {
+ return this.name + ": " + this.message;
+};
+
+/**
+ * Return true if a list represents a JS array.
+ */
+json.isJSArray = function(l) {
+ if (isNil(l))
+ return true;
+ var v = car(l);
+ if (isSymbol(v))
+ return false;
+ if (isList(v))
+ if (!isNil(v) && isSymbol(car(v)))
+ return false;
+ return true;
+};
+
+/**
+ * Converts JSON properties to values.
+ */
+json.jsPropertiesToValues = function(propertiesSoFar, o, i) {
+ if (isNil(i))
+ return propertiesSoFar;
+ var p = car(i);
+ var jsv = o[p];
+ var v = json.jsValToValue(jsv);
+
+ if (typeof p == 'string') {
+ var n = '' + p;
+ if (n.slice(0, 1) == '@')
+ return json.jsPropertiesToValues(cons(mklist(attribute, "'" + n.slice(1), v), propertiesSoFar), o, cdr(i));
+ if (isList(v) && !json.isJSArray(v))
+ return json.jsPropertiesToValues(cons(cons(element, cons("'" + n, v)), propertiesSoFar), o, cdr(i));
+ return json.jsPropertiesToValues(cons(mklist(element, "'" + n, v), propertiesSoFar), o, cdr(i));
+ }
+ return json.jsPropertiesToValues(cons(v, propertiesSoFar), o, cdr(i));
+};
+
+/**
+ * Converts a JSON val to a value.
+ */
+json.jsValToValue = function(jsv) {
+ if (jsv == null)
+ return null;
+ if (isList(jsv))
+ return json.jsPropertiesToValues(mklist(), jsv, reverse(range(0, jsv.length)));
+ if (typeof jsv == 'object')
+ return json.jsPropertiesToValues(mklist(), jsv, reverse(properties(jsv)));
+ if (typeof jsv == 'string')
+ return '' + jsv;
+ return jsv;
+}
+
+/**
+ * Return true if a list of strings contains a JSON document.
+ */
+json.isJSON = function(l) {
+ if (isNil(l))
+ return false;
+ var s = car(l).slice(0, 1);
+ return s == "[" || s == "{";
+};
+
+/**
+ * Convert a list of strings representing a JSON document to a list of values.
+ */
+json.readJSON = function(l) {
+ var s = writeStrings(l);
+ var obj;
+ eval('obj = { \"val\": ' + s + " }");
+ return json.jsValToValue(obj.val);
+};
+
+/**
+ * Convert a list of values to JSON array elements.
+ */
+json.valuesToJSElements = function(a, l, i) {
+ if (isNil(l))
+ return a;
+ var pv = json.valueToJSVal(car(l));
+ a[i] = pv
+ return json.valuesToJSElements(a, cdr(l), i + 1);
+};
+
+/**
+ * Convert a value to a JSON value.
+ */
+json.valueToJSVal = function(v) {
+ if (!isList(v))
+ return v;
+ if (json.isJSArray(v))
+ return json.valuesToJSElements(range(0, v.length), v, 0);
+ return json.valuesToJSProperties({}, v);
+};
+
+/**
+ * Convert a list of values to JSON properties.
+ */
+json.valuesToJSProperties = function(o, l) {
+ if (isNil(l))
+ return o;
+ var token = car(l);
+ if (isTaggedList(token, attribute)) {
+ var pv = json.valueToJSVal(attributeValue(token));
+ o['@' + attributeName(token).slice(1)] = pv;
+ } else if (isTaggedList(token, element)) {
+ if (elementHasValue(token)) {
+ var pv = json.valueToJSVal(elementValue(token));
+ o[elementName(token).slice(1)] = pv;
+ } else {
+ var child = {};
+ o[elementName(token).slice(1)] = child;
+ json.valuesToJSProperties(child, elementChildren(token));
+ }
+ }
+ return json.valuesToJSProperties(o, cdr(l));
+};
+
+/**
+ * Convert a list of values to a list of strings representing a JSON document.
+ */
+json.writeJSON = function(l) {
+ var jsv;
+ if (json.isJSArray(l))
+ jsv = json.valuesToJSElements(range(0, l.length), l, 0);
+ else
+ jsv = json.valuesToJSProperties({}, l);
+ var s = json.toJSON(jsv);
+ return mklist(s);
+}
+
+/**
+ * Convert a list + params to a JSON-RPC request.
+ */
+json.jsonRequest = function(id, func, params) {
+ var r = mklist(mklist("'id", id), mklist("'method", func), mklist("'params", params));
+ return json.writeJSON(valuesToElements(r));
+};
+
+/**
+ * Convert a value to a JSON-RPC result.
+ */
+json.jsonResult = function(id, val) {
+ return json.writeJSON(valuesToElements(mklist(mklist("'id", id), mklist("'result", val))));
+};
+
+/**
+ * Convert a JSON-RPC result to a value.
+ */
+json.jsonResultValue = function(s) {
+ var jsres = json.readJSON(s);
+ var res = elementsToValues(jsres);
+ var val = cadr(assoc("'result", res));
+ if (isList(val) && !json.isJSArray(val))
+ return mklist(val);
+ return val;
+};
+
+/**
+ * Escape a character.
+ */
+json.escapeJSONChar = function(c) {
+ if(c == "\"" || c == "\\") return "\\" + c;
+ if (c == "\b") return "\\b";
+ if (c == "\f") return "\\f";
+ if (c == "\n") return "\\n";
+ if (c == "\r") return "\\r";
+ if (c == "\t") return "\\t";
+ var hex = c.charCodeAt(0).toString(16);
+ if(hex.length == 1) return "\\u000" + hex;
+ if(hex.length == 2) return "\\u00" + hex;
+ if(hex.length == 3) return "\\u0" + hex;
+ return "\\u" + hex;
+};
+
+/**
+ * Encode a string into JSON format.
+ */
+json.escapeJSONString = function(s) {
+ // The following should suffice but Safari's regex is broken (doesn't support callback substitutions)
+ // return "\"" + s.replace(/([^\u0020-\u007f]|[\\\"])/g, json.escapeJSONChar) + "\"";
+
+ // Rather inefficient way to do it
+ var parts = s.split("");
+ for(var i = 0; i < parts.length; i++) {
+ var c = parts[i];
+ if(c == '"' || c == '\\' || c.charCodeAt(0) < 32 || c.charCodeAt(0) >= 128)
+ parts[i] = json.escapeJSONChar(parts[i]);
+ }
+ return "\"" + parts.join("") + "\"";
+};
+
+/**
+ * Marshall objects to JSON format.
+ */
+json.toJSON = function(o) {
+ if(o == null)
+ return "null";
+ if(o.constructor == String)
+ return json.escapeJSONString(o);
+ if(o.constructor == Number)
+ return o.toString();
+ if(o.constructor == Boolean)
+ return o.toString();
+ if(o.constructor == Date)
+ return '{javaClass: "java.util.Date", time: ' + o.valueOf() +'}';
+ if(o.constructor == Array) {
+ var v = [];
+ for(var i = 0; i < o.length; i++)
+ v.push(json.toJSON(o[i]));
+ return "[" + v.join(", ") + "]";
+ }
+ var v = [];
+ for(attr in o) {
+ if(o[attr] == null)
+ v.push("\"" + attr + "\": null");
+ else if(typeof o[attr] == "function")
+ ; // Skip
+ else
+ v.push(json.escapeJSONString(attr) + ": " + json.toJSON(o[attr]));
+ }
+ return "{" + v.join(", ") + "}";
+};
+
diff --git a/sca-cpp/branches/lightweight-sca/modules/js/htdocs/scdl.js b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/scdl.js
new file mode 100644
index 0000000000..50dab53e7c
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/scdl.js
@@ -0,0 +1,250 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * SCDL parsing functions.
+ */
+var scdl = {};
+
+/**
+ * Returns a composite element.
+ */
+scdl.composite = function(l) {
+ var cs = namedElementChildren("'composite", l);
+ if (isNil(cs))
+ return cs;
+ return car(cs);
+};
+
+/**
+ * Returns a list of components in a composite.
+ */
+scdl.components = function(l) {
+ var cs = namedElementChildren("'composite", l);
+ if (isNil(cs))
+ return cs;
+ return namedElementChildren("'component", car(cs));
+};
+
+/**
+ * Returns a list of service promotions in a composite.
+ */
+scdl.promotions = function(l) {
+ var cs = namedElementChildren("'composite", l);
+ if (isNil(cs))
+ return cs;
+ return namedElementChildren("'service", car(cs));
+};
+
+/**
+ * Returns the target of a service promotion.
+ */
+scdl.promote = function(l) {
+ var puri = namedAttributeValue("'promote", l);
+ if (isNil(puri))
+ return puri;
+ return car(tokens(puri));
+};
+
+/**
+ * Returns the name of a component, componentType, service or reference.
+ */
+scdl.name = function(l) {
+ return namedAttributeValue("'name", l);
+};
+
+/**
+ * Returns the description of a component, componentType, service or reference.
+ */
+scdl.documentation = function(l) {
+ var d = namedElementChildren("'documentation", l);
+ if (isNil(d))
+ return null;
+ if (!elementHasValue(car(d)))
+ return null;
+ var v = elementValue(car(d));
+ return v;
+};
+
+/**
+ * Returns the title of a component or componentType.
+ */
+scdl.title = function(l) {
+ return namedAttributeValue("'title", l);
+};
+
+/**
+ * Returns the display style of a component, componentType, reference or property.
+ */
+scdl.style = function(l) {
+ return namedAttributeValue("'style", l);
+};
+
+/**
+ * Returns the color of a component or componentType.
+ */
+scdl.color = function(l) {
+ return namedAttributeValue("'color", l);
+};
+
+/**
+ * Returns the x position of a component.
+ */
+scdl.x = function(l) {
+ return namedAttributeValue("'x", l);
+};
+
+/**
+ * Returns the y position of a component.
+ */
+scdl.y = function(l) {
+ return namedAttributeValue("'y", l);
+};
+
+/**
+ * Returns the implementation of a component.
+ */
+scdl.implementation = function(l) {
+ function filterImplementation(v) {
+ return isElement(v) && cadr(v).match("implementation.") != null;
+ }
+
+ var n = filter(filterImplementation, l);
+ if (isNil(n))
+ return null;
+ return car(n);
+};
+
+/**
+ * Returns the type of a component or componentType implementation.
+ */
+scdl.implementationType = function(l) {
+ return elementName(l).substring(1);
+};
+
+/**
+ * Returns the URI of a service, reference or implementation.
+ */
+scdl.uri = function(l) {
+ return namedAttributeValue("'uri", l);
+};
+
+/**
+ * Returns the align attribute of a service or reference.
+ */
+scdl.align = function(l) {
+ return namedAttributeValue("'align", l);
+};
+
+/**
+ * Returns the visible attribute of a service or reference.
+ */
+scdl.visible = function(l) {
+ return namedAttributeValue("'visible", l);
+};
+
+/**
+ * Returns the clonable attribute of a reference.
+ */
+scdl.clonable = function(l) {
+ return namedAttributeValue("'clonable", l);
+};
+
+/**
+ * Returns a list of services in a component or componentType.
+ */
+scdl.services = function(l) {
+ return namedElementChildren("'service", l);
+};
+
+/**
+ * Returns a list of references in a component or componentType.
+ */
+scdl.references = function(l) {
+ return namedElementChildren("'reference", l);
+};
+
+/**
+ * Returns a list of bindings in a service or reference.
+ */
+scdl.bindings = function(l) {
+ function filterBinding(v) {
+ return isElement(v) && cadr(v).match("binding.") != null;
+ }
+
+ return filter(filterBinding, l);
+};
+
+/**
+ * Returns the type of a binding.
+ */
+scdl.bindingType = function(l) {
+ return elementName(l).substring(1);
+};
+
+/**
+ * Returns the target of a reference.
+ */
+scdl.target = function(l) {
+ function targetURI() {
+ function bindingsTarget(l) {
+ if (isNil(l))
+ return null;
+ var u = scdl.uri(car(l));
+ if (!isNil(u))
+ return u;
+ return bindingsTarget(cdr(l));
+ }
+
+ var t = namedAttributeValue("'target", l);
+ if (!isNil(t))
+ return t;
+ return bindingsTarget(scdl.bindings(l));
+ }
+ var turi = targetURI();
+ if (isNil(turi))
+ return turi;
+ return car(tokens(turi));
+};
+
+/**
+ * Returns a list of properties in a component or componentType.
+ */
+scdl.properties = function(l) {
+ return namedElementChildren("'property", l);
+};
+
+/**
+ * Returns the value of a property.
+ */
+scdl.propertyValue = function(l) {
+ if (!elementHasValue(l))
+ return '';
+ return elementValue(l);
+};
+
+/**
+ * Convert a list of elements to a name -> element assoc list.
+ */
+scdl.nameToElementAssoc = function(l) {
+ if (isNil(l))
+ return l;
+ return cons(mklist(scdl.name(car(l)), car(l)), scdl.nameToElementAssoc(cdr(l)));
+};
+
diff --git a/sca-cpp/branches/lightweight-sca/modules/js/htdocs/ui.css b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/ui.css
new file mode 100644
index 0000000000..ddc21b2095
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/ui.css
@@ -0,0 +1,709 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+body {
+margin-top: 0px; margin-bottom: 2px; margin-left: 2px; margin-right: 2px;
+font-family: Arial; font-style: normal; font-variant: normal; font-size: 14px;
+background-color: #ffffff; opacity: 1;
+-webkit-text-size-adjust: none;
+-webkit-touch-callout: none;
+-webkit-tap-highlight-color: rgba(0,0,0,0);
+-webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none;
+cursor: default;
+-webkit-backface-visibility: hidden;
+}
+
+.delayed {
+visibility: hidden;
+}
+
+.fixed {
+position: fixed;
+}
+
+.devicewidth {
+position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: hidden;
+}
+
+.mainbody {
+position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: visible;
+-webkit-backface-visibility: hidden;
+}
+
+.viewcontainer3dm {
+position: absolute; left: 0px; top: 35px; width: 100%;
+-webkit-backface-visibility: hidden;
+}
+
+.viewcontainer3d {
+position: absolute; left: 0px; top: 35px; width: 100%;
+-webkit-backface-visibility: hidden;
+}
+
+.leftviewloading3dm {
+position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: hidden;
+z-index: -10; background-color: #ffffff;
+-webkit-transform: translate(100%, 0px);
+-moz-transform: translate(100%, 0px);
+-ms-transform: translate(100%, 0px);
+-o-transform: translate(100%, 0px);
+transform: translate(100%, 0px);
+-webkit-backface-visibility: hidden;
+}
+
+.rightviewloading3dm {
+position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: hidden;
+z-index: -10; background-color: #ffffff;
+-webkit-transform: translate(-100%, 0px);
+-moz-transform: translate(-100%, 0px);
+-ms-transform: translate(-100%, 0px);
+-o-transform: translate(-100%, 0px);
+transform: translate(-100%, 0px);
+-webkit-backface-visibility: hidden;
+}
+
+.viewloading3d {
+position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: hidden;
+visibility: hidden; z-index: -10; background-color: #ffffff;
+-webkit-transform: translate(100%, 0px);
+-moz-transform: translate(100%, 0px);
+-ms-transform: translate(100%, 0px);
+-o-transform: translate(100%, 0px);
+transform: translate(100%, 0px);
+-webkit-backface-visibility: hidden;
+}
+
+.viewloaded3dm {
+position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: visible;
+z-index: 0; background-color: #ffffff;
+-webkit-transition: -webkit-transform 0.4s ease-in-out;
+-moz-transition: -moz-transform 0.4s ease-in-out;
+-ms-transition: -ms-transform 0.4s ease-in-out;
+-o-transition: -o-transform 0.4s ease-in-out;
+transition: transform 0.4s ease-in-out;
+-webkit-transform: translate(0px, 0px);
+-moz-transform: translate(0px, 0px);
+-ms-transform: translate(0px, 0px);
+-o-transform: translate(0px, 0px);
+transform: translate(0px, 0px);
+-webkit-backface-visibility: hidden;
+}
+
+.viewloaded3d {
+position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: visible;
+z-index: 0; background-color: #ffffff;
+-webkit-transform: translate(0px, 0px);
+-moz-transform: translate(0px, 0px);
+-ms-transform: translate(0px, 0px);
+-o-transform: translate(0px, 0px);
+transform: translate(0px, 0px);
+-webkit-backface-visibility: hidden;
+}
+
+.viewunloading3dm {
+position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: hidden;
+z-index: 0; background-color: #ffffff;
+-webkit-transform: translate(0px, 0px);
+-moz-transform: translate(0px, 0px);
+-ms-transform: translate(0px, 0px);
+-o-transform: translate(0px, 0px);
+transform: translate(0px, 0px);
+-webkit-backface-visibility: hidden;
+}
+
+.leftviewunloaded3dm {
+position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: hidden;
+z-index: -10; background-color: #ffffff;
+-webkit-transition: -webkit-transform 0.4s ease-in-out;
+-moz-transition: -moz-transform 0.4s ease-in-out;
+-ms-transition: -ms-transform 0.4s ease-in-out;
+-o-transition: -o-transform 0.4s ease-in-out;
+transition: transform 0.4s ease-in-out;
+-webkit-transform: translate(-100%, 0px);
+-moz-transform: translate(-100%, 0px);
+-ms-transform: translate(-100%, 0px);
+-o-transform: translate(-100%, 0px);
+transform: translate(-100%, 0px);
+-webkit-backface-visibility: hidden;
+}
+
+.rightviewunloaded3dm {
+position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: hidden;
+z-index: -10; background-color: #ffffff;
+-webkit-transition: -webkit-transform 0.4s ease-in-out;
+-moz-transition: -moz-transform 0.4s ease-in-out;
+-ms-transition: -ms-transform 0.4s ease-in-out;
+-o-transition: -o-transform 0.4s ease-in-out;
+transition: transform 0.4s ease-in-out;
+-webkit-transform: translate(100%, 0px);
+-moz-transform: translate(100%, 0px);
+-ms-transform: translate(100%, 0px);
+-o-transform: translate(100%, 0px);
+transform: translate(100%, 0px);
+-webkit-backface-visibility: hidden;
+}
+
+.body {
+width: 100%; height: 5000px; overflow: visible;
+-webkit-backface-visibility: hidden;
+}
+
+.viewhead {
+position: absolute; left: 0px; top: 35px; height: 35px; line-height: 35px; width: 100%; z-index: 8;
+font-size: 110%; font-weight: bold; background-color: #f1f1f1; color: #000000;
+border-top: 1px; border-bottom: 1px; border-left: 0px; border-right: 0px;
+border-style: solid; border-top-color: #e5e5e5; border-bottom-color: #e5e5e5;
+overflow: hidden;
+-webkit-backface-visibility: hidden;
+}
+
+.viewheadbackground {
+position: absolute; left: 0px; top: 35px; height: 35px; line-height: 35px; width: 2500px; z-index: 7;
+background-color: #f1f1f1;
+border-top: 1px; border-bottom: 1px; border-left: 0px; border-right: 0px;
+border-style: solid; border-top-color: #e5e5e5; border-bottom-color: #e5e5e5;
+overflow: hidden;
+-webkit-backface-visibility: hidden;
+}
+
+.viewfoot {
+position: absolute; left: 0px; bottom: 0px; height: 25px; line-height: 25px; width: 100%; z-index: 8;
+font-size: 12px; background-color: #ffffff; color: #404040;
+border-top: 1px; border-bottom: 1px; border-left: 0px; border-right: 0px;
+border-style: solid; border-top-color: #e5e5e5; border-bottom-color: #ffffff;
+overflow: hidden;
+-webkit-backface-visibility: hidden;
+}
+
+.status {
+position: absolute; left: 0px; bottom: 0px; height: 35px; line-height: 35px; width: 100%; z-index: 9;
+font-size: 12px; background-color: #ffffff; color: #404040;
+border-top: 0px; border-bottom: 0px; border-left: 0px; border-right: 0px;
+border-style: solid; border-top-color: #e5e5e5; border-bottom-color: #ffffff;
+overflow: hidden;
+-webkit-transform: translate(0px, 0px);
+-moz-transform: translate(0px, 0px);
+-ms-transform: translate(0px, 0px);
+-o-transform: translate(0px, 0px);
+transform: translate(0px, 0px);
+-webkit-backface-visibility: hidden;
+}
+
+.statusout3 {
+position: absolute; left: 0px; bottom: 0px; height: 35px; line-height: 35px; width: 100%; z-index: 9;
+font-size: 12px; background-color: #ffffff; color: #404040;
+border-top: 0px; border-bottom: 0px; border-left: 0px; border-right: 0px;
+border-style: solid; border-top-color: #e5e5e5; border-bottom-color: #ffffff;
+overflow: hidden;
+-webkit-transition: -webkit-transform 0.4s ease-in-out 3s;
+-moz-transition: -moz-transform 0.4s ease-in-out 3s;
+-ms-transition: -ms-transform 0.4s ease-in-out 3s;
+-o-transition: -o-transform 0.4s ease-in-out 3s;
+transition: transform 0.4s ease-in-out 3s;
+-webkit-transform: translate(0px, 35px);
+-moz-transform: translate(0px, 35px);
+-ms-transform: translate(0px, 35px);
+-o-transform: translate(0px, 35px);
+transform: translate(0px, 35px);
+-webkit-backface-visibility: hidden;
+}
+
+.statusout1 {
+position: absolute; left: 0px; bottom: 0px; height: 35px; line-height: 35px; width: 100%; z-index: 9;
+font-size: 12px; background-color: #ffffff; color: #404040;
+border-top: 0px; border-bottom: 0px; border-left: 0px; border-right: 0px;
+border-style: solid; border-top-color: #e5e5e5; border-bottom-color: #ffffff;
+overflow: hidden;
+-webkit-transition: -webkit-transform 0.4s ease-in-out 1s;
+-moz-transition: -moz-transform 0.4s ease-in-out 1s;
+-ms-transition: -ms-transform 0.4s ease-in-out 1s;
+-o-transition: -o-transform 0.4s ease-in-out 1s;
+transition: transform 0.4s ease-in-out 1s;
+-webkit-transform: translate(0px, 35px);
+-moz-transform: translate(0px, 35px);
+-ms-transform: translate(0px, 35px);
+-o-transform: translate(0px, 35px);
+transform: translate(0px, 35px);
+-webkit-backface-visibility: hidden;
+}
+
+.okstatus {
+font-size: 110%; font-weight: bold; padding-left: 6px; padding-right: 6px; white-space: nowrap; text-decoration: none;
+background-color: #f1f1f1; color: #000000;
+width: 100%; margin-left: auto; margin-right: auto; text-align: center; float: right;
+}
+
+.errorstatus {
+font-size: 110%; font-weight: bold; padding-left: 6px; padding-right: 6px; white-space: nowrap; text-decoration: none;
+background-color: #d14836; color: #ffffff;
+width: 100%; margin-left: auto; margin-right: auto; text-align: center; float: right;
+}
+
+.viewfootbackground {
+position: absolute; left: 0px; bottom: 0px; height: 25px; line-height: 25px; width: 2500px; z-index: 7;
+background-color: #ffffff;
+border-top: 1px; border-bottom: 1px; border-left: 0px; border-right: 0px;
+border-style: solid; border-top-color: #e5e5e5; border-bottom-color: #ffffff;
+overflow: hidden;
+-webkit-backface-visibility: hidden;
+}
+
+.viewcontent {
+position: absolute; left: 0px; top: 38px; width: 100%;
+-webkit-backface-visibility: hidden;
+}
+
+.viewform {
+position: absolute; left: 0px; top: 40px; width: 100%;
+}
+
+table {
+border: 0px; border-collapse: collapse; border-color: #a2bae7; border-style: solid;
+font-family: Arial; font-style: normal; font-variant: normal; font-size: 14px;
+overflow: visible;
+}
+
+.trb {
+border-bottom: 1px; border-bottom-style: solid; border-color: #dcdcdc;
+}
+
+th {
+font-size: 110%; font-weight: bold; background-color: #f1f1f1; color: #000000;
+text-align: left; padding-left: 2px; padding-right: 8px; padding-top: 0px; padding-bottom: 0px; vertical-align: middle; white-space: nowrap;
+border-top: 1px; border-bottom: 1px; border-left: 1px; border-right: 1px; border-style: solid; border-top-color: #e5e5e5; border-bottom-color: #e5e5e5; border-left-color: #e5e5e5; border-right-color: #e5e5e5;
+overflow: hidden;
+}
+
+.section {
+font-size: 110%; font-weight: bold; background-color: #f1f1f1; color: #000000; height: 30px; line-height: 30px;
+text-align: left; padding-top: 0px; padding-bottom: 0px; padding-left: 2px; padding-right: 2px; white-space: nowrap;
+border-top: 1px; border-bottom: 1px; border-left: 0px; border-right: 0px; border-style: solid; border-top-color: #e5e5e5; border-bottom-color: #e5e5e5; border-left-color: #e5e5e5; border-right-color: #e5e5e5;
+overflow: hidden;
+}
+
+.hsection {
+width: 100%; height: 0px; visibility: hidden;
+border-top: 0px; border-bottom: 0px; border-left: 0px; border-right: 0px; border-style: solid; border-bottom-color: #000000; background-color: #ffffff;
+padding-left: 2px; padding-right: 2px; padding-top: 0px; padding-bottom: 0px; margin-bottom: 0px; margin-left: auto; margin-right: auto; text-align: center;
+}
+
+.fsection{
+width: 100%; height: 0px; visibility: hidden;
+border-top: 0px; border-bottom: 0px; border-left: 0px; border-right: 0px; border-style: solid; border-top-color: #a2bae7;
+padding: 0px; margin-top: 0px; margin-left: auto; margin-right: auto; text-align: center;
+}
+
+.bluetext {
+color: #4787ed;
+}
+
+.redtext {
+color: #d14836;
+}
+
+.mirror {
+display: inline-block;
+-webkit-transform: scaleX(-1);
+-moz-transform: scaleX(-1);
+-ms-transform: scaleX(-1);
+-o-transform: scaleX(-1);
+transform: scaleX(-1);
+}
+
+.greentext {
+color: #009900;
+}
+
+.text {
+padding-top: 3px; padding-bottom: 4px; vertical-align: middle; white-space: nowrap;
+}
+
+.link {
+padding-top: 3px; padding-bottom: 4px; vertical-align: middle; white-space: nowrap;
+}
+
+.checkbox {
+padding-top: 3px; padding-bottom: 4px; vertical-align: middle; white-space: nowrap;
+}
+
+.thl {
+border-left: 0px;
+}
+
+.thr {
+border-right: 0px;
+}
+
+.ths {
+padding: 0px;
+}
+
+td {
+padding-left: 2px; padding-top: 2px; padding-right: 8px; white-space: nowrap; vertical-align: middle; border: 0px;
+}
+
+.tdl {
+border-right: 1px; border-style: solid; border-color: #a2bae7; width: 10px;
+}
+
+.tdr {
+border-left: 1px; border-style: solid; border-color: #a2bae7;
+}
+
+.tdw {
+padding-left: 2px; padding-top: 2px; padding-right: 8px; white-space: normal; vertical-align: middle;
+}
+
+.datatd {
+border-top: 1px; border-bottom: 1px; border-style: solid; border-color: #dcdcdc; width: 10px; vertical-align: middle;
+}
+
+.datatdl {
+border-right: 1px; border-top: 1px; border-bottom: 1px; border-style: solid; border-color: #dcdcdc; width: 10px; vertical-align: middle;
+}
+
+.datatdltop {
+border-right: 1px; border-top: 1px; border-bottom: 1px; border-style: solid; border-color: #dcdcdc; width: 10px; vertical-align: top;
+}
+
+.datatdr {
+border-left: 1px; border-top: 1px; border-bottom: 1px; border-style: solid; border-color: #dcdcdc; vertical-align: middle;
+}
+
+.datatable {
+border-top: 1px; border-bottom: 1px; border-style: solid; border-color: #dcdcdc;
+overflow: visible;
+}
+
+.databg {
+opacity: .6;
+-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)";
+filter: alpha(opacity=60);
+}
+
+.guide {
+border: 1px; border-style: solid; border-color: #c0c0c0;
+}
+
+iframe {
+border: 0px; margin: 0px; padding: 0px;
+}
+
+.fakeframe {
+padding: 3px; background-color: #dcdcdc; color: #000000;
+}
+
+input {
+vertical-align: middle;
+font-family: Arial; font-style: normal; font-variant: normal; font-size: 15px;
+outline: none;
+-webkit-text-size-adjust: 100%;
+}
+
+button {
+vertical-align: middle;
+font-family: Arial; font-style: normal; font-variant: normal; font-size: 15px;
+outline: none;
+-webkit-text-size-adjust: 100%;
+}
+
+textarea {
+font-family: Arial; font-style: normal; font-variant: normal; font-size: 15px;
+outline: none;
+overflow: auto; resize: none;
+}
+
+.flatentry {
+font-family: Arial; font-style: normal; font-variant: normal; font-size: 15px;
+-webkit-appearance: none; appearance: none;
+border: 1px solid #d9d9d9!important; border-top: 1px solid silver!important;
+box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box;
+border-radius: 1px; -webkit-border-radius: 1px; -moz-border-radius: 1px;
+margin: 1px!important; padding: 3px 1px 3px 3px;
+}
+
+.graphentry {
+font-family: Arial; font-style: normal; font-variant: normal; font-size: 13px;
+-webkit-appearance: none; appearance: none;
+border: 1px solid #d9d9d9!important; border-top: 1px solid silver!important;
+box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box;
+border-radius: 1px; -webkit-border-radius: 1px; -moz-border-radius: 1px;
+margin: 0px; padding: 0px;
+}
+
+.flatcheckbox {
+}
+
+.editablewidget {
+-webkit-user-select: text; -moz-user-select: text; -ms-user-select: text; user-select: text;
+outline: none; -moz-outline-style: none;
+}
+
+.noneditablewidget {
+outline: none; -moz-outline-style: none;
+}
+
+.editablesvg {
+background-color: transparent;
+font-family: inherit; font-style: inherit; font-variant: inherit; font-size: inherit; font-weight: inherit;
+padding: 0px; margin: 0px;
+overflow: auto; resize: none;
+outline: none; -moz-outline-style: none;
+-webkit-appearance: none; -webkit-text-size-adjust: 100%;
+border: 0px;
+}
+
+a:link {
+color: #357ae8; text-decoration: none; white-space: nowrap; cursor: pointer;
+}
+
+a:visited {
+color: #357ae8; text-decoration: none; white-space: nowrap; cursor: pointer;
+}
+
+.tbarmenu {
+position: absolute; top: 0px; left: 0px; z-index: 10; width: 100%; margin: 0px; padding: 0px; border-collapse: separate;
+height: 35px; line-height: 35px; background-color: #2c2c2c;
+border-top: 1px; border-bottom: 1px; border-left: 0px; border-right: 0px; border-style: solid; border-top-color: #2c2c2c; border-bottom-color: #2c2c2c;
+-webkit-backface-visibility: hidden;
+}
+
+.tbarbackground {
+position: absolute; top: 0px; left: 0px; z-index: 9; width: 2500px; margin: 0px; padding: 0px; border-collapse: separate;
+height: 35px; line-height: 35px; background-color: #2c2c2c;
+border-top: 1px; border-bottom: 1px; border-left: 0px; border-right: 0px; border-style: solid; border-top-color: #2c2c2c; border-bottom-color: #2c2c2c;
+overflow: hidden;
+-webkit-backface-visibility: hidden;
+}
+
+.tbarleft {
+padding-left: 2px; padding-right: 6px; white-space: nowrap; float: left;
+}
+
+.tbarright {
+padding-left: 6px; padding-right: 2px; white-space: nowrap; float: right;
+}
+
+.tbaramenu {
+font-size: 110%; color: #cccccc; text-decoration: none; white-space: nowrap;
+}
+
+.tbarsmenu {
+font-size: 110%; font-weight: bold; color: #ffffff; text-decoration: none; white-space: nowrap;
+}
+
+.amenu {
+padding-left: 2px; padding-right: 6px; white-space: nowrap; color: #808080; text-decoration: none; float: left;
+}
+
+.smenu {
+padding-left: 2px; padding-right: 6px; white-space: nowrap; color: #000000; text-decoration: none; float: left;
+}
+
+.cmenu {
+font-size: 18px; padding-left: 6px; padding-right: 6px; white-space: nowrap; color: #000000; text-decoration: none;
+width: 100%; margin-left: auto; margin-right: auto; text-align: center; float: right;
+}
+
+.bcmenu {
+font-size: 22px; padding-left: 2px; padding-right: 6px; white-space: nowrap; color: #000000; text-decoration: none;
+}
+
+.rmenu {
+padding-left: 2px; padding-right: 2px; white-space: nowrap; white-space: nowrap; float: right;
+}
+
+h1 {
+font-size: 150%; font-weight: bold; vertical-align: middle; margin-top: 5px; margin-bottom: 5px; margin-left: 2px; margin-right: 2px; white-space: nowrap;
+}
+
+h2 {
+font-size: 120%; font-weight: bold; vertical-align: middle; margin-top: 5px; margin-bottom: 5px; margin-left: 2px; margin-right: 2px; white-space: nowrap;
+}
+
+.hd1 {
+font-size: 150%; font-weight: bold; white-space: nowrap;
+}
+
+.hd2 {
+font-size: 120%; font-weight: bold; white-space: nowrap;
+}
+
+img {
+border: 0px;
+}
+
+.plusminus {
+font-size: 18px; font-family: "Courier New";
+}
+
+.imgbutton {
+width: 142px; height: 64px; margin-left: 20px; margin-right: 20px; padding: 0px; border: 1px; cursor: pointer;
+}
+
+.graybutton {
+display: inline-block; text-align: center; color: #444; font-weight: bold;
+padding-top: 0px; padding-bottom: 0px; padding-left: 4px; padding-right: 4px;
+height: 28px; line-height: 28px; min-width: 30px;
+-webkit-border-radius: 2px; -moz-border-radius: 2px; border-radius: 2px;
+border: 1px solid gainsboro; background-color: whiteSmoke;
+background-image: -webkit-gradient(linear,left top,left bottom,from(whiteSmoke),to(#f1f1f1));
+background-image: -webkit-linear-gradient(top,whiteSmoke,#f1f1f1);
+background-image: -moz-linear-gradient(top,whiteSmoke,#f1f1f1);
+background-image: -ms-linear-gradient(top,whiteSmoke,#f1f1f1);
+background-image: -o-linear-gradient(top,whiteSmoke,#f1f1f1);
+background-image: linear-gradient(top,whiteSmoke,#f1f1f1);
+cursor: default;
+}
+
+.graybutton:hover {
+border: 1px solid #c6c6c6; color: #333; text-shadow: 0 1px rgba(0, 0, 0, 0.3); background-color: #f8f8f8;
+background-image: -webkit-gradient(linear,left top,left bottom,from(#f8f8f8),to(#f1f1f1));
+background-image: -webkit-linear-gradient(top,#f8f8f8,#f1f1f1);
+background-image: -moz-linear-gradient(top,#f8f8f8,#f1f1f1);
+background-image: -ms-linear-gradient(top,#f8f8f8,#f1f1f1);
+background-image: -o-linear-gradient(top,#f8f8f8,#f1f1f1);
+background-image: linear-gradient(top,#f8f8f8,#f1f1f1);
+}
+
+.graybutton:active {
+background-color: #f6f6f6;
+background-image: -webkit-gradient(linear,left top,left bottom,from(#f6f6f6),to(#f1f1f1));
+background-image: -webkit-linear-gradient(top,#f6f6f6,#f1f1f1);
+background-image: -moz-linear-gradient(top,#f6f6f6,#f1f1f1);
+background-image: -ms-linear-gradient(top,#f6f6f6,#f1f1f1);
+background-image: -o-linear-gradient(top,#f6f6f6,#f1f1f1);
+background-image: linear-gradient(top,#f6f6f6,#f1f1f1);
+-webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
+}
+
+.graybutton:disabled {
+color: #c0c0c0;
+}
+
+.bluebutton {
+border: 1px solid #3079ed; color: white; text-shadow: 0 1px rgba(0, 0, 0, 0.1); background-color: #4d90fe;
+background-image: -webkit-gradient(linear,left top,left bottom,from(#4d90fe),to(#4787ed));
+background-image: -webkit-linear-gradient(top,#4d90fe,#4787ed);
+background-image: -moz-linear-gradient(top,#4d90fe,#4787ed);
+background-image: -ms-linear-gradient(top,#4d90fe,#4787ed);
+background-image: -o-linear-gradient(top,#4d90fe,#4787ed);
+background-image: linear-gradient(top,#4d90fe,#4787ed);
+}
+
+.bluebutton:disabled {
+color: #c0c0c0;
+}
+
+.bluebutton:hover {
+border: 1px solid #2f5bb7; color: white; text-shadow: 0 1px rgba(0, 0, 0, 0.3); background-color: #357ae8;
+background-image: -webkit-gradient(linear,left top,left bottom,from(#4d90fe),to(#357ae8));
+background-image: -webkit-linear-gradient(top,#4d90fe,#357ae8);
+background-image: -moz-linear-gradient(top,#4d90fe,#357ae8);
+background-image: -ms-linear-gradient(top,#4d90fe,#357ae8);
+background-image: -o-linear-gradient(top,#4d90fe,#357ae8);
+background-image: linear-gradient(top,#4d90fe,#357ae8);
+}
+
+.bluebutton:hover:disabled {
+color: #c0c0c0;
+}
+
+.redbutton {
+border: 1px solid transparent; color: white; text-shadow: 0 1px rgba(0, 0, 0, 0.1); background-color: #d14836;
+background-image: -webkit-gradient(linear,left top,left bottom,from(#dd4b39),to(#d14836));
+background-image: -webkit-linear-gradient(top,#dd4b39,#d14836);
+background-image: -moz-linear-gradient(top,#dd4b39,#d14836);
+background-image: -ms-linear-gradient(top,#dd4b39,#d14836);
+background-image: -o-linear-gradient(top,#dd4b39,#d14836);
+background-image: linear-gradient(top,#dd4b39,#d14836);
+-webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.3); -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.3); -ms-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.3);
+-o-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.3); box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.3);
+}
+
+.redbutton:disabled {
+color: #c0c0c0;
+}
+
+.redbutton:hover {
+border: 1px solid #b0281a; border-bottom-color: #af301f; color: white; background-color: #c53727;
+background-image: -webkit-linear-gradient(top,#dd4b39,#c53727);
+background-image: -moz-linear-gradient(top,#dd4b39,#c53727);
+background-image: -ms-linear-gradient(top,#dd4b39,#c53727);
+background-image: -o-linear-gradient(top,#dd4b39,#c53727);
+background-image: linear-gradient(top,#dd4b39,#c53727);
+-webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); -ms-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
+-o-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
+}
+
+.redbutton:hover:disabled {
+color: #c0c0c0;
+}
+
+.box {
+width: 150px; display: inline-block;
+border: 1px; border-style: solid; border-color: #dcdcdc; border-collapse: collapse;
+white-space: nowrap; margin: 2px; padding: 2px; vertical-align: top;
+}
+
+.appicon {
+float: left;
+height: 50px; width: 50px; vertical-align: top; margin: 0px; padding: 0px;
+}
+
+.apptitle {
+font-weight: bold;
+}
+
+.note {
+font-size: 12px; color: #808080;
+}
+
+.pagediv {
+position: absolute; display: block; overflow: visible;
+-webkit-backface-visibility: hidden;
+}
+
+.graphdiv {
+position: absolute; display: block; overflow: visible;
+-webkit-backface-visibility: hidden;
+}
+
+.g {
+position: absolute; display: block; overflow: visible;
+-webkit-backface-visibility: hidden;
+}
+
+.path {
+position: absolute; background: transparent; display: block; overflow: visible;
+visibility: visible;
+-webkit-backface-visibility: hidden;
+}
+
+.gtitle {
+position: absolute;
+margin: 4px; padding: 0px; line-height: 15px; vertical-align: middle; white-space: nowrap;
+font-family: Arial; font-style: normal; font-variant: normal; font-size: 13px; cursor: default;
+background: transparent; display: block; overflow: visible;
+-webkit-text-size-adjust: none;
+-webkit-touch-callout: none;
+-webkit-tap-highlight-color: rgba(0,0,0,0);
+-webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none;
+}
+
diff --git a/sca-cpp/branches/lightweight-sca/modules/js/htdocs/ui.js b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/ui.js
new file mode 100644
index 0000000000..fb53598390
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/ui.js
@@ -0,0 +1,409 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * UI utility functions.
+ */
+
+var ui = {};
+
+/**
+ * Return a child element of a node with the given id.
+ */
+ui.elementByID = function(node, id) {
+ if (node.skipNode == true)
+ return null;
+ for (var i in node.childNodes) {
+ var child = node.childNodes[i];
+ if (child.id == id)
+ return child;
+ var gchild = ui.elementByID(child, id);
+ if (gchild != null)
+ return gchild;
+ }
+ return null;
+};
+
+/**
+ * Return the current document, or a child element with the given id.
+ */
+function $(id) {
+ if (id == document)
+ return document;
+ return ui.elementByID($(document), id);
+};
+
+/**
+ * Return a list of elements with the given class name.
+ */
+ui.elementsByClassName = function(node, c) {
+ return nodeList(node.getElementsByClassName(c));
+};
+
+/**
+ * Return the query string of a URL.
+ */
+ui.query = function(url) {
+ var u = '' + url;
+ var q = u.indexOf('?');
+ return q >= 0? u.substring(q + 1) : '';
+};
+
+/**
+ * Return the fragment part of a URL.
+ */
+ui.fragment = function(url) {
+ var u = '' + url;
+ var h = u.indexOf('#');
+ return h >= 0? u.substring(h + 1) : '';
+};
+
+/**
+ * Return the path and parameters of a URL.
+ */
+ui.pathandparams = function(url) {
+ var u = '' + url;
+ var ds = u.indexOf('//');
+ var u2 = ds > 0? u.substring(ds + 2) : u;
+ var s = u2.indexOf('/');
+ return s > 0? u2.substring(s) : '';
+};
+
+/**
+ * Return a dictionary of query parameters in a URL.
+ */
+ui.queryParams = function(url) {
+ var qp = new Array();
+ var qs = ui.query(url).split('&');
+ for (var i = 0; i < qs.length; i++) {
+ var e = qs[i].indexOf('=');
+ if (e > 0)
+ qp[qs[i].substring(0, e)] = unescape(qs[i].substring(e + 1));
+ }
+ return qp;
+};
+
+/**
+ * Return a dictionary of fragment parameters in a URL.
+ */
+ui.fragmentParams = function(url) {
+ var qp = new Array();
+ var qs = ui.fragment(url).split('&');
+ for (var i = 0; i < qs.length; i++) {
+ var e = qs[i].indexOf('=');
+ if (e > 0)
+ qp[qs[i].substring(0, e)] = unescape(qs[i].substring(e + 1));
+ }
+ return qp;
+};
+
+/**
+ * Convert a base64-encoded image to a data URL.
+ */
+ui.b64img = function(b64) {
+ return 'data:image/png;base64,' + b64;
+};
+
+/**
+ * Declare a CSS stylesheet.
+ */
+ui.declareCSS = function(s) {
+ var e = document.createElement('style');
+ e.type = 'text/css';
+ e.textContent = s;
+ return e;
+};
+
+/**
+ * Declare a script.
+ */
+ui.declareScript = function(s) {
+ var e = document.createElement('script');
+ e.type = 'text/javascript';
+ e.text = s;
+ return e;
+};
+
+/**
+ * Return the scripts elements under a given element.
+ */
+ui.innerScripts = function(e) {
+ return map(function(s) { return s.text; }, nodeList(e.getElementsByTagName('script')));
+};
+
+/**
+ * Evaluate a script.
+ */
+ui.evalScript = function(s) {
+ return eval('(function() {\n' + s + '\n})();');
+};
+
+/**
+ * Include a script.
+ */
+ui.includeScript = function(s) {
+ //log('include', s);
+ return eval(s);
+};
+
+/**
+ * Return true if the client is a mobile device.
+ */
+ui.mobiledetected = false;
+ui.mobile = false;
+ui.isMobile = function() {
+ if (ui.mobiledetected)
+ return ui.mobile;
+ var ua = navigator.userAgent;
+ if (ua.match(/iPhone/i) || ua.match(/iPad/i) || ua.match(/Android/i) || ua.match(/Blackberry/i) || ua.match(/WebOs/i))
+ ui.mobile = true;
+ ui.mobiledetected = true;
+ return ui.mobile;
+};
+
+/**
+ * Convert a CSS position to a numeric position.
+ */
+ui.numpos = function(p) {
+ return p == ''? 0 : Number(p.substr(0, p.length - 2));
+};
+
+/**
+ * Convert a numeric position to a CSS pixel position.
+ */
+ui.pixpos = function(p) {
+ return p + 'px';
+};
+
+/**
+ * Default orientation change behavior.
+ */
+ui.onorientationchange = function(e) {
+
+ // Scroll to the top and hide the address bar
+ window.scrollTo(0, 0);
+
+ // Change fixed position elements to absolute then back to fixed
+ // to make sure they're correctly layed out after the orientation
+ // change
+ map(function(e) {
+ e.style.position = 'absolute';
+ return e;
+ }, ui.elementsByClassName(document, 'fixed'));
+
+ setTimeout(function() {
+ map(function(e) {
+ e.style.position = 'fixed';
+ return e;
+ }, ui.elementsByClassName(document, 'fixed'));
+ }, 0);
+ return true;
+};
+
+/**
+ * Default page load behavior.
+ */
+ui.onload = function() {
+
+ // Scroll to the top and hide the address bar
+ window.scrollTo(0, 0);
+
+ // Initialize fixed position elements only after the page is loaded,
+ // to workaround layout issues with fixed position on mobile devices
+ setTimeout(function() {
+ map(function(e) {
+ e.style.position = 'fixed';
+ return e;
+ }, ui.elementsByClassName(document, 'fixed'));
+ }, 0);
+ return true;
+};
+
+/**
+ * Navigate to a new document.
+ */
+ui.navigate = function(url, win) {
+ //log('navigate', url, win);
+
+ // Open a new window
+ if (win == '_blank') {
+ window.top.open(url, win);
+ return false;
+ }
+
+ // Open a new document in the current window
+ if (win == '_self') {
+ window.top.open(url, win);
+ return false;
+ }
+
+ // Reload the current window
+ if (win == '_reload') {
+ window.top.location = url;
+ window.top.location.reload();
+ return false;
+ }
+
+ // Let the current top window handle the navigation
+ if (win == '_view') {
+ if (!window.top.onnavigate)
+ return window.top.open(url, '_self');
+ window.top.onnavigate(url);
+ return false;
+ }
+
+ window.top.open(url, win);
+ return false;
+}
+
+/**
+ * Build a portable <a href> tag.
+ */
+ui.href = function(id, loc, target, html) {
+ if (target == '_blank')
+ return '<a id="' + id + '" href="' + loc + '" target="_blank">' + html + '</a>';
+ return '<a id="' + id + '" href="' + loc + '" onclick="return ui.navigate(\'' + loc + '\', \'' + target + '\');">' + html + '</a>';
+};
+
+/**
+ * Build a menu bar.
+ */
+ui.menu = function(id, name, href, target, hilight) {
+ function Menu() {
+ this.content = function() {
+ if (hilight == true)
+ return ui.href(id, href, target, '<span class="tbarsmenu">' + name + '</span>');
+ else if (hilight == false)
+ return ui.href(id, href, target, '<span class="tbaramenu">' + name + '</span>');
+ else
+ return ui.href(id, href, target, '<span class="' + hilight + '">' + name + '</span>');
+ };
+ }
+ return new Menu();
+};
+
+ui.menufunc = function(id, name, fun, hilight) {
+ function Menu() {
+ this.content = function() {
+ function href(id, fun, html) {
+ return '<a id="' + id + '" href="/" onclick="' + fun + '">' + html + '</a>';
+ }
+
+ if (hilight == true)
+ return href(id, fun, '<span class="tbarsmenu">' + name + '</span>');
+ else if (hilight == false)
+ return href(id, fun, '<span class="tbaramenu">' + name + '</span>');
+ else
+ return href(id, fun, '<span class="' + hilight + '">' + name + '</span>');
+ };
+ }
+ return new Menu();
+};
+
+ui.menubar = function(left, right) {
+ var bar = '';
+ for (i in left)
+ bar = bar + '<span class="tbarleft">' + left[i].content() + '</span>';
+ for (i in right)
+ bar = bar + '<span class="tbarright">' + right[i].content() + '</span>';
+ return bar;
+};
+
+/**
+ * Convert a list of elements to an HTML table.
+ */
+ui.datatable = function(l) {
+
+ function indent(i) {
+ if (i == 0)
+ return '';
+ return '&nbsp;&nbsp;' + indent(i - 1);
+ }
+
+ function rows(l, i) {
+ if (isNil(l))
+ return '';
+ var e = car(l);
+
+ // Convert a list of simple values into a list of name value pairs
+ if (!isList(e))
+ return rows(expandElementValues("'value", l), i);
+
+ // Convert a list of complex values into a list of name value pairs
+ if (isList(car(e)))
+ return rows(expandElementValues("'value", l), i);
+
+ // Generate table row for a simple element value
+ if (elementHasValue(e)) {
+ var v = elementValue(e);
+ if (!isList(v)) {
+ return '<tr><td class="datatdl">' + indent(i) + elementName(e).slice(1) + '</td>' +
+ '<td class="datatdr tdw">' + (v != null? v : '') + '</td></tr>' +
+ rows(cdr(l), i);
+ }
+
+ return rows(expandElementValues(elementName(e), v), i) + rows(cdr(l), i);
+ }
+
+ // Generate table row for an element with children
+ return '<tr><td class="datatdl">' + indent(i) + elementName(e).slice(1) + '</td>' +
+ '<td class="datatdr tdw">' + '</td></tr>' +
+ rows(elementChildren(e), i + 1) +
+ rows(cdr(l), i);
+ }
+
+ return '<table class="datatable ' + (window.name == 'dataFrame'? ' databg' : '') + '" style="width: 100%;">' + rows(l, 0) + '</table>';
+}
+
+/**
+ * Convert a list of elements to an HTML single column table.
+ */
+ui.datalist = function(l) {
+
+ function rows(l, i) {
+ if (isNil(l))
+ return '';
+ var e = car(l);
+
+ // Convert a list of simple values into a list of name value pairs
+ if (!isList(e))
+ return rows(expandElementValues("'value", l), i);
+
+ // Convert a list of complex values into a list of name value pairs
+ if (isList(car(e)))
+ return rows(expandElementValues("'value", l), i);
+
+ // Generate table row for a simple element value
+ if (elementHasValue(e)) {
+ var v = elementValue(e);
+ if (!isList(v)) {
+ return '<tr><td class="datatd tdw">' + (v != null? v : '') + '</td></tr>' +
+ rows(cdr(l), i);
+ }
+
+ return rows(expandElementValues(elementName(e), v), i) + rows(cdr(l), i);
+ }
+
+ // Generate rows for an element's children
+ return rows(elementChildren(e), i + 1) + rows(cdr(l), i);
+ }
+
+ return '<table class="datatable ' + (window.name == 'dataFrame'? ' databg' : '') + '" style="width: 100%;">' + rows(l, 0) + '</table>';
+}
+
diff --git a/sca-cpp/branches/lightweight-sca/modules/js/htdocs/util.js b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/util.js
new file mode 100644
index 0000000000..0f7de94289
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/util.js
@@ -0,0 +1,471 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * Simple utility functions.
+ */
+
+/**
+ * Scheme-like lists.
+ */
+function cons(car, cdr) {
+ var a = new Array();
+ a.push(car);
+ return a.concat(cdr);
+}
+
+function car(l) {
+ return l[0];
+}
+
+function first(l) {
+ return l[0];
+}
+
+function cdr(l) {
+ return l.slice(1);
+}
+
+function rest(l) {
+ return l.slice(1);
+}
+
+function cadr(l) {
+ return l[1];
+}
+
+function cddr(l) {
+ return l.slice(2);
+}
+
+function caddr(l) {
+ return l[2];
+}
+
+function cdddr(l) {
+ return l.slice(3);
+}
+
+function cadddr(l) {
+ return l[3];
+}
+
+function append(a, b) {
+ return a.concat(b);
+}
+
+function reverse(l) {
+ return l.slice(0).reverse();
+}
+
+function range(a, b) {
+ var l = new Array();
+ for (var x = a; x < b; x++)
+ l.push(x);
+ return l;
+}
+
+function isNil(v) {
+ return (v == null || typeof v == 'undefined' || (v.constructor == Array && v.length == 0));
+}
+
+function isSymbol(v) {
+ return (typeof v == 'string' && v.slice(0, 1) == "'");
+}
+
+function isString(v) {
+ return (typeof v == 'string' && v.slice(0, 1) != "'");
+}
+
+function isList(v) {
+ return (v != null && typeof v != 'undefined' && v.constructor == Array);
+}
+
+function isTaggedList(v, t) {
+ return (isList(v) && !isNil(v) && car(v) == t);
+}
+
+var emptylist = new Array();
+
+function mklist() {
+ if (arguments.length == 0)
+ return emptylist;
+ var a = new Array();
+ for (i = 0; i < arguments.length; i++)
+ a[i] = arguments[i];
+ return a;
+}
+
+function length(l) {
+ return l.length;
+}
+
+/**
+ * Scheme-like associations.
+ */
+function assoc(k, l) {
+ if (isNil(l))
+ return emptylist;
+ var n = l.length;
+ for(var i = 0; i < n; i++) {
+ if (k == car(l[i]))
+ return l[i];
+ }
+ return emptylist;
+}
+
+/**
+ * Map, filter and reduce functions.
+ */
+function map(f, l) {
+ if (isNil(l))
+ return l;
+ var n = l.length;
+ var a = new Array();
+ for(var i = 0; i < n; i++) {
+ a.push(f(l[i]));
+ }
+ return a;
+}
+
+function filter(f, l) {
+ if (isNil(l))
+ return l;
+ var n = l.length;
+ var a = new Array();
+ for(var i = 0; i < n; i++) {
+ if (f(l[i]))
+ a.push(l[i]);
+ }
+ return a;
+}
+
+function reduce(f, i, l) {
+ if (isNil(l))
+ return i;
+ return reduce(f, f(i, car(l)), cdr(l));
+}
+
+/**
+ * Split a path into a list of segments.
+ */
+function tokens(path) {
+ return filter(function(s) { return length(s) != 0; }, path.split("/"));
+}
+
+/**
+ * Debug log a value.
+ */
+var rconsole;
+
+function debug(v) {
+ try {
+ var s = '';
+ for (i = 0; i < arguments.length; i++) {
+ s = s + writeValue(arguments[i]);
+ if (i < arguments.length)
+ s = s + ' ';
+ }
+
+ if (rconsole) {
+ try {
+ rconsole.log(s);
+ } catch (e) {}
+ }
+ try {
+ console.log(s);
+ } catch (e) {}
+ } catch (e) {}
+ return true;
+}
+
+/**
+ * Dump an object to the console.
+ */
+function dump(o) {
+ try {
+ for (f in o) {
+ try {
+ debug('dump ' + f + '=' + o[f]);
+ } catch (e) {}
+ }
+ } catch (e) {}
+ return true;
+}
+
+/**
+ * Return true if the current browser is Internet Explorer.
+ */
+function isIE() {
+ if (typeof isIE.detected != 'undefined')
+ return isIE.detected;
+ isIE.detected = navigator.appName == 'Microsoft Internet Explorer';
+ return isIE.detected;
+};
+
+/**
+ * External build configuration.
+ */
+var config;
+if (isNil(config))
+ config = {};
+
+/**
+ * Simple assert function.
+ */
+function AssertException() {
+}
+
+AssertException.prototype.toString = function () {
+ return 'AssertException';
+};
+
+function assert(exp) {
+ if (!exp)
+ throw new AssertException();
+}
+
+/**
+ * Write a list of strings.
+ */
+function writeStrings(l) {
+ if (isNil(l))
+ return '';
+ var s = '';
+ var n = l.length;
+ for(var i = 0; i < n; i++) {
+ s = s + l[i];
+ }
+ return s;
+}
+
+/**
+ * Write a value using a Scheme-like syntax.
+ */
+function writeValue(v) {
+ function writePrimitive(p) {
+ if (isSymbol(p))
+ return '' + p.substring(1);
+ if (isString(p))
+ return '"' + p + '"';
+ return '' + p;
+ }
+
+ function writeList(l) {
+ if (isNil(l))
+ return '';
+ return ' ' + writeValue(car(l)) + writeList(cdr(l));
+ }
+
+ if (!isList(v))
+ return writePrimitive(v);
+ if (isNil(v))
+ return '()';
+ return '(' + writeValue(car(v)) + writeList(cdr(v)) + ')';
+}
+
+/**
+ * Apply a function and memoize its result.
+ */
+function memo(obj, key, f) {
+ if (!('memo' in obj)) {
+ obj.memo = {};
+ return obj.memo[key] = f();
+ }
+ if (key in obj.memo)
+ return obj.memo[key];
+ return obj.memo[key] = f();
+}
+
+/**
+ * Un-memoize stored results.
+ */
+function unmemo(obj) {
+ obj.memo = {};
+ return true;
+}
+
+/**
+ * Local storage.
+ */
+var lstorage = {};
+lstorage.enabled = true;
+
+/**
+ * Get an item.
+ */
+lstorage.getItem = function(k) {
+ if (!lstorage.enabled)
+ return null;
+ try {
+ return localStorage.getItem(k);
+ } catch(e) {
+ return null;
+ }
+}
+
+/**
+ * Set an item.
+ */
+lstorage.setItem = function(k, v) {
+ if (!lstorage.enabled)
+ return null;
+ try {
+ return localStorage.setItem(k, v);
+ } catch(e) {
+ return null;
+ }
+}
+
+/**
+ * Remove an item.
+ */
+lstorage.removeItem = function(k) {
+ if (!lstorage.enabled)
+ return null;
+ try {
+ return localStorage.removeItem(k);
+ } catch(e) {
+ return null;
+ }
+}
+
+/**
+ * Returns a list of the properties of an object.
+ */
+function properties(o) {
+ var a = new Array();
+ for (p in o)
+ a.push(p);
+ return a;
+}
+
+/**
+ * Convert a host name to a domain name.
+ */
+function domainname(host) {
+ var ds = host.indexOf('//');
+ if (ds != -1)
+ return domainname(host.substring(ds + 2));
+ var s = host.indexOf('/');
+ if (s != -1)
+ return domainname(host.substring(0, s));
+ var h = reverse(host.split('.'));
+ var d = (!isNil(cddr(h)) && caddr(h) == 'www')? mklist(car(h), cadr(h), caddr(h)) : mklist(car(h), cadr(h));
+ return reverse(d).join('.');
+}
+
+/**
+ * Return true if a host name is a subdomain.
+ */
+function issubdomain(host) {
+ return host.split('.').length > 2;
+}
+
+/**
+ * Return true if the document cookie contains auth information.
+ */
+function hasauthcookie() {
+ return !isNil(document.cookie) &&
+ (document.cookie.indexOf('TuscanyOpenAuth=') != -1 ||
+ document.cookie.indexOf('TuscanyOAuth1=') != -1 ||
+ document.cookie.indexOf('TuscanyOAuth2=') != -1 ||
+ document.cookie.indexOf('TuscanyOpenIDAuth=') != -1);
+}
+
+/**
+ * Clear auth information from the document cookie.
+ */
+function clearauthcookie() {
+ document.cookie = 'TuscanyOpenAuth=; expires=' + new Date(1970,01,01).toGMTString() + '; domain=.' + domainname(window.location.hostname) + '; path=/';
+ document.cookie = 'TuscanyOAuth1=; expires=' + new Date(1970,01,01).toGMTString() + '; domain=.' + domainname(window.location.hostname) + '; path=/';
+ document.cookie = 'TuscanyOAuth2=; expires=' + new Date(1970,01,01).toGMTString() + '; domain=.' + domainname(window.location.hostname) + '; path=/';
+ document.cookie = 'TuscanyOpenIDAuth=; expires=' + new Date(1970,01,01).toGMTString() + '; domain=.' + domainname(window.location.hostname) + '; path=/';
+ return true;
+}
+
+/**
+ * Format a string like Python format.
+ */
+function format() {
+ var i = 0;
+ var s = '';
+ for (a in arguments) {
+ s = i == 0? arguments[a] : s.replace('{' + a + '}', arguments[a]);
+ i++;
+ }
+ return s;
+}
+
+/**
+ * Functions with side effects. Use with moderation.
+ */
+
+/**
+ * Set the car of a list.
+ */
+function setcar(l, v) {
+ l[0] = v;
+ return l;
+}
+
+/**
+ * Set the cadr of a list.
+ */
+function setcadr(l, v) {
+ l[1] = v;
+ return l;
+}
+
+/**
+ * Set the caddr of a list.
+ */
+function setcaddr(l, v) {
+ l[2] = v;
+ return l;
+}
+
+/**
+ * Append the elements of a list to a list.
+ */
+function setappend(a, b) {
+ if (isNil(b))
+ return a;
+ a.push(car(b));
+ return setappend(a, cdr(b));
+}
+
+/**
+ * Set the cdr of a list.
+ */
+function setcdr(a, b) {
+ a.length = 1;
+ return setappend(a, b);
+}
+
+/**
+ * Set the contents of a list.
+ */
+function setlist(a, b) {
+ if (b == a)
+ return b;
+ a.length = 0;
+ return setappend(a, b);
+}
+
diff --git a/sca-cpp/branches/lightweight-sca/modules/js/htdocs/xmlutil.js b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/xmlutil.js
new file mode 100644
index 0000000000..4d943cce75
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/modules/js/htdocs/xmlutil.js
@@ -0,0 +1,256 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * XML handling functions.
+ */
+
+/**
+ * Convert a DOM node list to a regular list.
+ */
+function nodeList(n) {
+ var l = new Array();
+ if (isNil(n))
+ return l;
+ for (var i = 0; i < n.length; i++)
+ l[i] = n[i];
+ return l;
+}
+
+/**
+ * Append a list of nodes to a parent node.
+ */
+function appendNodes(nodes, p) {
+ if (isNil(nodes))
+ return p;
+ p.appendChild(car(nodes));
+ return appendNodes(cdr(nodes), p);
+};
+
+/**
+ * Return the child attributes of an element.
+ */
+function childAttributes(e) {
+ return filter(function(n) { return n.nodeType == 2; }, nodeList(e.attributes));
+}
+
+/**
+ * Return the child elements of an element.
+ */
+function childElements(e) {
+ return filter(function(n) { return n.nodeType == 1; }, nodeList(e.childNodes));
+}
+
+/**
+ * Return the child text nodes of an element.
+ */
+function childText(e) {
+ function trim(s) {
+ return s.replace(/^\s*/, '').replace(/\s*$/, '');
+ }
+ return filter(function(n) { return n.nodeType == 3 && trim(n.nodeValue) != ''; }, nodeList(e.childNodes));
+}
+
+/**
+ * Read a list of XML attributes.
+ */
+function readAttributes(p, a) {
+ if (isNil(a))
+ return a;
+ var x = car(a);
+ return cons(mklist(attribute, "'" + x.nodeName, x.nodeValue), readAttributes(p, cdr(a)));
+}
+
+/**
+ * Read an XML element.
+ */
+function readElement(e, childf) {
+ var l = append(append(mklist(element, "'" + e.nodeName), readAttributes(e, childf(e))), readElements(childElements(e), childf));
+ var t = childText(e);
+ if (isNil(t))
+ return l;
+ return append(l, mklist(car(t).nodeValue));
+}
+
+/**
+ * Read a list of XML elements.
+ */
+function readElements(l, childf) {
+ if (isNil(l))
+ return l;
+ return cons(readElement(car(l), childf), readElements(cdr(l), childf));
+}
+
+/**
+ * Return true if a list of strings contains an XML document.
+ */
+function isXML(l) {
+ if (isNil(l))
+ return false;
+ return car(l).substring(0, 5) == '<?xml';
+}
+
+/**
+ * Parse a list of strings representing an XML document.
+ */
+function parseXML(l) {
+ var s = writeStrings(l);
+ var p = new DOMParser();
+ return p.parseFromString(s, "text/xml");
+}
+
+/**
+ * Read a list of values from an XML document.
+ */
+function readXMLDocument(doc) {
+ var root = childElements(doc);
+ if (isNil(root))
+ return mklist();
+ return mklist(readElement(car(root), childAttributes));
+}
+
+/**
+ * Read a list of values from an XHTML element.
+ */
+function readXHTMLElement(xhtml) {
+ // Special XHTML attribute filtering on IE
+ function ieChildAttributes(e) {
+ var a = filter(function(n) {
+ // Filter out empty and internal DOM attributes
+ if (n.nodeType != 2 || isNil(n.nodeValue) || n.nodeValue == '')
+ return false;
+ if (n.nodeName == 'contentEditable' || n.nodeName == 'maxLength' || n.nodeName == 'loop' || n.nodeName == 'start')
+ return false;
+ return true;
+ }, nodeList(e.attributes));
+
+ if (e.style.cssText == '')
+ return a;
+
+ // Add style attribute
+ var sa = new Object();
+ sa.nodeName = 'style';
+ sa.nodeValue = e.style.cssText;
+ return cons(sa, a);
+ }
+
+ var childf = (typeof(XMLSerializer) != 'undefined')? childAttributes : ieChildAttributes;
+ return mklist(readElement(xhtml, childf));
+}
+
+/**
+ * Read a list of values from a list of strings representing an XML document.
+ */
+function readXML(l) {
+ return readXMLDocument(parseXML(l));
+}
+
+/**
+ * Return a list of strings representing an XML document.
+ */
+function writeXMLDocument(doc) {
+ if (typeof(XMLSerializer) != 'undefined')
+ return mklist(new XMLSerializer().serializeToString(doc));
+ return mklist(doc.xml);
+}
+
+/**
+ * Write a list of XML element and attribute tokens.
+ */
+function expandElementValues(n, l) {
+ if (isNil(l))
+ return l;
+ return cons(cons(element, cons(n, car(l))), expandElementValues(n, cdr(l)));
+}
+
+function writeList(l, node, doc) {
+ if (isNil(l))
+ return node;
+
+ var token = car(l);
+ if (isTaggedList(token, attribute)) {
+ if (isIE()) {
+ var aname = attributeName(token).substring(1);
+ if (aname != 'xmlns')
+ node.setAttribute(aname, '' + attributeValue(token));
+ } else
+ node.setAttribute(attributeName(token).substring(1), '' + attributeValue(token));
+
+ } else if (isTaggedList(token, element)) {
+
+ function mkelem(tok, doc) {
+ function xmlns(l) {
+ if (isNil(l))
+ return null;
+ var t = car(l);
+ if (isTaggedList(t, attribute)) {
+ if (attributeName(t).substring(1) == 'xmlns')
+ return attributeValue(t);
+ }
+ return xmlns(cdr(l));
+ }
+
+ var ns = xmlns(elementChildren(tok));
+ if (isIE())
+ return doc.createElementNS(ns != null? ns : node.namespaceURI, elementName(tok).substring(1));
+ if (ns == null)
+ return doc.createElement(elementName(tok).substring(1));
+ return doc.createElementNS(ns, elementName(tok).substring(1));
+ }
+
+ if (elementHasValue(token)) {
+ var v = elementValue(token);
+ if (isList(v)) {
+ var e = expandElementValues(elementName(token), v);
+ writeList(e, node, doc);
+ } else {
+ var child = mkelem(token, doc);
+ writeList(elementChildren(token), child, doc);
+ node.appendChild(child);
+ }
+ } else {
+ var child = mkelem(token, doc);
+ writeList(elementChildren(token), child, doc);
+ node.appendChild(child);
+ }
+ } else
+ node.appendChild(doc.createTextNode('' + token));
+
+ writeList(cdr(l), node, doc);
+ return node;
+}
+
+/**
+ * Make a new XML document.
+ */
+function mkXMLDocument() {
+ return document.implementation.createDocument('', '', null);
+}
+
+/**
+ * Convert a list of values to a list of strings representing an XML document.
+ */
+function writeXML(l, xmlTag) {
+ var doc = mkXMLDocument();
+ writeList(l, doc, doc);
+ if (!xmlTag)
+ return writeXMLDocument(doc);
+ return mklist('<?xml version="1.0" encoding="UTF-8"?>\n' + writeXMLDocument(doc) + '\n');
+}
+