function sum(data, extractor)
{
    if(!extractor)
    {
       extractor = function(a)
       {
           return a;
       }
    }
    var sum = 0;
    for (x in data)
    {
        sum += extractor(data[x]);
    }
    return sum;
}

function mean(data, extractor)
{
    return sum(data, extractor) / data.length;
}

function std_dev(data)
{
    var my_mean = mean(data);
    var squares = 0;
    for (var i = 0; i < data.length; i++)
    {
        squares += Math.pow(data[i] - my_mean, 2);
    }
    return Math.sqrt(squares / data.length);
}

function a_max(data, compartor)
{
    if (data == null || data.length == 0) {
        return null;
    }
    var max = data[0];
    if (!compartor)
    {
        compartor = function(a, b) {
            return a - b;
        }
    }

    for (var x in data)
    {
        if (compartor(data[x], max) > 0)
        {
            max = data[x];
        }
    }
    return max;
}

/**
 * curryAgg is used to curry the aggrigate functions so that they can be passed to Array.map etc.
 *
 * @param func the function to curry.
 * @param extractor function used to ectract a value from the iterated object.
 */
function curryAgg(func , extractor)
{
    return function(data)
    {
        return func(data, extractor);
    }
}

/**
 * Hashes the data;
 *
 * @param data array of data points
 * @param hash_func function(to_hash) { return hash_code; }
 * @param filter function(to_keep) {return keep=true;}
 * @param overwright_on_colishion if false, each bucket contains an array of data points.
 */
function hash(data, hash_func, filter, overwright_on_colishion)
{
    var toRet = new Array();
    var hash_code;
    for (var i = 0; i < data.length; i++)
    {
        hash_code = hash_func(data[i]);

        if (!filter(hash_code)) {
            if ((!(hash_code in toRet)) && (!overwright_on_colishion))
            {
                toRet[hash_code] = new Array();
                toRet[hash_code].push(data[i]);
            }
            else
            {
                if (overwright_on_colishion)
                {
                    toRet[hash_code] = data[i];
                } else
                {
                    toRet[hash_code].push(data[i]);
                }
            }
        }
    }
    return toRet;
}
