Skip to content

Instantly share code, notes, and snippets.

@pkamenarsky
Created June 20, 2013 10:50
Show Gist options
  • Save pkamenarsky/5821817 to your computer and use it in GitHub Desktop.
Save pkamenarsky/5821817 to your computer and use it in GitHub Desktop.
/* Thunk
Creates a thunk representing the given closure.
Since we want automatic memoization of as many expressions as possible, we
use a JS object as a sort of tagged pointer, where the member x denotes the
object actually pointed to. If a "pointer" points to a thunk, it has a
member 't' which is set to true; if it points to a value, be it a function,
a value of an algebraic type of a primitive value, it has no member 't'.
When a thunk is evaluated, by reading the member 'x' of the "pointer," the
closure is evaluated and the getter removed, to be replaced with the value
returned by the thunk, and the getter finally returns the return value of
the closure.
*/
function T(f) {
return new Thunk(f);
}
function Thunk(f) {
this.f = f;
}
/* Apply
Applies the function f to the arguments args. If the application is under-
saturated, a closure is returned, awaiting further arguments. If it is over-
saturated, the function is fully applied, and the result (assumed to be a
function) is then applied to the remaining arguments.
*/
function A(f, args) {
f = f instanceof Thunk ? E(f) : f;
// Closure does some funny stuff with functions that occasionally
// results in non-functions getting applied, so we have to deal with
// it.
if(!f.apply) {
return f;
}
var arity = f.arity ? f.arity : f.length;
if(args.length === arity) {
return f.apply(null, args);
}
if(args.length > arity) {
var first = args.splice(0, arity);
return A(f.apply(null, first), args);
} else {
var g = function() {
var as = args.concat(Array.prototype.slice.call(arguments));
return A(f, as);
};
g.arity = arity - args.length;
return g;
}
}
/* Eval
Evaluate the given thunk t into head normal form.
If the "thunk" we get isn't actually a thunk, just return it.
*/
function E(t) {
if(t instanceof Thunk) {
if(t.f) {
t.x = t.f();
t.f = 0;
}
return t.x;
}
return t;
}
/* Throw an error.
We need to be able to use throw as an exception so we wrap it in a function.
*/
function die(err) {
throw err;
}
function quot(a, b) {
return (a-a%b)/b;
}
function quotRemI(a, b) {
return [1, (a-a%b)/b, a%b];
}
// 32 bit integer multiplication, with correct overflow behavior
// note that |0 or >>>0 needs to be applied to the result, for int and word
// respectively.
function imul(a, b) {
// ignore high a * high a as the result will always be truncated
var lows = (a & 0xffff) * (b & 0xffff); // low a * low b
var aB = (a & 0xffff) * (b & 0xffff0000); // low a * high b
var bA = (a & 0xffff0000) * (b & 0xffff); // low b * high a
return lows + aB + bA; // sum will not exceed 52 bits, so it's safe
}
function addC(a, b) {
var x = a+b;
return [1, x & 0xffffffff, x > 0x7fffffff];
}
function subC(a, b) {
var x = a-b;
return [1, x & 0xffffffff, x < -2147483648];
}
function sinh (arg) {
return (Math.exp(arg) - Math.exp(-arg)) / 2;
}
function tanh (arg) {
return (Math.exp(arg) - Math.exp(-arg)) / (Math.exp(arg) + Math.exp(-arg));
}
function cosh (arg) {
return (Math.exp(arg) + Math.exp(-arg)) / 2;
}
// Scratch space for byte arrays.
var rts_scratchBuf = new ArrayBuffer(8);
var rts_scratchW32 = new Uint32Array(rts_scratchBuf);
var rts_scratchFloat = new Float32Array(rts_scratchBuf);
var rts_scratchDouble = new Float64Array(rts_scratchBuf);
function decodeFloat(x) {
rts_scratchFloat[0] = x;
var sign = x < 0 ? -1 : 1;
var exp = ((rts_scratchW32[0] >> 23) & 0xff) - 150;
var man = rts_scratchW32[0] & 0x7fffff;
if(exp === 0) {
++exp;
} else {
man |= (1 << 23);
}
return [1, sign*man, exp];
}
function decodeDouble(x) {
rts_scratchDouble[0] = x;
var sign = x < 0 ? -1 : 1;
var manHigh = rts_scratchW32[1] & 0xfffff;
var manLow = rts_scratchW32[0];
var exp = ((rts_scratchW32[1] >> 20) & 0x7ff) - 1075;
if(exp === 0) {
++exp;
} else {
manHigh |= (1 << 20);
}
return [1, sign, manHigh, manLow, exp];
}
function err(str) {
die(toJSStr(str)[1]);
}
/* unpackCString#
NOTE: update constructor tags if the code generator starts munging them.
*/
function unCStr(str) {return unAppCStr(str, [1]);}
function unFoldrCStr(str, f, z) {
var acc = z;
for(var i = str.length-1; i >= 0; --i) {
acc = A(f, [[1, str.charCodeAt(i)], acc]);
}
return acc;
}
function unAppCStr(str, chrs) {
var i = arguments[2] ? arguments[2] : 0;
if(i >= str.length) {
return E(chrs);
} else {
return [2,[1,str.charCodeAt(i)],T(function() {
return unAppCStr(str,chrs,i+1);
})];
}
}
function charCodeAt(str, i) {return str.charCodeAt(i);}
function fromJSStr(str) {
return unCStr(E(str)[1]);
}
function toJSStr(hsstr) {
var s = '';
for(var str = E(hsstr); str[0] == 2; str = E(str[2])) {
s += String.fromCharCode(E(str[1])[1]);
}
return [1,s];
}
// newMutVar
function nMV(val) {
return ({x: val});
}
// readMutVar
function rMV(mv) {
return mv.x;
}
// writeMutVar
function wMV(mv, val) {
mv.x = val;
}
function localeEncoding() {
var le = newByteArr(5);
le['b']['i8'] = 'U'.charCodeAt(0);
le['b']['i8'] = 'T'.charCodeAt(0);
le['b']['i8'] = 'F'.charCodeAt(0);
le['b']['i8'] = '-'.charCodeAt(0);
le['b']['i8'] = '8'.charCodeAt(0);
return le;
}
var isFloatNaN = isDoubleNaN = isNaN;
function isDoubleInfinite(d) {
return (d === Infinity);
}
var isFloatInfinite = isDoubleInfinite;
function isDoubleNegativeZero(x) {
return (x===0 && (1/x)===-Infinity);
}
var isFloatNegativeZero = isDoubleNegativeZero;
function strEq(a, b) {
return a == b;
}
function strOrd(a, b) {
var ord;
if(a < b) {
ord = [1];
} else if(a == b) {
ord = [2];
} else {
ord = [3];
}
return ord;
}
function jsCatch(act, handler) {
try {
return A(act,[0]);
} catch(e) {
return A(handler,[e, 0]);
}
}
function hs_eqWord64(a, b) {
return (a[0] == b[0] && a[1] == b[1]);
}
// Word64# representation: (Word, Word)
function hs_wordToWord64(low) {
return [0, low];
}
function hs_mkWord64(high, low) {
return [high, low];
}
var coercionToken = undefined;
/* Haste represents constructors internally using 1 for the first constructor,
2 for the second, etc.
However, dataToTag should use 0, 1, 2, etc. Also, booleans might be unboxed.
*/
function dataToTag(x) {
if(x instanceof Array) {
return x[0]-1;
} else {
return x-1;
}
}
function __word_encodeDouble(d, e) {
return d * Math.pow(2,e);
}
var __word_encodeFloat = __word_encodeDouble;
var jsRound = Math.round; // Stupid GHC doesn't like periods in FFI IDs...
if(typeof _ == 'undefined') {
var _ = undefined;
}
function jsAlert(val) {
if(typeof alert != 'undefined') {
alert(val);
} else {
print(val);
}
}
function jsLog(val) {
console.log(val);
}
function jsPrompt(str) {
var val;
if(typeof prompt != 'undefined') {
val = prompt(str);
} else {
print(str);
val = readline();
}
return val == undefined ? '' : val.toString();
}
function jsEval(str) {
var x = eval(str);
return x == undefined ? '' : x.toString();
}
function isNull(obj) {
return obj === null;
}
function jsRead(str) {
return Number(str);
}
function jsShowI(val) {return val.toString();}
function jsShow(val) {
var ret = val.toString();
return val == Math.round(val) ? ret + '.0' : ret;
}
function jsSetCB(elem, evt, cb) {
// Count return press in single line text box as a change event.
if(evt == 'change' && elem.type.toLowerCase() == 'text') {
setCB(elem, 'keyup', function(k) {
if(k == '\n'.charCodeAt(0)) {
A(cb,[[1,k.keyCode]]);
}
});
}
var fun;
switch(evt) {
case 'click':
case 'dblclick':
case 'mouseup':
case 'mousedown':
fun = function(x) {A(cb,[[1,x.button]]);};
break;
case 'keypress':
case 'keyup':
case 'keydown':
fun = function(x) {A(cb,[[1,x.keyCode]]);};
break;
default:
fun = function() {A(cb,[]);};
break;
}
return setCB(elem, evt, fun);
}
function setCB(elem, evt, cb) {
if(elem.addEventListener) {
elem.addEventListener(evt, cb, false);
return true;
} else if(elem.attachEvent) {
elem.attachEvent('on'+evt, cb);
return true;
}
return false;
}
function jsSetTimeout(msecs, cb) {
window.setTimeout(function() {A(cb,[]);}, msecs);
}
// Degenerate versions of u_iswspace, u_iswalnum and u_iswalpha.
function u_iswspace(c) {
return c==9 || c==10 || c==13 || c==32;
}
function u_iswalnum(c) {
return (c >= 48 && c <= 57) || u_iswalpha(c);
}
// [a-zA-ZåäöÅÄÖ]
function u_iswalpha(c) {
return (c >= 65 && c <= 90) || (c >= 97 && c <= 122) ||
c == 229 || c == 228 || c == 246 ||
c == 197 || c == 196 || c == 214;
}
function jsGet(elem, prop) {
return elem[prop].toString();
}
function jsSet(elem, prop, val) {
elem[prop] = val;
}
function jsGetStyle(elem, prop) {
return elem.style[prop].toString();
}
function jsSetStyle(elem, prop, val) {
elem.style[prop] = val;
}
function jsKillChild(child, parent) {
parent.removeChild(child);
}
function jsClearChildren(elem) {
while(elem.hasChildNodes()){
elem.removeChild(elem.lastChild);
}
}
function jsFind(elem) {
var e = document.getElementById(elem)
if(e) {
return [2,[1,e]];
}
return [1];
}
function jsCreateElem(tag) {
return document.createElement(tag);
}
function jsGetChildBefore(elem) {
elem = elem.previousSibling;
while(elem) {
if(typeof elem.tagName != 'undefined') {
return [2,[1,elem]];
}
elem = elem.previousSibling;
}
return [1];
}
function jsGetLastChild(elem) {
var len = elem.childNodes.length;
for(var i = len-1; i >= 0; --i) {
if(typeof elem.childNodes[i].tagName != 'undefined') {
return [2,[1,elem.childNodes[i]]];
}
}
return [1];
}
function jsGetChildren(elem) {
var children = [1];
var len = elem.childNodes.length;
for(var i = len-1; i >= 0; --i) {
if(typeof elem.childNodes[i].tagName != 'undefined') {
children = [2, [1,elem.childNodes[i]], children];
}
}
return children;
}
function jsSetChildren(elem, children) {
children = E(children);
jsClearChildren(elem, 0);
while(children[0] === 2) {
elem.appendChild(E(E(children[1])[1]));
children = E(children[2]);
}
}
function jsAppendChild(child, container) {
container.appendChild(child);
}
function jsAddChildBefore(child, container, after) {
container.insertBefore(child, after);
}
var jsRand = Math.random;
// Concatenate a Haskell list of JS strings
function jsCat(strs, sep) {
var arr = [];
strs = E(strs);
while(strs[0] != 1) {
strs = E(strs);
arr.push(E(strs[1])[1]);
strs = E(strs[2]);
}
return arr.join(sep);
}
// Escape all double quotes in a string
function jsUnquote(str) {
return str.replace(/"/, '\\"');
}
// Parse a JSON message into a Haste.JSON.JSON value.
// As this pokes around inside Haskell values, it'll need to be updated if:
// * Haste.JSON.JSON changes;
// * E() starts to choke on non-thunks;
// * data constructor code generation changes; or
// * Just and Nothing change tags.
function jsParseJSON(str) {
try {
var js = JSON.parse(str);
var hs = toHS(js);
} catch(_) {
return [1];
}
return [2,hs];
}
function toHS(obj) {
switch(typeof obj) {
case 'number':
return [1, [1, jsRead(obj)]];
case 'string':
return [2, [1, obj]];
break;
case 'boolean':
return [3, obj]; // Booleans are special wrt constructor tags!
break;
case 'object':
if(obj instanceof Array) {
return [4, arr2lst(obj, 0)];
} else {
// Object type but not array - it's a dictionary.
// The RFC doesn't say anything about the ordering of keys, but
// considering that lots of people rely on keys being "in order" as
// defined by "the same way someone put them in at the other end,"
// it's probably a good idea to put some cycles into meeting their
// misguided expectations.
var ks = [];
for(var k in obj) {
ks.unshift(k);
}
var xs = [1];
for(var i in ks) {
xs = [2, [1, [1,ks[i]], toHS(obj[ks[i]])], xs];
}
return [5, xs];
}
}
}
function arr2lst(arr, elem) {
if(elem >= arr.length) {
return [1];
}
return [2, toHS(arr[elem]), T(function() {return arr2lst(arr,elem+1);})]
}
function ajaxReq(method, url, async, postdata, cb) {
var xhr = new XMLHttpRequest();
xhr.open(method, url, async);
xhr.setRequestHeader('Cache-control', 'no-cache');
xhr.onreadystatechange = function() {
if(xhr.readyState == 4) {
if(xhr.status == 200) {
A(cb,[[1,xhr.responseText]]);
} else {
A(cb,[[1,""]]); // Nothing
}
}
}
xhr.send(postdata);
}
function u_towlower(charCode) {
return String.fromCharCode(charCode).toLowerCase().charCodeAt(0);
}
function u_towupper(charCode) {
return String.fromCharCode(charCode).toUpperCase().charCodeAt(0);
}
// MVar implementation.
// Since Haste isn't concurrent, takeMVar and putMVar don't block on empty
// and full MVars respectively, but terminate the program since they would
// otherwise be blocking forever.
function newMVar() {
return ({empty: true});
}
function tryTakeMVar(mv) {
if(mv.empty) {
return [1, 0, undefined];
} else {
mv.empty = true;
mv.x = null;
return [1, 1, mv.x];
}
}
function takeMVar(mv) {
if(mv.empty) {
// TODO: real BlockedOnDeadMVar exception, perhaps?
err("Attempted to take empty MVar!");
}
mv.empty = true;
mv.x = null;
return mv.x;
}
function putMVar(mv, val) {
if(!mv.empty) {
// TODO: real BlockedOnDeadMVar exception, perhaps?
err("Attempted to put full MVar!");
}
mv.empty = false;
mv.x = val;
}
function tryPutMVar(mv, val) {
if(!mv.empty) {
return 0;
} else {
mv.empty = false;
mv.x = val;
return 1;
}
}
function sameMVar(a, b) {
return (a == b);
}
function isEmptyMVar(mv) {
return mv.empty ? 1 : 0;
}
// Implementation of stable names.
// Unlike native GHC, the garbage collector isn't going to move data around
// in a way that we can detect, so each object could serve as its own stable
// name if it weren't for the fact we can't turn a JS reference into an
// integer.
// So instead, each object has a unique integer attached to it, which serves
// as its stable name.
var __next_stable_name = 1;
function makeStableName(x) {
if(!x.stableName) {
x.stableName = __next_stable_name;
__next_stable_name += 1;
}
return x.stableName;
}
function eqStableName(x, y) {
return (x == y) ? 1 : 0;
}
/**
* Constructs a two's-complement integer an array containing bits of the
* integer in 32-bit (signed) pieces, given in little-endian order (i.e.,
* lowest-order bits in the first piece), and the sign of -1 or 0.
*
* See the from* functions below for other convenient ways of constructing
* Integers.
*
* The internal representation of an integer is an array of 32-bit signed
* pieces, along with a sign (0 or -1) that indicates the contents of all the
* other 32-bit pieces out to infinity. We use 32-bit pieces because these are
* the size of integers on which Javascript performs bit-operations. For
* operations like addition and multiplication, we split each number into 16-bit
* pieces, which can easily be multiplied within Javascript's floating-point
* representation without overflow or change in sign.
*
* @constructor
* @param {Array.<number>} bits Array containing the bits of the number.
* @param {number} sign The sign of the number: -1 for negative and 0 positive.
*/
var Integer = function(bits, sign) {
/**
* @type {!Array.<number>}
* @private
*/
this.bits_ = [];
/**
* @type {number}
* @private
*/
this.sign_ = sign;
// Copy the 32-bit signed integer values passed in. We prune out those at the
// top that equal the sign since they are redundant.
var top = true;
for (var i = bits.length - 1; i >= 0; i--) {
var val = bits[i] | 0;
if (!top || val != sign) {
this.bits_[i] = val;
top = false;
}
}
};
// NOTE: Common constant values ZERO, ONE, NEG_ONE, etc. are defined below the
// from* methods on which they depend.
/**
* A cache of the Integer representations of small integer values.
* @type {!Object}
* @private
*/
Integer.IntCache_ = {};
/**
* Returns an Integer representing the given (32-bit) integer value.
* @param {number} value A 32-bit integer value.
* @return {!Integer} The corresponding Integer value.
*/
var I_fromInt = function(value) {
if (-128 <= value && value < 128) {
var cachedObj = Integer.IntCache_[value];
if (cachedObj) {
return cachedObj;
}
}
var obj = new Integer([value | 0], value < 0 ? -1 : 0);
if (-128 <= value && value < 128) {
Integer.IntCache_[value] = obj;
}
return obj;
};
/**
* Returns an Integer representing the given value, provided that it is a finite
* number. Otherwise, zero is returned.
* @param {number} value The value in question.
* @return {!Integer} The corresponding Integer value.
*/
var I_fromNumber = function(value) {
if (isNaN(value) || !isFinite(value)) {
return Integer.ZERO;
} else if (value < 0) {
return I_negate(I_fromNumber(-value));
} else {
var bits = [];
var pow = 1;
for (var i = 0; value >= pow; i++) {
bits[i] = (value / pow) | 0;
pow *= Integer.TWO_PWR_32_DBL_;
}
return new Integer(bits, 0);
}
};
/**
* Returns a Integer representing the value that comes by concatenating the
* given entries, each is assumed to be 32 signed bits, given in little-endian
* order (lowest order bits in the lowest index), and sign-extending the highest
* order 32-bit value.
* @param {Array.<number>} bits The bits of the number, in 32-bit signed pieces,
* in little-endian order.
* @return {!Integer} The corresponding Integer value.
*/
Integer.fromBits = function(bits) {
var high = bits[bits.length - 1];
return new Integer(bits, high & (1 << 31) ? -1 : 0);
};
/**
* Returns an Integer representation of the given string, written using the
* given radix.
* @param {string} str The textual representation of the Integer.
* @param {number=} opt_radix The radix in which the text is written.
* @return {!Integer} The corresponding Integer value.
*/
I_fromString = function(str, opt_radix) {
if (str.length == 0) {
throw Error('number format error: empty string');
}
var radix = opt_radix || 10;
if (radix < 2 || 36 < radix) {
throw Error('radix out of range: ' + radix);
}
if (str.charAt(0) == '-') {
return I_negate(I_fromString(str.substring(1), radix));
} else if (str.indexOf('-') >= 0) {
throw Error('number format error: interior "-" character');
}
// Do several (8) digits each time through the loop, so as to
// minimize the calls to the very expensive emulated div.
var radixToPower = I_fromNumber(Math.pow(radix, 8));
var result = Integer.ZERO;
for (var i = 0; i < str.length; i += 8) {
var size = Math.min(8, str.length - i);
var value = parseInt(str.substring(i, i + size), radix);
if (size < 8) {
var power = I_fromNumber(Math.pow(radix, size));
result = I_add(I_mul(result, power), I_fromNumber(value));
} else {
result = I_mul(result, radixToPower);
result = I_add(add, I_fromNumber(value));
}
}
return result;
};
/**
* A number used repeatedly in calculations. Self must appear before the first
* call to the from* functions below.
* @type {number}
* @private
*/
Integer.TWO_PWR_32_DBL_ = (1 << 16) * (1 << 16);
/** @type {!Integer} */
Integer.ZERO = I_fromInt(0);
/** @type {!Integer} */
Integer.ONE = I_fromInt(1);
/**
* @type {!Integer}
* @private
*/
Integer.TWO_PWR_24_ = I_fromInt(1 << 24);
/**
* Returns the value, assuming it is a 32-bit integer.
* @return {number} The corresponding int value.
*/
var I_toInt = function(self) {
return self.bits_.length > 0 ? self.bits_[0] : self.sign_;
};
var I_toWord = function(self) {
return I_toInt(self) >>> 0;
};
/** @return {number} The closest floating-point representation to self value. */
var I_toNumber = function(self) {
if (isNegative(self)) {
return -I_toNumber(I_negate(self));
} else {
var val = 0;
var pow = 1;
for (var i = 0; i < self.bits_.length; i++) {
val += getBitsUnsigned(self, i) * pow;
pow *= Integer.TWO_PWR_32_DBL_;
}
return val;
}
};
/**
* Returns the index-th 32-bit (signed) piece of the Integer according to
* little-endian order (i.e., index 0 contains the smallest bits).
* @param {number} index The index in question.
* @return {number} The requested 32-bits as a signed number.
*/
var getBits = function(self, index) {
if (index < 0) {
return 0; // Allowing self simplifies bit shifting operations below...
} else if (index < self.bits_.length) {
return self.bits_[index];
} else {
return self.sign_;
}
};
/**
* Returns the index-th 32-bit piece as an unsigned number.
* @param {number} index The index in question.
* @return {number} The requested 32-bits as an unsigned number.
*/
var getBitsUnsigned = function(self, index) {
var val = getBits(self, index);
return val >= 0 ? val : Integer.TWO_PWR_32_DBL_ + val;
};
/** @return {number} The sign bit of self number, -1 or 0. */
var getSign = function(self) {
return self.sign_;
};
/** @return {boolean} Whether self value is zero. */
var isZero = function(self) {
if (self.sign_ != 0) {
return false;
}
for (var i = 0; i < self.bits_.length; i++) {
if (self.bits_[i] != 0) {
return false;
}
}
return true;
};
/** @return {boolean} Whether self value is negative. */
var isNegative = function(self) {
return self.sign_ == -1;
};
/** @return {boolean} Whether self value is odd. */
var isOdd = function(self) {
return (self.bits_.length == 0) && (self.sign_ == -1) ||
(self.bits_.length > 0) && ((self.bits_[0] & 1) != 0);
};
/**
* @param {Integer} other Integer to compare against.
* @return {boolean} Whether self Integer equals the other.
*/
var I_equals = function(self, other) {
if (self.sign_ != other.sign_) {
return false;
}
var len = Math.max(self.bits_.length, other.bits_.length);
for (var i = 0; i < len; i++) {
if (getBits(self, i) != getBits(other, i)) {
return false;
}
}
return true;
};
/**
* @param {Integer} other Integer to compare against.
* @return {boolean} Whether self Integer does not equal the other.
*/
var I_notEquals = function(self, other) {
return !I_equals(self, other);
};
/**
* @param {Integer} other Integer to compare against.
* @return {boolean} Whether self Integer is greater than the other.
*/
var greaterThan = function(self, other) {
return I_compare(self, other) > 0;
};
/**
* @param {Integer} other Integer to compare against.
* @return {boolean} Whether self Integer is greater than or equal to the other.
*/
var greaterThanOrEqual = function(self, other) {
return I_compare(self, other) >= 0;
};
/**
* @param {Integer} other Integer to compare against.
* @return {boolean} Whether self Integer is less than the other.
*/
var lessThan = function(self, other) {
return I_compare(self, other) < 0;
};
/**
* @param {Integer} other Integer to compare against.
* @return {boolean} Whether self Integer is less than or equal to the other.
*/
var lessThanOrEqual = function(self, other) {
return I_compare(self, other) <= 0;
};
/**
* Compares self Integer with the given one.
* @param {Integer} other Integer to compare against.
* @return {number} 0 if they are the same, 1 if the self is greater, and -1
* if the given one is greater.
*/
var I_compare = function(self, other) {
var diff = I_sub(self, other);
if (isNegative(diff)) {
return -1;
} else if (isZero(diff)) {
return 0;
} else {
return +1;
}
};
var I_compareInt = function(self, other) {
return I_compare(self, I_fromInt(other));
}
/**
* Returns an integer with only the first numBits bits of self value, sign
* extended from the final bit.
* @param {number} numBits The number of bits by which to shift.
* @return {!Integer} The shorted integer value.
*/
var shorten = function(self, numBits) {
var arr_index = (numBits - 1) >> 5;
var bit_index = (numBits - 1) % 32;
var bits = [];
for (var i = 0; i < arr_index; i++) {
bits[i] = getBits(self, i);
}
var sigBits = bit_index == 31 ? 0xFFFFFFFF : (1 << (bit_index + 1)) - 1;
var val = getBits(self, arr_index) & sigBits;
if (val & (1 << bit_index)) {
val |= 0xFFFFFFFF - sigBits;
bits[arr_index] = val;
return new Integer(bits, -1);
} else {
bits[arr_index] = val;
return new Integer(bits, 0);
}
};
/** @return {!Integer} The negation of self value. */
var I_negate = function(self) {
return I_add(not(self), Integer.ONE);
};
/**
* Returns the sum of self and the given Integer.
* @param {Integer} other The Integer to add to self.
* @return {!Integer} The Integer result.
*/
var I_add = function(self, other) {
var len = Math.max(self.bits_.length, other.bits_.length);
var arr = [];
var carry = 0;
for (var i = 0; i <= len; i++) {
var a1 = getBits(self, i) >>> 16;
var a0 = getBits(self, i) & 0xFFFF;
var b1 = getBits(other, i) >>> 16;
var b0 = getBits(other, i) & 0xFFFF;
var c0 = carry + a0 + b0;
var c1 = (c0 >>> 16) + a1 + b1;
carry = c1 >>> 16;
c0 &= 0xFFFF;
c1 &= 0xFFFF;
arr[i] = (c1 << 16) | c0;
}
return Integer.fromBits(arr);
};
/**
* Returns the difference of self and the given Integer.
* @param {Integer} other The Integer to subtract from self.
* @return {!Integer} The Integer result.
*/
var I_sub = function(self, other) {
return I_add(self, I_negate(other));
};
/**
* Returns the product of self and the given Integer.
* @param {Integer} other The Integer to multiply against self.
* @return {!Integer} The product of self and the other.
*/
var I_mul = function(self, other) {
if (isZero(self)) {
return Integer.ZERO;
} else if (isZero(other)) {
return Integer.ZERO;
}
if (isNegative(self)) {
if (isNegative(other)) {
return I_mul(I_negate(self), I_negate(other));
} else {
return I_negate(I_mul(I_negate(self), other));
}
} else if (isNegative(other)) {
return I_negate(I_mul(self, I_negate(other)));
}
// If both numbers are small, use float multiplication
if (lessThan(self, Integer.TWO_PWR_24_) &&
lessThan(other, Integer.TWO_PWR_24_)) {
return I_fromNumber(I_toNumber(self) * I_toNumber(other));
}
// Fill in an array of 16-bit products.
var len = self.bits_.length + other.bits_.length;
var arr = [];
for (var i = 0; i < 2 * len; i++) {
arr[i] = 0;
}
for (var i = 0; i < self.bits_.length; i++) {
for (var j = 0; j < other.bits_.length; j++) {
var a1 = getBits(self, i) >>> 16;
var a0 = getBits(self, i) & 0xFFFF;
var b1 = getBits(other, j) >>> 16;
var b0 = getBits(other, j) & 0xFFFF;
arr[2 * i + 2 * j] += a0 * b0;
Integer.carry16_(arr, 2 * i + 2 * j);
arr[2 * i + 2 * j + 1] += a1 * b0;
Integer.carry16_(arr, 2 * i + 2 * j + 1);
arr[2 * i + 2 * j + 1] += a0 * b1;
Integer.carry16_(arr, 2 * i + 2 * j + 1);
arr[2 * i + 2 * j + 2] += a1 * b1;
Integer.carry16_(arr, 2 * i + 2 * j + 2);
}
}
// Combine the 16-bit values into 32-bit values.
for (var i = 0; i < len; i++) {
arr[i] = (arr[2 * i + 1] << 16) | arr[2 * i];
}
for (var i = len; i < 2 * len; i++) {
arr[i] = 0;
}
return new Integer(arr, 0);
};
/**
* Carries any overflow from the given index into later entries.
* @param {Array.<number>} bits Array of 16-bit values in little-endian order.
* @param {number} index The index in question.
* @private
*/
Integer.carry16_ = function(bits, index) {
while ((bits[index] & 0xFFFF) != bits[index]) {
bits[index + 1] += bits[index] >>> 16;
bits[index] &= 0xFFFF;
}
};
var I_mod = function(self, other) {
return I_rem(I_add(other, I_rem(self, other)), other);
}
var I_div = function(self, other) {
if(greaterThan(self, Integer.ZERO) != greaterThan(other, Integer.ZERO)) {
if(I_rem(self, other) != Integer.ZERO) {
return I_sub(I_quot(self, other), Integer.ONE);
}
}
return I_quot(self, other);
}
var I_quotRem = function(self, other) {
return [1, I_quot(self, other), I_rem(self, other)];
}
var I_divMod = function(self, other) {
return [1, I_div(self, other), I_mod(self, other)];
}
/**
* Returns self Integer divided by the given one.
* @param {Integer} other Th Integer to divide self by.
* @return {!Integer} Self value divided by the given one.
*/
var I_quot = function(self, other) {
if (isZero(other)) {
throw Error('division by zero');
} else if (isZero(self)) {
return Integer.ZERO;
}
if (isNegative(self)) {
if (isNegative(other)) {
return I_quot(I_negate(self), I_negate(other));
} else {
return I_negate(I_quot(I_negate(self), other));
}
} else if (isNegative(other)) {
return I_negate(I_quot(self, I_negate(other)));
}
// Repeat the following until the remainder is less than other: find a
// floating-point that approximates remainder / other *from below*, add self
// into the result, and subtract it from the remainder. It is critical that
// the approximate value is less than or equal to the real value so that the
// remainder never becomes negative.
var res = Integer.ZERO;
var rem = self;
while (greaterThanOrEqual(rem, other)) {
// Approximate the result of division. Self may be a little greater or
// smaller than the actual value.
var approx = Math.max(1, Math.floor(I_toNumber(rem) / I_toNumber(other)));
// We will tweak the approximate result by changing it in the 48-th digit or
// the smallest non-fractional digit, whichever is larger.
var log2 = Math.ceil(Math.log(approx) / Math.LN2);
var delta = (log2 <= 48) ? 1 : Math.pow(2, log2 - 48);
// Decrease the approximation until it is smaller than the remainder. Note
// that if it is too large, the product overflows and is negative.
var approxRes = I_fromNumber(approx);
var approxRem = I_mul(approxRes, other);
while (isNegative(approxRem) || greaterThan(approxRem, rem)) {
approx -= delta;
approxRes = I_fromNumber(approx);
approxRem = I_mul(approxRes, other);
}
// We know the answer can't be zero... and actually, zero would cause
// infinite recursion since we would make no progress.
if (isZero(approxRes)) {
approxRes = Integer.ONE;
}
res = I_add(res, approxRes);
rem = I_sub(rem, approxRem);
}
return res;
};
/**
* Returns self Integer modulo the given one.
* @param {Integer} other The Integer by which to mod.
* @return {!Integer} Self value modulo the given one.
*/
var I_rem = function(self, other) {
return I_sub(self, I_mul(I_quot(self, other), other));
};
/** @return {!Integer} The bitwise-NOT of self value. */
var not = function(self) {
var len = self.bits_.length;
var arr = [];
for (var i = 0; i < len; i++) {
arr[i] = ~self.bits_[i];
}
return new Integer(arr, ~self.sign_);
};
/**
* Returns the bitwise-AND of self Integer and the given one.
* @param {Integer} other The Integer to AND with self.
* @return {!Integer} The bitwise-AND of self and the other.
*/
var I_and = function(self, other) {
var len = Math.max(self.bits_.length, other.bits_.length);
var arr = [];
for (var i = 0; i < len; i++) {
arr[i] = getBits(self, i) & getBits(other, i);
}
return new Integer(arr, self.sign_ & other.sign_);
};
/**
* Returns the bitwise-OR of self Integer and the given one.
* @param {Integer} other The Integer to OR with self.
* @return {!Integer} The bitwise-OR of self and the other.
*/
var I_or = function(self, other) {
var len = Math.max(self.bits_.length, other.bits_.length);
var arr = [];
for (var i = 0; i < len; i++) {
arr[i] = getBits(self, i) | getBits(other, i);
}
return new Integer(arr, self.sign_ | other.sign_);
};
/**
* Returns the bitwise-XOR of self Integer and the given one.
* @param {Integer} other The Integer to XOR with self.
* @return {!Integer} The bitwise-XOR of self and the other.
*/
var I_xor = function(self, other) {
var len = Math.max(self.bits_.length, other.bits_.length);
var arr = [];
for (var i = 0; i < len; i++) {
arr[i] = getBits(self, i) ^ getBits(other, i);
}
return new Integer(arr, self.sign_ ^ other.sign_);
};
/**
* Returns self value with bits shifted to the left by the given amount.
* @param {number} numBits The number of bits by which to shift.
* @return {!Integer} Self shifted to the left by the given amount.
*/
var I_shiftLeft = function(self, numBits) {
var arr_delta = numBits >> 5;
var bit_delta = numBits % 32;
var len = self.bits_.length + arr_delta + (bit_delta > 0 ? 1 : 0);
var arr = [];
for (var i = 0; i < len; i++) {
if (bit_delta > 0) {
arr[i] = (getBits(self, i - arr_delta) << bit_delta) |
(getBits(self, i - arr_delta - 1) >>> (32 - bit_delta));
} else {
arr[i] = getBits(self, i - arr_delta);
}
}
return new Integer(arr, self.sign_);
};
/**
* Returns self value with bits shifted to the right by the given amount.
* @param {number} numBits The number of bits by which to shift.
* @return {!Integer} Self shifted to the right by the given amount.
*/
var I_shiftRight = function(self, numBits) {
var arr_delta = numBits >> 5;
var bit_delta = numBits % 32;
var len = self.bits_.length - arr_delta;
var arr = [];
for (var i = 0; i < len; i++) {
if (bit_delta > 0) {
arr[i] = (getBits(self, i + arr_delta) >>> bit_delta) |
(getBits(self, i + arr_delta + 1) << (32 - bit_delta));
} else {
arr[i] = getBits(self, i + arr_delta);
}
}
return new Integer(arr, self.sign_);
};
var I_signum = function(self) {
var cmp = I_compare(self, Integer.ZERO);
if(cmp > 0) {
return Integer.ONE
}
if(cmp < 0) {
return I_sub(Integer.ZERO, Integer.ONE);
}
return Integer.ZERO;
};
var I_abs = function(self) {
if(I_compare(self, Integer.ZERO) < 0) {
return I_sub(Integer.ZERO, self);
}
return self;
};
var I_decodeDouble = function(x) {
var dec = decodeDouble(x);
var mantissa = Integer.fromBits([dec[3], dec[2]]);
if(dec[1] < 0) {
mantissa = I_negate(mantissa);
}
return [1, dec[4], mantissa];
}
var I_toString = function(self) {
var radix = 10;
if (isZero(self)) {
return '0';
} else if (isNegative(self)) {
return '-' + I_toString(I_negate(self));
}
// Do several (6) digits each time through the loop, so as to
// minimize the calls to the very expensive emulated div.
var radixToPower = I_fromNumber(Math.pow(radix, 6));
var rem = self;
var result = '';
while (true) {
var remDiv = I_div(rem, radixToPower);
var intval = I_toInt(I_sub(rem, I_mul(remDiv, radixToPower)));
var digits = intval.toString();
rem = remDiv;
if (isZero(rem)) {
return digits + result;
} else {
while (digits.length < 6) {
digits = '0' + digits;
}
result = '' + digits + result;
}
}
};
var I_fromRat = function(a, b) {
return I_toNumber(a) / I_toNumber(b);
}
// Joseph Myers' MD5 implementation; used under the BSD license.
function md5cycle(x, k) {
var a = x[0], b = x[1], c = x[2], d = x[3];
a = ff(a, b, c, d, k[0], 7, -680876936);
d = ff(d, a, b, c, k[1], 12, -389564586);
c = ff(c, d, a, b, k[2], 17, 606105819);
b = ff(b, c, d, a, k[3], 22, -1044525330);
a = ff(a, b, c, d, k[4], 7, -176418897);
d = ff(d, a, b, c, k[5], 12, 1200080426);
c = ff(c, d, a, b, k[6], 17, -1473231341);
b = ff(b, c, d, a, k[7], 22, -45705983);
a = ff(a, b, c, d, k[8], 7, 1770035416);
d = ff(d, a, b, c, k[9], 12, -1958414417);
c = ff(c, d, a, b, k[10], 17, -42063);
b = ff(b, c, d, a, k[11], 22, -1990404162);
a = ff(a, b, c, d, k[12], 7, 1804603682);
d = ff(d, a, b, c, k[13], 12, -40341101);
c = ff(c, d, a, b, k[14], 17, -1502002290);
b = ff(b, c, d, a, k[15], 22, 1236535329);
a = gg(a, b, c, d, k[1], 5, -165796510);
d = gg(d, a, b, c, k[6], 9, -1069501632);
c = gg(c, d, a, b, k[11], 14, 643717713);
b = gg(b, c, d, a, k[0], 20, -373897302);
a = gg(a, b, c, d, k[5], 5, -701558691);
d = gg(d, a, b, c, k[10], 9, 38016083);
c = gg(c, d, a, b, k[15], 14, -660478335);
b = gg(b, c, d, a, k[4], 20, -405537848);
a = gg(a, b, c, d, k[9], 5, 568446438);
d = gg(d, a, b, c, k[14], 9, -1019803690);
c = gg(c, d, a, b, k[3], 14, -187363961);
b = gg(b, c, d, a, k[8], 20, 1163531501);
a = gg(a, b, c, d, k[13], 5, -1444681467);
d = gg(d, a, b, c, k[2], 9, -51403784);
c = gg(c, d, a, b, k[7], 14, 1735328473);
b = gg(b, c, d, a, k[12], 20, -1926607734);
a = hh(a, b, c, d, k[5], 4, -378558);
d = hh(d, a, b, c, k[8], 11, -2022574463);
c = hh(c, d, a, b, k[11], 16, 1839030562);
b = hh(b, c, d, a, k[14], 23, -35309556);
a = hh(a, b, c, d, k[1], 4, -1530992060);
d = hh(d, a, b, c, k[4], 11, 1272893353);
c = hh(c, d, a, b, k[7], 16, -155497632);
b = hh(b, c, d, a, k[10], 23, -1094730640);
a = hh(a, b, c, d, k[13], 4, 681279174);
d = hh(d, a, b, c, k[0], 11, -358537222);
c = hh(c, d, a, b, k[3], 16, -722521979);
b = hh(b, c, d, a, k[6], 23, 76029189);
a = hh(a, b, c, d, k[9], 4, -640364487);
d = hh(d, a, b, c, k[12], 11, -421815835);
c = hh(c, d, a, b, k[15], 16, 530742520);
b = hh(b, c, d, a, k[2], 23, -995338651);
a = ii(a, b, c, d, k[0], 6, -198630844);
d = ii(d, a, b, c, k[7], 10, 1126891415);
c = ii(c, d, a, b, k[14], 15, -1416354905);
b = ii(b, c, d, a, k[5], 21, -57434055);
a = ii(a, b, c, d, k[12], 6, 1700485571);
d = ii(d, a, b, c, k[3], 10, -1894986606);
c = ii(c, d, a, b, k[10], 15, -1051523);
b = ii(b, c, d, a, k[1], 21, -2054922799);
a = ii(a, b, c, d, k[8], 6, 1873313359);
d = ii(d, a, b, c, k[15], 10, -30611744);
c = ii(c, d, a, b, k[6], 15, -1560198380);
b = ii(b, c, d, a, k[13], 21, 1309151649);
a = ii(a, b, c, d, k[4], 6, -145523070);
d = ii(d, a, b, c, k[11], 10, -1120210379);
c = ii(c, d, a, b, k[2], 15, 718787259);
b = ii(b, c, d, a, k[9], 21, -343485551);
x[0] = add32(a, x[0]);
x[1] = add32(b, x[1]);
x[2] = add32(c, x[2]);
x[3] = add32(d, x[3]);
}
function cmn(q, a, b, x, s, t) {
a = add32(add32(a, q), add32(x, t));
return add32((a << s) | (a >>> (32 - s)), b);
}
function ff(a, b, c, d, x, s, t) {
return cmn((b & c) | ((~b) & d), a, b, x, s, t);
}
function gg(a, b, c, d, x, s, t) {
return cmn((b & d) | (c & (~d)), a, b, x, s, t);
}
function hh(a, b, c, d, x, s, t) {
return cmn(b ^ c ^ d, a, b, x, s, t);
}
function ii(a, b, c, d, x, s, t) {
return cmn(c ^ (b | (~d)), a, b, x, s, t);
}
function md51(s) {
txt = '';
var n = s.length,
state = [1732584193, -271733879, -1732584194, 271733878], i;
for (i=64; i<=s.length; i+=64) {
md5cycle(state, md5blk(s.substring(i-64, i)));
}
s = s.substring(i-64);
var tail = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
for (i=0; i<s.length; i++)
tail[i>>2] |= s.charCodeAt(i) << ((i%4) << 3);
tail[i>>2] |= 0x80 << ((i%4) << 3);
if (i > 55) {
md5cycle(state, tail);
for (i=0; i<16; i++) tail[i] = 0;
}
tail[14] = n*8;
md5cycle(state, tail);
return state;
}
/* there needs to be support for Unicode here,
* unless we pretend that we can redefine the MD-5
* algorithm for multi-byte characters (perhaps
* by adding every four 16-bit characters and
* shortening the sum to 32 bits). Otherwise
* I suggest performing MD-5 as if every character
* was two bytes--e.g., 0040 0025 = @%--but then
* how will an ordinary MD-5 sum be matched?
* There is no way to standardize text to something
* like UTF-8 before transformation; speed cost is
* utterly prohibitive. The JavaScript standard
* itself needs to look at this: it should start
* providing access to strings as preformed UTF-8
* 8-bit unsigned value arrays.
*/
function md5blk(s) { /* I figured global was faster. */
var md5blks = [], i; /* Andy King said do it this way. */
for (i=0; i<64; i+=4) {
md5blks[i>>2] = s.charCodeAt(i)
+ (s.charCodeAt(i+1) << 8)
+ (s.charCodeAt(i+2) << 16)
+ (s.charCodeAt(i+3) << 24);
}
return md5blks;
}
var hex_chr = '0123456789abcdef'.split('');
function rhex(n)
{
var s='', j=0;
for(; j<4; j++)
s += hex_chr[(n >> (j * 8 + 4)) & 0x0F]
+ hex_chr[(n >> (j * 8)) & 0x0F];
return s;
}
function hex(x) {
for (var i=0; i<x.length; i++)
x[i] = rhex(x[i]);
return x.join('');
}
function md5(s) {
return hex(md51(s));
}
/* this function is much faster,
so if possible we use it. Some IEs
are the only ones I know of that
need the idiotic second function,
generated by an if clause. */
function add32(a, b) {
return (a + b) & 0xFFFFFFFF;
}
if (md5('hello') != '5d41402abc4b2a76b9719d911017c592') {
function add32(x, y) {
var lsw = (x & 0xFFFF) + (y & 0xFFFF),
msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 0xFFFF);
}
}
// Functions for dealing with arrays.
function newArr(n, x) {
var arr = [];
for(; n >= 0; --n) {
arr.push(x);
}
return arr;
}
// Create all views at once; perhaps it's wasteful, but it's better than having
// to check for the right view at each read or write.
function newByteArr(n) {
// Pad the thing to multiples of 8.
var padding = 8 - n % 8;
if(padding < 8) {
n += padding;
}
var arr = {};
var buffer = new ArrayBuffer(n);
var views = {};
views['i8'] = new Int8Array(buffer);
views['i16'] = new Int16Array(buffer);
views['i32'] = new Int32Array(buffer);
views['w8'] = new Uint8Array(buffer);
views['w16'] = new Uint16Array(buffer);
views['w32'] = new Uint32Array(buffer);
views['f32'] = new Float32Array(buffer);
views['f64'] = new Float64Array(buffer);
arr['b'] = buffer;
arr['v'] = views;
// ByteArray and Addr are the same thing, so keep an offset if we get
// casted.
arr['off'] = 0;
return arr;
}
// An attempt at emulating pointers enough for ByteString and Text to be
// usable without patching the hell out of them.
// The general idea is that Addr# is a byte array with an associated offset.
function plusAddr(addr, off) {
var newaddr = {};
newaddr['off'] = addr['off'] + off;
newaddr['b'] = addr['b'];
newaddr['v'] = addr['v'];
return newaddr;
}
function writeOffAddr(type, elemsize, addr, off, x) {
addr['v'][type][addr.off/elemsize + off] = x;
}
function readOffAddr(type, elemsize, addr, off) {
return addr['v'][type][addr.off/elemsize + off];
}
// Two addresses are equal if they point to the same buffer and have the same
// offset. For other comparisons, just use the offsets - nobody in their right
// mind would check if one pointer is less than another, completely unrelated,
// pointer and then act on that information anyway.
function addrEq(a, b) {
if(a == b) {
return true;
}
return a && b && a['b'] == b['b'] && a['off'] == b['off'];
}
function addrLT(a, b) {
if(a) {
return b && a['off'] < b['off'];
} else {
return (b != 0);
}
}
function addrGT(a, b) {
if(b) {
return a && a['off'] > b['off'];
} else {
return (a != 0);
}
}
var _0/*GHC.Base.++*/ = function(_1,_2){
var _3 = E(_1);
if(_3[0]==1){
var _4 = E(_2);
}else{
var _5 = _3[1];
var _6 = _3[2];
var _7 = T(function(){
return _0/*GHC.Base.++*/(_6,_2);
});
var _4 = [2,_5,_7];
}
return _4;
};
var _8/*GHC.List.lvl*/ = T(function(){
return unCStr(": empty list");
});
var _9/*GHC.List.prel_list_str*/ = T(function(){
return unCStr("Prelude.");
});
var _a/*GHC.List.errorEmptyList*/ = function(_b){
var _c = T(function(){
return _0/*GHC.Base.++*/(_b,_8/*GHC.List.lvl*/);
});
var _d = _0/*GHC.Base.++*/(_9/*GHC.List.prel_list_str*/,_c);
var _e = err(_d);
return _e;
};
var _f/*GHC.List.lvl12*/ = T(function(){
return unCStr("head");
});
var _g/*GHC.List.badHead*/ = T(function(){
return _a/*GHC.List.errorEmptyList*/(_f/*GHC.List.lvl12*/);
});
var _h/*GHC.Show.itos*/ = function(_i,_j){
var _k = jsShowI(_i);
var _l = [1,_k];
var _m = fromJSStr(_l);
var _n = _0/*GHC.Base.++*/(_m,_j);
return _n;
};
var _o/*GHC.Show.shows11*/ = [1,41];
var _p/*GHC.Show.shows12*/ = [1,40];
var _q/*GHC.Show.$wshowSignedInt*/ = function(_r,_s,_t){
var _u = _s<0;
if(_u){
var _v = _r>6;
if(_v){
var _w = T(function(){
var _x = [2,_o/*GHC.Show.shows11*/,_t];
return _h/*GHC.Show.itos*/(_s,_x);
});
var _y = [2,_p/*GHC.Show.shows12*/,_w];
}else{
var _y = _h/*GHC.Show.itos*/(_s,_t);
}
var _z = _y;
}else{
var _z = _h/*GHC.Show.itos*/(_s,_t);
}
return _z;
};
var _A/*GHC.Tuple.()*/ = [1];
var _B/*GHC.Types.[]*/ = [1];
var _C/*Main.main_go*/ = function(_D,_E){
var _F = _E<=1;
if(_F){
var _G = [1,_D];
var _H = [2,_G,_B/*GHC.Types.[]*/];
}else{
var _I = T(function(){
var _J = E(_D);
if(_J==2147483647){
var _K = [1];
}else{
var _L = _E-1|0;
var _M = _J+1|0;
var _N = _C/*Main.main_go*/(_M,_L);
var _K = _N;
}
return _K;
});
var _O = [1,_D];
var _H = [2,_O,_I];
}
return _H;
};
var _P/*Main.main2*/ = T(function(){
return _C/*Main.main_go*/(100,50);
});
var _Q/*Main.main1*/ = function(_){
var _R = E(_P/*Main.main2*/);
if(_R[0]==1){
var _S = E(_g/*GHC.List.badHead*/);
}else{
var _T = _R[1];
var _U = E(_T);
var _V = _U[1];
var _W = _q/*GHC.Show.$wshowSignedInt*/(0,_V,_B/*GHC.Types.[]*/);
var _X = toJSStr(_W);
var _Y = _X[1];
var _Z = jsLog(_Y);
var _S = _A/*GHC.Tuple.()*/;
}
return _S;
};
var _10/*Main.main*/ = function(_){
return _Q/*Main.main1*/(_);
};
A(_10, [0]);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment