diff options
author | Felix Lange <fjl@twurst.com> | 2014-10-23 21:01:27 +0800 |
---|---|---|
committer | Felix Lange <fjl@twurst.com> | 2014-10-23 21:01:27 +0800 |
commit | 69baa465ea69ae60eed802445cf0132b9eb69934 (patch) | |
tree | b09da7582b5c4850d4db13aee808f2fef2f97de0 /cmd/mist/assets/ext | |
parent | 50fd46924900869e7210217c6a07979b544991c8 (diff) | |
parent | feef194829b07570e91873ed5d1e8cc51e8fa430 (diff) | |
download | go-tangerine-69baa465ea69ae60eed802445cf0132b9eb69934.tar go-tangerine-69baa465ea69ae60eed802445cf0132b9eb69934.tar.gz go-tangerine-69baa465ea69ae60eed802445cf0132b9eb69934.tar.bz2 go-tangerine-69baa465ea69ae60eed802445cf0132b9eb69934.tar.lz go-tangerine-69baa465ea69ae60eed802445cf0132b9eb69934.tar.xz go-tangerine-69baa465ea69ae60eed802445cf0132b9eb69934.tar.zst go-tangerine-69baa465ea69ae60eed802445cf0132b9eb69934.zip |
Merge eth-go repository into go-ethereum
mist, etheruem have been moved to cmd/
Diffstat (limited to 'cmd/mist/assets/ext')
-rw-r--r-- | cmd/mist/assets/ext/big.js | 380 | ||||
-rw-r--r-- | cmd/mist/assets/ext/ethereum.js | 295 | ||||
-rw-r--r-- | cmd/mist/assets/ext/filter.js | 49 | ||||
-rw-r--r-- | cmd/mist/assets/ext/home.html | 22 | ||||
-rw-r--r-- | cmd/mist/assets/ext/html_messaging.js | 464 | ||||
-rw-r--r-- | cmd/mist/assets/ext/http.js | 13 | ||||
-rw-r--r-- | cmd/mist/assets/ext/q.js | 1909 | ||||
-rw-r--r-- | cmd/mist/assets/ext/qml_messaging.js | 13 | ||||
-rw-r--r-- | cmd/mist/assets/ext/qt_messaging_adapter.js | 21 | ||||
-rw-r--r-- | cmd/mist/assets/ext/string.js | 58 | ||||
-rw-r--r-- | cmd/mist/assets/ext/test.html | 44 |
11 files changed, 3268 insertions, 0 deletions
diff --git a/cmd/mist/assets/ext/big.js b/cmd/mist/assets/ext/big.js new file mode 100644 index 000000000..db633fd2f --- /dev/null +++ b/cmd/mist/assets/ext/big.js @@ -0,0 +1,380 @@ +var bigInt = (function () { + var base = 10000000, logBase = 7; + var sign = { + positive: false, + negative: true + }; + + var normalize = function (first, second) { + var a = first.value, b = second.value; + var length = a.length > b.length ? a.length : b.length; + for (var i = 0; i < length; i++) { + a[i] = a[i] || 0; + b[i] = b[i] || 0; + } + for (var i = length - 1; i >= 0; i--) { + if (a[i] === 0 && b[i] === 0) { + a.pop(); + b.pop(); + } else break; + } + if (!a.length) a = [0], b = [0]; + first.value = a; + second.value = b; + }; + + var parse = function (text, first) { + if (typeof text === "object") return text; + text += ""; + var s = sign.positive, value = []; + if (text[0] === "-") { + s = sign.negative; + text = text.slice(1); + } + var base = 10; + if (text.slice(0, 2) == "0x") { + base = 16; + text = text.slice(2); + } + else { + var texts = text.split("e"); + if (texts.length > 2) throw new Error("Invalid integer"); + if (texts[1]) { + var exp = texts[1]; + if (exp[0] === "+") exp = exp.slice(1); + exp = parse(exp); + if (exp.lesser(0)) throw new Error("Cannot include negative exponent part for integers"); + while (exp.notEquals(0)) { + texts[0] += "0"; + exp = exp.prev(); + } + } + text = texts[0]; + } + if (text === "-0") text = "0"; + text = text.toUpperCase(); + var isValid = (base == 16 ? /^[0-9A-F]*$/ : /^[0-9]+$/).test(text); + if (!isValid) throw new Error("Invalid integer"); + if (base == 16) { + var val = bigInt(0); + while (text.length) { + v = text.charCodeAt(0) - 48; + if (v > 9) + v -= 7; + text = text.slice(1); + val = val.times(16).plus(v); + } + return val; + } + else { + while (text.length) { + var divider = text.length > logBase ? text.length - logBase : 0; + value.push(+text.slice(divider)); + text = text.slice(0, divider); + } + var val = bigInt(value, s); + if (first) normalize(first, val); + return val; + } + }; + + var goesInto = function (a, b) { + var a = bigInt(a, sign.positive), b = bigInt(b, sign.positive); + if (a.equals(0)) throw new Error("Cannot divide by 0"); + var n = 0; + do { + var inc = 1; + var c = bigInt(a.value, sign.positive), t = c.times(10); + while (t.lesser(b)) { + c = t; + inc *= 10; + t = t.times(10); + } + while (c.lesserOrEquals(b)) { + b = b.minus(c); + n += inc; + } + } while (a.lesserOrEquals(b)); + + return { + remainder: b.value, + result: n + }; + }; + + var bigInt = function (value, s) { + var self = { + value: value, + sign: s + }; + var o = { + value: value, + sign: s, + negate: function (m) { + var first = m || self; + return bigInt(first.value, !first.sign); + }, + abs: function (m) { + var first = m || self; + return bigInt(first.value, sign.positive); + }, + add: function (n, m) { + var s, first = self, second; + if (m) (first = parse(n)) && (second = parse(m)); + else second = parse(n, first); + s = first.sign; + if (first.sign !== second.sign) { + first = bigInt(first.value, sign.positive); + second = bigInt(second.value, sign.positive); + return s === sign.positive ? + o.subtract(first, second) : + o.subtract(second, first); + } + normalize(first, second); + var a = first.value, b = second.value; + var result = [], + carry = 0; + for (var i = 0; i < a.length || carry > 0; i++) { + var sum = (a[i] || 0) + (b[i] || 0) + carry; + carry = sum >= base ? 1 : 0; + sum -= carry * base; + result.push(sum); + } + return bigInt(result, s); + }, + plus: function (n, m) { + return o.add(n, m); + }, + subtract: function (n, m) { + var first = self, second; + if (m) (first = parse(n)) && (second = parse(m)); + else second = parse(n, first); + if (first.sign !== second.sign) return o.add(first, o.negate(second)); + if (first.sign === sign.negative) return o.subtract(o.negate(second), o.negate(first)); + if (o.compare(first, second) === -1) return o.negate(o.subtract(second, first)); + var a = first.value, b = second.value; + var result = [], + borrow = 0; + for (var i = 0; i < a.length; i++) { + var tmp = a[i] - borrow; + borrow = tmp < b[i] ? 1 : 0; + var minuend = (borrow * base) + tmp - b[i]; + result.push(minuend); + } + return bigInt(result, sign.positive); + }, + minus: function (n, m) { + return o.subtract(n, m); + }, + multiply: function (n, m) { + var s, first = self, second; + if (m) (first = parse(n)) && (second = parse(m)); + else second = parse(n, first); + s = first.sign !== second.sign; + var a = first.value, b = second.value; + var resultSum = []; + for (var i = 0; i < a.length; i++) { + resultSum[i] = []; + var j = i; + while (j--) { + resultSum[i].push(0); + } + } + var carry = 0; + for (var i = 0; i < a.length; i++) { + var x = a[i]; + for (var j = 0; j < b.length || carry > 0; j++) { + var y = b[j]; + var product = y ? (x * y) + carry : carry; + carry = product > base ? Math.floor(product / base) : 0; + product -= carry * base; + resultSum[i].push(product); + } + } + var max = -1; + for (var i = 0; i < resultSum.length; i++) { + var len = resultSum[i].length; + if (len > max) max = len; + } + var result = [], carry = 0; + for (var i = 0; i < max || carry > 0; i++) { + var sum = carry; + for (var j = 0; j < resultSum.length; j++) { + sum += resultSum[j][i] || 0; + } + carry = sum > base ? Math.floor(sum / base) : 0; + sum -= carry * base; + result.push(sum); + } + return bigInt(result, s); + }, + times: function (n, m) { + return o.multiply(n, m); + }, + divmod: function (n, m) { + var s, first = self, second; + if (m) (first = parse(n)) && (second = parse(m)); + else second = parse(n, first); + s = first.sign !== second.sign; + if (bigInt(first.value, first.sign).equals(0)) return { + quotient: bigInt([0], sign.positive), + remainder: bigInt([0], sign.positive) + }; + if (second.equals(0)) throw new Error("Cannot divide by zero"); + var a = first.value, b = second.value; + var result = [], remainder = []; + for (var i = a.length - 1; i >= 0; i--) { + var n = [a[i]].concat(remainder); + var quotient = goesInto(b, n); + result.push(quotient.result); + remainder = quotient.remainder; + } + result.reverse(); + return { + quotient: bigInt(result, s), + remainder: bigInt(remainder, first.sign) + }; + }, + divide: function (n, m) { + return o.divmod(n, m).quotient; + }, + over: function (n, m) { + return o.divide(n, m); + }, + mod: function (n, m) { + return o.divmod(n, m).remainder; + }, + pow: function (n, m) { + var first = self, second; + if (m) (first = parse(n)) && (second = parse(m)); + else second = parse(n, first); + var a = first, b = second; + if (b.lesser(0)) return ZERO; + if (b.equals(0)) return ONE; + var result = bigInt(a.value, a.sign); + + if (b.mod(2).equals(0)) { + var c = result.pow(b.over(2)); + return c.times(c); + } else { + return result.times(result.pow(b.minus(1))); + } + }, + next: function (m) { + var first = m || self; + return o.add(first, 1); + }, + prev: function (m) { + var first = m || self; + return o.subtract(first, 1); + }, + compare: function (n, m) { + var first = self, second; + if (m) (first = parse(n)) && (second = parse(m, first)); + else second = parse(n, first); + normalize(first, second); + if (first.value.length === 1 && second.value.length === 1 && first.value[0] === 0 && second.value[0] === 0) return 0; + if (second.sign !== first.sign) return first.sign === sign.positive ? 1 : -1; + var multiplier = first.sign === sign.positive ? 1 : -1; + var a = first.value, b = second.value; + for (var i = a.length - 1; i >= 0; i--) { + if (a[i] > b[i]) return 1 * multiplier; + if (b[i] > a[i]) return -1 * multiplier; + } + return 0; + }, + compareAbs: function (n, m) { + var first = self, second; + if (m) (first = parse(n)) && (second = parse(m, first)); + else second = parse(n, first); + first.sign = second.sign = sign.positive; + return o.compare(first, second); + }, + equals: function (n, m) { + return o.compare(n, m) === 0; + }, + notEquals: function (n, m) { + return !o.equals(n, m); + }, + lesser: function (n, m) { + return o.compare(n, m) < 0; + }, + greater: function (n, m) { + return o.compare(n, m) > 0; + }, + greaterOrEquals: function (n, m) { + return o.compare(n, m) >= 0; + }, + lesserOrEquals: function (n, m) { + return o.compare(n, m) <= 0; + }, + isPositive: function (m) { + var first = m || self; + return first.sign === sign.positive; + }, + isNegative: function (m) { + var first = m || self; + return first.sign === sign.negative; + }, + isEven: function (m) { + var first = m || self; + return first.value[0] % 2 === 0; + }, + isOdd: function (m) { + var first = m || self; + return first.value[0] % 2 === 1; + }, + toString: function (m) { + var first = m || self; + var str = "", len = first.value.length; + while (len--) { + if (first.value[len].toString().length === 8) str += first.value[len]; + else str += (base.toString() + first.value[len]).slice(-logBase); + } + while (str[0] === "0") { + str = str.slice(1); + } + if (!str.length) str = "0"; + var s = (first.sign === sign.positive || str == "0") ? "" : "-"; + return s + str; + }, + toHex: function (m) { + var first = m || self; + var str = ""; + var l = this.abs(); + while (l > 0) { + var qr = l.divmod(256); + var b = qr.remainder.toJSNumber(); + str = (b >> 4).toString(16) + (b & 15).toString(16) + str; + l = qr.quotient; + } + return (this.isNegative() ? "-" : "") + "0x" + str; + }, + toJSNumber: function (m) { + return +o.toString(m); + }, + valueOf: function (m) { + return o.toJSNumber(m); + } + }; + return o; + }; + + var ZERO = bigInt([0], sign.positive); + var ONE = bigInt([1], sign.positive); + var MINUS_ONE = bigInt([1], sign.negative); + + var fnReturn = function (a) { + if (typeof a === "undefined") return ZERO; + return parse(a); + }; + fnReturn.zero = ZERO; + fnReturn.one = ONE; + fnReturn.minusOne = MINUS_ONE; + return fnReturn; +})(); + +if (typeof module !== "undefined") { + module.exports = bigInt; +} + diff --git a/cmd/mist/assets/ext/ethereum.js b/cmd/mist/assets/ext/ethereum.js new file mode 100644 index 000000000..697a404a3 --- /dev/null +++ b/cmd/mist/assets/ext/ethereum.js @@ -0,0 +1,295 @@ +// Main Ethereum library +window.eth = { + prototype: Object(), + _callbacks: {}, + _onCallbacks: {}, + + test: function() { + var t = undefined; + postData({call: "test"}) + navigator.qt.onmessage = function(d) {console.log("onmessage called"); t = d; } + for(;;) { + if(t !== undefined) { + return t + } + } + }, + + mutan: function(code, cb) { + postData({call: "mutan", args: [code]}, cb) + }, + + toHex: function(str) { + var hex = ""; + for(var i = 0; i < str.length; i++) { + var n = str.charCodeAt(i).toString(16); + hex += n.length < 2 ? '0' + n : n; + } + + return hex; + }, + + toAscii: function(hex) { + // Find termination + var str = ""; + var i = 0, l = hex.length; + for(; i < l; i+=2) { + var code = hex.charCodeAt(i) + if(code == 0) { + break; + } + + str += String.fromCharCode(parseInt(hex.substr(i, 2), 16)); + } + + return str; + }, + + fromAscii: function(str, pad) { + if(pad === undefined) { + pad = 32 + } + + var hex = this.toHex(str); + + while(hex.length < pad*2) + hex += "00"; + + return hex + }, + + + // Retrieve block + // + // Either supply a number or a string. Type is determent for the lookup method + // string - Retrieves the block by looking up the hash + // number - Retrieves the block by looking up the block number + getBlock: function(numberOrHash, cb) { + var func; + if(typeof numberOrHash == "string") { + func = "getBlockByHash"; + } else { + func = "getBlockByNumber"; + } + postData({call: func, args: [numberOrHash]}, cb); + }, + + // Create transaction + // + // Transact between two state objects + transact: function(params, cb) { + if(params === undefined) { + params = {}; + } + + if(params.endowment !== undefined) + params.value = params.endowment; + if(params.code !== undefined) + params.data = params.code; + + // Make sure everything is string + var fields = ["to", "from", "value", "gas", "gasPrice"]; + for(var i = 0; i < fields.length; i++) { + if(params[fields[i]] === undefined) { + params[fields[i]] = ""; + } + params[fields[i]] = params[fields[i]].toString(); + } + + var data; + if(typeof params.data === "object") { + data = ""; + for(var i = 0; i < params.data.length; i++) { + data += params.data[i] + } + } else { + data = params.data; + } + + postData({call: "transact", args: [params.from, params.to, params.value, params.gas, params.gasPrice, "0x"+data]}, cb); + }, + + getMessages: function(filter, cb) { + postData({call: "messages", args: [filter]}, cb); + }, + + getStorageAt: function(address, storageAddress, cb) { + postData({call: "getStorage", args: [address, storageAddress]}, cb); + }, + + getEachStorageAt: function(address, cb){ + postData({call: "getEachStorage", args: [address]}, cb); + }, + + getKey: function(cb) { + postData({call: "getKey"}, cb); + }, + + getTxCountAt: function(address, cb) { + postData({call: "getTxCountAt", args: [address]}, cb); + }, + getIsMining: function(cb){ + postData({call: "getIsMining"}, cb) + }, + getIsListening: function(cb){ + postData({call: "getIsListening"}, cb) + }, + getCoinBase: function(cb){ + postData({call: "getCoinBase"}, cb); + }, + getPeerCount: function(cb){ + postData({call: "getPeerCount"}, cb); + }, + getBalanceAt: function(address, cb) { + postData({call: "getBalance", args: [address]}, cb); + }, + getTransactionsFor: function(address, cb) { + postData({call: "getTransactionsFor", args: [address]}, cb); + }, + + getSecretToAddress: function(sec, cb) { + postData({call: "getSecretToAddress", args: [sec]}, cb); + }, + + /* + watch: function(address, storageAddrOrCb, cb) { + var ev; + if(cb === undefined) { + cb = storageAddrOrCb; + storageAddrOrCb = ""; + ev = "object:"+address; + } else { + ev = "storage:"+address+":"+storageAddrOrCb; + } + + eth.on(ev, cb) + + postData({call: "watch", args: [address, storageAddrOrCb]}); + }, + + disconnect: function(address, storageAddrOrCb, cb) { + var ev; + if(cb === undefined) { + cb = storageAddrOrCb; + storageAddrOrCb = ""; + ev = "object:"+address; + } else { + ev = "storage:"+address+":"+storageAddrOrCb; + } + + eth.off(ev, cb) + + postData({call: "disconnect", args: [address, storageAddrOrCb]}); + }, + */ + + watch: function(options) { + var filter = new Filter(options); + filter.number = newWatchNum().toString() + + postData({call: "watch", args: [options, filter.number]}) + + return filter; + }, + + set: function(props) { + postData({call: "set", args: props}); + }, + + on: function(event, cb) { + if(eth._onCallbacks[event] === undefined) { + eth._onCallbacks[event] = []; + } + + eth._onCallbacks[event].push(cb); + + return this + }, + + off: function(event, cb) { + if(eth._onCallbacks[event] !== undefined) { + var callbacks = eth._onCallbacks[event]; + for(var i = 0; i < callbacks.length; i++) { + if(callbacks[i] === cb) { + delete callbacks[i]; + } + } + } + + return this + }, + + trigger: function(event, data) { + var callbacks = eth._onCallbacks[event]; + if(callbacks !== undefined) { + for(var i = 0; i < callbacks.length; i++) { + // Figure out whether the returned data was an array + // array means multiple return arguments (multiple params) + if(data instanceof Array) { + callbacks[i].apply(this, data); + } else { + callbacks[i].call(this, data); + } + } + } + }, +} + + +var Filter = function(options) { + this.options = options; +}; +Filter.prototype.changed = function(callback) { + // Register the watched:<number>. Qml will call the appropriate event if anything + // interesting happens in the land of Go. + eth.on("watched:"+this.number, callback) +} +Filter.prototype.getMessages = function(cb) { + return eth.getMessages(this.options, cb) +} + +var watchNum = 0; +function newWatchNum() { + return watchNum++; +} + +function postData(data, cb) { + data._seed = Math.floor(Math.random() * 1000000) + if(cb) { + eth._callbacks[data._seed] = cb; + } + + if(data.args === undefined) { + data.args = []; + } + + navigator.qt.postMessage(JSON.stringify(data)); +} + +navigator.qt.onmessage = function(ev) { + var data = JSON.parse(ev.data) + + if(data._event !== undefined) { + eth.trigger(data._event, data.data); + } else { + if(data._seed) { + var cb = eth._callbacks[data._seed]; + if(cb) { + cb.call(this, data.data) + + // Remove the "trigger" callback + delete eth._callbacks[ev._seed]; + } + } + } +} + +eth.on("chain:changed", function() { +}) + +eth.on("messages", { /* filters */}, function(messages){ +}) + +eth.on("pending:changed", function() { +}) + diff --git a/cmd/mist/assets/ext/filter.js b/cmd/mist/assets/ext/filter.js new file mode 100644 index 000000000..c23706249 --- /dev/null +++ b/cmd/mist/assets/ext/filter.js @@ -0,0 +1,49 @@ +var ethx = { + prototype: Object, + + watch: function(options) { + return new Filter(options); + }, + + note: function() { + var args = Array.prototype.slice.call(arguments, 0); + var o = [] + for(var i = 0; i < args.length; i++) { + o.push(args[i].toString()) + } + + eth.notef(o); + }, +}; + +var Filter = function(options) { + this.callbacks = []; + this.options = options; + + if(options === "chain") { + this.id = eth.newFilterString(options); + } else if(typeof options === "object") { + this.id = eth.newFilter(options); + } +}; + +Filter.prototype.changed = function(callback) { + this.callbacks.push(callback); + + var self = this; + messages.connect(function(messages, id) { + if(id == self.id) { + for(var i = 0; i < self.callbacks.length; i++) { + self.callbacks[i].call(self, messages); + } + } + }); +}; + +Filter.prototype.uninstall = function() { + eth.uninstallFilter(this.id) +} + +Filter.prototype.messages = function() { + return eth.messages(this.id) +} diff --git a/cmd/mist/assets/ext/home.html b/cmd/mist/assets/ext/home.html new file mode 100644 index 000000000..a524e8403 --- /dev/null +++ b/cmd/mist/assets/ext/home.html @@ -0,0 +1,22 @@ +<!doctype> +<html> +<head> +<title>Ethereum</title> + +<style type="text/css"> +h1 { + text-align: center; + font-family: Courier; + font-size: 50pt; +} +</style> +</head> + +<body> +<h1>... Ethereum ...</h1> +<ul> + <li><a href="http://std.eth">std::Service</a></li> +</ul> +</body> +</html> + diff --git a/cmd/mist/assets/ext/html_messaging.js b/cmd/mist/assets/ext/html_messaging.js new file mode 100644 index 000000000..91310e998 --- /dev/null +++ b/cmd/mist/assets/ext/html_messaging.js @@ -0,0 +1,464 @@ +// The magic return variable. The magic return variable will be set during the execution of the QML call. +(function(window) { + var Promise = window.Promise; + if(typeof(Promise) === "undefined") { + var Promise = Q.Promise; + } + + function isPromise(o) { + return typeof o === "object" && o.then + } + + window.eth = { + _callbacks: {}, + _events: {}, + prototype: Object(), + + toHex: function(str) { + var hex = ""; + for(var i = 0; i < str.length; i++) { + var n = str.charCodeAt(i).toString(16); + hex += n.length < 2 ? '0' + n : n; + } + + return hex; + }, + + toAscii: function(hex) { + // Find termination + var str = ""; + var i = 0, l = hex.length; + for(; i < l; i+=2) { + var code = hex.charCodeAt(i) + if(code == 0) { + break; + } + + str += String.fromCharCode(parseInt(hex.substr(i, 2), 16)); + } + + return str; + }, + + fromAscii: function(str, pad) { + if(pad === undefined) { + pad = 32 + } + + var hex = this.toHex(str); + + while(hex.length < pad*2) + hex += "00"; + + return hex + }, + + block: function(numberOrHash) { + return new Promise(function(resolve, reject) { + var func; + if(typeof numberOrHash == "string") { + func = "getBlockByHash"; + } else { + func = "getBlockByNumber"; + } + + postData({call: func, args: [numberOrHash]}, function(block) { + if(block) + resolve(block); + else + reject("not found"); + + }); + }); + }, + + transact: function(params) { + if(params === undefined) { + params = {}; + } + + if(params.endowment !== undefined) + params.value = params.endowment; + if(params.code !== undefined) + params.data = params.code; + + + var promises = [] + if(isPromise(params.to)) { + promises.push(params.to.then(function(_to) { params.to = _to; })); + } + if(isPromise(params.from)) { + promises.push(params.from.then(function(_from) { params.from = _from; })); + } + + if(typeof params.data !== "object" || isPromise(params.data)) { + params.data = [params.data] + } + + var data = params.data; + for(var i = 0; i < params.data.length; i++) { + if(isPromise(params.data[i])) { + var promise = params.data[i]; + var _i = i; + promises.push(promise.then(function(_arg) { params.data[_i] = _arg; })); + } + } + + // Make sure everything is string + var fields = ["value", "gas", "gasPrice"]; + for(var i = 0; i < fields.length; i++) { + if(params[fields[i]] === undefined) { + params[fields[i]] = ""; + } + params[fields[i]] = params[fields[i]].toString(); + } + + // Load promises then call the last "transact". + return Q.all(promises).then(function() { + return new Promise(function(resolve, reject) { + params.data = params.data.join(""); + postData({call: "transact", args: params}, function(data) { + if(data[1]) + reject(data[0]); + else + resolve(data[0]); + }); + }); + }) + }, + + compile: function(code) { + return new Promise(function(resolve, reject) { + postData({call: "compile", args: [code]}, function(data) { + if(data[1]) + reject(data[0]); + else + resolve(data[0]); + }); + }); + }, + + balanceAt: function(address) { + var promises = []; + + if(isPromise(address)) { + promises.push(address.then(function(_address) { address = _address; })); + } + + return Q.all(promises).then(function() { + return new Promise(function(resolve, reject) { + postData({call: "getBalanceAt", args: [address]}, function(balance) { + resolve(balance); + }); + }); + }); + }, + + countAt: function(address) { + var promises = []; + + if(isPromise(address)) { + promises.push(address.then(function(_address) { address = _address; })); + } + + return Q.all(promises).then(function() { + return new Promise(function(resolve, reject) { + postData({call: "getCountAt", args: [address]}, function(count) { + resolve(count); + }); + }); + }); + }, + + codeAt: function(address) { + var promises = []; + + if(isPromise(address)) { + promises.push(address.then(function(_address) { address = _address; })); + } + + return Q.all(promises).then(function() { + return new Promise(function(resolve, reject) { + postData({call: "getCodeAt", args: [address]}, function(code) { + resolve(code); + }); + }); + }); + }, + + storageAt: function(address, storageAddress) { + var promises = []; + + if(isPromise(address)) { + promises.push(address.then(function(_address) { address = _address; })); + } + + if(isPromise(storageAddress)) { + promises.push(storageAddress.then(function(_sa) { storageAddress = _sa; })); + } + + return Q.all(promises).then(function() { + return new Promise(function(resolve, reject) { + postData({call: "getStorageAt", args: [address, storageAddress]}, function(entry) { + resolve(entry); + }); + }); + }); + }, + + stateAt: function(address, storageAddress) { + return this.storageAt(address, storageAddress); + }, + + call: function(params) { + if(params === undefined) { + params = {}; + } + + if(params.endowment !== undefined) + params.value = params.endowment; + if(params.code !== undefined) + params.data = params.code; + + + var promises = [] + if(isPromise(params.to)) { + promises.push(params.to.then(function(_to) { params.to = _to; })); + } + if(isPromise(params.from)) { + promises.push(params.from.then(function(_from) { params.from = _from; })); + } + + if(isPromise(params.data)) { + promises.push(params.data.then(function(_code) { params.data = _code; })); + } else { + if(typeof params.data === "object") { + data = ""; + for(var i = 0; i < params.data.length; i++) { + data += params.data[i] + } + } else { + data = params.data; + } + } + + // Make sure everything is string + var fields = ["value", "gas", "gasPrice"]; + for(var i = 0; i < fields.length; i++) { + if(params[fields[i]] === undefined) { + params[fields[i]] = ""; + } + params[fields[i]] = params[fields[i]].toString(); + } + + // Load promises then call the last "transact". + return Q.all(promises).then(function() { + return new Promise(function(resolve, reject) { + postData({call: "call", args: params}, function(data) { + if(data[1]) + reject(data[0]); + else + resolve(data[0]); + }); + }); + }) + }, + + watch: function(params) { + return new Filter(params); + }, + + secretToAddress: function(key) { + var promises = []; + if(isPromise(key)) { + promises.push(key.then(function(_key) { key = _key; })); + } + + return Q.all(promises).then(function() { + return new Promise(function(resolve, reject) { + postData({call: "getSecretToAddress", args: [key]}, function(address) { + resolve(address); + }); + }); + }); + }, + + on: function(event, cb) { + if(eth._events[event] === undefined) { + eth._events[event] = []; + } + + eth._events[event].push(cb); + + return this + }, + + off: function(event, cb) { + if(eth._events[event] !== undefined) { + var callbacks = eth._events[event]; + for(var i = 0; i < callbacks.length; i++) { + if(callbacks[i] === cb) { + delete callbacks[i]; + } + } + } + + return this + }, + + trigger: function(event, data) { + var callbacks = eth._events[event]; + if(callbacks !== undefined) { + for(var i = 0; i < callbacks.length; i++) { + // Figure out whether the returned data was an array + // array means multiple return arguments (multiple params) + if(data instanceof Array) { + callbacks[i].apply(this, data); + } else { + callbacks[i].call(this, data); + } + } + } + }, + }; + + // Eth object properties + Object.defineProperty(eth, "key", { + get: function() { + return new Promise(function(resolve, reject) { + postData({call: "getKey"}, function(k) { + resolve(k); + }); + }); + }, + }); + + Object.defineProperty(eth, "gasPrice", { + get: function() { + return "10000000000000" + } + }); + + Object.defineProperty(eth, "coinbase", { + get: function() { + return new Promise(function(resolve, reject) { + postData({call: "getCoinBase"}, function(coinbase) { + resolve(coinbase); + }); + }); + }, + }); + + Object.defineProperty(eth, "listening", { + get: function() { + return new Promise(function(resolve, reject) { + postData({call: "getIsListening"}, function(listening) { + resolve(listening); + }); + }); + }, + }); + + + Object.defineProperty(eth, "mining", { + get: function() { + return new Promise(function(resolve, reject) { + postData({call: "getIsMining"}, function(mining) { + resolve(mining); + }); + }); + }, + }); + + Object.defineProperty(eth, "peerCount", { + get: function() { + return new Promise(function(resolve, reject) { + postData({call: "getPeerCount"}, function(peerCount) { + resolve(peerCount); + }); + }); + }, + }); + + var filters = []; + var Filter = function(options) { + filters.push(this); + + this.callbacks = []; + this.options = options; + + var call; + if(options === "chain") { + call = "newFilterString" + } else if(typeof options === "object") { + call = "newFilter" + } + + var self = this; // Cheaper than binding + this.promise = new Promise(function(resolve, reject) { + postData({call: call, args: [options]}, function(id) { + self.id = id; + + resolve(id); + }); + }); + }; + + Filter.prototype.changed = function(callback) { + var self = this; + this.promise.then(function(id) { + self.callbacks.push(callback); + }); + }; + + Filter.prototype.trigger = function(messages, id) { + if(id == this.id) { + for(var i = 0; i < this.callbacks.length; i++) { + this.callbacks[i].call(this, messages); + } + } + }; + + Filter.prototype.uninstall = function() { + this.promise.then(function(id) { + postData({call: "uninstallFilter", args:[id]}); + }); + }; + + Filter.prototype.messages = function() { + var self=this; + return Q.all([this.promise]).then(function() { + var id = self.id + return new Promise(function(resolve, reject) { + postData({call: "getMessages", args: [id]}, function(messages) { + resolve(messages); + }); + }); + }); + }; + + // Register to the messages callback. "messages" will be emitted when new messages + // from the client have been created. + eth.on("messages", function(messages, id) { + for(var i = 0; i < filters.length; i++) { + filters[i].trigger(messages, id); + } + }); + + + var g_seed = 1; + function postData(data, cb) { + data._seed = g_seed; + if(cb) { + eth._callbacks[data._seed] = cb; + } + + if(data.args === undefined) { + data.args = []; + } + + g_seed++; + + window._messagingAdapter.call(this, JSON.stringify(data)) + } +})(this); diff --git a/cmd/mist/assets/ext/http.js b/cmd/mist/assets/ext/http.js new file mode 100644 index 000000000..725ce8e6b --- /dev/null +++ b/cmd/mist/assets/ext/http.js @@ -0,0 +1,13 @@ +// this function is included locally, but you can also include separately via a header definition +function request(url, callback) { + var xhr = new XMLHttpRequest(); + xhr.onreadystatechange = (function(req) { + return function() { + if(req.readyState === 4) { + callback(req); + } + } + })(xhr); + xhr.open('GET', url, true); + xhr.send(''); +} diff --git a/cmd/mist/assets/ext/q.js b/cmd/mist/assets/ext/q.js new file mode 100644 index 000000000..23c4245ee --- /dev/null +++ b/cmd/mist/assets/ext/q.js @@ -0,0 +1,1909 @@ +// vim:ts=4:sts=4:sw=4: +/*! + * + * Copyright 2009-2012 Kris Kowal under the terms of the MIT + * license found at http://github.com/kriskowal/q/raw/master/LICENSE + * + * With parts by Tyler Close + * Copyright 2007-2009 Tyler Close under the terms of the MIT X license found + * at http://www.opensource.org/licenses/mit-license.html + * Forked at ref_send.js version: 2009-05-11 + * + * With parts by Mark Miller + * Copyright (C) 2011 Google Inc. + * + * Licensed 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. + * + */ + +(function (definition) { + // Turn off strict mode for this function so we can assign to global.Q + /* jshint strict: false */ + + // This file will function properly as a <script> tag, or a module + // using CommonJS and NodeJS or RequireJS module formats. In + // Common/Node/RequireJS, the module exports the Q API and when + // executed as a simple <script>, it creates a Q global instead. + + // Montage Require + if (typeof bootstrap === "function") { + bootstrap("promise", definition); + + // CommonJS + } else if (typeof exports === "object" && typeof module === "object") { + module.exports = definition(); + + // RequireJS + } else if (typeof define === "function" && define.amd) { + define(definition); + + // SES (Secure EcmaScript) + } else if (typeof ses !== "undefined") { + if (!ses.ok()) { + return; + } else { + ses.makeQ = definition; + } + + // <script> + } else { + Q = definition(); + } + +})(function () { +"use strict"; + +var hasStacks = false; +try { + throw new Error(); +} catch (e) { + hasStacks = !!e.stack; +} + +// All code after this point will be filtered from stack traces reported +// by Q. +var qStartingLine = captureLine(); +var qFileName; + +// shims + +// used for fallback in "allResolved" +var noop = function () {}; + +// Use the fastest possible means to execute a task in a future turn +// of the event loop. +var nextTick =(function () { + // linked list of tasks (single, with head node) + var head = {task: void 0, next: null}; + var tail = head; + var flushing = false; + var requestTick = void 0; + var isNodeJS = false; + + function flush() { + /* jshint loopfunc: true */ + + while (head.next) { + head = head.next; + var task = head.task; + head.task = void 0; + var domain = head.domain; + + if (domain) { + head.domain = void 0; + domain.enter(); + } + + try { + task(); + + } catch (e) { + if (isNodeJS) { + // In node, uncaught exceptions are considered fatal errors. + // Re-throw them synchronously to interrupt flushing! + + // Ensure continuation if the uncaught exception is suppressed + // listening "uncaughtException" events (as domains does). + // Continue in next event to avoid tick recursion. + if (domain) { + domain.exit(); + } + setTimeout(flush, 0); + if (domain) { + domain.enter(); + } + + throw e; + + } else { + // In browsers, uncaught exceptions are not fatal. + // Re-throw them asynchronously to avoid slow-downs. + setTimeout(function() { + throw e; + }, 0); + } + } + + if (domain) { + domain.exit(); + } + } + + flushing = false; + } + + nextTick = function (task) { + tail = tail.next = { + task: task, + domain: isNodeJS && process.domain, + next: null + }; + + if (!flushing) { + flushing = true; + requestTick(); + } + }; + + if (typeof process !== "undefined" && process.nextTick) { + // Node.js before 0.9. Note that some fake-Node environments, like the + // Mocha test runner, introduce a `process` global without a `nextTick`. + isNodeJS = true; + + requestTick = function () { + process.nextTick(flush); + }; + + } else if (typeof setImmediate === "function") { + // In IE10, Node.js 0.9+, or https://github.com/NobleJS/setImmediate + if (typeof window !== "undefined") { + requestTick = setImmediate.bind(window, flush); + } else { + requestTick = function () { + setImmediate(flush); + }; + } + + } else if (typeof MessageChannel !== "undefined") { + // modern browsers + // http://www.nonblocking.io/2011/06/windownexttick.html + var channel = new MessageChannel(); + // At least Safari Version 6.0.5 (8536.30.1) intermittently cannot create + // working message ports the first time a page loads. + channel.port1.onmessage = function () { + requestTick = requestPortTick; + channel.port1.onmessage = flush; + flush(); + }; + var requestPortTick = function () { + // Opera requires us to provide a message payload, regardless of + // whether we use it. + channel.port2.postMessage(0); + }; + requestTick = function () { + setTimeout(flush, 0); + requestPortTick(); + }; + + } else { + // old browsers + requestTick = function () { + setTimeout(flush, 0); + }; + } + + return nextTick; +})(); + +// Attempt to make generics safe in the face of downstream +// modifications. +// There is no situation where this is necessary. +// If you need a security guarantee, these primordials need to be +// deeply frozen anyway, and if you don’t need a security guarantee, +// this is just plain paranoid. +// However, this **might** have the nice side-effect of reducing the size of +// the minified code by reducing x.call() to merely x() +// See Mark Miller’s explanation of what this does. +// http://wiki.ecmascript.org/doku.php?id=conventions:safe_meta_programming +var call = Function.call; +function uncurryThis(f) { + return function () { + return call.apply(f, arguments); + }; +} +// This is equivalent, but slower: +// uncurryThis = Function_bind.bind(Function_bind.call); +// http://jsperf.com/uncurrythis + +var array_slice = uncurryThis(Array.prototype.slice); + +var array_reduce = uncurryThis( + Array.prototype.reduce || function (callback, basis) { + var index = 0, + length = this.length; + // concerning the initial value, if one is not provided + if (arguments.length === 1) { + // seek to the first value in the array, accounting + // for the possibility that is is a sparse array + do { + if (index in this) { + basis = this[index++]; + break; + } + if (++index >= length) { + throw new TypeError(); + } + } while (1); + } + // reduce + for (; index < length; index++) { + // account for the possibility that the array is sparse + if (index in this) { + basis = callback(basis, this[index], index); + } + } + return basis; + } +); + +var array_indexOf = uncurryThis( + Array.prototype.indexOf || function (value) { + // not a very good shim, but good enough for our one use of it + for (var i = 0; i < this.length; i++) { + if (this[i] === value) { + return i; + } + } + return -1; + } +); + +var array_map = uncurryThis( + Array.prototype.map || function (callback, thisp) { + var self = this; + var collect = []; + array_reduce(self, function (undefined, value, index) { + collect.push(callback.call(thisp, value, index, self)); + }, void 0); + return collect; + } +); + +var object_create = Object.create || function (prototype) { + function Type() { } + Type.prototype = prototype; + return new Type(); +}; + +var object_hasOwnProperty = uncurryThis(Object.prototype.hasOwnProperty); + +var object_keys = Object.keys || function (object) { + var keys = []; + for (var key in object) { + if (object_hasOwnProperty(object, key)) { + keys.push(key); + } + } + return keys; +}; + +var object_toString = uncurryThis(Object.prototype.toString); + +function isObject(value) { + return value === Object(value); +} + +// generator related shims + +// FIXME: Remove this function once ES6 generators are in SpiderMonkey. +function isStopIteration(exception) { + return ( + object_toString(exception) === "[object StopIteration]" || + exception instanceof QReturnValue + ); +} + +// FIXME: Remove this helper and Q.return once ES6 generators are in +// SpiderMonkey. +var QReturnValue; +if (typeof ReturnValue !== "undefined") { + QReturnValue = ReturnValue; +} else { + QReturnValue = function (value) { + this.value = value; + }; +} + +// long stack traces + +var STACK_JUMP_SEPARATOR = "From previous event:"; + +function makeStackTraceLong(error, promise) { + // If possible, transform the error stack trace by removing Node and Q + // cruft, then concatenating with the stack trace of `promise`. See #57. + if (hasStacks && + promise.stack && + typeof error === "object" && + error !== null && + error.stack && + error.stack.indexOf(STACK_JUMP_SEPARATOR) === -1 + ) { + var stacks = []; + for (var p = promise; !!p; p = p.source) { + if (p.stack) { + stacks.unshift(p.stack); + } + } + stacks.unshift(error.stack); + + var concatedStacks = stacks.join("\n" + STACK_JUMP_SEPARATOR + "\n"); + error.stack = filterStackString(concatedStacks); + } +} + +function filterStackString(stackString) { + var lines = stackString.split("\n"); + var desiredLines = []; + for (var i = 0; i < lines.length; ++i) { + var line = lines[i]; + + if (!isInternalFrame(line) && !isNodeFrame(line) && line) { + desiredLines.push(line); + } + } + return desiredLines.join("\n"); +} + +function isNodeFrame(stackLine) { + return stackLine.indexOf("(module.js:") !== -1 || + stackLine.indexOf("(node.js:") !== -1; +} + +function getFileNameAndLineNumber(stackLine) { + // Named functions: "at functionName (filename:lineNumber:columnNumber)" + // In IE10 function name can have spaces ("Anonymous function") O_o + var attempt1 = /at .+ \((.+):(\d+):(?:\d+)\)$/.exec(stackLine); + if (attempt1) { + return [attempt1[1], Number(attempt1[2])]; + } + + // Anonymous functions: "at filename:lineNumber:columnNumber" + var attempt2 = /at ([^ ]+):(\d+):(?:\d+)$/.exec(stackLine); + if (attempt2) { + return [attempt2[1], Number(attempt2[2])]; + } + + // Firefox style: "function@filename:lineNumber or @filename:lineNumber" + var attempt3 = /.*@(.+):(\d+)$/.exec(stackLine); + if (attempt3) { + return [attempt3[1], Number(attempt3[2])]; + } +} + +function isInternalFrame(stackLine) { + var fileNameAndLineNumber = getFileNameAndLineNumber(stackLine); + + if (!fileNameAndLineNumber) { + return false; + } + + var fileName = fileNameAndLineNumber[0]; + var lineNumber = fileNameAndLineNumber[1]; + + return fileName === qFileName && + lineNumber >= qStartingLine && + lineNumber <= qEndingLine; +} + +// discover own file name and line number range for filtering stack +// traces +function captureLine() { + if (!hasStacks) { + return; + } + + try { + throw new Error(); + } catch (e) { + var lines = e.stack.split("\n"); + var firstLine = lines[0].indexOf("@") > 0 ? lines[1] : lines[2]; + var fileNameAndLineNumber = getFileNameAndLineNumber(firstLine); + if (!fileNameAndLineNumber) { + return; + } + + qFileName = fileNameAndLineNumber[0]; + return fileNameAndLineNumber[1]; + } +} + +function deprecate(callback, name, alternative) { + return function () { + if (typeof console !== "undefined" && + typeof console.warn === "function") { + console.warn(name + " is deprecated, use " + alternative + + " instead.", new Error("").stack); + } + return callback.apply(callback, arguments); + }; +} + +// end of shims +// beginning of real work + +/** + * Constructs a promise for an immediate reference, passes promises through, or + * coerces promises from different systems. + * @param value immediate reference or promise + */ +function Q(value) { + // If the object is already a Promise, return it directly. This enables + // the resolve function to both be used to created references from objects, + // but to tolerably coerce non-promises to promises. + if (value instanceof Promise) { + return value; + } + + // assimilate thenables + if (isPromiseAlike(value)) { + return coerce(value); + } else { + return fulfill(value); + } +} +Q.resolve = Q; + +/** + * Performs a task in a future turn of the event loop. + * @param {Function} task + */ +Q.nextTick = nextTick; + +/** + * Controls whether or not long stack traces will be on + */ +Q.longStackSupport = false; + +/** + * Constructs a {promise, resolve, reject} object. + * + * `resolve` is a callback to invoke with a more resolved value for the + * promise. To fulfill the promise, invoke `resolve` with any value that is + * not a thenable. To reject the promise, invoke `resolve` with a rejected + * thenable, or invoke `reject` with the reason directly. To resolve the + * promise to another thenable, thus putting it in the same state, invoke + * `resolve` with that other thenable. + */ +Q.defer = defer; +function defer() { + // if "messages" is an "Array", that indicates that the promise has not yet + // been resolved. If it is "undefined", it has been resolved. Each + // element of the messages array is itself an array of complete arguments to + // forward to the resolved promise. We coerce the resolution value to a + // promise using the `resolve` function because it handles both fully + // non-thenable values and other thenables gracefully. + var messages = [], progressListeners = [], resolvedPromise; + + var deferred = object_create(defer.prototype); + var promise = object_create(Promise.prototype); + + promise.promiseDispatch = function (resolve, op, operands) { + var args = array_slice(arguments); + if (messages) { + messages.push(args); + if (op === "when" && operands[1]) { // progress operand + progressListeners.push(operands[1]); + } + } else { + nextTick(function () { + resolvedPromise.promiseDispatch.apply(resolvedPromise, args); + }); + } + }; + + // XXX deprecated + promise.valueOf = function () { + if (messages) { + return promise; + } + var nearerValue = nearer(resolvedPromise); + if (isPromise(nearerValue)) { + resolvedPromise = nearerValue; // shorten chain + } + return nearerValue; + }; + + promise.inspect = function () { + if (!resolvedPromise) { + return { state: "pending" }; + } + return resolvedPromise.inspect(); + }; + + if (Q.longStackSupport && hasStacks) { + try { + throw new Error(); + } catch (e) { + // NOTE: don't try to use `Error.captureStackTrace` or transfer the + // accessor around; that causes memory leaks as per GH-111. Just + // reify the stack trace as a string ASAP. + // + // At the same time, cut off the first line; it's always just + // "[object Promise]\n", as per the `toString`. + promise.stack = e.stack.substring(e.stack.indexOf("\n") + 1); + } + } + + // NOTE: we do the checks for `resolvedPromise` in each method, instead of + // consolidating them into `become`, since otherwise we'd create new + // promises with the lines `become(whatever(value))`. See e.g. GH-252. + + function become(newPromise) { + resolvedPromise = newPromise; + promise.source = newPromise; + + array_reduce(messages, function (undefined, message) { + nextTick(function () { + newPromise.promiseDispatch.apply(newPromise, message); + }); + }, void 0); + + messages = void 0; + progressListeners = void 0; + } + + deferred.promise = promise; + deferred.resolve = function (value) { + if (resolvedPromise) { + return; + } + + become(Q(value)); + }; + + deferred.fulfill = function (value) { + if (resolvedPromise) { + return; + } + + become(fulfill(value)); + }; + deferred.reject = function (reason) { + if (resolvedPromise) { + return; + } + + become(reject(reason)); + }; + deferred.notify = function (progress) { + if (resolvedPromise) { + return; + } + + array_reduce(progressListeners, function (undefined, progressListener) { + nextTick(function () { + progressListener(progress); + }); + }, void 0); + }; + + return deferred; +} + +/** + * Creates a Node-style callback that will resolve or reject the deferred + * promise. + * @returns a nodeback + */ +defer.prototype.makeNodeResolver = function () { + var self = this; + return function (error, value) { + if (error) { + self.reject(error); + } else if (arguments.length > 2) { + self.resolve(array_slice(arguments, 1)); + } else { + self.resolve(value); + } + }; +}; + +/** + * @param resolver {Function} a function that returns nothing and accepts + * the resolve, reject, and notify functions for a deferred. + * @returns a promise that may be resolved with the given resolve and reject + * functions, or rejected by a thrown exception in resolver + */ +Q.Promise = promise; // ES6 +Q.promise = promise; +function promise(resolver) { + if (typeof resolver !== "function") { + throw new TypeError("resolver must be a function."); + } + var deferred = defer(); + try { + resolver(deferred.resolve, deferred.reject, deferred.notify); + } catch (reason) { + deferred.reject(reason); + } + return deferred.promise; +} + +promise.race = race; // ES6 +promise.all = all; // ES6 +promise.reject = reject; // ES6 +promise.resolve = Q; // ES6 + +// XXX experimental. This method is a way to denote that a local value is +// serializable and should be immediately dispatched to a remote upon request, +// instead of passing a reference. +Q.passByCopy = function (object) { + //freeze(object); + //passByCopies.set(object, true); + return object; +}; + +Promise.prototype.passByCopy = function () { + //freeze(object); + //passByCopies.set(object, true); + return this; +}; + +/** + * If two promises eventually fulfill to the same value, promises that value, + * but otherwise rejects. + * @param x {Any*} + * @param y {Any*} + * @returns {Any*} a promise for x and y if they are the same, but a rejection + * otherwise. + * + */ +Q.join = function (x, y) { + return Q(x).join(y); +}; + +Promise.prototype.join = function (that) { + return Q([this, that]).spread(function (x, y) { + if (x === y) { + // TODO: "===" should be Object.is or equiv + return x; + } else { + throw new Error("Can't join: not the same: " + x + " " + y); + } + }); +}; + +/** + * Returns a promise for the first of an array of promises to become fulfilled. + * @param answers {Array[Any*]} promises to race + * @returns {Any*} the first promise to be fulfilled + */ +Q.race = race; +function race(answerPs) { + return promise(function(resolve, reject) { + // Switch to this once we can assume at least ES5 + // answerPs.forEach(function(answerP) { + // Q(answerP).then(resolve, reject); + // }); + // Use this in the meantime + for (var i = 0, len = answerPs.length; i < len; i++) { + Q(answerPs[i]).then(resolve, reject); + } + }); +} + +Promise.prototype.race = function () { + return this.then(Q.race); +}; + +/** + * Constructs a Promise with a promise descriptor object and optional fallback + * function. The descriptor contains methods like when(rejected), get(name), + * set(name, value), post(name, args), and delete(name), which all + * return either a value, a promise for a value, or a rejection. The fallback + * accepts the operation name, a resolver, and any further arguments that would + * have been forwarded to the appropriate method above had a method been + * provided with the proper name. The API makes no guarantees about the nature + * of the returned object, apart from that it is usable whereever promises are + * bought and sold. + */ +Q.makePromise = Promise; +function Promise(descriptor, fallback, inspect) { + if (fallback === void 0) { + fallback = function (op) { + return reject(new Error( + "Promise does not support operation: " + op + )); + }; + } + if (inspect === void 0) { + inspect = function () { + return {state: "unknown"}; + }; + } + + var promise = object_create(Promise.prototype); + + promise.promiseDispatch = function (resolve, op, args) { + var result; + try { + if (descriptor[op]) { + result = descriptor[op].apply(promise, args); + } else { + result = fallback.call(promise, op, args); + } + } catch (exception) { + result = reject(exception); + } + if (resolve) { + resolve(result); + } + }; + + promise.inspect = inspect; + + // XXX deprecated `valueOf` and `exception` support + if (inspect) { + var inspected = inspect(); + if (inspected.state === "rejected") { + promise.exception = inspected.reason; + } + + promise.valueOf = function () { + var inspected = inspect(); + if (inspected.state === "pending" || + inspected.state === "rejected") { + return promise; + } + return inspected.value; + }; + } + + return promise; +} + +Promise.prototype.toString = function () { + return "[object Promise]"; +}; + +Promise.prototype.then = function (fulfilled, rejected, progressed) { + var self = this; + var deferred = defer(); + var done = false; // ensure the untrusted promise makes at most a + // single call to one of the callbacks + + function _fulfilled(value) { + try { + return typeof fulfilled === "function" ? fulfilled(value) : value; + } catch (exception) { + return reject(exception); + } + } + + function _rejected(exception) { + if (typeof rejected === "function") { + makeStackTraceLong(exception, self); + try { + return rejected(exception); + } catch (newException) { + return reject(newException); + } + } + return reject(exception); + } + + function _progressed(value) { + return typeof progressed === "function" ? progressed(value) : value; + } + + nextTick(function () { + self.promiseDispatch(function (value) { + if (done) { + return; + } + done = true; + + deferred.resolve(_fulfilled(value)); + }, "when", [function (exception) { + if (done) { + return; + } + done = true; + + deferred.resolve(_rejected(exception)); + }]); + }); + + // Progress propagator need to be attached in the current tick. + self.promiseDispatch(void 0, "when", [void 0, function (value) { + var newValue; + var threw = false; + try { + newValue = _progressed(value); + } catch (e) { + threw = true; + if (Q.onerror) { + Q.onerror(e); + } else { + throw e; + } + } + + if (!threw) { + deferred.notify(newValue); + } + }]); + + return deferred.promise; +}; + +/** + * Registers an observer on a promise. + * + * Guarantees: + * + * 1. that fulfilled and rejected will be called only once. + * 2. that either the fulfilled callback or the rejected callback will be + * called, but not both. + * 3. that fulfilled and rejected will not be called in this turn. + * + * @param value promise or immediate reference to observe + * @param fulfilled function to be called with the fulfilled value + * @param rejected function to be called with the rejection exception + * @param progressed function to be called on any progress notifications + * @return promise for the return value from the invoked callback + */ +Q.when = when; +function when(value, fulfilled, rejected, progressed) { + return Q(value).then(fulfilled, rejected, progressed); +} + +Promise.prototype.thenResolve = function (value) { + return this.then(function () { return value; }); +}; + +Q.thenResolve = function (promise, value) { + return Q(promise).thenResolve(value); +}; + +Promise.prototype.thenReject = function (reason) { + return this.then(function () { throw reason; }); +}; + +Q.thenReject = function (promise, reason) { + return Q(promise).thenReject(reason); +}; + +/** + * If an object is not a promise, it is as "near" as possible. + * If a promise is rejected, it is as "near" as possible too. + * If it’s a fulfilled promise, the fulfillment value is nearer. + * If it’s a deferred promise and the deferred has been resolved, the + * resolution is "nearer". + * @param object + * @returns most resolved (nearest) form of the object + */ + +// XXX should we re-do this? +Q.nearer = nearer; +function nearer(value) { + if (isPromise(value)) { + var inspected = value.inspect(); + if (inspected.state === "fulfilled") { + return inspected.value; + } + } + return value; +} + +/** + * @returns whether the given object is a promise. + * Otherwise it is a fulfilled value. + */ +Q.isPromise = isPromise; +function isPromise(object) { + return isObject(object) && + typeof object.promiseDispatch === "function" && + typeof object.inspect === "function"; +} + +Q.isPromiseAlike = isPromiseAlike; +function isPromiseAlike(object) { + return isObject(object) && typeof object.then === "function"; +} + +/** + * @returns whether the given object is a pending promise, meaning not + * fulfilled or rejected. + */ +Q.isPending = isPending; +function isPending(object) { + return isPromise(object) && object.inspect().state === "pending"; +} + +Promise.prototype.isPending = function () { + return this.inspect().state === "pending"; +}; + +/** + * @returns whether the given object is a value or fulfilled + * promise. + */ +Q.isFulfilled = isFulfilled; +function isFulfilled(object) { + return !isPromise(object) || object.inspect().state === "fulfilled"; +} + +Promise.prototype.isFulfilled = function () { + return this.inspect().state === "fulfilled"; +}; + +/** + * @returns whether the given object is a rejected promise. + */ +Q.isRejected = isRejected; +function isRejected(object) { + return isPromise(object) && object.inspect().state === "rejected"; +} + +Promise.prototype.isRejected = function () { + return this.inspect().state === "rejected"; +}; + +//// BEGIN UNHANDLED REJECTION TRACKING + +// This promise library consumes exceptions thrown in handlers so they can be +// handled by a subsequent promise. The exceptions get added to this array when +// they are created, and removed when they are handled. Note that in ES6 or +// shimmed environments, this would naturally be a `Set`. +var unhandledReasons = []; +var unhandledRejections = []; +var trackUnhandledRejections = true; + +function resetUnhandledRejections() { + unhandledReasons.length = 0; + unhandledRejections.length = 0; + + if (!trackUnhandledRejections) { + trackUnhandledRejections = true; + } +} + +function trackRejection(promise, reason) { + if (!trackUnhandledRejections) { + return; + } + + unhandledRejections.push(promise); + if (reason && typeof reason.stack !== "undefined") { + unhandledReasons.push(reason.stack); + } else { + unhandledReasons.push("(no stack) " + reason); + } +} + +function untrackRejection(promise) { + if (!trackUnhandledRejections) { + return; + } + + var at = array_indexOf(unhandledRejections, promise); + if (at !== -1) { + unhandledRejections.splice(at, 1); + unhandledReasons.splice(at, 1); + } +} + +Q.resetUnhandledRejections = resetUnhandledRejections; + +Q.getUnhandledReasons = function () { + // Make a copy so that consumers can't interfere with our internal state. + return unhandledReasons.slice(); +}; + +Q.stopUnhandledRejectionTracking = function () { + resetUnhandledRejections(); + trackUnhandledRejections = false; +}; + +resetUnhandledRejections(); + +//// END UNHANDLED REJECTION TRACKING + +/** + * Constructs a rejected promise. + * @param reason value describing the failure + */ +Q.reject = reject; +function reject(reason) { + var rejection = Promise({ + "when": function (rejected) { + // note that the error has been handled + if (rejected) { + untrackRejection(this); + } + return rejected ? rejected(reason) : this; + } + }, function fallback() { + return this; + }, function inspect() { + return { state: "rejected", reason: reason }; + }); + + // Note that the reason has not been handled. + trackRejection(rejection, reason); + + return rejection; +} + +/** + * Constructs a fulfilled promise for an immediate reference. + * @param value immediate reference + */ +Q.fulfill = fulfill; +function fulfill(value) { + return Promise({ + "when": function () { + return value; + }, + "get": function (name) { + return value[name]; + }, + "set": function (name, rhs) { + value[name] = rhs; + }, + "delete": function (name) { + delete value[name]; + }, + "post": function (name, args) { + // Mark Miller proposes that post with no name should apply a + // promised function. + if (name === null || name === void 0) { + return value.apply(void 0, args); + } else { + return value[name].apply(value, args); + } + }, + "apply": function (thisp, args) { + return value.apply(thisp, args); + }, + "keys": function () { + return object_keys(value); + } + }, void 0, function inspect() { + return { state: "fulfilled", value: value }; + }); +} + +/** + * Converts thenables to Q promises. + * @param promise thenable promise + * @returns a Q promise + */ +function coerce(promise) { + var deferred = defer(); + nextTick(function () { + try { + promise.then(deferred.resolve, deferred.reject, deferred.notify); + } catch (exception) { + deferred.reject(exception); + } + }); + return deferred.promise; +} + +/** + * Annotates an object such that it will never be + * transferred away from this process over any promise + * communication channel. + * @param object + * @returns promise a wrapping of that object that + * additionally responds to the "isDef" message + * without a rejection. + */ +Q.master = master; +function master(object) { + return Promise({ + "isDef": function () {} + }, function fallback(op, args) { + return dispatch(object, op, args); + }, function () { + return Q(object).inspect(); + }); +} + +/** + * Spreads the values of a promised array of arguments into the + * fulfillment callback. + * @param fulfilled callback that receives variadic arguments from the + * promised array + * @param rejected callback that receives the exception if the promise + * is rejected. + * @returns a promise for the return value or thrown exception of + * either callback. + */ +Q.spread = spread; +function spread(value, fulfilled, rejected) { + return Q(value).spread(fulfilled, rejected); +} + +Promise.prototype.spread = function (fulfilled, rejected) { + return this.all().then(function (array) { + return fulfilled.apply(void 0, array); + }, rejected); +}; + +/** + * The async function is a decorator for generator functions, turning + * them into asynchronous generators. Although generators are only part + * of the newest ECMAScript 6 drafts, this code does not cause syntax + * errors in older engines. This code should continue to work and will + * in fact improve over time as the language improves. + * + * ES6 generators are currently part of V8 version 3.19 with the + * --harmony-generators runtime flag enabled. SpiderMonkey has had them + * for longer, but under an older Python-inspired form. This function + * works on both kinds of generators. + * + * Decorates a generator function such that: + * - it may yield promises + * - execution will continue when that promise is fulfilled + * - the value of the yield expression will be the fulfilled value + * - it returns a promise for the return value (when the generator + * stops iterating) + * - the decorated function returns a promise for the return value + * of the generator or the first rejected promise among those + * yielded. + * - if an error is thrown in the generator, it propagates through + * every following yield until it is caught, or until it escapes + * the generator function altogether, and is translated into a + * rejection for the promise returned by the decorated generator. + */ +Q.async = async; +function async(makeGenerator) { + return function () { + // when verb is "send", arg is a value + // when verb is "throw", arg is an exception + function continuer(verb, arg) { + var result; + + // Until V8 3.19 / Chromium 29 is released, SpiderMonkey is the only + // engine that has a deployed base of browsers that support generators. + // However, SM's generators use the Python-inspired semantics of + // outdated ES6 drafts. We would like to support ES6, but we'd also + // like to make it possible to use generators in deployed browsers, so + // we also support Python-style generators. At some point we can remove + // this block. + + if (typeof StopIteration === "undefined") { + // ES6 Generators + try { + result = generator[verb](arg); + } catch (exception) { + return reject(exception); + } + if (result.done) { + return Q(result.value); + } else { + return when(result.value, callback, errback); + } + } else { + // SpiderMonkey Generators + // FIXME: Remove this case when SM does ES6 generators. + try { + result = generator[verb](arg); + } catch (exception) { + if (isStopIteration(exception)) { + return Q(exception.value); + } else { + return reject(exception); + } + } + return when(result, callback, errback); + } + } + var generator = makeGenerator.apply(this, arguments); + var callback = continuer.bind(continuer, "next"); + var errback = continuer.bind(continuer, "throw"); + return callback(); + }; +} + +/** + * The spawn function is a small wrapper around async that immediately + * calls the generator and also ends the promise chain, so that any + * unhandled errors are thrown instead of forwarded to the error + * handler. This is useful because it's extremely common to run + * generators at the top-level to work with libraries. + */ +Q.spawn = spawn; +function spawn(makeGenerator) { + Q.done(Q.async(makeGenerator)()); +} + +// FIXME: Remove this interface once ES6 generators are in SpiderMonkey. +/** + * Throws a ReturnValue exception to stop an asynchronous generator. + * + * This interface is a stop-gap measure to support generator return + * values in older Firefox/SpiderMonkey. In browsers that support ES6 + * generators like Chromium 29, just use "return" in your generator + * functions. + * + * @param value the return value for the surrounding generator + * @throws ReturnValue exception with the value. + * @example + * // ES6 style + * Q.async(function* () { + * var foo = yield getFooPromise(); + * var bar = yield getBarPromise(); + * return foo + bar; + * }) + * // Older SpiderMonkey style + * Q.async(function () { + * var foo = yield getFooPromise(); + * var bar = yield getBarPromise(); + * Q.return(foo + bar); + * }) + */ +Q["return"] = _return; +function _return(value) { + throw new QReturnValue(value); +} + +/** + * The promised function decorator ensures that any promise arguments + * are settled and passed as values (`this` is also settled and passed + * as a value). It will also ensure that the result of a function is + * always a promise. + * + * @example + * var add = Q.promised(function (a, b) { + * return a + b; + * }); + * add(Q(a), Q(B)); + * + * @param {function} callback The function to decorate + * @returns {function} a function that has been decorated. + */ +Q.promised = promised; +function promised(callback) { + return function () { + return spread([this, all(arguments)], function (self, args) { + return callback.apply(self, args); + }); + }; +} + +/** + * sends a message to a value in a future turn + * @param object* the recipient + * @param op the name of the message operation, e.g., "when", + * @param args further arguments to be forwarded to the operation + * @returns result {Promise} a promise for the result of the operation + */ +Q.dispatch = dispatch; +function dispatch(object, op, args) { + return Q(object).dispatch(op, args); +} + +Promise.prototype.dispatch = function (op, args) { + var self = this; + var deferred = defer(); + nextTick(function () { + self.promiseDispatch(deferred.resolve, op, args); + }); + return deferred.promise; +}; + +/** + * Gets the value of a property in a future turn. + * @param object promise or immediate reference for target object + * @param name name of property to get + * @return promise for the property value + */ +Q.get = function (object, key) { + return Q(object).dispatch("get", [key]); +}; + +Promise.prototype.get = function (key) { + return this.dispatch("get", [key]); +}; + +/** + * Sets the value of a property in a future turn. + * @param object promise or immediate reference for object object + * @param name name of property to set + * @param value new value of property + * @return promise for the return value + */ +Q.set = function (object, key, value) { + return Q(object).dispatch("set", [key, value]); +}; + +Promise.prototype.set = function (key, value) { + return this.dispatch("set", [key, value]); +}; + +/** + * Deletes a property in a future turn. + * @param object promise or immediate reference for target object + * @param name name of property to delete + * @return promise for the return value + */ +Q.del = // XXX legacy +Q["delete"] = function (object, key) { + return Q(object).dispatch("delete", [key]); +}; + +Promise.prototype.del = // XXX legacy +Promise.prototype["delete"] = function (key) { + return this.dispatch("delete", [key]); +}; + +/** + * Invokes a method in a future turn. + * @param object promise or immediate reference for target object + * @param name name of method to invoke + * @param value a value to post, typically an array of + * invocation arguments for promises that + * are ultimately backed with `resolve` values, + * as opposed to those backed with URLs + * wherein the posted value can be any + * JSON serializable object. + * @return promise for the return value + */ +// bound locally because it is used by other methods +Q.mapply = // XXX As proposed by "Redsandro" +Q.post = function (object, name, args) { + return Q(object).dispatch("post", [name, args]); +}; + +Promise.prototype.mapply = // XXX As proposed by "Redsandro" +Promise.prototype.post = function (name, args) { + return this.dispatch("post", [name, args]); +}; + +/** + * Invokes a method in a future turn. + * @param object promise or immediate reference for target object + * @param name name of method to invoke + * @param ...args array of invocation arguments + * @return promise for the return value + */ +Q.send = // XXX Mark Miller's proposed parlance +Q.mcall = // XXX As proposed by "Redsandro" +Q.invoke = function (object, name /*...args*/) { + return Q(object).dispatch("post", [name, array_slice(arguments, 2)]); +}; + +Promise.prototype.send = // XXX Mark Miller's proposed parlance +Promise.prototype.mcall = // XXX As proposed by "Redsandro" +Promise.prototype.invoke = function (name /*...args*/) { + return this.dispatch("post", [name, array_slice(arguments, 1)]); +}; + +/** + * Applies the promised function in a future turn. + * @param object promise or immediate reference for target function + * @param args array of application arguments + */ +Q.fapply = function (object, args) { + return Q(object).dispatch("apply", [void 0, args]); +}; + +Promise.prototype.fapply = function (args) { + return this.dispatch("apply", [void 0, args]); +}; + +/** + * Calls the promised function in a future turn. + * @param object promise or immediate reference for target function + * @param ...args array of application arguments + */ +Q["try"] = +Q.fcall = function (object /* ...args*/) { + return Q(object).dispatch("apply", [void 0, array_slice(arguments, 1)]); +}; + +Promise.prototype.fcall = function (/*...args*/) { + return this.dispatch("apply", [void 0, array_slice(arguments)]); +}; + +/** + * Binds the promised function, transforming return values into a fulfilled + * promise and thrown errors into a rejected one. + * @param object promise or immediate reference for target function + * @param ...args array of application arguments + */ +Q.fbind = function (object /*...args*/) { + var promise = Q(object); + var args = array_slice(arguments, 1); + return function fbound() { + return promise.dispatch("apply", [ + this, + args.concat(array_slice(arguments)) + ]); + }; +}; +Promise.prototype.fbind = function (/*...args*/) { + var promise = this; + var args = array_slice(arguments); + return function fbound() { + return promise.dispatch("apply", [ + this, + args.concat(array_slice(arguments)) + ]); + }; +}; + +/** + * Requests the names of the owned properties of a promised + * object in a future turn. + * @param object promise or immediate reference for target object + * @return promise for the keys of the eventually settled object + */ +Q.keys = function (object) { + return Q(object).dispatch("keys", []); +}; + +Promise.prototype.keys = function () { + return this.dispatch("keys", []); +}; + +/** + * Turns an array of promises into a promise for an array. If any of + * the promises gets rejected, the whole array is rejected immediately. + * @param {Array*} an array (or promise for an array) of values (or + * promises for values) + * @returns a promise for an array of the corresponding values + */ +// By Mark Miller +// http://wiki.ecmascript.org/doku.php?id=strawman:concurrency&rev=1308776521#allfulfilled +Q.all = all; +function all(promises) { + return when(promises, function (promises) { + var countDown = 0; + var deferred = defer(); + array_reduce(promises, function (undefined, promise, index) { + var snapshot; + if ( + isPromise(promise) && + (snapshot = promise.inspect()).state === "fulfilled" + ) { + promises[index] = snapshot.value; + } else { + ++countDown; + when( + promise, + function (value) { + promises[index] = value; + if (--countDown === 0) { + deferred.resolve(promises); + } + }, + deferred.reject, + function (progress) { + deferred.notify({ index: index, value: progress }); + } + ); + } + }, void 0); + if (countDown === 0) { + deferred.resolve(promises); + } + return deferred.promise; + }); +} + +Promise.prototype.all = function () { + return all(this); +}; + +/** + * Waits for all promises to be settled, either fulfilled or + * rejected. This is distinct from `all` since that would stop + * waiting at the first rejection. The promise returned by + * `allResolved` will never be rejected. + * @param promises a promise for an array (or an array) of promises + * (or values) + * @return a promise for an array of promises + */ +Q.allResolved = deprecate(allResolved, "allResolved", "allSettled"); +function allResolved(promises) { + return when(promises, function (promises) { + promises = array_map(promises, Q); + return when(all(array_map(promises, function (promise) { + return when(promise, noop, noop); + })), function () { + return promises; + }); + }); +} + +Promise.prototype.allResolved = function () { + return allResolved(this); +}; + +/** + * @see Promise#allSettled + */ +Q.allSettled = allSettled; +function allSettled(promises) { + return Q(promises).allSettled(); +} + +/** + * Turns an array of promises into a promise for an array of their states (as + * returned by `inspect`) when they have all settled. + * @param {Array[Any*]} values an array (or promise for an array) of values (or + * promises for values) + * @returns {Array[State]} an array of states for the respective values. + */ +Promise.prototype.allSettled = function () { + return this.then(function (promises) { + return all(array_map(promises, function (promise) { + promise = Q(promise); + function regardless() { + return promise.inspect(); + } + return promise.then(regardless, regardless); + })); + }); +}; + +/** + * Captures the failure of a promise, giving an oportunity to recover + * with a callback. If the given promise is fulfilled, the returned + * promise is fulfilled. + * @param {Any*} promise for something + * @param {Function} callback to fulfill the returned promise if the + * given promise is rejected + * @returns a promise for the return value of the callback + */ +Q.fail = // XXX legacy +Q["catch"] = function (object, rejected) { + return Q(object).then(void 0, rejected); +}; + +Promise.prototype.fail = // XXX legacy +Promise.prototype["catch"] = function (rejected) { + return this.then(void 0, rejected); +}; + +/** + * Attaches a listener that can respond to progress notifications from a + * promise's originating deferred. This listener receives the exact arguments + * passed to ``deferred.notify``. + * @param {Any*} promise for something + * @param {Function} callback to receive any progress notifications + * @returns the given promise, unchanged + */ +Q.progress = progress; +function progress(object, progressed) { + return Q(object).then(void 0, void 0, progressed); +} + +Promise.prototype.progress = function (progressed) { + return this.then(void 0, void 0, progressed); +}; + +/** + * Provides an opportunity to observe the settling of a promise, + * regardless of whether the promise is fulfilled or rejected. Forwards + * the resolution to the returned promise when the callback is done. + * The callback can return a promise to defer completion. + * @param {Any*} promise + * @param {Function} callback to observe the resolution of the given + * promise, takes no arguments. + * @returns a promise for the resolution of the given promise when + * ``fin`` is done. + */ +Q.fin = // XXX legacy +Q["finally"] = function (object, callback) { + return Q(object)["finally"](callback); +}; + +Promise.prototype.fin = // XXX legacy +Promise.prototype["finally"] = function (callback) { + callback = Q(callback); + return this.then(function (value) { + return callback.fcall().then(function () { + return value; + }); + }, function (reason) { + // TODO attempt to recycle the rejection with "this". + return callback.fcall().then(function () { + throw reason; + }); + }); +}; + +/** + * Terminates a chain of promises, forcing rejections to be + * thrown as exceptions. + * @param {Any*} promise at the end of a chain of promises + * @returns nothing + */ +Q.done = function (object, fulfilled, rejected, progress) { + return Q(object).done(fulfilled, rejected, progress); +}; + +Promise.prototype.done = function (fulfilled, rejected, progress) { + var onUnhandledError = function (error) { + // forward to a future turn so that ``when`` + // does not catch it and turn it into a rejection. + nextTick(function () { + makeStackTraceLong(error, promise); + if (Q.onerror) { + Q.onerror(error); + } else { + throw error; + } + }); + }; + + // Avoid unnecessary `nextTick`ing via an unnecessary `when`. + var promise = fulfilled || rejected || progress ? + this.then(fulfilled, rejected, progress) : + this; + + if (typeof process === "object" && process && process.domain) { + onUnhandledError = process.domain.bind(onUnhandledError); + } + + promise.then(void 0, onUnhandledError); +}; + +/** + * Causes a promise to be rejected if it does not get fulfilled before + * some milliseconds time out. + * @param {Any*} promise + * @param {Number} milliseconds timeout + * @param {Any*} custom error message or Error object (optional) + * @returns a promise for the resolution of the given promise if it is + * fulfilled before the timeout, otherwise rejected. + */ +Q.timeout = function (object, ms, error) { + return Q(object).timeout(ms, error); +}; + +Promise.prototype.timeout = function (ms, error) { + var deferred = defer(); + var timeoutId = setTimeout(function () { + if (!error || "string" === typeof error) { + error = new Error(error || "Timed out after " + ms + " ms"); + error.code = "ETIMEDOUT"; + } + deferred.reject(error); + }, ms); + + this.then(function (value) { + clearTimeout(timeoutId); + deferred.resolve(value); + }, function (exception) { + clearTimeout(timeoutId); + deferred.reject(exception); + }, deferred.notify); + + return deferred.promise; +}; + +/** + * Returns a promise for the given value (or promised value), some + * milliseconds after it resolved. Passes rejections immediately. + * @param {Any*} promise + * @param {Number} milliseconds + * @returns a promise for the resolution of the given promise after milliseconds + * time has elapsed since the resolution of the given promise. + * If the given promise rejects, that is passed immediately. + */ +Q.delay = function (object, timeout) { + if (timeout === void 0) { + timeout = object; + object = void 0; + } + return Q(object).delay(timeout); +}; + +Promise.prototype.delay = function (timeout) { + return this.then(function (value) { + var deferred = defer(); + setTimeout(function () { + deferred.resolve(value); + }, timeout); + return deferred.promise; + }); +}; + +/** + * Passes a continuation to a Node function, which is called with the given + * arguments provided as an array, and returns a promise. + * + * Q.nfapply(FS.readFile, [__filename]) + * .then(function (content) { + * }) + * + */ +Q.nfapply = function (callback, args) { + return Q(callback).nfapply(args); +}; + +Promise.prototype.nfapply = function (args) { + var deferred = defer(); + var nodeArgs = array_slice(args); + nodeArgs.push(deferred.makeNodeResolver()); + this.fapply(nodeArgs).fail(deferred.reject); + return deferred.promise; +}; + +/** + * Passes a continuation to a Node function, which is called with the given + * arguments provided individually, and returns a promise. + * @example + * Q.nfcall(FS.readFile, __filename) + * .then(function (content) { + * }) + * + */ +Q.nfcall = function (callback /*...args*/) { + var args = array_slice(arguments, 1); + return Q(callback).nfapply(args); +}; + +Promise.prototype.nfcall = function (/*...args*/) { + var nodeArgs = array_slice(arguments); + var deferred = defer(); + nodeArgs.push(deferred.makeNodeResolver()); + this.fapply(nodeArgs).fail(deferred.reject); + return deferred.promise; +}; + +/** + * Wraps a NodeJS continuation passing function and returns an equivalent + * version that returns a promise. + * @example + * Q.nfbind(FS.readFile, __filename)("utf-8") + * .then(console.log) + * .done() + */ +Q.nfbind = +Q.denodeify = function (callback /*...args*/) { + var baseArgs = array_slice(arguments, 1); + return function () { + var nodeArgs = baseArgs.concat(array_slice(arguments)); + var deferred = defer(); + nodeArgs.push(deferred.makeNodeResolver()); + Q(callback).fapply(nodeArgs).fail(deferred.reject); + return deferred.promise; + }; +}; + +Promise.prototype.nfbind = +Promise.prototype.denodeify = function (/*...args*/) { + var args = array_slice(arguments); + args.unshift(this); + return Q.denodeify.apply(void 0, args); +}; + +Q.nbind = function (callback, thisp /*...args*/) { + var baseArgs = array_slice(arguments, 2); + return function () { + var nodeArgs = baseArgs.concat(array_slice(arguments)); + var deferred = defer(); + nodeArgs.push(deferred.makeNodeResolver()); + function bound() { + return callback.apply(thisp, arguments); + } + Q(bound).fapply(nodeArgs).fail(deferred.reject); + return deferred.promise; + }; +}; + +Promise.prototype.nbind = function (/*thisp, ...args*/) { + var args = array_slice(arguments, 0); + args.unshift(this); + return Q.nbind.apply(void 0, args); +}; + +/** + * Calls a method of a Node-style object that accepts a Node-style + * callback with a given array of arguments, plus a provided callback. + * @param object an object that has the named method + * @param {String} name name of the method of object + * @param {Array} args arguments to pass to the method; the callback + * will be provided by Q and appended to these arguments. + * @returns a promise for the value or error + */ +Q.nmapply = // XXX As proposed by "Redsandro" +Q.npost = function (object, name, args) { + return Q(object).npost(name, args); +}; + +Promise.prototype.nmapply = // XXX As proposed by "Redsandro" +Promise.prototype.npost = function (name, args) { + var nodeArgs = array_slice(args || []); + var deferred = defer(); + nodeArgs.push(deferred.makeNodeResolver()); + this.dispatch("post", [name, nodeArgs]).fail(deferred.reject); + return deferred.promise; +}; + +/** + * Calls a method of a Node-style object that accepts a Node-style + * callback, forwarding the given variadic arguments, plus a provided + * callback argument. + * @param object an object that has the named method + * @param {String} name name of the method of object + * @param ...args arguments to pass to the method; the callback will + * be provided by Q and appended to these arguments. + * @returns a promise for the value or error + */ +Q.nsend = // XXX Based on Mark Miller's proposed "send" +Q.nmcall = // XXX Based on "Redsandro's" proposal +Q.ninvoke = function (object, name /*...args*/) { + var nodeArgs = array_slice(arguments, 2); + var deferred = defer(); + nodeArgs.push(deferred.makeNodeResolver()); + Q(object).dispatch("post", [name, nodeArgs]).fail(deferred.reject); + return deferred.promise; +}; + +Promise.prototype.nsend = // XXX Based on Mark Miller's proposed "send" +Promise.prototype.nmcall = // XXX Based on "Redsandro's" proposal +Promise.prototype.ninvoke = function (name /*...args*/) { + var nodeArgs = array_slice(arguments, 1); + var deferred = defer(); + nodeArgs.push(deferred.makeNodeResolver()); + this.dispatch("post", [name, nodeArgs]).fail(deferred.reject); + return deferred.promise; +}; + +/** + * If a function would like to support both Node continuation-passing-style and + * promise-returning-style, it can end its internal promise chain with + * `nodeify(nodeback)`, forwarding the optional nodeback argument. If the user + * elects to use a nodeback, the result will be sent there. If they do not + * pass a nodeback, they will receive the result promise. + * @param object a result (or a promise for a result) + * @param {Function} nodeback a Node.js-style callback + * @returns either the promise or nothing + */ +Q.nodeify = nodeify; +function nodeify(object, nodeback) { + return Q(object).nodeify(nodeback); +} + +Promise.prototype.nodeify = function (nodeback) { + if (nodeback) { + this.then(function (value) { + nextTick(function () { + nodeback(null, value); + }); + }, function (error) { + nextTick(function () { + nodeback(error); + }); + }); + } else { + return this; + } +}; + +// All code before this point will be filtered from stack traces. +var qEndingLine = captureLine(); + +return Q; + +}); + diff --git a/cmd/mist/assets/ext/qml_messaging.js b/cmd/mist/assets/ext/qml_messaging.js new file mode 100644 index 000000000..8222c848d --- /dev/null +++ b/cmd/mist/assets/ext/qml_messaging.js @@ -0,0 +1,13 @@ +function HandleMessage(data) { + var message; + try { message = JSON.parse(data) } catch(e) {}; + + if(message) { + switch(message.type) { + case "coinbase": + return eth.coinBase(); + case "block": + return eth.blockByNumber(0); + } + } +} diff --git a/cmd/mist/assets/ext/qt_messaging_adapter.js b/cmd/mist/assets/ext/qt_messaging_adapter.js new file mode 100644 index 000000000..ff6976177 --- /dev/null +++ b/cmd/mist/assets/ext/qt_messaging_adapter.js @@ -0,0 +1,21 @@ +window._messagingAdapter = function(data) { + navigator.qt.postMessage(data); +}; + +navigator.qt.onmessage = function(ev) { + var data = JSON.parse(ev.data) + + if(data._event !== undefined) { + eth.trigger(data._event, data.data); + } else { + if(data._seed) { + var cb = eth._callbacks[data._seed]; + if(cb) { + cb.call(this, data.data) + + // Remove the "trigger" callback + delete eth._callbacks[ev._seed]; + } + } + } +} diff --git a/cmd/mist/assets/ext/string.js b/cmd/mist/assets/ext/string.js new file mode 100644 index 000000000..2473b5c36 --- /dev/null +++ b/cmd/mist/assets/ext/string.js @@ -0,0 +1,58 @@ +String.prototype.pad = function(l, r) { + if (r === undefined) { + r = l + if (!(this.substr(0, 2) == "0x" || /^\d+$/.test(this))) + l = 0 + } + var ret = this.bin(); + while (ret.length < l) + ret = "\0" + ret + while (ret.length < r) + ret = ret + "\0" + return ret; +} + +String.prototype.unpad = function() { + var i = this.length; + while (i && this[i - 1] == "\0") + --i + return this.substr(0, i) +} + +String.prototype.bin = function() { + if (this.substr(0, 2) == "0x") { + bytes = [] + var i = 2; + + // Check if it's odd - pad with a zero if so. + if (this.length % 2) + bytes.push(parseInt(this.substr(i++, 1), 16)) + + for (; i < this.length - 1; i += 2) + bytes.push(parseInt(this.substr(i, 2), 16)); + + return String.fromCharCode.apply(String, bytes); + } else if (/^\d+$/.test(this)) + return bigInt(this.substr(0)).toHex().bin() + + // Otherwise we'll return the "String" object instead of an actual string + return this.substr(0, this.length) +} + +String.prototype.unbin = function() { + var i, l, o = ''; + for(i = 0, l = this.length; i < l; i++) { + var n = this.charCodeAt(i).toString(16); + o += n.length < 2 ? '0' + n : n; + } + + return "0x" + o; +} + +String.prototype.dec = function() { + return bigInt(this.substr(0)).toString() +} + +String.prototype.hex = function() { + return bigInt(this.substr(0)).toHex() +} diff --git a/cmd/mist/assets/ext/test.html b/cmd/mist/assets/ext/test.html new file mode 100644 index 000000000..4bac7d36f --- /dev/null +++ b/cmd/mist/assets/ext/test.html @@ -0,0 +1,44 @@ +<!doctype> +<html> +<head> +<title>Tests</title> +</head> + +<body> +<button onclick="test();">Test me</button> + +<script type="text/javascript"> +function test() { + var filter = eth.watch({ + latest: -1, + from: "e6716f9544a56c530d868e4bfbacb172315bdead", + altered: ["aabb", {id: "eeff", "at": "aabb"}], + }); + + filter.changed(function(messages) { + console.log("messages", messages) + }) + + filter.getMessages(function(messages) { + console.log("getMessages", messages) + }); + + eth.getEachStorageAt("9ef0f0d81e040012600b0c1abdef7c48f720f88a", function(entries) { + for(var i = 0; i < entries.length; i++) { + console.log(entries[i].key, " : ", entries[i].value) + } + }) + + eth.getBlock("f70097659f329a09642a27f11338d9269de64f1d4485786e36bfc410832148cd", function(block) { + console.log(block) + }) + + eth.mutan("var a = 10", function(code) { + console.log("code", code) + }); +} +</script> + +</body> + +</html> |