text: ﻿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;
  }
  