
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1517415 13f79535-47bb-0310-9956-ffa450edef68
714 lines
15 KiB
JavaScript
714 lines
15 KiB
JavaScript
/*
|
|
* 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 cell(car, cdr) {
|
|
this.car = car;
|
|
this.cdr = cdr;
|
|
}
|
|
|
|
cell.prototype.toString = function() {
|
|
return writeValue(this);
|
|
};
|
|
|
|
function cons(car, cdr) {
|
|
return new cell(car, cdr);
|
|
}
|
|
|
|
var nil = new cell(undefined, null);
|
|
|
|
function mklist() {
|
|
if(arguments.length == 0)
|
|
return nil;
|
|
var l = nil;
|
|
for(var i = arguments.length - 1; i >= 0; i--)
|
|
l = cons(arguments[i], l);
|
|
return l;
|
|
}
|
|
|
|
function mkalist(a) {
|
|
if(a.length == 0)
|
|
return nil;
|
|
var l = nil;
|
|
for(var i = a.length - 1; i >= 0; i--)
|
|
l = cons(a[i], l);
|
|
return l;
|
|
}
|
|
|
|
function car(l) {
|
|
if(l.cdr == null)
|
|
throw new Error('car out of bounds');
|
|
//error('car out of bounds');
|
|
return l.car;
|
|
}
|
|
|
|
function cdr(l) {
|
|
if(l.cdr == null)
|
|
throw new Error('cdr out of bounds');
|
|
//error('cdr out of bounds');
|
|
return l.cdr;
|
|
}
|
|
|
|
function cadr(l) {
|
|
return car(cdr(l));
|
|
}
|
|
|
|
function cddr(l) {
|
|
return cdr(cdr(l));
|
|
}
|
|
|
|
function caddr(l) {
|
|
return car(cdr(cdr(l)));
|
|
}
|
|
|
|
function cdddr(l) {
|
|
return cdr(cdr(cdr(l)));
|
|
}
|
|
|
|
function cadddr(l) {
|
|
return car(cdr(cdr(cdr(l))));
|
|
}
|
|
|
|
function last(l) {
|
|
if(l == nil)
|
|
throw new Error('last out of bounds');
|
|
//error('last out of bounds');
|
|
if(cdr(l) == nil)
|
|
return car(l);
|
|
return last(cdr(l));
|
|
}
|
|
|
|
function append(a, b) {
|
|
if(a == nil)
|
|
return b;
|
|
return cons(car(a), append(cdr(a), b));
|
|
}
|
|
|
|
function reverse(l) {
|
|
function reverseIter(acc, l) {
|
|
if(l == nil)
|
|
return acc;
|
|
return reverseIter(cons(car(l), acc), cdr(l));
|
|
}
|
|
return reverseIter(nil, l);
|
|
}
|
|
|
|
function seq(start, end) {
|
|
if(start == end)
|
|
return mklist(start);
|
|
if(start < end)
|
|
return cons(start, seq(start + 1, end));
|
|
return cons(start, seq(start - 1, end));
|
|
}
|
|
|
|
function isNull(v) {
|
|
return v == nil || v == null || typeof v == 'undefined';
|
|
}
|
|
|
|
function isSymbol(v) {
|
|
return typeof v == 'string' && v[0] == "'";
|
|
}
|
|
|
|
function isString(v) {
|
|
return typeof v == 'string' && v[0] != "'";
|
|
}
|
|
|
|
function isList(v) {
|
|
return v != null && typeof v != 'undefined' && typeof v.cdr != 'undefined';
|
|
}
|
|
|
|
function isTaggedList(v, t) {
|
|
return isList(v) && v != nil && car(v) == t;
|
|
}
|
|
|
|
function mkarray(l) {
|
|
return reduce(function(a, v) {
|
|
a[a.length] = v;
|
|
return a;
|
|
}, [], l);
|
|
}
|
|
|
|
function length(l) {
|
|
function lengthRef(c, l) {
|
|
if(l == nil)
|
|
return c;
|
|
return lengthRef(c + 1, cdr(l));
|
|
}
|
|
return lengthRef(0, l);
|
|
}
|
|
|
|
/**
|
|
* Scheme-like associations.
|
|
*/
|
|
function assoc(k, l) {
|
|
if(l == nil)
|
|
return nil;
|
|
var c = car(l);
|
|
if(isList(c) && c != nil && k == car(c))
|
|
return c;
|
|
return assoc(k, cdr(l));
|
|
}
|
|
|
|
/**
|
|
* Map, filter and reduce functions.
|
|
*/
|
|
function map(f, l) {
|
|
if(l == nil)
|
|
return nil;
|
|
return cons(f(car(l)), map(f, cdr(l)));
|
|
}
|
|
|
|
function filter(f, l) {
|
|
if(l == nil)
|
|
return nil;
|
|
if (f(car(l)))
|
|
return cons(car(l), filter(f, cdr(l)));
|
|
return filter(f, cdr(l));
|
|
}
|
|
|
|
function reduce(f, i, l) {
|
|
function reduceAccumulate(acc, l) {
|
|
if(l == nil)
|
|
return acc;
|
|
return reduceAccumulate(f(acc, car(l)), cdr(l));
|
|
};
|
|
return reduceAccumulate(i, l);
|
|
}
|
|
|
|
/**
|
|
* Sort.
|
|
*/
|
|
function sort(f, l) {
|
|
return mkalist(mkarray(l).sort(f));
|
|
}
|
|
|
|
/**
|
|
* String split, join and tokenize functions.
|
|
*/
|
|
function split(s, d) {
|
|
return mkalist(s.split(d));
|
|
}
|
|
|
|
function join(l, d) {
|
|
return mkarray(l).join(d);
|
|
}
|
|
|
|
function tokens(path) {
|
|
return filter(function(s) { return s.length != 0; }, split(path, '/'));
|
|
}
|
|
|
|
/**
|
|
* Log values to debug log.
|
|
*/
|
|
if(window.debugging == undefined)
|
|
window.debugging = false;
|
|
var remoteLog;
|
|
var bufferedLog;
|
|
|
|
function debug() {
|
|
if (!window.debugging)
|
|
return false;
|
|
var s = '';
|
|
for(var i = 0; i < arguments.length; i++) {
|
|
s += writeValue(arguments[i]);
|
|
if(i < arguments.length)
|
|
s += ' ';
|
|
}
|
|
if(remoteLog)
|
|
remoteLog.log(s);
|
|
if (bufferedLog)
|
|
bufferedLog[bufferedLog.length] = s;
|
|
return console.log(s);
|
|
}
|
|
|
|
function error() {
|
|
var s = '';
|
|
for(var i = 0; i < arguments.length; i++) {
|
|
s += writeValue(arguments[i]);
|
|
var a = arguments[i];
|
|
if(a != null && typeof a == 'object' && typeof a.stack != 'undefined') {
|
|
s += ' ';
|
|
s += writeValue(a.stack);
|
|
}
|
|
if(i < arguments.length)
|
|
s = s + ' ';
|
|
}
|
|
|
|
if(remoteLog)
|
|
remoteLog.error(s);
|
|
if (bufferedLog) {
|
|
try { throw new Error(); } catch(t) { bufferedLog[bufferedLog.length] = writeValue(t.stack); }
|
|
bufferedLog[bufferedLog.length] = s;
|
|
}
|
|
return console.error(s);
|
|
}
|
|
|
|
/**
|
|
* Log uncaught errors.
|
|
*/
|
|
if (typeof window != 'undefined') {
|
|
window.onerror = function(msg, url, line) {
|
|
error('window.onerror', msg, url, line);
|
|
return false;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Buffer log entries in memory.
|
|
*/
|
|
function bufferLog() {
|
|
bufferedLog = [];
|
|
return true;
|
|
}
|
|
|
|
function printLog() {
|
|
if (!bufferedLog)
|
|
return false;
|
|
for(var i in bufferedLog)
|
|
console.log(bufferedLog[i]);
|
|
return true;
|
|
}
|
|
|
|
function clearLog() {
|
|
bufferedLog = [];
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Dump an object to the log.
|
|
*/
|
|
function dump(o) {
|
|
if (!window.debugging)
|
|
return false;
|
|
for(var f in o)
|
|
debug('dump', f, '=', o[f]);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Return true if the current browser is Internet Explorer.
|
|
*/
|
|
function isMSIE() {
|
|
if(typeof isMSIE.detected != 'undefined')
|
|
return isMSIE.detected;
|
|
isMSIE.detected = navigator.userAgent.match(/MSIE/i);
|
|
return isMSIE.detected;
|
|
}
|
|
|
|
/**
|
|
* External build configuration.
|
|
*/
|
|
var config;
|
|
if(isNull(config))
|
|
config = {};
|
|
|
|
/**
|
|
* Assertion.
|
|
*/
|
|
function assert(exp) {
|
|
if(!exp)
|
|
throw new Error('assertion failed');
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Write a list of strings.
|
|
*/
|
|
function writeStrings(l) {
|
|
return reduce(function(a, s) { return a + s; }, '', 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(l == nil)
|
|
return '';
|
|
return ' ' + writeValue(car(l)) + writeList(cdr(l));
|
|
}
|
|
|
|
if(!isList(v))
|
|
return writePrimitive(v);
|
|
if(v == nil)
|
|
return '()';
|
|
return '(' + writeValue(car(v)) + writeList(cdr(v)) + ')';
|
|
}
|
|
|
|
/**
|
|
* Apply a function and memoize its result.
|
|
*/
|
|
function memo(obj, key, f) {
|
|
if(typeof obj.memo == 'undefined') {
|
|
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, prefix) {
|
|
if(!prefix) {
|
|
obj.memo = {};
|
|
return true;
|
|
}
|
|
if(typeof obj.memo == 'undefined') {
|
|
obj.memo = {};
|
|
return true;
|
|
}
|
|
for(var key in obj.memo) {
|
|
if(key.substring(0, prefix.length) == prefix)
|
|
delete obj.memo[key];
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Local storage.
|
|
*/
|
|
var lstorage = {};
|
|
lstorage.enabled = true;
|
|
|
|
/**
|
|
* Get a key.
|
|
*/
|
|
lstorage.key = function(i) {
|
|
if(!lstorage.enabled)
|
|
return undefined;
|
|
return localStorage.key(i);
|
|
};
|
|
|
|
/**
|
|
* Return the number of keys.
|
|
*/
|
|
lstorage.length = function() {
|
|
if(!lstorage.enabled)
|
|
return 0;
|
|
return localStorage.length;
|
|
};
|
|
|
|
/**
|
|
* Get an item.
|
|
*/
|
|
lstorage.getItem = function(k) {
|
|
if(!lstorage.enabled)
|
|
return undefined;
|
|
return localStorage.getItem(k);
|
|
};
|
|
|
|
/**
|
|
* Set an item.
|
|
*/
|
|
lstorage.setItem = function(k, v) {
|
|
if(!lstorage.enabled)
|
|
return v;
|
|
if (localStorage.getItem(k) != v)
|
|
return localStorage.setItem(k, v);
|
|
else
|
|
return v;
|
|
};
|
|
|
|
/**
|
|
* Remove an item.
|
|
*/
|
|
lstorage.removeItem = function(k) {
|
|
if(!lstorage.enabled)
|
|
return undefined;
|
|
return localStorage.removeItem(k);
|
|
};
|
|
|
|
/**
|
|
* Returns a list of the properties of an object.
|
|
*/
|
|
function properties(o) {
|
|
var l = nil;
|
|
for(var p in o)
|
|
l = cons(p, l);
|
|
return reverse(l);
|
|
}
|
|
|
|
/**
|
|
* Convert a DOM node list to a regular list.
|
|
*/
|
|
function nodeList(n) {
|
|
if (n == null || n.length == 0)
|
|
return nil;
|
|
var l = nil;
|
|
for (var i = n.length - 1; i >= 0; i--)
|
|
l = cons(n[i], l);
|
|
return l;
|
|
}
|
|
|
|
/**
|
|
* 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(split(host, '.'));
|
|
var d = (cddr(h) != nil && caddr(h) == 'www')? mklist(car(h), cadr(h), caddr(h)) : mklist(car(h), cadr(h));
|
|
return join(reverse(d), '.');
|
|
}
|
|
|
|
/**
|
|
* Convert a host name to a top domain name.
|
|
*/
|
|
function topDomainName(host) {
|
|
var d = reverse(split(domainName(host),'.'));
|
|
return join(mklist(car(d), cadr(d)), '.');
|
|
}
|
|
|
|
/**
|
|
* Return true if a host name is a subdomain.
|
|
*/
|
|
function isSubDomain(host) {
|
|
return length(split(host, '.')) > 2;
|
|
}
|
|
|
|
/**
|
|
* Clear auth information from the document cookie.
|
|
*/
|
|
function clearAuthCookie() {
|
|
var d = new Date(1970,01,01).toGMTString();
|
|
var dn = domainName(window.location.hostname);
|
|
document.cookie = 'TuscanyOpenAuth=; expires=' + d + '; domain=.' + dn + '; path=/; secure; httponly';
|
|
document.cookie = 'TuscanyOAuth1=; expires=' + d + '; domain=.' + dn + '; path=/; secure; httponly';
|
|
document.cookie = 'TuscanyOAuth2=; expires=' + d + '; domain=.' + dn + '; path=/; secure; httponly';
|
|
document.cookie = 'TuscanyOpenIDAuth=; expires=' + d + '; domain=.' + dn + '; path=/; secure; httponly';
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Format a string like Python format.
|
|
*/
|
|
function format() {
|
|
var i = 0;
|
|
var s = '';
|
|
for(var a = 0; a < arguments.length; a++) {
|
|
s = i == 0? arguments[a] : s.replace('{' + a + '}', arguments[a]);
|
|
i++;
|
|
}
|
|
return s;
|
|
}
|
|
|
|
/**
|
|
* Parse an XML dateTime.
|
|
*/
|
|
function xmlDateTime(xml) {
|
|
var re = /^([0-9]{4,})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})(\.[0-9]+)?(Z|([+-])([0-9]{2}):([0-9]{2}))?$/;
|
|
var match = xml.match(re);
|
|
if(!match)
|
|
return new Date();
|
|
return new Date(Date.UTC(match[1], parseInt(match[2]) - 1, match[3],
|
|
match[9]? parseInt(match[4]) + parseInt(match[10]) * (match[9] == '+'? 1 : -1) : match[4],
|
|
match[9]? parseInt(match[5]) + parseInt(match[11]) * (match[9] == '+'? 1 : -1) : match[5],
|
|
match[6], 0));
|
|
}
|
|
|
|
/**
|
|
* Encode a string to a url-safe base64 format.
|
|
*/
|
|
function safeB64Encode(s) {
|
|
return btoa(s).replace(/\+/g, '-').replace(/\//g, '_').replace(/\=+$/, '');
|
|
}
|
|
|
|
/**
|
|
* Decode a url-safe base64 encoded string.
|
|
*/
|
|
function safeB64Decode(s) {
|
|
return atob((s.replace(/\-/g, '+').replace(/\_/g, '/') + '===').substring(0, s.length + (s.length % 4)));
|
|
}
|
|
|
|
/**
|
|
* Return a uuid4.
|
|
*/
|
|
function uuid4() {
|
|
if(window.crypto && window.crypto.getRandomValues) {
|
|
var b = new Uint16Array(8);
|
|
window.crypto.getRandomValues(b);
|
|
function s4(n) {
|
|
var s = '000' + n.toString(16);
|
|
return s.substr(s.length - 4);
|
|
}
|
|
return s4(b[0]) + s4(b[1]) + '-' + s4(b[2]) + '-' + s4(b[3]) + '-' + s4(b[4]) + '-' + s4(b[5]) + s4(b[6]) + s4(b[7]);
|
|
} else {
|
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
|
var r = Math.random() * 16 | 0
|
|
return (c == 'x'? r : (r & 0x3 | 0x8)).toString(16);
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Convert an hexadecimal string to ascii.
|
|
*/
|
|
function hex2Ascii(x) {
|
|
var a = '';
|
|
for(var i = 0; i < x.length; i += 2)
|
|
a += String.fromCharCode(parseInt(x.substr(i, 2), 16));
|
|
return a;
|
|
}
|
|
|
|
/**
|
|
* Functions with side effects. Use with moderation.
|
|
*/
|
|
|
|
/**
|
|
* Set the car of a list.
|
|
*/
|
|
function setcar(l, v) {
|
|
l.car = v;
|
|
return l;
|
|
}
|
|
|
|
/**
|
|
* Set the cadr of a list.
|
|
*/
|
|
function setcadr(l, v) {
|
|
l.cdr.car = v;
|
|
return l;
|
|
}
|
|
|
|
/**
|
|
* Set the caddr of a list.
|
|
*/
|
|
function setcaddr(l, v) {
|
|
l.cdr.cdr.car = v;
|
|
return l;
|
|
}
|
|
|
|
/**
|
|
* Set the cdr of a list.
|
|
*/
|
|
function setcdr(a, b) {
|
|
a.cdr = b;
|
|
return a;
|
|
}
|
|
|
|
/**
|
|
* Set the contents of a list.
|
|
*/
|
|
function setList(a, b) {
|
|
if(b == a)
|
|
return a;
|
|
a.car = b.car;
|
|
a.cdr = b.cdr;
|
|
return a;
|
|
}
|
|
|
|
/**
|
|
* Append the elements of a list to a list.
|
|
*/
|
|
function setAppend(a, b) {
|
|
if(b.cdr == null)
|
|
return a;
|
|
return setList(a, append(a, b));
|
|
}
|
|
|
|
/**
|
|
* Uncomment to run the tests.
|
|
*/
|
|
/*
|
|
(function testUtil() {
|
|
console.log('Testing...');
|
|
|
|
assert(car(cons(1, nil)) == 1);
|
|
assert(car(mklist(1)) == 1);
|
|
assert(cadr(mklist(1, 2)) == 2);
|
|
|
|
assert(0 == length(nil));
|
|
assert(1 == length(mklist(1)));
|
|
assert(2 == length(cons(1, mklist(2))));
|
|
|
|
assert(car(append(mklist(1), mklist(2))) == 1);
|
|
assert(car(cdr(append(mklist(1), mklist(2)))) == 2);
|
|
assert(car(cdr(cdr(append(mklist(1), mklist(2, 3))))) == 3);
|
|
assert(isNull(cdr(cdr(cdr(append(mklist(1), mklist(2, 3)))))));
|
|
assert(last(mklist(1, 2, 3)) == 3);
|
|
assert('' + mklist(1, 2, 3) == '(1 2 3)');
|
|
|
|
function square(v) { return v * v; }
|
|
assert(isNull(map(square, nil)));
|
|
var m = map(square, mklist(2, 3));
|
|
assert(car(m) == 4);
|
|
assert(car(cdr(m)) == 9);
|
|
|
|
function add(x, y) { return x + y; }
|
|
assert(reduce(add, 0, mklist(1, 2, 3)) == 6);
|
|
|
|
function isPositive(x) { return x >= 0; }
|
|
assert(car(filter(isPositive, mklist(1, -1, 2, -2))) == 1);
|
|
assert(cadr(filter(isPositive, mklist(1, -1, 2, -2))) == 2);
|
|
|
|
assert(isNull(reverse(nil)));
|
|
assert(car(reverse(mklist(1, 2, 3))) == 3);
|
|
assert(cadr(reverse(mklist(1, 2, 3))) == 2);
|
|
|
|
var l = mklist(mklist('x', 'X'), mklist('a', 'A'), mklist('y', 'Y'), mklist('a', 'AA'));
|
|
assert(car(assoc('a', l)) == 'a');
|
|
assert(isNull(assoc('z', l)));
|
|
|
|
var s = seq(0.0, 1000.0);
|
|
assert(1001 == length(s));
|
|
function seqreduce(acc, v) { return acc + 1.0; }
|
|
assert(1001 == reduce(seqreduce, 0.0, s));
|
|
|
|
function compare(a, b) { return a < b? -1 : a == b? 0 : 1; }
|
|
var l2 = sort(compare, mklist(4, 3, 1, 2));
|
|
assert(car(l2) == 1);
|
|
assert(last(l2) == 4);
|
|
|
|
var t = new Date();
|
|
var p = nil;
|
|
for(var i = 0; i < 100000; i++) {
|
|
p = cons(i, p);
|
|
}
|
|
for(var i = 0; i < 100000; i++) {
|
|
var x = car(p);
|
|
p = cdr(p);
|
|
}
|
|
console.log('list perf', new Date() - t, 'ms');
|
|
|
|
console.log('OK');
|
|
return true;
|
|
})();
|
|
*/
|
|
|