summaryrefslogtreecommitdiffstats
path: root/sandbox/sebastien/cpp/apr-2/modules/js
diff options
context:
space:
mode:
Diffstat (limited to 'sandbox/sebastien/cpp/apr-2/modules/js')
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/js/Makefile.am29
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/js/eval.hpp308
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/js/htdocs/atomutil.js169
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/js/htdocs/component.js561
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/js/htdocs/elemutil.js231
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/js/htdocs/graph.js638
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/js/htdocs/scdl.js163
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/js/htdocs/ui.css121
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/js/htdocs/ui.js233
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/js/htdocs/util.js208
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/js/htdocs/xmlutil.js197
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/js/js-test.cpp52
12 files changed, 2910 insertions, 0 deletions
diff --git a/sandbox/sebastien/cpp/apr-2/modules/js/Makefile.am b/sandbox/sebastien/cpp/apr-2/modules/js/Makefile.am
new file mode 100644
index 0000000000..8c88f32c0f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/js/Makefile.am
@@ -0,0 +1,29 @@
+# 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.
+
+incl_HEADERS = *.hpp
+incldir = $(prefix)/include/modules/js
+
+moddir = $(prefix)/modules/js
+nobase_dist_mod_DATA = htdocs/*.js htdocs/*.css
+EXTRA_DIST = htdocs/*.js htdocs/*.css
+
+js_test_SOURCES = js-test.cpp
+js_test_LDFLAGS = -lmozjs
+
+noinst_PROGRAMS = js-test
+TESTS = js-test
diff --git a/sandbox/sebastien/cpp/apr-2/modules/js/eval.hpp b/sandbox/sebastien/cpp/apr-2/modules/js/eval.hpp
new file mode 100644
index 0000000000..b7c69a1a0c
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/js/eval.hpp
@@ -0,0 +1,308 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_js_hpp
+#define tuscany_js_hpp
+
+/**
+ * Javascript evaluation functions.
+ */
+
+#define XP_UNIX
+#include <jsapi.h>
+#include "string.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "element.hpp"
+#include "monad.hpp"
+
+namespace tuscany {
+namespace js {
+
+/**
+ * Report Javascript errors.
+ */
+void reportError(unused ::JSContext *cx, const char *message, JSErrorReport *report) {
+#ifdef WANT_MAINTAINER_MODE
+ cdebug << (const char*)(report->filename? report->filename : "<no filename>") << ":"
+ << (int)report->lineno << ":" << message << endl;
+#endif
+}
+
+/**
+ * Encapsulates a JavaScript runtime. Shared by multiple threads in
+ * a process.
+ */
+class JSRuntime {
+public:
+ JSRuntime() {
+ // Create JS runtime
+ rt = JS_NewRuntime(8L * 1024L * 1024L);
+ if(rt == NULL)
+ cleanup();
+ }
+
+ operator ::JSRuntime*() const {
+ return rt;
+ }
+private:
+ bool cleanup() {
+ if(rt != NULL) {
+ JS_DestroyRuntime(rt);
+ rt = NULL;
+ }
+ JS_ShutDown();
+ return true;
+ }
+
+ ::JSRuntime* rt;
+} jsRuntime;
+
+JSClass jsGlobalClass = { "global", JSCLASS_GLOBAL_FLAGS, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
+ JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, JSCLASS_NO_OPTIONAL_MEMBERS};
+
+/**
+ * Represents a JavaScript context. Create one per thread.
+ */
+class JSContext {
+public:
+ JSContext() {
+ // Create JS context
+ cx = JS_NewContext(jsRuntime, 8192);
+ if(cx == NULL)
+ return;
+ JS_SetOptions(cx, JSOPTION_VAROBJFIX);
+ JS_SetVersion(cx, JSVERSION_DEFAULT);
+ JS_SetErrorReporter(cx, reportError);
+
+ // Create global JS object
+ global = JS_NewObject(cx, &jsGlobalClass, NULL, NULL);
+ if(global == NULL) {
+ cleanup();
+ return;
+ }
+
+ // Populate global object with the standard globals, like Object and Array
+ if(!JS_InitStandardClasses(cx, global)) {
+ cleanup();
+ return;
+ }
+ }
+
+ ~JSContext() {
+ cleanup();
+ }
+
+ operator ::JSContext*() const {
+ return cx;
+ }
+
+ JSObject* getGlobal() const {
+ return global;
+ }
+
+private:
+ bool cleanup() {
+ if(cx != NULL) {
+ JS_DestroyContext(cx);
+ cx = NULL;
+ }
+ return true;
+ }
+
+ ::JSContext* cx;
+ JSObject* global;
+};
+
+/**
+ * Returns true if a list represents a JS array.
+ */
+const bool isJSArray(const list<value>& l) {
+ if(isNil(l))
+ return true;
+ const value v = car(l);
+ if (isSymbol(v))
+ return false;
+ if(isList(v)) {
+ if(!isNil((list<value>)v) && isSymbol(car<value>(v)))
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Converts JS properties to values.
+ */
+const list<value> jsPropertiesToValues(const list<value>& propertiesSoFar, JSObject* o, JSObject* i, const js::JSContext& cx) {
+
+ const value jsValToValue(const jsval& jsv, const js::JSContext& cx);
+
+ jsid id;
+ if(!JS_NextProperty(cx, i, &id) || id == JSVAL_VOID)
+ return propertiesSoFar;
+ jsval jsv;
+ if(!JS_GetPropertyById(cx, o, id, &jsv))
+ return propertiesSoFar;
+ const value val = jsValToValue(jsv, cx);
+
+ jsval idv;
+ JS_IdToValue(cx, id, &idv);
+ if(JSVAL_IS_STRING(idv)) {
+ if (isNil(val) && !isList(val))
+ return jsPropertiesToValues(propertiesSoFar, o, i, cx);
+ const string name = JS_GetStringBytes(JSVAL_TO_STRING(idv));
+ if (substr(name, 0, 1) == atsign)
+ return jsPropertiesToValues(cons<value>(mklist<value>(attribute, c_str(substr(name, 1)), val), propertiesSoFar), o, i, cx);
+ if (isList(val) && !isJSArray(val))
+ return jsPropertiesToValues(cons<value>(cons<value>(element, cons<value>(c_str(name), list<value>(val))), propertiesSoFar), o, i, cx);
+ return jsPropertiesToValues(cons<value> (mklist<value> (element, c_str(name), val), propertiesSoFar), o, i, cx);
+ }
+ return jsPropertiesToValues(cons(val, propertiesSoFar), o, i, cx);
+}
+
+/**
+ * Converts a JS val to a value.
+ */
+const value jsValToValue(const jsval& jsv, const js::JSContext& cx) {
+ switch(JS_TypeOfValue(cx, jsv)) {
+ case JSTYPE_STRING: {
+ return value(string(JS_GetStringBytes(JSVAL_TO_STRING(jsv))));
+ }
+ case JSTYPE_BOOLEAN: {
+ return value((bool)JSVAL_TO_BOOLEAN(jsv));
+ }
+ case JSTYPE_NUMBER: {
+ jsdouble jsd;
+ JS_ValueToNumber(cx, jsv, &jsd);
+ return value((double)jsd);
+ }
+ case JSTYPE_OBJECT: {
+ JSObject* o = JSVAL_TO_OBJECT(jsv);
+ if (o == NULL)
+ return value();
+ JSObject* i = JS_NewPropertyIterator(cx, o);
+ if(i == NULL)
+ return value(list<value> ());
+ const value pv = jsPropertiesToValues(list<value> (), o, i, cx);
+ return pv;
+ }
+ default: {
+ return value();
+ }
+ }
+}
+
+/**
+ * Converts a list of values to JS array elements.
+ */
+JSObject* valuesToJSElements(JSObject* a, const list<value>& l, int i, const js::JSContext& cx) {
+ const jsval valueToJSVal(const value& val, const js::JSContext& cx);
+ if (isNil(l))
+ return a;
+ jsval pv = valueToJSVal(car(l), cx);
+ JS_SetElement(cx, a, i, &pv);
+ return valuesToJSElements(a, cdr(l), ++i, cx);
+}
+
+/**
+ * Converts a value to a JS val.
+ */
+const jsval valueToJSVal(const value& val, const js::JSContext& cx) {
+ JSObject* valuesToJSProperties(JSObject* o, const list<value>& l, const js::JSContext& cx);
+
+ switch(type(val)) {
+ case value::String: {
+ return STRING_TO_JSVAL(JS_NewStringCopyZ(cx, c_str((string)val)));
+ }
+ case value::Symbol: {
+ return STRING_TO_JSVAL(JS_NewStringCopyZ(cx, c_str((string)val)));
+ }
+ case value::Bool: {
+ return BOOLEAN_TO_JSVAL((bool)val);
+ }
+ case value::Number: {
+ return DOUBLE_TO_JSVAL(JS_NewDouble(cx, (double)val));
+ }
+ case value::List: {
+ if (isJSArray(val))
+ return OBJECT_TO_JSVAL(valuesToJSElements(JS_NewArrayObject(cx, 0, NULL), val, 0, cx));
+ return OBJECT_TO_JSVAL(valuesToJSProperties(JS_NewObject(cx, NULL, NULL, NULL), val, cx));
+ }
+ default: {
+ return JSVAL_VOID;
+ }
+ }
+}
+
+/**
+ * Converts a list of values to JS properties.
+ */
+JSObject* valuesToJSProperties(JSObject* o, const list<value>& l, const js::JSContext& cx) {
+ if (isNil(l))
+ return o;
+
+ // Write an attribute
+ const value token(car(l));
+
+ if (isTaggedList(token, attribute)) {
+ jsval pv = valueToJSVal(attributeValue(token), cx);
+ JS_SetProperty(cx, o, c_str(atsign + string(attributeName(token))), &pv);
+
+ } else if (isTaggedList(token, element)) {
+
+ // Write the value of an element
+ if (elementHasValue(token)) {
+ jsval pv = valueToJSVal(elementValue(token), cx);
+ JS_SetProperty(cx, o, c_str(string(elementName(token))), &pv);
+
+ } else {
+
+ // Write a parent element
+ JSObject* child = JS_NewObject(cx, NULL, NULL, NULL);
+ jsval pv = OBJECT_TO_JSVAL(child);
+ JS_SetProperty(cx, o, c_str(string(elementName(token))), &pv);
+
+ // Write its children
+ valuesToJSProperties(child, elementChildren(token), cx);
+ }
+ }
+
+ // Go on
+ return valuesToJSProperties(o, cdr(l), cx);
+}
+
+/**
+ * Evaluate a script provided as a string.
+ */
+const failable<value> evalScript(const string& s) {
+ js::JSContext cx;
+ jsval rval;
+ JSBool rc = JS_EvaluateScript(cx, cx.getGlobal(), c_str(s), (uintN)length(s), "eval.js", 1, &rval);
+ if (rc != JS_TRUE) {
+ return mkfailure<value>("Couldn't evaluate Javascript script.");
+ }
+ return jsValToValue(rval, cx);
+}
+
+}
+}
+
+#endif /* tuscany_js_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/atomutil.js b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/atomutil.js
new file mode 100644
index 0000000000..6b998dceda
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/atomutil.js
@@ -0,0 +1,169 @@
+/*
+ * 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 = new Object();
+
+/**
+ * Convert a list of elements to a list of values representing an ATOM entry.
+ */
+atom.entryElementsToValues = function(e) {
+ var lt = filter(selector(mklist(element, "'title")), e);
+ var t = isNil(lt)? '' : elementValue(car(lt));
+ var li = filter(selector(mklist(element, "'id")), e);
+ var i = isNil(li)? '' : elementValue(car(li));
+ var lc = filter(selector(mklist(element, "'content")), e);
+ return mklist(t, i, elementValue(car(lc)));
+};
+
+/**
+ * Convert a list of elements to a list of values representing ATOM entries.
+ */
+atom.entriesElementsToValues = function(e) {
+ if (isNil(e))
+ return e;
+ return cons(atom.entryElementsToValues(car(e)), atom.entriesElementsToValues(cdr(e)));
+};
+
+/**
+ * Convert a list of strings to a list of values representing an ATOM entry.
+ */
+atom.readATOMEntry = function(l) {
+ var e = readXML(l);
+ if (isNil(e))
+ return mklist();
+ return atom.entryElementsToValues(car(e));
+};
+
+/**
+ * Convert a list of values representy an ATOM entry to a value.
+ */
+atom.entryValue = function(e) {
+ var v = elementsToValues(mklist(caddr(e)));
+ return cons(car(e), (cadr(e), cdr(car(v))));
+};
+
+/**
+ * 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));
+ if (isNil(e))
+ return mklist(elementValue(car(t)), elementValue(car(i)));
+ return cons(elementValue(car(t)), cons(elementValue(car(i)), atom.entriesElementsToValues(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 an ATOM feed containing elements to an ATOM feed containing values.
+ */
+atom.feedValues = function(e) {
+ function feedValuesLoop(e) {
+ if (isNil(e))
+ return e;
+ return cons(entryValue(car(e)), feedValuesLoop(cdr(e)));
+ }
+
+ return cons(car(e), cons(cadr(e), feedValuesLoop(cddr(e))));
+};
+
+/**
+ * Convert a list of values representy an ATOM entry to a list of elements.
+ */
+atom.entryElement = function(l) {
+ return mklist(element, "'entry", mklist(attribute, "'xmlns", "http://www.w3.org/2005/Atom"),
+ mklist(element, "'title", mklist(attribute, "'type", "text"), car(l)),
+ mklist(element, "'id", cadr(l)),
+ mklist(element, "'content", mklist(attribute, "'type", (isList(caddr(l))? "application/xml" : "text")), caddr(l)),
+ mklist(element, "'link", mklist(attribute, "'href", cadr(l))));
+};
+
+/**
+ * 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(l) {
+ return writeXML(mklist(atom.entryElement(l)), true);
+};
+
+/**
+ * Convert a list of values representing an ATOM feed to an ATOM feed.
+ */
+atom.writeATOMFeed = function(l) {
+ 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)));
+ if (isNil(cddr(l)))
+ return writeXML(mklist(f), true);
+ var fe = append(f, atom.entriesElements(cddr(l)));
+ return writeXML(mklist(fe), true);
+};
+
+/**
+ * Convert an ATOM entry containing a value to an ATOM entry containing an item element.
+ */
+atom.entryValuesToElements = function(v) {
+ if (isList(caddr(v)))
+ return cons(car(v), cons(cadr(v), valuesToElements(mklist(cons("'item", caddr(v))))));
+ return cons(car(v), cons(cadr(v), valuesToElements(mklist(mklist("'item", caddr(v))))));
+};
+
+/**
+ * Convert an ATOM feed containing values to an ATOM feed containing elements.
+ */
+atom.feedValuesToElements = function(v) {
+ function feedValuesToElementsLoop(v) {
+ if (isNil(v))
+ return v;
+ return cons(atom.entryValuesToElements(car(v)), feedValuesToElementsLoop(cdr(v)));
+ }
+
+ return cons(car(v), cons(cadr(v), feedValuesToElementsLoop(cddr(v))));
+};
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/component.js b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/component.js
new file mode 100644
index 0000000000..9ce6aa86e5
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/component.js
@@ -0,0 +1,561 @@
+/*
+ * 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.
+ */
+
+/**
+ * Escape a character.
+ */
+var JSONClient = new Object();
+
+JSONClient.escapeJSONChar = function(c) {
+ if(c == "\"" || c == "\\") return "\\" + c;
+ else if (c == "\b") return "\\b";
+ else if (c == "\f") return "\\f";
+ else if (c == "\n") return "\\n";
+ else if (c == "\r") return "\\r";
+ else if (c == "\t") return "\\t";
+ var hex = c.charCodeAt(0).toString(16);
+ if(hex.length == 1) return "\\u000" + hex;
+ else if(hex.length == 2) return "\\u00" + hex;
+ else if(hex.length == 3) return "\\u0" + hex;
+ else 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";
+ } else if(o.constructor == String) {
+ return JSONClient.escapeJSONString(o);
+ } else if(o.constructor == Number) {
+ return o.toString();
+ } else if(o.constructor == Boolean) {
+ return o.toString();
+ } else if(o.constructor == Date) {
+ return '{javaClass: "java.util.Date", time: ' + o.valueOf() +'}';
+ } else if(o.constructor == Array) {
+ var v = [];
+ for(var i = 0; i < o.length; i++) v.push(JSONClient.toJSON(o[i]));
+ return "[" + v.join(", ") + "]";
+ } else {
+ 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(cname, uri, objectID) {
+ this.uri = "/references/" + cname + "/" + uri;
+ this.objectID = objectID;
+ this.apply = this._createApplyMethod();
+
+ if (typeof DOMParser == "undefined") {
+ DOMParser = function () {}
+
+ DOMParser.prototype.parseFromString = function (str, contentType) {
+ if (typeof ActiveXObject != "undefined") {
+ var d = new ActiveXObject("MSXML.DomDocument");
+ d.loadXML(str);
+ return d;
+ } else if (typeof XMLHttpRequest != "undefined") {
+ var req = new XMLHttpRequest;
+ req.open("GET", "data:" + (contentType || "application/xml") +
+ ";charset=utf-8," + encodeURIComponent(str), false);
+ if (req.overrideMimeType) {
+ req.overrideMimeType(contentType);
+ }
+ req.send(null);
+ return req.responseXML;
+ }
+ }
+ }
+}
+
+/**
+ * HTTPBindingClient.Exception.
+ */
+HTTPBindingClient.Exception = function(code, message, javaStack) {
+ this.code = code;
+ var name;
+ if(javaStack) {
+ this.javaStack = javaStack;
+ var m = javaStack.match(/^([^:]*)/);
+ if(m) name = m[0];
+ }
+ if(name) this.name = name;
+ else this.name = "HTTPBindingClientException";
+ this.message = message;
+};
+
+HTTPBindingClient.Exception.CODE_REMOTE_EXCEPTION = 490;
+HTTPBindingClient.Exception.CODE_ERR_CLIENT = 550;
+HTTPBindingClient.Exception.CODE_ERR_PARSE = 590;
+HTTPBindingClient.Exception.CODE_ERR_NOMETHOD = 591;
+HTTPBindingClient.Exception.CODE_ERR_UNMARSHALL = 592;
+HTTPBindingClient.Exception.CODE_ERR_MARSHALL = 593;
+
+HTTPBindingClient.Exception.prototype = new Error();
+HTTPBindingClient.Exception.prototype.toString = function(code, msg) {
+ return this.name + ": " + this.message;
+};
+
+/**
+ * Default top level exception handler.
+ */
+HTTPBindingClient.default_ex_handler = function(e) {
+ alert(e);
+};
+
+/**
+ * Client settable variables
+ */
+HTTPBindingClient.toplevel_ex_handler = HTTPBindingClient.default_ex_handler;
+HTTPBindingClient.profile_async = false;
+HTTPBindingClient.max_req_active = 1;
+HTTPBindingClient.requestId = 1;
+
+/**
+ * HTTPBindingClient implementation
+ */
+HTTPBindingClient.prototype._createApplyMethod = function() {
+ var fn = function() {
+ var args = [];
+ var callback = null;
+ var methodName = arguments[0];
+ for(var i = 1; i < arguments.length; i++) args.push(arguments[i]);
+
+ if(typeof args[args.length - 1] == "function") callback = args.pop();
+
+ var req = fn.client._makeRequest.call(fn.client, methodName, args, callback);
+ if(callback == null) {
+ return fn.client._sendRequest.call(fn.client, req);
+ } else {
+ HTTPBindingClient.async_requests.push(req);
+ HTTPBindingClient.kick_async();
+ return req.requestId;
+ }
+ };
+ fn.client = this;
+ return fn;
+};
+
+HTTPBindingClient._getCharsetFromHeaders = function(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";
+};
+
+/**
+ * Async queue globals
+ */
+HTTPBindingClient.async_requests = [];
+HTTPBindingClient.async_inflight = {};
+HTTPBindingClient.async_responses = [];
+HTTPBindingClient.async_timeout = null;
+HTTPBindingClient.num_req_active = 0;
+
+HTTPBindingClient._async_handler = function() {
+ HTTPBindingClient.async_timeout = null;
+
+ while(HTTPBindingClient.async_responses.length > 0) {
+ var res = HTTPBindingClient.async_responses.shift();
+ if(res.canceled) continue;
+ if(res.profile) res.profile.dispatch = new Date();
+ try {
+ res.cb(res.result, res.ex, res.profile);
+ } catch(e) {
+ HTTPBindingClient.toplevel_ex_handler(e);
+ }
+ }
+
+ while(HTTPBindingClient.async_requests.length > 0 && HTTPBindingClient.num_req_active < HTTPBindingClient.max_req_active) {
+ var req = HTTPBindingClient.async_requests.shift();
+ if(req.canceled) continue;
+ req.client._sendRequest.call(req.client, req);
+ }
+};
+
+HTTPBindingClient.kick_async = function() {
+ if(HTTPBindingClient.async_timeout == null)
+ HTTPBindingClient.async_timeout = setTimeout(HTTPBindingClient._async_handler, 0);
+};
+
+HTTPBindingClient.cancelRequest = function(requestId) {
+ /* If it is in flight then mark it as canceled in the inflight map
+ and the XMLHttpRequest callback will discard the reply. */
+ if(HTTPBindingClient.async_inflight[requestId]) {
+ HTTPBindingClient.async_inflight[requestId].canceled = true;
+ return true;
+ }
+
+ /* If its not in flight yet then we can just mark it as canceled in
+ the the request queue and it will get discarded before being sent. */
+ for(var i in HTTPBindingClient.async_requests) {
+ if(HTTPBindingClient.async_requests[i].requestId == requestId) {
+ HTTPBindingClient.async_requests[i].canceled = true;
+ return true;
+ }
+ }
+
+ /* It may have returned from the network and be waiting for its callback
+ to be dispatched, so mark it as canceled in the response queue
+ and the response will get discarded before calling the callback. */
+ for(var i in HTTPBindingClient.async_responses) {
+ if(HTTPBindingClient.async_responses[i].requestId == requestId) {
+ HTTPBindingClient.async_responses[i].canceled = true;
+ return true;
+ }
+ }
+
+ return false;
+};
+
+HTTPBindingClient.prototype._makeRequest = function(methodName, args, cb) {
+ var req = {};
+ req.client = this;
+ req.requestId = HTTPBindingClient.requestId++;
+
+ var obj = {};
+ obj.id = req.requestId;
+ if (this.objectID)
+ obj.method = ".obj#" + this.objectID + "." + methodName;
+ else
+ obj.method = methodName;
+ obj.params = args;
+
+ if (cb) req.cb = cb;
+ if (HTTPBindingClient.profile_async)
+ req.profile = { "submit": new Date() };
+ req.data = JSONClient.toJSON(obj);
+
+ return req;
+};
+
+HTTPBindingClient.prototype._sendRequest = function(req) {
+ if(req.profile) req.profile.start = new Date();
+
+ /* Get free http object from the pool */
+ var http = HTTPBindingClient.poolGetHTTPRequest();
+ HTTPBindingClient.num_req_active++;
+
+ /* Send the request */
+ http.open("POST", this.uri, (req.cb != null));
+ http.setRequestHeader("Content-type", "application/json-rpc");
+
+ /* Construct call back if we have one */
+ if(req.cb) {
+ var self = this;
+ http.onreadystatechange = function() {
+ if(http.readyState == 4) {
+ http.onreadystatechange = function () {};
+ var res = { "cb": req.cb, "result": null, "ex": null};
+ if (req.profile) {
+ res.profile = req.profile;
+ res.profile.end = new Date();
+ }
+ try { res.result = self._handleResponse(http); }
+ catch(e) { res.ex = e; }
+ if(!HTTPBindingClient.async_inflight[req.requestId].canceled)
+ HTTPBindingClient.async_responses.push(res);
+ delete HTTPBindingClient.async_inflight[req.requestId];
+ HTTPBindingClient.kick_async();
+ }
+ };
+ } else {
+ http.onreadystatechange = function() {};
+ }
+
+ HTTPBindingClient.async_inflight[req.requestId] = req;
+
+ try {
+ http.send(req.data);
+ } catch(e) {
+ HTTPBindingClient.poolReturnHTTPRequest(http);
+ HTTPBindingClient.num_req_active--;
+ throw new HTTPBindingClient.Exception(HTTPBindingClient.Exception.CODE_ERR_CLIENT, "Connection failed");
+ }
+
+ if(!req.cb) return this._handleResponse(http);
+};
+
+HTTPBindingClient.prototype._handleResponse = function(http) {
+ /* Get the charset */
+ if(!this.charset) {
+ this.charset = HTTPBindingClient._getCharsetFromHeaders(http);
+ }
+
+ /* Get request results */
+ var status, statusText, data;
+ try {
+ status = http.status;
+ statusText = http.statusText;
+ data = http.responseText;
+ } catch(e) {
+ HTTPBindingClient.poolReturnHTTPRequest(http);
+ HTTPBindingClient.num_req_active--;
+ HTTPBindingClient.kick_async();
+ throw new HTTPBindingClient.Exception(HTTPBindingClient.Exception.CODE_ERR_CLIENT, "Connection failed");
+ }
+
+ /* Return http object to the pool; */
+ HTTPBindingClient.poolReturnHTTPRequest(http);
+ HTTPBindingClient.num_req_active--;
+
+ /* Unmarshall the response */
+ if(status != 200) {
+ throw new HTTPBindingClient.Exception(status, statusText);
+ }
+ var obj;
+ try {
+ eval("obj = " + data);
+ } catch(e) {
+ throw new HTTPBindingClient.Exception(550, "error parsing result");
+ }
+ if(obj.error)
+ throw new HTTPBindingClient.Exception(obj.error.code, obj.error.msg, obj.error.trace);
+ var res = obj.result;
+
+ /* Handle CallableProxy */
+ if(res && res.objectID && res.JSONRPCType == "CallableReference")
+ return new HTTPBindingClient(this.uri, res.objectID);
+
+ return res;
+};
+
+
+/**
+ * XMLHttpRequest wrapper code
+ */
+HTTPBindingClient.http_spare = [];
+HTTPBindingClient.http_max_spare = 8;
+
+HTTPBindingClient.poolGetHTTPRequest = function() {
+ if(HTTPBindingClient.http_spare.length > 0) {
+ return HTTPBindingClient.http_spare.pop();
+ }
+ return HTTPBindingClient.getHTTPRequest();
+};
+
+HTTPBindingClient.poolReturnHTTPRequest = function(http) {
+ if(HTTPBindingClient.http_spare.length >= HTTPBindingClient.http_max_spare)
+ delete http;
+ else
+ HTTPBindingClient.http_spare.push(http);
+};
+
+HTTPBindingClient.msxmlNames = [ "MSXML2.XMLHTTP.5.0",
+ "MSXML2.XMLHTTP.4.0",
+ "MSXML2.XMLHTTP.3.0",
+ "MSXML2.XMLHTTP",
+ "Microsoft.XMLHTTP" ];
+
+HTTPBindingClient.getHTTPRequest = function() {
+ /* Mozilla XMLHttpRequest */
+ try {
+ HTTPBindingClient.httpObjectName = "XMLHttpRequest";
+ return new XMLHttpRequest();
+ } catch(e) {}
+
+ /* Microsoft MSXML ActiveX */
+ for (var i=0; i < HTTPBindingClient.msxmlNames.length; i++) {
+ try {
+ HTTPBindingClient.httpObjectName = HTTPBindingClient.msxmlNames[i];
+ return new ActiveXObject(HTTPBindingClient.msxmlNames[i]);
+ } catch (e) {}
+ }
+
+ /* None found */
+ HTTPBindingClient.httpObjectName = null;
+ throw new HTTPBindingClient.Exception(0, "Can't create XMLHttpRequest object");
+};
+
+
+HTTPBindingClient.prototype.get = function(id, responseFunction) {
+ var xhr = HTTPBindingClient.getHTTPRequest();
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState == 4) {
+ if (xhr.status == 200) {
+ var strDocument = xhr.responseText;
+ var xmlDocument = xhr.responseXML;
+ if(!xmlDocument || xmlDocument.childNodes.length==0){
+ xmlDocument = (new DOMParser()).parseFromString(strDocument, "text/xml");
+ }
+ if (responseFunction != null) responseFunction(xmlDocument);
+ } else {
+ alert("get - Error getting data from the server");
+ }
+ }
+ }
+ xhr.open("GET", this.uri + '/' + id, true);
+ xhr.send(null);
+};
+
+HTTPBindingClient.prototype.post = function (entry, responseFunction) {
+ var xhr = HTTPBindingClient.getHTTPRequest();
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState == 4) {
+ if (xhr.status == 201) {
+ var strDocument = xhr.responseText;
+ var xmlDocument = xhr.responseXML;
+ if(!xmlDocument || xmlDocument.childNodes.length==0){
+ xmlDocument = (new DOMParser()).parseFromString(strDocument, "text/xml");
+ }
+ if (responseFunction != null) responseFunction(xmlDocument);
+ } else {
+ alert("post - Error getting data from the server");
+ }
+ }
+ }
+ xhr.open("POST", this.uri, true);
+ xhr.setRequestHeader("Content-Type", "application/atom+xml;type=entry");
+ xhr.send(entry);
+};
+
+HTTPBindingClient.prototype.put = function (id, entry, responseFunction) {
+ var xhr = HTTPBindingClient.getHTTPRequest();
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState == 4) {
+ if (xhr.status == 200) {
+ var strDocument = xhr.responseText;
+ var xmlDocument = xhr.responseXML;
+ if(!xmlDocument || xmlDocument.childNodes.length==0){
+ xmlDocument = (new DOMParser()).parseFromString(strDocument, "text/xml");
+ }
+ if (responseFunction != null) responseFunction(xmlDocument);
+ } else {
+ alert("put - Error getting data from the server");
+ }
+ }
+ }
+ xhr.open("PUT", this.uri + '/' + id, true);
+ xhr.setRequestHeader("Content-Type", "application/atom+xml;type=entry");
+ xhr.send(entry);
+};
+
+HTTPBindingClient.prototype.del = function (id, responseFunction) {
+ var xhr = HTTPBindingClient.getHTTPRequest();
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState == 4) {
+ if (xhr.status == 200) {
+ if (responseFunction != null) responseFunction();
+ } else {
+ alert("delete - Error getting data from the server");
+ }
+ }
+ }
+ xhr.open("DELETE", this.uri + '/' + id, true);
+ xhr.send(null);
+};
+
+/**
+ * Public API.
+ */
+
+var sca = new Object();
+
+/**
+ * Return a component.
+ */
+sca.component = function(name) {
+ function ClientComponent(name) {
+ this.name = name;
+ }
+
+ return new ClientComponent(name);
+};
+
+/**
+ * Return a reference proxy.
+ */
+sca.reference = function(comp, name) {
+ return new HTTPBindingClient(comp.name, name);
+};
+
+/**
+ * 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/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/elemutil.js b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/elemutil.js
new file mode 100644
index 0000000000..00baab06c8
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/elemutil.js
@@ -0,0 +1,231 @@
+/*
+ * 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) {
+ if (!isList(v) || isNil(v) || car(v) != element)
+ return false;
+ return true;
+}
+
+/**
+ * Return true if a value is an attribute.
+ */
+function isAttribute(v) {
+ if (!isList(v) || isNil(v) || car(v) != attribute)
+ return false;
+ return true;
+}
+
+/**
+ * Return the name of an attribute.
+ */
+function attributeName(l) {
+ return cadr(l);
+}
+
+/**
+ * Return the value of an attribute.
+ */
+function attributeValue(l) {
+ return caddr(l);
+}
+
+/**
+ * Return the name of an element.
+ */
+function elementName(l) {
+ return cadr(l);
+}
+
+/**
+ * Return true if an element has children.
+ */
+function elementHasChildren(l) {
+ return !isNil(cddr(l));
+}
+
+/**
+ * Return the children of an element.
+ */
+function elementChildren(l) {
+ return cddr(l);
+}
+
+
+/**
+ * Return true if an element has a value.
+ */
+function elementHasValue(l) {
+ r = reverse(l);
+ if (isSymbol(car(r)))
+ return false;
+ if (isList(car(r)) && !isNil(car(r)) && isSymbol(car(car(r))))
+ return false;
+ return true;
+}
+
+/**
+ * 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) {
+ if (!isList(v))
+ return false;
+ if (isNil(v))
+ return false;
+ if (!isSymbol(car(v)))
+ return false;
+ return true;
+}
+
+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(1), 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 value of the attribute with the given name.
+ */
+function namedAttributeValue(name, l) {
+ var f = filter(function(v) { return isAttribute(v) && attributeName(v) == name; }, l);
+ if (isNil(f))
+ return null;
+ return caddr(car(f));
+}
+
+/**
+ * Return child elements with the given name.
+ */
+function namedElementChildren(name, l) {
+ 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);
+}
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/graph.js b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/graph.js
new file mode 100644
index 0000000000..883b3aa801
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/graph.js
@@ -0,0 +1,638 @@
+/*
+ * 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.
+ */
+
+/**
+ * SVG and VML component rendering functions.
+ */
+
+var graph = new Object();
+
+/**
+ * Detect browser VML support.
+ */
+graph.supportsVML = function() {
+ if (typeof graph.supportsVML.supported != 'undefined')
+ return graph.supportsVML.supported;
+ graph.supportsVML.supported = navigator.appName == 'Microsoft Internet Explorer';
+ return graph.supportsVML.supported;
+};
+
+/**
+ * Detect browser SVG support.
+ */
+graph.supportsSVG = function() {
+ if (typeof graph.supportsSVG.supported != 'undefined')
+ return graph.supportsSVG.supported;
+ graph.supportsSVG.supported = navigator.appName != 'Microsoft Internet Explorer';
+ return graph.supportsSVG.supported;
+};
+
+/**
+ * Basic colors
+ */
+graph.red = 'red';
+graph.green = 'green';
+graph.blue = 'blue';
+graph.yellow = 'yellow';
+graph.orange = '#ffa500';
+graph.gray = 'gray'
+
+/**
+ * Base path class.
+ */
+graph.BasePath = function() {
+ this.path = '';
+ this.x = 0;
+ this.y = 0;
+
+ this.pos = function(x, y) {
+ this.x = x;
+ this.y = y;
+ return this;
+ };
+
+ this.xpos = function() {
+ return this.x;
+ };
+
+ this.ypos = function() {
+ return this.y;
+ };
+
+ this.rmove = function(x, y) {
+ return this.move(this.x + x, this.y + y);
+ };
+
+ this.rline = function(x, y) {
+ return this.line(this.x + x, this.y + y);
+ };
+
+ this.rcurve = function(x1, y1, x, y) {
+ return this.curve(this.x + x1, this.y + y1, this.x + x1 + x, this.y + y1 + y);
+ };
+
+ this.str = function() {
+ return this.path;
+ };
+};
+
+/**
+ * Rendering functions that work both with VML and SVG.
+ */
+var graph;
+
+/**
+ * VML rendering.
+ */
+if (graph.supportsVML()) {
+
+ graph.vmlns='urn:schemas-microsoft-com:vml';
+ document.write('<xml:namespace ns="urn:schemas-microsoft-com:vml" prefix="v" />');
+
+ /**
+ * Make a graph.
+ */
+ graph.mkgraph = function() {
+ var div = document.createElement('div');
+ div.id = 'vmldiv';
+ document.body.appendChild(div);
+
+ var vmlg = document.createElement('v:group');
+ vmlg.style.width = 500;
+ vmlg.style.height = 500;
+ vmlg.coordsize = '500,500';
+ div.appendChild(vmlg);
+
+ graph.dragging = null;
+
+ function draggable(n) {
+ if (n == vmlg)
+ return null;
+ if (n.nodeName == 'group')
+ return n;
+ return draggable(n.parentNode);
+ }
+
+ vmlg.onmousedown = function() {
+ window.event.returnValue = false;
+ graph.dragging = draggable(window.event.srcElement);
+ if (graph.dragging == null)
+ return false;
+ graph.dragging.parentNode.appendChild(graph.dragging);
+ graph.dragX = window.event.clientX;
+ graph.dragY = window.event.clientY;
+ vmlg.setCapture();
+ return false;
+ };
+
+ vmlg.onmouseup = function() {
+ if (graph.dragging == null)
+ return false;
+ graph.dragging = null;
+ vmlg.releaseCapture();
+ return false;
+ };
+
+ vmlg.onmousemove = function() {
+ if (graph.dragging == null)
+ return false;
+ var origX = graph.dragging.coordorigin.X;
+ var origY = graph.dragging.coordorigin.Y;
+ var newX = origX - (window.event.clientX - graph.dragX);
+ var newY = origY - (window.event.clientY - graph.dragY);
+ graph.dragX = window.event.clientX;
+ graph.dragY = window.event.clientY;
+ graph.dragging.setAttribute('coordorigin', newX + ' ' + newY);
+ return false;
+ };
+
+ graph.textWidthDiv = document.createElement('span');
+ graph.textWidthDiv.style.visibility = 'hidden'
+ div.appendChild(graph.textWidthDiv);
+
+ return vmlg;
+ };
+
+ /**
+ * Make a shape path.
+ */
+ graph.mkpath = function() {
+ function Path() {
+ this.BasePath = graph.BasePath;
+ this.BasePath();
+
+ this.move = function(x, y) {
+ this.path += 'M ' + x + ',' + y + ' ';
+ return this.pos(x, y);
+ };
+
+ this.line = function(x, y) {
+ this.path += 'L ' + x + ',' + y + ' ';
+ return this.pos(x, y);
+ };
+
+ this.curve = function(x1, y1, x, y) {
+ this.path += 'QB ' + x1 + ',' + y1 + ',' + x + ',' + y + ' ';
+ return this.pos(x, y);
+ };
+
+ this.end = function() {
+ this.path += 'X E';
+ return this;
+ };
+ }
+
+ return new Path();
+ };
+
+ /**
+ * Make a title element.
+ */
+ graph.mktitle = function(t) {
+ var title = document.createElement('v:textbox');
+ title.style.left = '25';
+ title.style.top = '5';
+ title.style.position = 'absolute';
+ var tnode = document.createTextNode(t);
+ title.appendChild(tnode);
+ return title;
+ };
+
+ /**
+ * Return the width of a title.
+ */
+ graph.titlewidth = function(t) {
+ graph.textWidthDiv.innerHTML = t;
+ var twidth = graph.textWidthDiv.offsetWidth;
+ graph.textWidthDiv.innerHTML = '';
+ return twidth;
+ };
+
+ /**
+ * Make a component shape.
+ */
+ graph.mkcompshape = function(comp, cassoc) {
+ var name = scdl.name(comp);
+ var title = graph.mktitle(name);
+
+ var d = graph.mkcomppath(comp, cassoc).str();
+
+ var shape = document.createElement('v:shape');
+ shape.style.width = 500;
+ shape.style.height = 500;
+ shape.coordsize = '500,500';
+ shape.path = d;
+ shape.fillcolor = graph.color(comp);
+ shape.stroked = 'false';
+
+ var contour = document.createElement('v:shape');
+ contour.style.width = 500;
+ contour.style.height = 500;
+ contour.coordsize = '500,500';
+ contour.setAttribute('path', d);
+ contour.filled = 'false';
+ contour.strokecolor = graph.gray;
+ contour.strokeweight = '3';
+ contour.style.top = 1;
+ contour.style.left = 1;
+ var stroke = document.createElement('v:stroke');
+ stroke.opacity = '20%';
+ contour.appendChild(stroke);
+
+ var g = document.createElement('v:group');
+ g.style.width = 500;
+ g.style.height = 500;
+ g.coordsize = '500,500';
+ g.appendChild(shape);
+ g.appendChild(contour);
+ g.appendChild(title);
+ return g;
+ };
+}
+
+/**
+ * SVG rendering.
+ */
+if (graph.supportsSVG()) {
+
+ graph.svgns='http://www.w3.org/2000/svg';
+
+ /**
+ * Make a graph.
+ */
+ graph.mkgraph = function() {
+ var div = document.createElement('div');
+ div.id = 'svgdiv';
+ document.body.appendChild(div);
+
+ var svg = document.createElementNS(graph.svgns, 'svg');
+ svg.style.height = '100%';
+ svg.style.width = '100%';
+ div.appendChild(svg);
+
+ graph.dragging = null;
+
+ function draggable(n) {
+ if (n == svg)
+ return null;
+ if (n.nodeName == 'g')
+ return n;
+ return draggable(n.parentNode);
+ }
+
+ svg.onmousedown = function(e) {
+ if (e.preventDefault)
+ e.preventDefault();
+ else
+ e.returnValue= false;
+ graph.dragging = draggable(e.target);
+ if (graph.dragging == null)
+ return false;
+ graph.dragging.parentNode.appendChild(graph.dragging);
+ var pos = typeof e.touches != "undefined" ? e.touches[0] : e;
+ graph.dragX = pos.clientX;
+ graph.dragY = pos.clientY;
+ return false;
+ };
+
+ svg.ontouchstart = svg.onmousedown;
+
+ svg.onmouseup = function(e) {
+ if (graph.dragging == null)
+ return false;
+ graph.dragging = null;
+ return false;
+ };
+
+ svg.ontouchend = svg.onmouseup;
+
+ svg.onmousemove = function(e) {
+ if (graph.dragging == null)
+ return false;
+ var matrix = graph.dragging.getCTM();
+ var pos = typeof e.touches != "undefined" ? e.touches[0] : e;
+ var newX = Number(matrix.e) + (pos.clientX - graph.dragX);
+ var newY = Number(matrix.f) + (pos.clientY - graph.dragY);
+ graph.dragX = pos.clientX;
+ graph.dragY = pos.clientY;
+ graph.dragging.setAttribute('transform', 'translate(' + newX + ',' + newY + ')');
+ return false;
+ };
+
+ svg.ontouchmove = svg.onmousemove;
+
+ graph.textWidthSvg = document.createElementNS(graph.svgns, 'svg');
+ graph.textWidthSvg.style.visibility = 'hidden';
+ graph.textWidthSvg.style.height = '0px';
+ graph.textWidthSvg.style.width = '0px';
+ div.appendChild(graph.textWidthSvg);
+
+ return svg;
+ };
+
+ /**
+ * Make a shape path.
+ */
+ graph.mkpath = function() {
+ function Path() {
+ this.BasePath = graph.BasePath;
+ this.BasePath();
+
+ this.move = function(x, y) {
+ this.path += 'M' + x + ',' + y + ' ';
+ return this.pos(x, y);
+ };
+
+ this.line = function(x, y) {
+ this.path += 'L' + x + ',' + y + ' ';
+ return this.pos(x, y);
+ };
+
+ this.curve = function(x1, y1, x, y) {
+ this.path += 'Q' + x1 + ',' + y1 + ' ' + x + ',' + y + ' ';
+ return this.pos(x, y);
+ };
+
+ this.end = function() {
+ this.path += 'Z';
+ return this;
+ };
+ }
+
+ return new Path();
+ };
+
+ /**
+ * Make a title element.
+ */
+ graph.mktitle = function(t) {
+ var title = document.createElementNS(graph.svgns, 'text');
+ title.setAttribute('text-anchor', 'start');
+ title.setAttribute('x', 5);
+ title.setAttribute('y', 15);
+ title.appendChild(document.createTextNode(t));
+ graph.textWidthSvg.appendChild(title);
+ return title;
+ };
+
+ /**
+ * Return a width of a title.
+ */
+ graph.titlewidth = function(t) {
+ var title = graph.mktitle(t);
+ var width = title.getBBox().width;
+ graph.textWidthSvg.removeChild(title);
+ return width;
+ };
+
+ /**
+ * Make a component shape.
+ */
+ graph.mkcompshape = function(comp, cassoc) {
+ var name = scdl.name(comp);
+ var title = graph.mktitle(name);
+
+ var d = graph.mkcomppath(comp, cassoc).str();
+
+ var shape = document.createElementNS(graph.svgns, 'path');
+ shape.setAttribute('d', d);
+ shape.setAttribute('fill', graph.color(comp));
+
+ var contour = document.createElementNS(graph.svgns, 'path');
+ contour.setAttribute('d', d);
+ contour.setAttribute('fill', 'none');
+ contour.setAttribute('stroke', graph.gray);
+ contour.setAttribute('stroke-width', '4');
+ contour.setAttribute('stroke-opacity', '0.20');
+ contour.setAttribute('transform', 'translate(1,1)');
+
+ var g = document.createElementNS(graph.svgns, 'g');
+ g.appendChild(shape);
+ g.appendChild(contour);
+ g.appendChild(title);
+ return g;
+ };
+}
+
+/**
+ * Make a reference shape path, positioned to the right of a component shape.
+ */
+graph.mkrrefpath = function(ref, cassoc, path) {
+ var height = graph.refheight(ref, cassoc);
+ var ypos = path.ypos();
+ return path.rline(0,10).rline(0,10).rcurve(0,5,-5,0).rcurve(-5,0,0,-5).rcurve(0,-5,-5,0).rcurve(-5,0,0,5).rline(0,20).rcurve(0,5,5,0).rcurve(5,0,0,-5).rcurve(0,-5,5,0).rcurve(5,0,0,5).line(path.xpos(),ypos + height);
+};
+
+/**
+ * Make a reference shape path, positioned at the bottom of a component shape.
+ */
+graph.mkbrefpath = function(ref, cassoc, path) {
+ var width = graph.refwidth(ref, cassoc);
+ var xpos = path.xpos();
+ return path.line(xpos - width + 60,path.ypos()).rline(-10,0).rline(-10,0).rcurve(-5,0,0,-5).rcurve(0,-5,5,0).rcurve(5,0,0,-5).rcurve(0,-5,-5,0).rline(-20,0).rcurve(-5,0,0,5).rcurve(0,5,5,0).rcurve(5,0,0,5).rcurve(0,5,-5,0).line(xpos - width,path.ypos());
+};
+
+/**
+ * Make a service shape path, positioned to the left of a component shape.
+ */
+graph.mklsvcpath = function(svc, path) {
+ var height = 60;
+ var ypos = path.ypos();
+ return path.rline(0,-10).rline(0, -10).rcurve(0,-5,-5,0).rcurve(-5,0,0,5).rcurve(0,5,-5,0).rcurve(-5,0,0,-5).rline(0,-20).rcurve(0,-5,5,0).rcurve(5,0,0,5).rcurve(0,5,5,0).rcurve(5,0,0,-5).line(path.xpos(), ypos - height);
+};
+
+/**
+ * Make a service shape path, positioned at the top of a component shape.
+ */
+graph.mktsvcpath = function(svc, path) {
+ var width = 60;
+ var xpos = path.xpos();
+ return path.rline(10,0).rline(10,0).rcurve(5,0,0,-5).rcurve(0,-5,-5,0).rcurve(-5,0,0,-5).rcurve(0,-5,5,0).rline(20,0).rcurve(5,0,0,5).rcurve(0,5,-5,0).rcurve(-5,0,0,5).rcurve(0,5,5,0).line(xpos + width,path.ypos());
+};
+
+
+/**
+ * Return the services and references of a component.
+ */
+graph.tsvcs = function(comp) {
+ return filter(function(s) { return scdl.align(s) == 'top'; }, scdl.services(comp));
+};
+
+graph.lsvcs = function(comp) {
+ return filter(function(s) { var a = scdl.align(s); return a == null || a == 'left'; }, scdl.services(comp));
+};
+
+graph.brefs = function(comp) {
+ return filter(function(r) { return scdl.align(r) == 'bottom'; }, scdl.references(comp));
+};
+
+graph.rrefs = function(comp) {
+ return filter(function(r) { var a = scdl.align(r); return a == null || a == 'right'; }, scdl.references(comp));
+};
+
+/**
+ * Return the color of a component.
+ */
+graph.color = function(comp) {
+ var c = scdl.color(comp);
+ return c == null? graph.blue : c;
+}
+
+/**
+ * Return the height of a reference.
+ */
+graph.refheight = function(ref, cassoc) {
+ var target = assoc(scdl.target(ref), cassoc);
+ if (isNil(target))
+ return 60;
+ return graph.compheight(cadr(target), cassoc);
+}
+
+/**
+ * Return the total height of a list of references.
+ */
+graph.refsheight = function(refs, cassoc) {
+ if (isNil(refs))
+ return 0;
+ return graph.refheight(car(refs), cassoc) + graph.refsheight(cdr(refs), cassoc);
+}
+
+/**
+ * Return the height of a component.
+ */
+graph.compheight = function(comp, cassoc) {
+ var lsvcs = graph.lsvcs(comp);
+ var lsvcsh = Math.max(1, length(lsvcs)) * 60 + 20;
+ var rrefs = graph.rrefs(comp);
+ var rrefsh = graph.refsheight(rrefs, cassoc) + 20;
+ var height = Math.max(lsvcsh, rrefsh);
+ return height;
+};
+
+/**
+ * Return the width of a reference.
+ */
+graph.refwidth = function(ref, cassoc) {
+ var target = assoc(scdl.target(ref), cassoc);
+ if (isNil(target))
+ return 60;
+ return graph.compwidth(cadr(target), cassoc);
+}
+
+/**
+ * Return the total width of a list of references.
+ */
+graph.refswidth = function(refs, cassoc) {
+ if (isNil(refs))
+ return 0;
+ return graph.refwidth(car(refs), cassoc) + graph.refswidth(cdr(refs), cassoc);
+}
+
+/**
+ * Return the width of a component.
+ */
+graph.compwidth = function(comp, cassoc) {
+ var twidth = graph.titlewidth(scdl.name(comp)) + 20;
+ var tsvcs = graph.tsvcs(comp);
+ var tsvcsw = Math.max(1, length(tsvcs)) * 60 + 20;
+ var brefs = graph.brefs(comp);
+ var brefsw = graph.refswidth(brefs, cassoc) + 20;
+ var width = Math.max(twidth, Math.max(tsvcsw, brefsw));
+ return width;
+};
+
+/**
+* Make a component shape path.
+*/
+graph.mkcomppath = function(comp, cassoc) {
+ var tsvcs = graph.tsvcs(comp);
+ var lsvcs = graph.lsvcs(comp);
+ var brefs = graph.brefs(comp);
+ var rrefs = graph.rrefs(comp);
+
+ var height = graph.compheight(comp, cassoc);
+ var width = graph.compwidth(comp, cassoc);
+
+ var path = graph.mkpath().move(10,0);
+ for (var s = 0; s < length(tsvcs); s++)
+ path = graph.mktsvcpath(tsvcs[s], path);
+
+ path = path.line(width - 10,path.ypos()).rcurve(10,0,0,10);
+ for (var r = 0; r < length(rrefs); r++)
+ path = graph.mkrrefpath(rrefs[r], cassoc, path);
+
+ var boffset = 10 + graph.refswidth(brefs, cassoc);
+ path = path.line(path.xpos(),height - 10).rcurve(0,10,-10,0).line(boffset, path.ypos());
+ for (var r = 0; r < length(brefs); r++)
+ path = graph.mkbrefpath(brefs[r], cassoc, path);
+
+ var loffset = 10 + (length(lsvcs) * 60);
+ path = path.line(10,path.ypos()).rcurve(-10,0,0,-10).line(path.xpos(), loffset);
+ for (var s = 0; s < length(lsvcs); s++)
+ path = graph.mklsvcpath(lsvcs[s], path);
+
+ path = path.line(0,10).rcurve(0,-10,10,0);
+ return path.end();
+};
+
+/**
+ * Render a component.
+ */
+graph.component = function(comp, cassoc) {
+ return graph.mkcompshape(comp, cassoc);
+};
+
+/**
+ * Render a composite.
+ */
+graph.composite = function(compos) {
+ var name = scdl.name(compos);
+ var comps = scdl.components(compos);
+ var cassoc = scdl.nameToElementAssoc(comps);
+
+ function renderReference(ref, cassoc) {
+ var target = assoc(scdl.target(ref), cassoc);
+ if (isNil(target))
+ return mklist();
+ return renderComponent(cadr(target), cassoc);
+ }
+
+ function renderReferences(refs, cassoc) {
+ if (isNil(refs))
+ return mklist();
+ var rref = renderReference(car(refs), cassoc);
+ if (isNil(rref))
+ return renderReferences(cdr(refs), cassoc);
+ return append(rref, renderReferences(cdr(refs), cassoc));
+ }
+
+ function renderComponent(comp, cassoc) {
+ return append(renderReferences(scdl.references(comp), cassoc), mklist(graph.component(comp, cassoc)));
+ }
+
+ function renderComponents(comps, cassoc) {
+ if (isNil(comps))
+ return mklist();
+ return append(renderComponent(car(comps), cassoc), renderComponents(cdr(comps), cassoc));
+ }
+
+ var rcomps = renderComponents(comps, cassoc);
+ return rcomps;
+};
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/scdl.js b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/scdl.js
new file mode 100644
index 0000000000..baba0078fe
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/scdl.js
@@ -0,0 +1,163 @@
+/*
+ * 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 = new Object();
+
+/**
+ * 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 the name of a component, service or reference.
+ */
+scdl.name = function(l) {
+ return namedAttributeValue("'name", l);
+};
+
+/**
+ * Returns the color of a component.
+ */
+scdl.color = function(l) {
+ return namedAttributeValue("'color", 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 an 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 a list of services in a component.
+ */
+scdl.services = function(l) {
+ return namedElementChildren("'service", l);
+};
+
+/**
+ * Returns a list of references in a component.
+ */
+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 = 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.
+ */
+scdl.properties = function(l) {
+ return namedElementChildren("'property", l);
+};
+
+/**
+ * Returns the value of a property.
+ */
+scdl.propertyValue = function(l) {
+ 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/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/ui.css b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/ui.css
new file mode 100644
index 0000000000..d1413018a0
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/ui.css
@@ -0,0 +1,121 @@
+/*
+ * 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 {
+white-space: margin: 0px;
+font-family: arial,sans-serif; font-style: normal; font-variant: normal; font-size: 13px;
+}
+
+table {
+border: 1px; border-collapse: separate;
+font-family: arial,sans-serif; font-style: normal; font-variant: normal; font-size: 13px;
+}
+
+th {
+font-weight: bold; background-color: #e5ecf9; color: #598edd;
+text-align: left; padding-left: 2px; padding-right: 8px; padding-top: 2px; padding-bottom: 2px; vertical-align: text-top;
+border-top: 1px; border-bottom: 1px; border-left: 0px; border-right: 0px;
+border-style: solid; border-top-color: #a2bae7; border-bottom-color: #d1d3d4;
+}
+
+td {
+padding-left: 2px; padding-top: 2px; padding-right: 8px; vertical-align: text-top;
+}
+
+iframe {
+visibility: hidden; width: 0px; height: 0px;
+}
+
+input {
+vertical-align: middle;
+-webkit-text-size-adjust: 140%;
+}
+
+a:link {
+color: blue;
+}
+
+a:visited {
+color: blue;
+}
+
+.tdw {
+padding-left: 2px; padding-top: 2px; padding-right: 8px; white-space: normal; vertical-align: text-top;
+}
+
+.hd1 {
+font-size: 150%; font-weight: bold;
+}
+
+.hd2 {
+font-weight: bold;
+}
+
+.imgbutton {
+width: 142px; height: 64px; margin-left: 20px; margin-right: 20px; padding: 0px; border: 1px;
+cursor: pointer; cursor: hand;
+}
+
+.tbar {
+margin: 0px;
+padding-top: 0px; padding-left: 0px; padding-right: 0px; padding-bottom: 3px;
+border-bottom: 1px solid #a2bae7;
+}
+
+.ltbar {
+padding-left: 0px; padding-top: 0px; padding-right: 8px; white-space: nowrap; vertical-align: top;
+}
+
+.rtbar {
+padding-left: 8px; padding-right: 0px; padding-top: 0px; white-space: nowrap; vertical-align: top;
+text-align: right;
+}
+
+.suggest {
+background-color: #e5ecf9; color: #598edd;
+border-top: 1px; border-bottom: 1px; border-left: 1px; border-right: 1px;
+border-style: solid; border-top-color: #a2bae7; border-bottom-color: #d1d3d4;
+border-left-color: #d1d3d4; border-right-color: #d1d3d4;
+position: absolute;
+overflow: auto; overflow-x: hidden;
+cursor: default;
+padding: 0px; margin: 0px;
+}
+
+.suggestTable {
+border: 0px; border-collapse: separate;
+padding-left: 5px; padding-right: 5px; padding-top: 2px; padding-bottom: 2px;
+margin: 0px;
+}
+
+.suggestItem {
+padding-left: 2px; padding-top: 0px; padding-bottom: 0px; padding-right: 2px; vertical-align: text-top;
+background-color: #e5ecf9; color: #598edd;
+}
+
+.suggestHilighted {
+padding-left: 2px; padding-top: 0px; padding-bottom: 0px; padding-right: 2px; vertical-align: text-top;
+background-color: #598edd; color: #e5ecf9;
+}
+
+v\: * {
+behavior:url(#default#VML);
+display:inline-block;
+}
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/ui.js b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/ui.js
new file mode 100644
index 0000000000..fcd61571d1
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/ui.js
@@ -0,0 +1,233 @@
+/*
+ * 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 = new Object();
+
+/**
+ * Build a menu bar.
+ */
+ui.menu = function(name, href) {
+ function Menu(n, h) {
+ this.name = n;
+ this.href = h;
+
+ this.content = function() {
+ function complete(uri) {
+ if (uri.match('.*\.html$'))
+ return uri;
+ if (uri.match('.*/$'))
+ return uri + 'index.html';
+ return uri + '/index.html';
+ }
+
+ if (complete(this.href) != complete(window.top.location.pathname))
+ return '<a href="' + this.href + '" target="_parent">' + this.name + '</a>';
+ return '<span><b>' + this.name + '</b></span>';
+ };
+ }
+ return new Menu(name, href);
+};
+
+ui.menubar = function(left, right) {
+ var bar = '<table cellpadding="0" cellspacing="0" width="100%" class=tbar><tr>' +
+ '<td class=ltbar><table border="0" cellspacing="0" cellpadding="0"><tr>';
+ for (i in left)
+ bar = bar + '<td class=ltbar>' + left[i].content() + '</td>'
+
+ bar = bar + '</tr></table></td>' +
+ '<td class=rtbar><table border="0" cellpadding="0" cellspacing="0" align="right"><tr>';
+ for (i in right)
+ bar = bar + '<td class=rtbar>' + right[i].content() + '</td>'
+
+ bar = bar + '</tr></table></td></tr></table>';
+ return bar;
+};
+
+/**
+ * Autocomplete / suggest support for input fields
+ * To use it declare a 'suggest' function as follows:
+ * function suggestItems() {
+ * return new Array('abc', 'def', 'ghi');
+ * }
+ * then hook it to an input field as follows:
+ * suggest(document.yourForm.yourInputField, suggestItems);
+ */
+ui.selectSuggestion = function(node, value) {
+ for (;;) {
+ node = node.parentNode;
+ if (node.tagName.toLowerCase() == 'div')
+ break;
+ }
+ node.selectSuggestion(value);
+};
+
+ui.hilightSuggestion = function(node, over) {
+ if (over)
+ node.className = 'suggestHilighted';
+ node.className = 'suggestItem';
+};
+
+ui.suggest = function(input, suggestFunction) {
+ input.suggest = suggestFunction;
+
+ input.selectSuggestion = function(value) {
+ this.hideSuggestDiv();
+ this.value = value;
+ }
+
+ input.hideSuggestDiv = function() {
+ if (this.suggestDiv != null) {
+ this.suggestDiv.style.visibility = 'hidden';
+ }
+ }
+
+ input.showSuggestDiv = function() {
+ if (this.suggestDiv == null) {
+ this.suggestDiv = document.createElement('div');
+ this.suggestDiv.input = this;
+ this.suggestDiv.className = 'suggest';
+ input.parentNode.insertBefore(this.suggestDiv, input);
+ this.suggestDiv.style.visibility = 'hidden';
+ this.suggestDiv.style.zIndex = '99';
+
+ this.suggestDiv.selectSuggestion = function(value) {
+ this.input.selectSuggestion(value);
+ }
+ }
+
+ var values = this.suggest();
+ var items = '';
+ for (var i = 0; i < values.length; i++) {
+ if (values[i].indexOf(this.value) == -1)
+ continue;
+ if (items.length == 0)
+ items += '<table class=suggestTable>';
+ items += '<tr><td class="suggestItem" ' +
+ 'onmouseover="ui.hilightSuggestion(this, true)" onmouseout="ui.hilightSuggestion(this, false)" ' +
+ 'onmousedown="ui.selectSuggestion(this, \'' + values[i] + '\')">' + values[i] + '</td></tr>';
+ }
+ if (items.length != 0)
+ items += '</table>';
+ this.suggestDiv.innerHTML = items;
+
+ if (items.length != 0) {
+ var node = input;
+ var left = 0;
+ var top = 0;
+ for (;;) {
+ left += node.offsetLeft;
+ top += node.offsetTop;
+ node = node.offsetParent;
+ if (node.tagName.toLowerCase() == 'body')
+ break;
+ }
+ this.suggestDiv.style.left = left;
+ this.suggestDiv.style.top = top + input.offsetHeight;
+ this.suggestDiv.style.visibility = 'visible';
+ } else
+ this.suggestDiv.style.visibility = 'hidden';
+ }
+
+ input.onkeydown = function(event) {
+ this.showSuggestDiv();
+ };
+
+ input.onkeyup = function(event) {
+ this.showSuggestDiv();
+ };
+
+ input.onmousedown = function(event) {
+ this.showSuggestDiv();
+ };
+
+ input.onblur = function(event) {
+ setTimeout(function() { input.hideSuggestDiv(); }, 50);
+ };
+};
+
+/**
+ * Return the content document of a window.
+ */
+ui.content = function(win) {
+ if (!isNil(win.document))
+ return win.document;
+ if (!isNil(win.contentDocument))
+ return win.contentDocument;
+ return null;
+};
+
+/**
+ * Return a child element of a node with the given id.
+ */
+ui.elementByID = function(node, id) {
+ 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) {
+ if (!isNil(document.widget))
+ return widget;
+ return document;
+ }
+ return ui.elementByID($(document), id);
+};
+
+/**
+ * Initialize a widget.
+ */
+ui.onloadwidget = function() {
+ if (isNil(window.parent) || isNil(window.parent.ui) || isNil(window.parent.ui.widgets))
+ return true;
+ var pdoc = ui.content(window.parent);
+ for (w in window.parent.ui.widgets) {
+ var ww = ui.elementByID(pdoc, w).contentWindow;
+ if (ww == window) {
+ document.widget = ui.elementByID(pdoc, window.parent.ui.widgets[w]);
+ document.widget.innerHTML = document.body.innerHTML;
+ return true;
+ }
+ }
+ return true;
+};
+
+/**
+ * Load a widget into an element.
+ */
+ui.widgets = new Array();
+
+ui.bindwidget = function(f, el) {
+ window.ui.widgets[f] = el;
+ return f;
+};
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/util.js b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/util.js
new file mode 100644
index 0000000000..0f966b180e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/util.js
@@ -0,0 +1,208 @@
+/*
+ * 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) {
+ return new Array(car).concat(cdr);
+}
+
+function car(l) {
+ return l[0];
+}
+
+function first(l) {
+ return car(l);
+}
+
+function cdr(l) {
+ return l.slice(1);
+}
+
+function rest(l) {
+ return cdr(l);
+}
+
+function cadr(l) {
+ return car(cdr(l));
+}
+
+function cddr(l) {
+ return cdr(cdr(l));
+}
+
+function caddr(l) {
+ return car(cddr(l));
+}
+
+function append(a, b) {
+ return a.concat(b);
+}
+
+function reverse(l) {
+ return l.slice(0).reverse();
+}
+
+function isNil(v) {
+ if (v == null)
+ return true;
+ if ('' + v == 'undefined')
+ return true;
+ try {
+ if (isList(v) && v.length == 0)
+ return true;
+ } catch (e) {}
+ return false;
+}
+
+function isSymbol(v) {
+ if (typeof v == 'string' && v.slice(0, 1) == "'")
+ return true;
+ return false;
+}
+
+function isString(v) {
+ if (typeof v == 'string')
+ return true;
+ return false;
+}
+
+function isList(v) {
+ try {
+ if (v.constructor == Array)
+ return true;
+ } catch (e) {}
+ return false;
+}
+
+function isTaggedList(v, t) {
+ if (isList(v) && !isNil(v) && car(v) == t)
+ return true;
+ return false;
+}
+
+function mklist() {
+ 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 mklist();
+ if (k == car(car(l)))
+ return car(l);
+ return assoc(k, cdr(l));
+}
+
+/**
+ * Map and filter functions.
+ */
+function map(f, l) {
+ if (isNil(l))
+ return l;
+ return cons(f(car(l)), map(f, cdr(l)));
+}
+
+function filter(f, l) {
+ if (isNil(l))
+ return l;
+ if (f(car(l)))
+ return cons(car(l), filter(f, cdr(l)));
+ return filter(f, cdr(l));
+}
+
+/**
+ * Split a path into a list of segments.
+ */
+function tokens(path) {
+ return filter(function(s) { return length(s) != 0; }, path.split("/"));
+}
+
+/**
+ * Log a value.
+ */
+function log(v) {
+ try {
+ console.log(v);
+ } catch (e) {}
+ return true;
+}
+
+/**
+ * Dump an object to the debug console.
+ */
+function debug(o) {
+ try {
+ for (f in o) {
+ try {
+ console.log(f + '=' + o[f]);
+ } catch (e) {}
+ }
+ } catch (e) {}
+ return true;
+}
+
+/**
+ * Write a list of strings.
+ */
+function writeStrings(l) {
+ if (isNil(l))
+ return '';
+ return car(l) + writeStrings(cdr(l));
+}
+
+/**
+ * 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)) + ')';
+}
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/xmlutil.js b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/xmlutil.js
new file mode 100644
index 0000000000..1bec45f9b9
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/js/htdocs/xmlutil.js
@@ -0,0 +1,197 @@
+/*
+ * 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;
+}
+
+/**
+ * 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) {
+ return filter(function(n) { return n.nodeType == 3; }, nodeList(e.childNodes));
+}
+
+/**
+ * Read a list of XML attributes.
+ */
+function readAttributes(a) {
+ if (isNil(a))
+ return a;
+ return cons(mklist(attribute, "'" + car(a).nodeName, car(a).nodeValue), readAttributes(cdr(a)));
+}
+
+/**
+ * Read an XML element.
+ */
+function readElement(e) {
+ var l = append(append(mklist(element, "'" + e.nodeName), readAttributes(childAttributes(e))), readElements(childElements(e)));
+ 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) {
+ if (isNil(l))
+ return l;
+ return cons(readElement(car(l)), readElements(cdr(l)));
+}
+
+/**
+ * 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);
+ if (window.DOMParser) {
+ var p =new DOMParser();
+ return p.parseFromString(s, "text/xml");
+ }
+ var doc;
+ try {
+ doc = new ActiveXObject("MSXML2.DOMDocument");
+ } catch (e) {
+ doc = new ActiveXObject("Microsoft.XMLDOM");
+ }
+ doc.async = 'false';
+ doc.loadXML(s);
+ return doc;
+}
+
+/**
+ * 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)));
+}
+
+/**
+ * Read a list of values from a list of strings representing an XML document.
+ */
+function readXML(l) {
+ return readXMLDocument(parseXML(l));
+}
+
+/**
+ * Make an XML document.
+ */
+/**
+ * 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)) {
+ node.setAttribute(attributeName(token).substring(1), '' + attributeValue(token));
+ } else if (isTaggedList(token, element)) {
+ if (elementHasValue(token)) {
+ var v = elementValue(token);
+ if (isList(v)) {
+ var e = expandElementValues(elementName(token), v);
+ writeList(e, node, doc);
+ } else {
+ var child = doc.createElement(elementName(token).substring(1));
+ writeList(elementChildren(token), child, doc);
+ node.appendChild(child);
+ }
+ } else {
+ var child = doc.createElement(elementName(token).substring(1));
+ writeList(elementChildren(token), child, doc);
+ node.appendChild(child);
+ }
+ } else
+ node.appendChild(doc.createTextNode('' + token));
+ writeList(cdr(l), node, doc);
+ return node;
+}
+
+/**
+ * Convert a list of values to a list of strings representing an XML document.
+ */
+function writeXML(l, xmlTag) {
+ function mkdoc() {
+ if (document.implementation && document.implementation.createDocument)
+ return document.implementation.createDocument('', '', null);
+ return new ActiveXObject("MSXML2.DOMDocument");
+ }
+
+ var doc = mkdoc();
+ writeList(l, doc, doc);
+ if (!xmlTag)
+ return writeXMLDocument(doc);
+ return mklist('<?xml version="1.0" encoding="UTF-8"?>\n' + writeXMLDocument(doc) + '\n');
+}
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/js/js-test.cpp b/sandbox/sebastien/cpp/apr-2/modules/js/js-test.cpp
new file mode 100644
index 0000000000..9cbf000ac3
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/js/js-test.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test JavaScript evaluation functions.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "eval.hpp"
+
+namespace tuscany {
+namespace js {
+
+bool testJSEval() {
+ failable<value> v = evalScript("(function testJSON(n){ return JSON.parse(JSON.stringify(n)) })(5)");
+ assert(hasContent(v));
+ assert(content(v) == value(5));
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::js::testJSEval();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}