/*
Module to manipulate long integers
*/

var $module=(function($B){

eval($B.InjectBuiltins())

var $LongIntDict = {__class__:$B.$type,__name__:'LongInt'}

function add_pos(v1, v2){
    // Add two positive numbers
    // v1, v2 : strings
    // Return an instance of LongInt

    var res = '', carry = 0, iself=v1.length, sv=0
    for(var i=v2.length-1;i>=0;i--){
        iself--
        if(iself<0){sv=0}else{sv=parseInt(v1.charAt(iself))}
        x = (carry+sv+parseInt(v2.charAt(i))).toString()
        if(x.length==2){res=x.charAt(1)+res;carry=parseInt(x.charAt(0))}
        else{res=x+res;carry=0}
    }
    while(iself>0){
        iself--
        x = (carry+parseInt(v1.charAt(iself))).toString()
        if(x.length==2){res=x.charAt(1)+res;carry=parseInt(x.charAt(0))}
        else{res=x+res;carry=0}
    }
    if(carry){res=carry+res}        
    return {__class__:$LongIntDict, value:res, pos:true}
}

function check_shift(shift){
    // Check the argument of >> and <<
    if(!isinstance(shift, LongInt)){
        throw TypeError("shift must be LongInt, not '"+
            $B.get_class(shift).__name__+"'")
    }
    if(!shift.pos){throw ValueError("negative shift count")}
}

function clone(obj){
    // Used for traces
    var obj1 = {}
    for(var attr in obj){obj1[attr]=obj[attr]}
    return obj1
}

function comp_pos(v1, v2){
    // Compare two positive numbers
    if(v1.length>v2.length){return 1}
    else if(v1.length<v2.length){return -1}
    else{
        if(v1>v2){return 1}
        else if(v1<v2){return -1}
    }
    return 0
}

function divmod_pos(v1, v2){
    // v1, v2 : strings, represent 2 positive integers A and B
    // Return [a, b] where a and b are instances of LongInt
    // a = A // B, b = A % B
    var v1_init = v1, quotient, mod
    if(comp_pos(v1, v2)==-1){ // a < b
        quotient='0'
        mod = LongInt(v1)
    }else if(v2==v1){ // a = b
        quotient = '1';
        mod = LongInt('0')
    }else{
        var quotient = '', v1_init = v1
        var left = v1.substr(0, v2.length)
        if(v1<v2){left = v1.substr(0, v2.length+1)}
        var right = v1.substr(left.length)
        // mv2 maps integers i from 2 to 9 to i*v2, used as a cache to avoid
        // having to compute i*v2 each time
        var mv2 = {}
        // Javascript "safe integer" with the 15 first digits in v2,
        // used in the algorithm to test candidate values
        var jsv2 = parseInt(v2.substr(0,15))

        // Division algorithm
        // At each step in the division, v1 is split into substrings
        // "left" is the left part, with the same length as v2
        // "rest" is the rest of v1 after "left"
        // The algorithm finds the one-digit integer "candidate" such
        // that 0 <= left - candidate*v2 < v2
        // It stops when right is empty
        while(true){
            // Uses JS division to test an approximate result
            var jsleft = parseInt(left.substr(0,15))
            var candidate = Math.floor(jsleft/jsv2).toString()

            // Check that candidate is the correct result
            // Start by computing candidate*v2 : for this, use the table
            // mv2, which stores the multiples of v2 already calculated
            if(mv2[candidate]===undefined){
                mv2[candidate] = mul_pos(v2, candidate).value
            }
            if(comp_pos(left, mv2[candidate])==-1){
                // If left < candidate * v2, use candidate-1
                candidate--
                if(mv2[candidate]===undefined){
                    mv2[candidate] = mul_pos(v2, candidate).value
                }
            }

            // Add candidate to the quotient
            quotient += candidate

            // New value for left : left - v2*candidate
            left = sub_pos(left, mv2[candidate]).value

            // Stop if all digits in v1 have been used
            if(right.length==0){break}

            // Else, add next digit to left and remove it from right
            left += right.charAt(0)
            right = right.substr(1)
        }
        // Modulo is A - (A//B)*B
        mod = sub_pos(v1, mul_pos(quotient, v2).value)
    }
    return [LongInt(quotient), mod]
}

function mul_pos(v1, v2){
    // Multiply positive numbers v1 by v2
    // Make v2 smaller than v1
    if(v1.length<v2.length){var a=v1; v1=v2 ; v2=a}
    if(v2=='0'){return LongInt('0')}
    var cols = {}, i=v2.length, j
    
    // Built the object "cols", indexed by integers from 1 to nb1+nb2-2
    // where nb1 and nb2 are the number of digits in v1 and v2.
    // cols[n] is the sum of v1[i]*v2[j] for i+j = n
    
    while(i--){
        var car = v2.charAt(i)
        if(car=="0"){
            j = v1.length
            while(j--){
                if(cols[i+j]===undefined){cols[i+j]=0}
            }        
        }else if(car=="1"){
            j = v1.length
            while(j--){
                var z = parseInt(v1.charAt(j))
                if(cols[i+j]===undefined){cols[i+j]=z}
                else{cols[i+j] += z}
            }
        }else{
            var x = parseInt(car), j = v1.length, y, z
            while(j--){
                y = x * parseInt(v1.charAt(j))
                if(cols[i+j]===undefined){cols[i+j]=y}
                else{cols[i+j] += y}
            }
        }
    }

    // Transform cols so that cols[x] is a one-digit integers
    i = v1.length+v2.length-1
    while(i--){
        var col = cols[i].toString()
        if(col.length>1){
            // If the value in cols[i] has more than one digit, only keep the
            // last one and report the others at the right index
            // For instance if cols[i] = 123, keep 3 in cols[i], add 2 to
            // cols[i-1] and 1 to cols[i-2]
            cols[i] = parseInt(col.charAt(col.length-1))
            j = col.length
            while(j-->1){
                var report = parseInt(col.charAt(j-1))
                var pos = i-col.length+j
                if(cols[pos]===undefined){cols[pos]=report}
                else{cols[pos] += report}
            }
        }
    }

    // Find minimum index in cols
    // The previous loop may have introduced negative indices
    var imin
    for(var attr in cols){
        i = parseInt(attr)
        if(imin===undefined){imin=i}
        else if(i<imin){imin=i}
    }

    // Result is the concatenation of digits in cols
    var res = ''
    for(var i=imin;i<=v1.length+v2.length-2;i++){res+=cols[i].toString()}
    return LongInt(res)
}

function sub_pos(v1, v2){
    // Substraction of positive numbers with v1>=v2

    var res = '', carry = 0, i1=v1.length, sv=0
    
    // For all digits in v2, starting by the rightmost, substract it from
    // the matching digit in v1
    // This is the equivalent of the manual operation :
    //    12345678
    //   -   98765
    //
    // We begin by the rightmost operation : 8-5 (3, no carry),
    // then 7-6 (1, no carry)
    // then 6-7 (9, carry 1) and so on
    for(var i=v2.length-1;i>=0;i--){
        i1--
        sv = parseInt(v1.charAt(i1))
        x = (sv-carry-parseInt(v2.charAt(i)))
        if(x<0){res=(10+x)+res;carry=1}
        else{res=x+res;carry=0}
    }
    
    // If there are remaining digits in v1, substract the carry, if any
    while(i1>0){
        i1--
        x = (parseInt(v1.charAt(i1))-carry)
        if(x<0){res=(10+x)+res;carry=1}
        else{res=x+res;carry=0}
    }

    // Remove leading zeros and return the result
    while(res.charAt(0)=='0' && res.length>1){res=res.substr(1)}
    return {__class__:$LongIntDict, value:res, pos:true}
}

// Special methods to implement operations on instances of LongInt

$LongIntDict.__abs__ = function(self){
    return {__class__:$LongIntDict, value: self.value, pos:true}
}

$LongIntDict.__add__ = function(self, other){
    if (typeof other == 'number') other=LongInt(_b_.str(other))
    // Addition of "self" and "other"
    // If both have the same sign (+ or -) we add their absolute values
    // If they have different sign we use the substraction of their
    // absolute values
    var res
    if(self.pos&&other.pos){  // self > 0, other > 0
        return add_pos(self.value, other.value)
    }else if(!self.pos&&!other.pos){ // self < 0, other < 0
        res = add_pos(self.value, other.value)
        res.pos = false
        return res
    }else if(self.pos && !other.pos){ // self > 0, other < 0
        switch (comp_pos(self.value, other.value)){
            case 1:
                res = sub_pos(self.value, other.value)
                break
            case 0:
                res = {__class__:$LongIntDict, value:0, pos:true}
                break
            case -1:
                res = sub_pos(other.value, self.value)
                res.pos = false
                break
        }
        return res
    }else{ // self < 0, other > 0
        switch(comp_pos(self.value, other.value)){
            case 1:
                res = sub_pos(self.value, other.value)
                res.pos = false
                break
            case 0:
                res = {__class__:$LongIntDict, value:0, pos:true}
                break
            case -1:
                res = sub_pos(other.value, self.value)
                break
        }
        return res
    }
}

$LongIntDict.__and__ = function(self, other){
    if (typeof other == 'number') other=LongInt(_b_.str(other))
    // Bitwise "and" : build the binary representation of self and other
    var v1 = $LongIntDict.__index__(self)
    var v2 = $LongIntDict.__index__(other)
    // apply "and" on zeros and ones
    if(v1.length<v2.length){var temp=v2;v2=v1;v1=temp}
    var start = v1.length-v2.length
    var res = ''
    for(var i=0;i<v2.length;i++){
        if(v1.charAt(start+i)=='1' && v2.charAt(i)=='1'){res += '1'}
        else{res += '0'}
    }
    // Return the LongInt instance represented by res in base 2
    return LongInt(res, 2)
}

$LongIntDict.__divmod__ = function(self, other){
    if (typeof other == 'number') other=LongInt(_b_.str(other))

    var dm = divmod_pos(self.value, other.value)
    if(self.pos!==other.pos){
        if(dm[0].value!='0'){dm[0].pos = false}
        if(dm[1].value!='0'){
            // If self and other have different signs and self is not a multiple
            // of other, round to the previous integer
            dm[0] = $LongIntDict.__sub__(dm[0], LongInt('1'))
            dm[1] = $LongIntDict.__add__(dm[1], LongInt('1'))
        }
    }
    return dm    
}

$LongIntDict.__eq__ = function(self, other){
    if (typeof other == 'number') other=LongInt(_b_.str(other))
    return self.value==other.value && self.pos==other.pos
}

$LongIntDict.__floordiv__ = function(self, other){
    if (typeof other == 'number') other=LongInt(_b_.str(other))
    return $LongIntDict.__divmod__(self, other)[0]
}

$LongIntDict.__ge__ = function(self, other){
    if (typeof other == 'number') other=LongInt(_b_.str(other))
    if(self.value.length>other.value.length){return true}
    else if(self.value.length<other.value.length){return false}
    else{return self.value >= other.value}
}

$LongIntDict.__gt__ = function(self, other){
    return !$LongIntDict.__le__(self, other)
}

$LongIntDict.__index__ = function(self){
    // Used by bin()
    // returns a string with the binary value of self
    // The algorithm computes the result of the floor division of self by 2
    
    // XXX to do : negative integers
    
    var res = '', pos=self.value.length,
        temp = self.value, d
    while(true){
        d = divmod_pos(temp, '2')
        res = d[1].value + res
        temp = d[0].value
        if(temp=='0'){break}
    }
    return res
}

$LongIntDict.__invert__ = function(self){
    var bin = $LongIntDict.__index__(self)
    var res = ''
    for(var i=0;i<bin.length;i++){
        res += bin.charAt(i)=='0' ? '1' : '0'
    }
    return LongInt(res, 2)
}

$LongIntDict.__le__ = function(self, other){
    if (typeof other == 'number') other=LongInt(_b_.str(other))
    if(self.value.length>other.value.length){return false}
    else if(self.value.length<other.value.length){return true}
    else{return self.value <= other.value}
}

$LongIntDict.__lt__ = function(self, other){
    return !$LongIntDict.__ge__(self, other)
}

$LongIntDict.__lshift__ = function(self, shift){
    check_shift(shift)
    var res = self.value
    while(true){
        var x, carry=0, res1=''
        for(var i=res.length-1;i>=0;i--){
            x = (carry+parseInt(res.charAt(i))*2).toString()
            if(x.length==2){res1=x.charAt(1)+res1;carry=parseInt(x.charAt(0))}
            else{res1=x+res1;carry=0}
        }
        if(carry){res1=carry+res1}
        res=res1
        shift = sub_pos(shift.value, '1')
        if(shift.value=='0'){break}
    }
    return {__class__:$LongIntDict, value:res, pos:self.pos}
}

$LongIntDict.__mod__ = function(self, other){
    return $LongIntDict.__divmod__(self, other)[1]
}

$LongIntDict.__mro__ = [_b_.object.$dict]

$LongIntDict.__mul__ = function(self, other){
    if (typeof other == 'number') other=LongInt(_b_.str(other))
    var res = mul_pos(self.value, other.value)
    if(self.pos==other.pos){return res}
    res.pos = false
    return res
}

$LongIntDict.__neg__ = function(obj){
    return {__class__:$LongIntDict, value:obj.value, pos:!obj.pos}
}

$LongIntDict.__or__ = function(self, other){
    var v1 = $LongIntDict.__index__(self)
    var v2 = $LongIntDict.__index__(other)
    if(v1.length<v2.length){var temp=v2;v2=v1;v1=temp}
    var start = v1.length-v2.length
    var res = v1.substr(0, start)
    for(var i=0;i<v2.length;i++){
        if(v1.charAt(start+i)=='1' || v2.charAt(i)=='1'){res += '1'}
        else{res += '0'}
    }
    return LongInt(res, 2)
}


$LongIntDict.__pow__ = function(self, power){
    if (typeof power == "number") {
        power=LongInt(_b_.str(power))
    }else if(!isinstance(power, LongInt)){
        var msg = "power must be a LongDict, not '"
        throw TypeError(msg+$B.get_class(power).__name__+"'")
    }
    if(!power.pos){
        if(self.value=='1'){return self}
        // For all other integers, x**-n is 0
        return LongInt('0')
    }else if(power.value=='0'){
        return LongInt('1')
    }
    var res = {__class__:$LongIntDict, value:self.value, pos:self.pos}
    var pow = power.value
    while(true){
        pow = sub_pos(pow, '1').value
        if(pow == '0'){break}
        res = $LongIntDict.__mul__(res, self)
    }
    return res    
}

$LongIntDict.__rshift__ = function(self, shift){
    check_shift(shift)
    var res = self.value
    while(true){
        res = divmod_pos(res, '2')[0].value
        if(res.value=='0'){break}
        shift = sub_pos(shift.value, '1')
        if(shift.value=='0'){break}
    }
    return {__class__:$LongIntDict, value:res, pos:self.pos}
}

$LongIntDict.__str__ = $LongIntDict.__repr__ = function(self){
    var res = "LongInt('"
    if(!self.pos){res += '-'}
    return res+self.value+"')"
}

$LongIntDict.__sub__ = function(self, other){
    if (typeof other == 'number') other=LongInt(_b_.str(other))
    var res
    if(self.pos && other.pos){
        switch(comp_pos(self.value, other.value)){
            case 1:
                res = sub_pos(self.value, other.value)
                break
            case 0:
                res = {__class__:$LongIntDict, value:'0', pos:true}
                break
            case -1:
                res = sub_pos(other.value, self.value)
                res.pos = false
                break
        }
        return res
    }else if(!self.pos && !other.pos){
        switch(comp_pos(self.value, other.value)){
            case 1:
                res = sub_pos(self.value, other.value)
                res.pos = false
                break
            case 0:
                res = {__class__:$LongIntDict, value:'0', pos:true}
                break
            case -1:
                res = sub_pos(other.value, self.value)
                break
        }
        return res
    }else if(self.pos && !other.pos){
        return add_pos(self.value, other.value)
    }else{
        res = add_pos(self.value, other.value)
        res.pos = false
        return res
    }
}

$LongIntDict.__xor__ = function(self, other){
    var v1 = $LongIntDict.__index__(self)
    var v2 = $LongIntDict.__index__(other)
    if(v1.length<v2.length){var temp=v2;v2=v1;v1=temp}
    var start = v1.length-v2.length
    var res = v1.substr(0, start)
    for(var i=0;i<v2.length;i++){
        if(v1.charAt(start+i)=='1' && v2.charAt(i)=='0'){res += '1'}
        else if(v1.charAt(start+i)=='0' && v2.charAt(i)=='1'){res += '1'}
        else{res += '0'}
    }
    return LongInt(res, 2)
}

$LongIntDict.to_base = function(self, base){
    // Returns the string representation of self in specified base
    var res='', v=self.value
    while(v>0){
        var dm = divmod_pos(v, base.toString())
        res = parseInt(dm[1].value).toString(base)+res
        v = dm[0].value
        if(v==0){break}
    }
    return res
}

function digits(base){
    // Return an object where keys are all the digits valid in specified base
    // and value is "true"
    // Used to test if the string passed as first argument to LongInt is valid
    var is_digits = {}
    // Number from 0 to base, or from 0 to 9 if base > 10
    for(var i=0;i<base;i++){
        if(i==10){break}
        is_digits[i]=true
    }
    if(base>10){
        // Additional letters
        // For instance in base 16, add "abcdefABCDEF" as keys
        for(var i=0;i<base-10;i++){
            is_digits[String.fromCharCode(65+i)]=true
            is_digits[String.fromCharCode(97+i)]=true
        }
    }
    return is_digits
}

var MAX_SAFE_INTEGER = Math.pow(2, 53)-1;
var MIN_SAFE_INTEGER = -Number.MAX_SAFE_INTEGER;

function isSafeInteger(n) {
    return (typeof n === 'number' &&
        Math.round(n) === n &&
        Number.MIN_SAFE_INTEGER <= n &&
        n <= Number.MAX_SAFE_INTEGER);
}

function LongInt(value, base){
    if(arguments.length>2){
        throw _b_.TypeError("LongInt takes at most 2 arguments ("+
            arguments.length+" given)")
    }
    // base defaults to 10
    if(base===undefined){base = 10}
    else if(!isinstance(base, int)){
        throw TypeError("'"+$B.get_class(base).__name__+"' object cannot be interpreted as an integer")
    }
    if(base<0 || base==1 || base>36){
        throw ValueError("LongInt() base must be >= 2 and <= 36")
    }
    if(isinstance(value, float)){
        if(value>=0){value=Math.round(value.value)}
        else{value=Math.ceil(value.value)}
    }
    if(typeof value=='number'){
        if(isSafeInteger(value)){value = value.toString()}
        else{throw ValueError("argument of long_int is not a safe integer")}
    }else if(typeof value!='string'){
        throw ValueError("argument of long_int must be a string, not "+
            $B.get_class(value).__name__)
    }
    var has_prefix = false, pos = true, start = 0
    // Strip leading and trailing whitespaces
    while(value.charAt(0)==' ' && value.length){value = value.substr(1)}
    while(value.charAt(value.length-1)==' ' && value.length){
        value = value.substr(0, value.length-1)
    }
    // Check if string starts with + or -
    if(value.charAt(0)=='+'){has_prefix=true}
    else if(value.charAt(0)=='-'){has_prefix=true;pos=false}
    if(has_prefix){
        // Remove prefix
        if(value.length==1){
            // "+" or "-" alone are not valid arguments
            throw ValueError('LongInt argument is not a valid number: "'+value+'"')
        }else{value=value.substr(1)}
    }
    // Ignore leading zeros
    while(start<value.length-1 && value.charAt(start)=='0'){start++}
    value = value.substr(start)

    // Check if all characters in value are valid in the base
    var is_digits = digits(base), point = -1
    for(var i=0;i<value.length;i++){
        if(value.charAt(i)=='.' && point==-1){point=i}
        else if(!is_digits[value.charAt(i)]){
            throw ValueError('LongInt argument is not a valid number: "'+value+'"')
        }
    }
    if(point!=-1){value=value.substr(0,point)}
    if(base!=10){
        // Conversion to base 10
        var coef = '1', v10 = LongInt(0),
            pos = value.length, digit_base10
        while(pos--){
            digit_base10 = parseInt(value.charAt(pos), base).toString()
            digit_by_coef = mul_pos(coef, digit_base10).value
            v10 = add_pos(v10.value, digit_by_coef)
            coef = mul_pos(coef, base.toString()).value
        }
        return v10
    }
    return {__class__:$LongIntDict, value:value, pos:pos}
}

LongInt.__class__ = $B.$factory
LongInt.$dict = $LongIntDict
$LongIntDict.$factory = LongInt

return {LongInt:LongInt}

})(__BRYTHON__)
