| /* |
| * 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; |
| })(); |
| */ |
| |