﻿/* JSON support */



var smartColors = function (numColors, saturation, lightness) {

    var pad = function (text, p, width) {
        var ar = [];
        while (ar.length < width - text.length) {
            ar.push(p);
        }
        return ar.join("") + text;
    };
    var hslToRgb = function (h, s, l) {
        var r, g, b;

        if (s == 0) {
            r = g = b = l; // achromatic
        } else {

            function hue2Rgb(p, q, t) {
                if (t < 0) t += 1;
                if (t > 1) t -= 1;
                if (t < 1 / 6) return p + (q - p) * 6 * t;
                if (t < 1 / 2) return q;
                if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
                return p;
            }

            var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
            var p = 2 * l - q;
            r = hue2Rgb(p, q, h + 1 / 3);
            g = hue2Rgb(p, q, h);
            b = hue2Rgb(p, q, h - 1 / 3);
        }

        return [Math.floor(r * 255), Math.floor(g * 255), Math.floor(b * 255)];
    };
    var hueUniformizer = function (x) {
        return 1.04 * x + 0.04 * (Math.sin(18 * x + 0.5) - Math.sin(0.5));
    };
    if (saturation == null) {
        saturation = 1;
    }
    if (lightness == null) {
        lightness = 0.5;
    }

    saturation = 0.5 + saturation * 0.5;

    lightness = 1 / 3 + lightness * 1 / 3;

    var sVariations = [0.5 * saturation, 1 * saturation];
    var lVariations = [lightness - 1 / 6, lightness + 1 / 6];
    var retColors = [];
    var numHues = numColors <= 8 ? 8 : numColors;
    for (var k = 0; k < numColors; ++k) {
        var s = sVariations[Math.floor((k % 4) / 2)];
        var l = lVariations[k % 2];
        var h = (k % numHues) / numHues;
        var rgb = hslToRgb(hueUniformizer(h), s, l);
        retColors.push(
            ["#", pad(rgb[0].toString(16), "0", 2),
                pad(rgb[1].toString(16), "0", 2),
                pad(rgb[2].toString(16), "0", 2)].join(""));
    }
    return retColors;
};


if (!this.JSON) this.JSON = {};
(function () {

    function k(a) {
        return a < 10 ? "0" + a : a;
    }

    function n(a) {
        o.lastIndex = 0;
        return o.test(a) ? '"' + a.replace(o, function (c) {
            var d = q[c];
            return typeof d === "string" ? d : "\\u" + ("0000" + c.charCodeAt(0).toString(16)).slice(-4);
        }) + '"' : '"' + a + '"';
    }

    function l(a, c) {
        var d, f, i = g, e, b = c[a];
        if (b && typeof b === "object" && typeof b.toJSON === "function") b = b.toJSON(a);
        if (typeof j === "function") b = j.call(c, a, b);
        switch (typeof b) {
            case "string":
                return n(b);
            case "number":
                return isFinite(b) ? String(b) : "null";
            case "boolean":
            case "null":
                return String(b);
            case "object":
                if (!b) return "null";
                g += m;
                e = [];
                if (Object.prototype.toString.apply(b) === "[object Array]") {
                    f = b.length;
                    for (a = 0; a < f; a += 1) e[a] = l(a, b) || "null";
                    c = e.length === 0 ? "[]" : g ? "[\n" + g + e.join(",\n" + g) + "\n" + i + "]" : "[" + e.join(",") + "]";
                    g = i;
                    return c;
                }
                if (j && typeof j === "object") {
                    f = j.length;
                    for (a = 0; a < f; a += 1) {
                        d = j[a];
                        if (typeof d === "string") if (c = l(d, b)) e.push(n(d) + (g ? ": " : ":") + c);
                    }
                } else for (d in b) if (Object.hasOwnProperty.call(b, d)) if (c = l(d, b)) e.push(n(d) + (g ? ": " : ":") + c);
                c = e.length === 0 ? "{}" : g ? "{\n" + g + e.join(",\n" + g) + "\n" + i + "}" : "{" + e.join(",") + "}";
                g = i;
                return c;
        }
    }

    if (typeof Date.prototype.toJSON !== "function") {
        Date.prototype.toJSON = function () { return isFinite(this.valueOf()) ? this.getUTCFullYear() + "-" + k(this.getUTCMonth() + 1) + "-" + k(this.getUTCDate()) + "T" + k(this.getUTCHours()) + ":" + k(this.getUTCMinutes()) + ":" + k(this.getUTCSeconds()) + "Z" : null; };
        String.prototype.toJSON = Number.prototype.toJSON = Boolean.prototype.toJSON = function () { return this.valueOf(); };
    }
    var p = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
        o = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, g, m, q = { "\u0008": "\\b", "\t": "\\t", "\n": "\\n", "\u000c": "\\f", "\r": "\\r", '"': '\\"', "\\": "\\\\" }, j;
    if (typeof JSON.stringify !== "function")
        JSON.stringify = function (a, c, d) {
            var f;
            m = g = "";
            if (typeof d === "number") for (f = 0; f < d; f += 1) m += " ";
            else if (typeof d === "string") m = d;
            if ((j = c) && typeof c !== "function" && (typeof c !== "object" || typeof c.length !== "number")) throw new Error("JSON.stringify");
            return l("",
                { "": a });
        };
    if (typeof JSON.parse !== "function")
        JSON.parse = function (a, c) {

            function d(f, i) {
                var e, b, h = f[i];
                if (h && typeof h === "object")
                    for (e in h)
                        if (Object.hasOwnProperty.call(h, e)) {
                            b = d(h, e);
                            if (b !== undefined) h[e] = b;
                            else delete h[e];
                        }
                return c.call(f, i, h);
            }

            a = String(a);
            p.lastIndex = 0;
            if (p.test(a)) a = a.replace(p, function (f) { return "\\u" + ("0000" + f.charCodeAt(0).toString(16)).slice(-4); });
            if (/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, "@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
                "]").replace(/(?:^|:|,)(?:\s*\[)+/g, ""))) {
                a = eval("(" + a + ")");
                return typeof c === "function" ? d({ "": a }, "") : a;
            }
            throw new SyntaxError("JSON.parse");
        };
})();


/* Dynamic JS loader */

var FileLoader = {
    loaded: {},
    load: function (filename, filetype) {
        if (!FileLoader.loaded[filename]) {
            if (filetype == "js") { //if filename is a external JavaScript file
                var fileref = document.createElement('script');
                fileref.setAttribute("type", "text/javascript");
                fileref.setAttribute("src", filename);
            } else if (filetype == "css") { //if filename is an external CSS file
                var fileref = document.createElement("link");
                fileref.setAttribute("rel", "stylesheet");
                fileref.setAttribute("type", "text/css");
                fileref.setAttribute("href", filename);
            }
            if (typeof fileref != "undefined") {
                document.getElementsByTagName("head")[0].appendChild(fileref);
            }
            FileLoader.loaded[filename] = true;
        }
    }
};
/* Nice round, useful for graphs */

var niceRound = function (value) {
    //if (value < 1.5) return 1;
    var zeroes = Math.floor(Math.log(value + 0.0001) / Math.log(10));
    var base = Math.pow(10, zeroes);
    var increment = value / base;
    if (increment < 1.5) {
        return 1 * base;
    } else if (increment < 3.5) {
        return 2 * base;
    } else if (increment < 7.5) {
        return 5 * base;
    } else {
        return 10 * base;
    }
};
/* Re-binding functions */

var bind = function (obj, func) {
    return function () { func.apply(obj, arguments); };
};
var event = function (obj, func) {
    return function () {
        var a = [this];
        for (var k = 0; k < arguments.length; ++k) {
            a.push(arguments[k]);
        }
        func.apply(obj, a);
    };
};
/* URL manipulators */

function getController() {
    var regex = new RegExp("^http\:\/\/(.+)[/]+([-_0-9a-zA-Z]+)[\?|/]?(.*)$");
    var results = regex.exec(window.location.href);
    var controllerString = "";
    if (results != null) {
        controllerString = "/" + results[2];
    }
    return controllerString;
}

function getFirstController() {
    var regex = new RegExp("^http\:\/\/([-_0-9a-zA-Z.:]+)[/]+([-_0-9a-zA-Z]+)[\?|/]?(.*)$");
    var results = regex.exec(window.location.href);
    var controllerString = "";
    if (results != null) {
        controllerString = "/" + results[2];
    }
    return controllerString;
}

function getURLParams() {
    var data = window.location.toString().split("?");
    var obj = {};
    if (data.length > 1) {
        data = data[1].split("#")[0].split("&");
        for (var k = 0; k < data.length; ++k) {
            var keyval = data[k].split("=");
            if (keyval.length > 1) {
                obj[keyval[0]] = keyval[1];
            }
        }
    }
    return obj;
}

function makeURLParams(newParams) {
    var baseUrl = window.location.toString().split("?")[0];
    var paramPart = [], pCount = 0;
    for (var i in newParams) {
        ++pCount;
        paramPart.push(i + "=" + newParams[i]);
    }
    if (pCount) {
        return baseUrl + "?" + paramPart.join("&");
    } else {
        return baseUrl;
    }
}


/* Date time formatting */

var Util = {
    formatTime: function (timestamp, padZeroes) {
        var time = '';
        var s = Math.floor(timestamp / 1000);
        var hh = Math.floor(s / 3600);
        if (hh > 0 || padZeroes) {
            if (hh < 10) {
                time += '0';
                time += hh;
            } else {
                time += hh;
            }
            time += ':';
        }
        var min = Math.floor((s % 3600) / 60);
        if (min < 10) {
            time += '0';
            time += min;
        } else {
            time += min;
        }
        var sec = s % 60;
        time += ':';
        if (sec < 10) {
            time += '0';
            time += sec;
        } else {
            time += sec;
        }
        return time;
    },
    minutesToHrMinutes: function (minutes) {
        var ret = "";
        if (minutes >= 60) {
            ret = Math.floor(minutes / 60) + " hours ";
        }
        return ret + (minutes % 60) + " minutes";
    }
};

function formatDate(dx, fmt, monthNames) {
    var d = new Date(dx);
    //dx.setUTCSeconds(d);
    var leftPad = function (n) {
        n = "" + n;
        return n.length == 1 ? "0" + n : n;
    };
    var r = [];
    var escape = false;
    if (monthNames == null)
        monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
    for (var i = 0; i < fmt.length; ++i) {
        var c = fmt.charAt(i);

        if (escape) {
            switch (c) {
                case 'h':
                    c = "" + d.getUTCHours();
                    break;
                case 'H':
                    c = leftPad(d.getUTCHours());
                    break;
                case 'M':
                    c = leftPad(d.getUTCMinutes());
                    break;
                case 'S':
                    c = leftPad(d.getUTCSeconds());
                    break;
                case 'd':
                    c = "" + d.getUTCDate();
                    break;
                case 'm':
                    c = "" + (d.getUTCMonth() + 1);
                    break;
                case 'y':
                    c = "" + d.getUTCFullYear();
                    break;
                case 'b':
                    c = "" + monthNames[d.getUTCMonth()];
                    break;
            }
            r.push(c);
            escape = false;
        } else {
            if (c == "%")
                escape = true;
            else
                r.push(c);
        }
    }
    return r.join("");
}


var dateFormat = function () {
    var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g,
        timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,
        timezoneClip = /[^-+\dA-Z]/g,
        pad = function (val, len) {
            val = String(val);
            len = len || 2;
            while (val.length < len) val = "0" + val;
            return val;
        };

    // Regexes and supporting functions are cached through closure
    return function (date, mask, utc) {
        var dF = dateFormat;

        // You can't provide utc if you skip other args (use the "UTC:" mask prefix)
        if (arguments.length == 1 && (typeof date == "string" || date instanceof String) && !/\d/.test(date)) {
            mask = date;
            date = undefined;
        }

        // Passing date through Date applies Date.parse, if necessary
        date = date ? new Date(date) : new Date();
        if (isNaN(date)) throw new SyntaxError("invalid date");

        mask = String(dF.masks[mask] || mask || dF.masks["default"]);

        // Allow setting the utc argument via the mask
        if (mask.slice(0, 4) == "UTC:") {
            mask = mask.slice(4);
            utc = true;
        }

        var _ = utc ? "getUTC" : "get",
            d = date[_ + "Date"](),
            D = date[_ + "Day"](),
            m = date[_ + "Month"](),
            y = date[_ + "FullYear"](),
            H = date[_ + "Hours"](),
            M = date[_ + "Minutes"](),
            s = date[_ + "Seconds"](),
            L = date[_ + "Milliseconds"](),
            o = utc ? 0 : date.getTimezoneOffset(),
            flags = {
                d: d,
                dd: pad(d),
                ddd: dF.i18n.dayNames[D],
                dddd: dF.i18n.dayNames[D + 7],
                m: m + 1,
                mm: pad(m + 1),
                mmm: dF.i18n.monthNames[m],
                mmmm: dF.i18n.monthNames[m + 12],
                yy: String(y).slice(2),
                yyyy: y,
                h: H % 12 || 12,
                hh: pad(H % 12 || 12),
                H: H,
                HH: pad(H),
                M: M,
                MM: pad(M),
                s: s,
                ss: pad(s),
                l: pad(L, 3),
                L: pad(L > 99 ? Math.round(L / 10) : L),
                t: H < 12 ? "a" : "p",
                tt: H < 12 ? "am" : "pm",
                T: H < 12 ? "A" : "P",
                TT: H < 12 ? "AM" : "PM",
                Z: utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""),
                o: (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4),
                S: ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10]
            };

        return mask.replace(token, function ($0) {
            return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);
        });
    };
} ();

// Some common format strings
dateFormat.masks = {
    "default": "ddd mmm dd yyyy HH:MM:ss",
    shortDate: "m/d/yy",
    mediumDate: "mmm d, yyyy",
    longDate: "mmmm d, yyyy",
    fullDate: "dddd, mmmm d, yyyy",
    shortTime: "h:MM TT",
    mediumTime: "h:MM:ss TT",
    longTime: "h:MM:ss TT Z",
    isoDate: "yyyy-mm-dd",
    isoTime: "HH:MM:ss",
    isoDateTime: "yyyy-mm-dd'T'HH:MM:ss",
    isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'"
};

// Internationalization strings
dateFormat.i18n = {
    dayNames: [
        "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
        "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
    ],
    monthNames: [
        "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
        "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
    ]
};

// For convenience...
Date.prototype.format = function (mask, utc) {
    return dateFormat(this, mask, utc);
};


var makeDateString = function (ticks, fmt) {
    var numTicks = parseInt(ticks);
    if (fmt) {
        return dateFormat(numTicks, fmt);
    }
    return dateFormat(numTicks, "dd/mm/yyyy HH:MM");
};

var makeTimeString = function (ticks, fmt) {
    var numTicks = parseInt(ticks);
    if (fmt) { return dateFormat(numTicks, fmt); }
    return dateFormat(numTicks, "HH:MM");
};

function duration(d1, d2) {
    var diff = dateToMS(d2) - dateToMS(d1);
    var diffDays = diff / 1000 / 3600 / 24;
    var wks = Math.floor(diffDays / 7);
    var dys = Math.round(diffDays - (wks * 7));
    var result = " ";
    if (wks) {
        result += (wks + " weeks ");
    }
    if (dys) {
        result += (dys + " days ");
    }
    if (result != " ")
        return result;
    else
        return " 0 days ";
}


function dateToMS(d) {
    return Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate());
}

function dateToMS_Time(d) {
    return Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds());
}

function textJoin(stringArray, separator, lastSeparator) {
    if (stringArray.length > 1) {
        var res = stringArray[0];
        for (var k = 1; k < stringArray.length - 1; ++k) {
            res += separator + stringArray[k];
        }
        res += lastSeparator + stringArray[stringArray.length - 1];
        return res;
    } else {
        if (stringArray.length > 0)
            return stringArray[0];
        else {
            return "";
        }
    }
}


/* Convertor */

var Convertor = {
    METRIC: 0,
    IMPERIAL: 1,
    UNIT_SYSTEM: 0, //default

    SPEED: ['km/h', 'mph'],
    DISTANCE: ['m', 'yd'],
    ALTITUDE: ['m', 'ft'],
    DISTANCE_KM: ['km', 'mi'],
    CALORIES: 'kcal',
    MS_KM_RATIO: 3.6,
    METER_TO_YARD: [1.0, 1.0936133],
    METER_TO_FEET: [1.0, 3.2808399],
    MY_TO_KM: [1000.0, 1760.0],
    KM_TO_MILES: [1.0, 0.621371],
    KG_TO_LBS: [1.0, 2.20462262],
    CM_TO_FT: [1.0, 0.032808399],

    fromDistance: function (val, ms) {
        return val / Convertor.METER_TO_YARD[ms] * Convertor.MY_TO_KM[ms];
    },

    toDistance: function (val, ms) {
        val *= Convertor.METER_TO_YARD[ms];
        if (val <= Convertor.MY_TO_KM[ms] && ms != 1) {
            return val;
        } else {
            val = val / Convertor.MY_TO_KM[ms];
            return val;
        }
    },

    toDistanceKM: function (val, ms) {
        val *= Convertor.METER_TO_YARD[ms];
        val = val / Convertor.MY_TO_KM[ms];
        return val;
    },

    toDistanceString: function (val, ms, digits) {
        digits = (digits == null ? 2 : digits);

        if (ms == null) {
            return Convertor.toDistanceString(val, Convertor.UNIT_SYSTEM, digits);
        }
        val *= Convertor.METER_TO_YARD[ms];
        if (val <= Convertor.MY_TO_KM[ms] && ms != 1) {
            return val.toFixed(0) + ' ' + Convertor.DISTANCE[ms];
        } else {
            val = val / Convertor.MY_TO_KM[ms];
            return val.toFixed(digits) + ' ' + Convertor.DISTANCE_KM[ms];
        }
    },

    toDistanceStringNMS: function (val) {
        return this.toDistanceString(val, Convertor.UNIT_SYSTEM);
    },

    toAltitudeString: function (val, ms) {
        if (ms == null) {
            return Convertor.toDistanceString(val, Convertor.UNIT_SYSTEM);
        }
        val *= Convertor.METER_TO_FEET[ms];
        return val.toFixed(0) + ' ' + Convertor.ALTITUDE[ms];
    },
    toAltitude: function (val, ms) {
        if (ms == null) {
            return Convertor.toDistanceString(val, Convertor.UNIT_SYSTEM);
        }
        val *= Convertor.METER_TO_FEET[ms];
        return val;
    },

    toAltitudeStringNMS: function (val) {
        return this.toAltitudeString(val, Convertor.UNIT_SYSTEM);
    },

    toSpeedString: function (val, ms) {
        if (ms == null) {
            return this.toSpeedStringNMS(val);
        }
        return this.toSpeed(val, ms) + ' ' + Convertor.SPEED[ms];
    },
    toSpeedStringNMS: function (val) {
        return this.toSpeed(val) + ' ' + Convertor.SPEED[Convertor.UNIT_SYSTEM];
    },

    toSpeed: function (val, ms) {
        if (ms == null) {
            return this.toSpeedNMS(val);
        }
        return (val * Convertor.MS_KM_RATIO * Convertor.KM_TO_MILES[ms]).toFixed(1);
    },

    fromSpeed: function (val, ms) {
        return val / Convertor.MS_KM_RATIO / Convertor.KM_TO_MILES[ms];
    },
    toSpeedFull: function (val, ms) {
        return (val * Convertor.MS_KM_RATIO * Convertor.KM_TO_MILES[ms]);
    },
    toSpeedNMS: function (val) {
        return (val * Convertor.MS_KM_RATIO * Convertor.KM_TO_MILES[Convertor.UNIT_SYSTEM]).toFixed(1);
    },

    toPaceString: function (val, ms) {
        if (ms == null) {
            return this.toPaceString(val, Convertor.UNIT_SYSTEM);
        }
        var valConv = val;
        var minkm = (1 / valConv) * 60;
        var seckm = Math.round((minkm - Math.floor(minkm)) * 60);
        if (seckm < 10) {
            seckm = "0" + seckm.toString();
        }
        return Math.floor(minkm) + ':' + seckm + ' min/' + Convertor.DISTANCE_KM[ms];
    },

    toCaloriesString: function (val) { return val + ' ' + Convertor.CALORIES; }
};
/* Natural sort */


var naturalSortAsc = function (a, b) {
    // setup temp-scope variables for comparison evauluation
    var x = a.toString().toLowerCase() || '';
    var y = b.toString().toLowerCase() || '';
    var nC = String.fromCharCode(0),
        xN = x.replace(/([-]{0,1}[0-9.]{1,})/g, nC + '$1' + nC).split(nC),
        yN = y.replace(/([-]{0,1}[0-9.]{1,})/g, nC + '$1' + nC).split(nC),
        xD = (new Date(x)).getTime(), yD = (new Date(y)).getTime();
    // natural sorting of dates
    if (xD && yD && xD < yD)
        return -1;
    else if (xD && yD && xD > yD)
        return 1;
    // natural sorting through split numeric strings and default strings
    for (var cLoc = 0, numS = Math.max(xN.length, yN.length); cLoc < numS; cLoc++)
        if ((parseFloat(xN[cLoc]) || xN[cLoc]) < (parseFloat(yN[cLoc]) || yN[cLoc]))
            return -1;
        else if ((parseFloat(xN[cLoc]) || xN[cLoc]) > (parseFloat(yN[cLoc]) || yN[cLoc]))
            return 1;
    return 0;
};
var naturalSortDesc = function (a, b) {
    // setup temp-scope variables for comparison evauluation
    var x = a.toString().toLowerCase() || '', y = b.toString().toLowerCase() || '',
        nC = String.fromCharCode(0),
        xN = x.replace(/([-]{0,1}[0-9.]{1,})/g, nC + '$1' + nC).split(nC),
        yN = y.replace(/([-]{0,1}[0-9.]{1,})/g, nC + '$1' + nC).split(nC),
        xD = (new Date(x)).getTime(), yD = (new Date(y)).getTime();
    // natural sorting of dates
    if (xD && yD && xD < yD)
        return 1;
    else if (xD && yD && xD > yD)
        return -1;
    // natural sorting through split numeric strings and default strings
    for (var cLoc = 0, numS = Math.max(xN.length, yN.length); cLoc < numS; cLoc++)
        if ((parseFloat(xN[cLoc]) || xN[cLoc]) < (parseFloat(yN[cLoc]) || yN[cLoc]))
            return 1;
        else if ((parseFloat(xN[cLoc]) || xN[cLoc]) > (parseFloat(yN[cLoc]) || yN[cLoc]))
            return -1;
    return 0;
};
var stripNaturalSortAsc = function (a, b) {
    return naturalSortAsc(a.replace(/(<([^>]+)>)/ig, ""), b.replace(/(<([^>]+)>)/ig, ""));
};
var stripNaturalSortDesc = function (a, b) {
    return naturalSortDesc(a.replace(/(<([^>]+)>)/ig, ""), b.replace(/(<([^>]+)>)/ig, ""));
};

function stringCleanup(str) {
    //var newstr = str.toString().replace("\n", "");
    var newstr = str.replace(/[\s]+[\s]+/, " ").replace(/^\s+/, "").replace(/\s+$/, "");
    return newstr;
}

var distanceSort = function (a, b) {
    var splitA = stringCleanup(a).toString().split(" "), splitB = stringCleanup(b).toString().split(" ");
    //if (splitA.length > 1 && splitB.length > 1)
    var realA = splitA[0] * 1.0;
    var realB = splitB[0] * 1.0;
    if (splitA[1] == 'km') realA *= 1000;
    if (splitB[1] == 'km') realB *= 1000;

    if (splitA[1] == 'mi') realA *= 1760; // yards
    if (splitB[1] == 'mi') realB *= 1760;

    return (realA < realB) ? -1 : ((realA == realB) ? 0 : 1);

};
var distanceSortAsc = function (a, b) {
    return distanceSort(a, b);
};
var distanceSortDesc = function (a, b) {
    return (0 - distanceSort(a, b));
};
var durationSortAsc = function (a, b) {
    return durationToNumber(stringCleanup(b)) - durationToNumber(stringCleanup(a));
};
var durationSortDesc = function (a, b) {
    return durationToNumber(stringCleanup(a)) - durationToNumber(stringCleanup(b));
};
var durationToNumber = function (dur) {
    var durationToNumberPart = function (num, text) {
        var reDays = /[d]+.*/i;
        if (reDays.exec(text)) {
            return num * 1.0;
        } else {
            return num * 7.0;
        }
    };
    if (dur == "Today") return 0;
    if (dur == "Finished" || dur == "Ended") return 9999;
    if (dur == "Not limited") {
        return 9998;
    }
    var splitDur = dur.toString().split(" ");
    var durNum = 0;
    if (splitDur.length > 1) {
        for (var k = 0; k < splitDur.length - 1; k += 2) {
            durNum += durationToNumberPart(splitDur[k], splitDur[k + 1]);
        }
    }
    return durNum;
};

function toHMS(ms) {
    var totalSec = ms / 1000;
    var hrs = Math.floor(totalSec / 60 / 60);
    var min = Math.floor(totalSec / 60 - (hrs * 60));
    var sec = Math.round(totalSec - (hrs * 60 * 60) - min * 60);
    var str = "";
    if (hrs > 0) str += hrs + "h ";
    if (min > 0 || hrs > 0) str += min + "m ";
    str += sec + "s";
    return str;
}


var applyDateCorrector = function () {
    $(".date-field").each(function (index) {
        shiftDateTZ(this);
    });
};
var shiftDateTZ = function (item) {
    var fmtChild = $(item).children('.date-fmt'), fmt = null;
    if (fmtChild.length) {
        fmt = fmtChild.val();
    }
    var tsChild = $(item).children('.date-val');
    if (tsChild.length) {
        var ts = tsChild.val();
        $(item).children('.date-show').html(makeDateString(ts, fmt));
    }
};
if (typeof ($) != "undefined") {
    $(document).ready(applyDateCorrector);
}

JQDialog = function (dialogParams) {
    var dialogDiv = $("<div></div>");
    $(dialogDiv).css({ "display": "none", "font-size": "13px", "padding": "20px" });
    $(document).append(dialogDiv);
    $(dialogDiv).dialog(dialogParams);
    var self = this;
    this.dialog = function (arg1, arg2, arg3, arg4, arg5) {
        $(dialogDiv).dialog(arg1, arg2, arg3, arg4, arg5);
    };
    this.setImageAndText = function (imgUrl, text) {
        var innerHtml = '<DIV STYLE="position:absolute; top:30px; left:10px; width:70px; height:70px">'
            + '<CENTER><img src="' + imgUrl + '" alt="Error" width="60" height="60" /></CENTER></DIV>'
                + '<DIV STYLE="position:absolute; top:40px; left:80px; width:200px;"><CENTER>'
                    + text + '</CENTER></DIV>';
        $(dialogDiv).html(innerHtml);
    };
    this.setHtml = function (html) {
        $(dialogDiv).html(html);
    };
    this.close = function () {
        $(dialogDiv).dialog('close');
    };
    this.open = function () {
        $(dialogDiv).dialog('open');
    };
    return true;
};







(function () {

    var jqDialog;
    $(document).ready(function () {
        $('.helpButton').live('click', function () {
            var helpDiv = "#" + this.id.replace("help", "helpDiv");
            if (!jqDialog) {
                jqDialog = new JQDialog({
                    title: "SportyPal Help",
                    width: 480
                });
            }
            jqDialog.setHtml($(helpDiv).html());
            jqDialog.open();
        });
    });

    //            $.getJSON("/WebHelpInfo/GetWebHelpDescription", { helpID: helpID }, function(response) {
    //                if (response.success) {
    //                    // display the message
    //                    $('#dialog-message').html(response.message);
    //                    centerAndShowDialog();
    //                }else{
    //                    // display the message
    //                    $('#dialog-message').html("Your message: Not Defined");    
    //                    centerAndShowDialog();            
    //                }
    //            });   

})();


// Added to fix array serialization in .post - parameter is renamed to arrayName[]
// in newer versions of jQuery.
jQuery.ajaxSettings.traditional = true;


// Simple JavaScript Templating
// John Resig - http://ejohn.org/ - MIT Licensed

(function ($) {
    var cache = {};
    var compiler = function (str) {
        var code = "var p=[],print=function(){p.push.apply(p,arguments);};" +
            "with(obj){p.push('" +
                str
                    .replace(/[\r\t\n]/g, " ")
                    .split("<@").join("\t")
                    .replace(/((^|@>)[^\t]*)'/g, "$1\r")
                    .replace(/\t=(.*?)@>/g, "',$1,'")
                    .split("\t").join("');")
                    .split("@>").join("\np.push('")
                    .split("\r").join("\\'")
                        + "');}return p.join('');";
        try {
            return new Function("obj", code);
        } catch (e) {
            console.log(code);
            console.log(JSON.stringify(e));
            throw e;
        }
    };
    $.utmpl = function tmpl(str, data) {
        var fn = !/\W/.test(str) ?
            cache[str] = cache[str] ||
                $.utmpl(document.getElementById(str).innerHTML) : compiler(str);
        return data ? fn(data) : fn;
    };
    $.fn.utmpl = function (str, data) {
        $(this).html($.utmpl(str, data));
    };
    $.fn.json = function () {
        return JSON.parse($(this).html());
    };


    $.unextend = function (obj, unextend) {
        var cpy = {};
        for (key in obj) {
            if (obj[key] != unextend[key]) {
                cpy[key] = obj[key];
            }
        }
        return cpy;
    };
})(jQuery);


