(function($) {

"use strict";

try {
    Object.defineProperties($, {

        // greatest common divisor
        GCD: {
            value: function() {
                var
                    iterator,
                    primeFactor = 2,
                    product = 1,
                    i = 0,
                    amount = 0,
                    remains = [],

                    everyoneAreMultipleOf = function(remains, factor) {
                        var
                            i = 0;

                        while(i < remains.length) {
                            if (!remains[i++].multipleOf(factor)) {
                                return false;
                            }
                        }

                        return true;
                    },

                    callback = function(r) {
                        primeFactor = iterator.primeFactor();
                        if(everyoneAreMultipleOf(r, primeFactor)) {
                            product *= primeFactor;
                        }
                    },

                    euclidesAlgorithm = function(a, b) {
                        var
                            rest = b;

                        while(rest !== 0) {
                           rest = a % b;
                           a = b;
                           b = rest;
                        }

                        return a;
                    };

                remains = Array.from(arguments);
                remains = remains.uniq();
                if(remains.length == 1) {
                    return remains[0];
                }

                // properties

                // se todos os números forem múltiplos entre si, o MDC será menor deles
                if(remains.areMultiples()) {
                    return remains.min();
                }

                // o algorítmo de Euclides é mais eficiente para calcular o MDC entre apenas dois números
                if(remains.length == 2) {
                    return euclidesAlgorithm(remains[0], remains[1]);
                }

                // dois números primos não são múltiplos entre si
                i = 0;
                while(true) {
                    if((remains[i]).isPrime()) {amount++;}
                    if(amount >= 2) {return 1;}
                    if(i == remains.length -1) {break;}
                    i++;
                }

                iterator = Math.PrimeFactorsDecomposition.Proxy
                    .new(remains);
                iterator.decompose(callback);

                return product;
            }
        },

        // least common multiple
        LCM: {
            value: function() {
                var
                    iterator,
                    primeFactor = 2,
                    remains = [],
                    product = 1,

                    callback = function() {
                        primeFactor = iterator.primeFactor();
                        product *= primeFactor;
                    },

                    for2Factors = function(numbers) {
                        var
                            product = 1,

                            callback = function(v) {
                                product *= v;
                            };

                        numbers.forEach(callback);

                        return product/Math.GCD.apply(null, numbers);
                    };

                remains = Array.from(arguments);
                remains = remains.uniq();
                if(remains.length == 1) {
                    return remains[0];
                }

                if(remains.areMultiples()) {
                    return remains.max();
                }

                if(remains.length == 2) {
                    return for2Factors(remains);
                }

                iterator = Math.PrimeFactorsDecomposition.Proxy
                    .new(remains);
                iterator.decompose(callback);

                return product;
            }
        }

    });

} catch(e) {}

})(Math);