/* Minification failed. Returning unminified contents.
(423,46-47): run-time warning JS1195: Expected expression: )
(423,49-50): run-time warning JS1195: Expected expression: >
(423,77-78): run-time warning JS1003: Expected ':': ,
(423,86-87): run-time warning JS1003: Expected ':': )
(423,96-97): run-time warning JS1004: Expected ';': )
(427,13-14): run-time warning JS1002: Syntax error: }
(431,46-47): run-time warning JS1004: Expected ';': {
(433,10-11): run-time warning JS1195: Expected expression: ,
(434,25-26): run-time warning JS1195: Expected expression: )
(436,9-10): run-time warning JS1002: Syntax error: }
(438,51-52): run-time warning JS1004: Expected ';': {
(444,10-11): run-time warning JS1195: Expected expression: ,
(446,62-63): run-time warning JS1004: Expected ';': {
(449,10-11): run-time warning JS1195: Expected expression: ,
(451,28-29): run-time warning JS1010: Expected identifier: (
(477,14-15): run-time warning JS1195: Expected expression: ,
(478,41-42): run-time warning JS1004: Expected ';': {
(480,14-15): run-time warning JS1195: Expected expression: ,
(481,39-40): run-time warning JS1004: Expected ';': {
(483,14-15): run-time warning JS1195: Expected expression: ,
(484,38-39): run-time warning JS1004: Expected ';': {
(486,14-15): run-time warning JS1195: Expected expression: ,
(487,41-42): run-time warning JS1004: Expected ';': {
(490,9-10): run-time warning JS1002: Syntax error: }
(492,39-40): run-time warning JS1010: Expected identifier: (
(494,14-15): run-time warning JS1195: Expected expression: ,
(495,35-36): run-time warning JS1004: Expected ';': {
(497,14-15): run-time warning JS1195: Expected expression: ,
(498,27-28): run-time warning JS1197: Too many errors. The file might not be a JavaScript file: :
(435,13-188): run-time warning JS1018: 'return' statement outside of function: return 'rooxxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { var r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8); return v.toString(16) });
(496,17-55): run-time warning JS1018: 'return' statement outside of function: return Number(n) === n && n % 1 === 0;
 */
/*!
 * DMDS Awards Platform Application wide JS
 *
 * Copyright 2013, Dan Truong
 */

//This ultra-lightweight library (only 196 bytes minified!) extends the javascript console object to provide configurable colored output.
(function () {
    // `consoleProxy`: a clone of the standard `console` object (only used to shorten the script by using `c` instead of `console`, here we could directly access the `console` object)
    var consoleProxy = console,

    // `i`: A simple iterator for the loop
        i = 3,

    // `schemes`: a 2-dimensional array to hold the respective identifiers & colors.
        schemes = [
            ["e", "s", "i"],
            ["#c0392b", "#2ecc71", "#3498db"]
        ];

    // **loop**: Loop from `i` to 0
    // For each identifier in the first inner-array of the `schemes` variable, we create a new property of the console object
    while (i--) consoleProxy[schemes[0][i]] = f(i);

    function f(j) {
        return function (m, s) {
            // Put the pieces together, apply the CSS rules, and match the corresponding color in the second inner-array of the `schemes` variable
            consoleProxy.log('%c' + m, s + ';border-left:3px solid ' + schemes[1][j] + ';padding-left: 5px;font-weight:bold;color:' + schemes[1][j])
        };
    }
})();

//https://css-tricks.com/snippets/jquery/check-if-element-exists/
$.fn.exists = function (callback) { var args = [].slice.call(arguments, 1); if (this.length) { callback.call(this, args); } return this; };

jQuery.fn.nullOrEmpty = function () {
    return $.awards.is.nullOrEmpty($(this[0]).val());
};
(function ($) {
    $.awards = {
        defaults: {
            gridPageSize: 20,
            DateTimeFormat: "M/D/YYYY h:mm A", //momentjs format
            LongDateTimeFormat: "dddd, MMMM DD, YYYY h:mm:ss A", //momentjs format
            DateFormat: "M/D/YYYY", //momentjs format
            LongDateFormat: "dddd, MMMM DD, YYYY" //momentjs format
        },
        settings: {},
        init: function (options) { $.awards.settings = $.extend({}, $.awards.defaults, options); },
        getBannerLabel: function ($insideBanner) { var label = ""; if ($insideBanner.length > 0) { label = $insideBanner.closest(".banner").find(".banner-label").text(); } return label; },
        getAjaxLoadingHTML: function ($container) { $.awards.showAjaxLoadingHTML($container); },
        showAjaxLoadingHTML: function ($container) { $container.prepend('<div class="loading-spinner checking"> <div class="rect1"></div> <div class="rect2"></div> <div class="rect3"></div> <div class="rect4"></div> <div class="rect5"></div> </div>'); },
        hideAjaxLoadingHTML: function ($container) { $container.find(".loading-spinner.checking").addClass("hidden"); },
        bindKendoValidation: function () {
            var elements = $("form").find("[data-role=combobox],[data-role=dropdownlist],[data-role=numerictextbox],[data-role=datetimepicker],[data-role=custom]");

            // Correct mutation event detection
            var hasMutationEvents = ("MutationEvent" in window),
				MutationObserver = window.WebKitMutationObserver || window.MutationObserver;

            if (MutationObserver) {
                var observer = new MutationObserver(function (mutations) {
                    //DEBUG: console.log(mutations);

                    var idx = 0,
						mutation,
						length = mutations.length;

                    for (; idx < length; idx++) {
                        mutation = mutations[idx];
                        if (mutation.attributeName === "class") {
                            $.awards.updateCssOnPropertyChange(mutation);
                        }
                    }
                }),
				config = { attributes: true, childList: false, characterData: false };

                elements.each(function () {
                    observer.observe(this, config);
                });
            } else if (hasMutationEvents) {
                elements.bind("DOMAttrModified", $.awards.updateCssOnPropertyChange);
            } else {
                elements.each(function () {
                    this.attachEvent("onpropertychange", $.awards.updateCssOnPropertyChange);
                });
            }
        },
        updateCssOnPropertyChange: function (e) {
            var element = $(e.target || e.srcElement);
            element.siblings("span.k-dropdown-wrap")
						.add(element.parent("span.k-numeric-wrap"))
						.add(element.siblings("div.k-editor"))
						.toggleClass("input-error", element.hasClass("input-validation-error"));
        },
        /** Misc functions - Start **/
        enable: {
            checkbox: function ($checkboxes, keepChecked) {
                $checkboxes.each(function () {
                    var $this = $(this);
                    $this.removeAttr('disabled')
                         .closest(".checkbox, .checkbox-wrapper")
                         .removeClass("disabledText");
                    if (!keepChecked) {
                        $this.removeAttr('checked');
                    }
                });
            }
        },
        disable: {
            checkbox: function ($checkboxes, keepChecked) {
                $checkboxes.each(function () {
                    var $this = $(this);
                    $this.attr('disabled', 'disabled')
                         .closest(".checkbox, .checkbox-wrapper")
                         .addClass("disabledText");
                    if (!keepChecked) {
                        $this.removeAttr('checked');
                    }
                });
            }
        },
        toggle: {
            checkbox: function ($checkbox, enableIt, skipChange) {
                if (enableIt) {
                    $checkbox.prop("checked", true);
                }
                else {
                    $checkbox.prop("checked", false);
                }
                if (!skipChange) {
                    $checkbox.change();
                }
            },
            buttonUI: function (options) {
                // required:
                // $button: jQuery object
                // condition: bool
                // trueText: string
                // trueClass: string
                // falseText: string
                // falseClass: string

                if (options) {
                    if (options.$button.length) {
                        if (typeof options.trueText === "undefined") {
                            options.trueText = options.$button.text();
                        }
                        if (typeof options.falseText === "undefined") {
                            options.falseText = options.$button.text();
                        }

                        options.$button.text(options.condition ? options.trueText : options.falseText);
                        if (!$.awards.is.nullOrEmpty(options.trueClass)) {
                            options.$button.toggleClass(options.trueClass, options.condition);
                        }
                        if (!$.awards.is.nullOrEmpty(options.falseClass)) {
                            options.$button.toggleClass(options.falseClass, !options.condition);
                        }
                    }
                }
            },
            button: function (options) {
                // required:
                // $button: jQuery object
                // disabled: bool condition
                // disabledText: string
                // enabledText: string
                if (options && options.$button.length) {
                    options.$button.toggleClass("disabled", options.disabled);
                    if (options.disabled) {
                        options.$button.attr("disabled", "disabled");
                        if (!$.awards.is.nullOrEmpty(options.disabledText)) {
                            options.$button.html(options.disabledText);
                        }
                    }
                    else {
                        options.$button.removeAttr("disabled");
                        if (!$.awards.is.nullOrEmpty(options.enabledText)) {
                            options.$button.html(options.enabledText);
                        }
                    }
                }
            }
        },
        mailcheck: function (options) {
            $("input[type='email']").each(function () {
                var $input = $(this);
                var $formGroup = $input.closest(".form-group");
                $input.on('blur', function () {
                    $formGroup.find(".mailcheck").remove();
                    $input.mailcheck({
                        suggested: function (element, suggestion) {
                            var guid = $.awards.guid();
                            $formGroup.append($("<div/>").addClass("mailcheck pull-right text-sm text-muted").html("{0} <a href='#' class='text-info bold' guid='{2}'>{1}</a>?".format(options.didYouMean, suggestion.full, guid)));
                            $("[guid='{0}']".format(guid)).click(function () {
                                var $link = $(this);
                                $input.val($link.text());
                                $link.closest(".mailcheck").remove();
                                return false;
                            });
                        },
                        empty: function (element) {
                        }
                    });
                });
            });
        },
        detect: {
            IE: function () {
                var ua = window.navigator.userAgent;

                var msie = ua.indexOf('MSIE ');
                if (msie > 0) {
                    // IE 10 or older => return version number
                    return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);
                }

                var trident = ua.indexOf('Trident/');
                if (trident > 0) {
                    // IE 11 => return version number
                    var rv = ua.indexOf('rv:');
                    return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10);
                }

                var edge = ua.indexOf('Edge/');
                if (edge > 0) {
                    // IE 12 => return version number
                    return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10);
                }

                // other browser
                return false;
            },
            /**
            * JavaScript Client Detection
            * (C) viazenetti GmbH (Christian Ludwig)
            * http://stackoverflow.com/a/18706818
            */
            all: function () {
                var unknown = '-';

                // screen
                var screenSize = '';
                if (screen.width) {
                    width = (screen.width) ? screen.width : '';
                    height = (screen.height) ? screen.height : '';
                    screenSize += '' + width + " x " + height;
                }

                // browser
                var nVer = navigator.appVersion;
                var nAgt = navigator.userAgent;
                var browser = navigator.appName;
                var version = '' + parseFloat(navigator.appVersion);
                var majorVersion = parseInt(navigator.appVersion, 10);
                var nameOffset, verOffset, ix;

                // Opera
                if ((verOffset = nAgt.indexOf('Opera')) != -1) {
                    browser = 'Opera';
                    version = nAgt.substring(verOffset + 6);
                    if ((verOffset = nAgt.indexOf('Version')) != -1) {
                        version = nAgt.substring(verOffset + 8);
                    }
                }
                // Opera Next
                if ((verOffset = nAgt.indexOf('OPR')) != -1) {
                    browser = 'Opera';
                    version = nAgt.substring(verOffset + 4);
                }
                    // Edge
                else if ((verOffset = nAgt.indexOf('Edge')) != -1) {
                    browser = 'Microsoft Edge';
                    version = nAgt.substring(verOffset + 5);
                }
                    // MSIE
                else if ((verOffset = nAgt.indexOf('MSIE')) != -1) {
                    browser = 'Microsoft Internet Explorer';
                    version = nAgt.substring(verOffset + 5);
                }
                    // Chrome
                else if ((verOffset = nAgt.indexOf('Chrome')) != -1) {
                    browser = 'Chrome';
                    version = nAgt.substring(verOffset + 7);
                }
                    // Safari
                else if ((verOffset = nAgt.indexOf('Safari')) != -1) {
                    browser = 'Safari';
                    version = nAgt.substring(verOffset + 7);
                    if ((verOffset = nAgt.indexOf('Version')) != -1) {
                        version = nAgt.substring(verOffset + 8);
                    }
                }
                    // Firefox
                else if ((verOffset = nAgt.indexOf('Firefox')) != -1) {
                    browser = 'Firefox';
                    version = nAgt.substring(verOffset + 8);
                }
                    // MSIE 11+
                else if (nAgt.indexOf('Trident/') != -1) {
                    browser = 'Microsoft Internet Explorer';
                    version = nAgt.substring(nAgt.indexOf('rv:') + 3);
                }
                    // Other browsers
                else if ((nameOffset = nAgt.lastIndexOf(' ') + 1) < (verOffset = nAgt.lastIndexOf('/'))) {
                    browser = nAgt.substring(nameOffset, verOffset);
                    version = nAgt.substring(verOffset + 1);
                    if (browser.toLowerCase() == browser.toUpperCase()) {
                        browser = navigator.appName;
                    }
                }
                // trim the version string
                if ((ix = version.indexOf(';')) != -1) version = version.substring(0, ix);
                if ((ix = version.indexOf(' ')) != -1) version = version.substring(0, ix);
                if ((ix = version.indexOf(')')) != -1) version = version.substring(0, ix);

                majorVersion = parseInt('' + version, 10);
                if (isNaN(majorVersion)) {
                    version = '' + parseFloat(navigator.appVersion);
                    majorVersion = parseInt(navigator.appVersion, 10);
                }

                // mobile version
                var mobile = /Mobile|mini|Fennec|Android|iP(ad|od|hone)/.test(nVer);

                // cookie
                var cookieEnabled = (navigator.cookieEnabled) ? true : false;

                if (typeof navigator.cookieEnabled == 'undefined' && !cookieEnabled) {
                    document.cookie = 'testcookie';
                    cookieEnabled = (document.cookie.indexOf('testcookie') != -1) ? true : false;
                }

                // system
                var os = unknown;
                var clientStrings = [
                    { s: 'Windows 10', r: /(Windows 10.0|Windows NT 10.0)/ },
                    { s: 'Windows 8.1', r: /(Windows 8.1|Windows NT 6.3)/ },
                    { s: 'Windows 8', r: /(Windows 8|Windows NT 6.2)/ },
                    { s: 'Windows 7', r: /(Windows 7|Windows NT 6.1)/ },
                    { s: 'Windows Vista', r: /Windows NT 6.0/ },
                    { s: 'Windows Server 2003', r: /Windows NT 5.2/ },
                    { s: 'Windows XP', r: /(Windows NT 5.1|Windows XP)/ },
                    { s: 'Windows 2000', r: /(Windows NT 5.0|Windows 2000)/ },
                    { s: 'Windows ME', r: /(Win 9x 4.90|Windows ME)/ },
                    { s: 'Windows 98', r: /(Windows 98|Win98)/ },
                    { s: 'Windows 95', r: /(Windows 95|Win95|Windows_95)/ },
                    { s: 'Windows NT 4.0', r: /(Windows NT 4.0|WinNT4.0|WinNT|Windows NT)/ },
                    { s: 'Windows CE', r: /Windows CE/ },
                    { s: 'Windows 3.11', r: /Win16/ },
                    { s: 'Android', r: /Android/ },
                    { s: 'Open BSD', r: /OpenBSD/ },
                    { s: 'Sun OS', r: /SunOS/ },
                    { s: 'Linux', r: /(Linux|X11)/ },
                    { s: 'iOS', r: /(iPhone|iPad|iPod)/ },
                    { s: 'Mac OS X', r: /Mac OS X/ },
                    { s: 'Mac OS', r: /(MacPPC|MacIntel|Mac_PowerPC|Macintosh)/ },
                    { s: 'QNX', r: /QNX/ },
                    { s: 'UNIX', r: /UNIX/ },
                    { s: 'BeOS', r: /BeOS/ },
                    { s: 'OS/2', r: /OS\/2/ },
                    { s: 'Search Bot', r: /(nuhk|Googlebot|Yammybot|Openbot|Slurp|MSNBot|Ask Jeeves\/Teoma|ia_archiver)/ }
                ];
                for (var id in clientStrings) {
                    var cs = clientStrings[id];
                    if (cs.r.test(nAgt)) {
                        os = cs.s;
                        break;
                    }
                }

                var osVersion = unknown;

                if (/Windows/.test(os)) {
                    osVersion = /Windows (.*)/.exec(os)[1];
                    os = 'Windows';
                }

                switch (os) {
                    case 'Mac OS X':
                        osVersion = /Mac OS X (10[\.\_\d]+)/.exec(nAgt)[1];
                        break;

                    case 'Android':
                        osVersion = /Android ([\.\_\d]+)/.exec(nAgt)[1];
                        break;

                    case 'iOS':
                        osVersion = /OS (\d+)_(\d+)_?(\d+)?/.exec(nVer);
                        osVersion = osVersion[1] + '.' + osVersion[2] + '.' + (osVersion[3] | 0);
                        break;
                }

                return {
                    screen: screenSize,
                    browser: browser,
                    browserVersion: version,
                    browserMajorVersion: majorVersion,
                    mobile: mobile,
                    os: os,
                    osVersion: osVersion,
                    cookies: cookieEnabled
                };
            }
        },
        hacks: {
            noBackButton: function () {
                window.location.hash = "no-back-button";
                window.location.hash = "Again-No-back-button";//again because google chrome don't insert first hash into history
                window.onhashchange = function () { window.location.hash = "no-back-button"; };
            }
        },
        setLongTimeout: function (callback, timeout_ms, context) {
            context = context || {
                target: new Date().getTime() + timeout_ms
            };

            const max_val = 2147483647;
            const diff = context.target - new Date().getTime();

            if (diff > max_val) {
                context.handle = setTimeout(() => setLongTimeout(callback, 0, context), max_val);
            }
            else {
                context.handle = setTimeout(callback, diff);
            }

            return context;
        },
        clearLongTimeout: function (context) {
            clearTimeout(context.handle);
        },
        guid: function () {
            return 'rooxxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { var r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8); return v.toString(16) });
        },

        progressbar: function (percent, $element) {
            var progressBarWidth = percent * $element.width() / 100;
            if (percent != 0)
                $element.find('div').animate({ width: progressBarWidth }, 500).html(percent + "%&nbsp;");
            else
                $element.find('div').animate({ width: progressBarWidth }, 500);
        },

        progressbar_indeterminate: function (text, $element) {
            var progressBarWidth = 100 * $element.width() / 100;
            $element.find('div').animate({ width: progressBarWidth }, 500).html(text);
        },
        notify: {
            user: function (type, title, message) {
                if (!$.awards.is.nullOrEmpty(message)) {
                    toastr.options = {
                        'closeButton': true,
                        'debug': false,
                        'newestOnTop': false,
                        'progressBar': false,
                        'positionClass': 'toast-bottom-center',
                        'preventDuplicates': false,
                        'onclick': null,
                        'showDuration': '300',
                        'hideDuration': '300',
                        'timeOut': '5000',
                        'extendedTimeOut': '1000',
                        'showEasing': 'linear',
                        'hideEasing': 'linear',
                        'showMethod': 'fadeIn',
                        'hideMethod': 'fadeOut'
                    };
                    if ($.awards.is.nullOrEmpty(title)) {
                        toastr[type](message);
                    }
                    else {
                        toastr[type](message, title);
                    }
                }
            },
            success: function (message) {
                $.awards.notify.user('success', '', message);
            },
            error: function (message) {
                $.awards.notify.user('error', '', message);
            },
            info: function (message) {
                $.awards.notify.user('info', '', message);
            },
            warning: function (message) {
                $.awards.notify.user('warning', '', message);
            }
        },
        is: {
            negativeInteger: function (n) {
                return $.awards.is.integer(n) && parseInt(n, 10) < 0;
            },
            integer: function (n) {
                return Number(n) === n && n % 1 === 0;
            },
            integerByValue: function (n) {
                return /^[0-9]+$/.test(n);
            },
            nullOrEmpty: function (str) {
                return (!str || 0 === str.length || /^\s*$/.test(str));
            },
            array: function (input) {
                return Object.prototype.toString.call(input) === '[object Array]';
            },
            alphaNumeric: function (str) {
                str = str.toString();
                if (str.length > 0) {
                    return /^\w+$/.test(str);
                }
                else {
                    return false;
                }
            },
            validDate: function (input) {
                var d = $.awards.convert.stringToDate(input);
                return (d instanceof Date) && !isNaN(d);
            },
            validURL: function (input) {
                if ($.awards.is.nullOrEmpty(input)) {
                    return false;
                }
                else {
                    return /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/.test(input);
                }
            },
            validTwitterHandle: function (input) {
                if ($.awards.is.nullOrEmpty(input)) {
                    return false;
                }
                else {
                    return /^@\w{1,32}$/.test(input);
                }
            }
        },
        popup: function (options) {
            var defaultOptions = {
                title: "",
                message: "",
                largeSize: false,
                buttons: [],
                includeCancelButton: false,
                cancelText: "Cancel",
                showCloseIcon: false,
                showCloseIconOnly: false,
                headerCssClass: "bg-primary",
                destroyModalOnClose: false,
                bodyCssClass: "",
                allowBackdrop: false,
                randomId: false,
                closeOnEsc: false,
                onShown: function (){}
            };
            options = $.extend({}, defaultOptions, options);

            if (options.showCloseIconOnly) {
                options.showCloseIcon = true;
            }

            var modalId = "TeeOhEmPopupModal";
            if (options.randomId) {
                modalId = "random" + $.awards.guid();
            }
            var $modal = $("#" + modalId);
            if ($modal.length > 0) {
                $modal.remove();
                $(".modal-backdrop.in").remove();
            }
            var htmlBuilder = [];
            if (options.allowBackdrop)
                htmlBuilder[htmlBuilder.length] = "<div class='modal' id='{0}' tabindex='-1' data-keyboard=" + (options.closeOnEsc ? 'true' : 'false') + " role='dialog' aria-labelledby='AlertModalLabel' aria-hidden='true'>".format(modalId);
            else
                htmlBuilder[htmlBuilder.length] = "<div data-backdrop='static' data-keyboard=" +(options.closeOnEsc?'true':'false') + " class='modal' id='{0}' tabindex='-1' role='dialog' aria-labelledby='AlertModalLabel' aria-hidden='true'>".format(modalId);
            htmlBuilder[htmlBuilder.length] = "<div class='modal-dialog {0}'>".format(options.largeSize ? "modal-lg" : "");
            htmlBuilder[htmlBuilder.length] = "<div class='modal-content'>";
            if (!$.awards.is.nullOrEmpty(options.title) || options.showCloseIcon) {
                htmlBuilder[htmlBuilder.length] = "<div class='modal-header {0}'>".format(options.headerCssClass);
                if (options.showCloseIcon) {
                    htmlBuilder[htmlBuilder.length] = "<button type='button' class='close' data-dismiss='modal' aria-hidden='true'>&times;</button>";
                }
                htmlBuilder[htmlBuilder.length] = options.title;
                htmlBuilder[htmlBuilder.length] = "</div>";
            }
            htmlBuilder[htmlBuilder.length] = "<div class='modal-body {0}'></div>".format(options.bodyCssClass);
            if (options.buttons.length > 0 || options.includeCancelButton) {
                htmlBuilder[htmlBuilder.length] = "<div class='modal-footer'></div>";
            }
            htmlBuilder[htmlBuilder.length] = "</div>";
            htmlBuilder[htmlBuilder.length] = "</div>";
            htmlBuilder[htmlBuilder.length] = "</div>";
            var html = htmlBuilder.join("");
            $("body").append(html);
            $modal = $("#" + modalId);
            var $modalBody = $modal.find(".modal-body");
            $modalBody.html(options.message);
            var $modalFooter = $modal.find(".modal-footer");

            if (options.includeCancelButton) {
                $modalFooter.append("<a role='button' class='btn btn-default pull-left' data-dismiss='modal'>{0}</a>".format(options.cancelText));
            }

            $.each(options.buttons, function (index, button) {
                var buttonId = $.awards.guid();
                $modalFooter.append("<a id='{0}' role='button' class='{3}' {1}>{2}</a>".format(buttonId, button.visible ? "" : "hidden", button.text, button.cssClass || "btn btn-primary"));
                $("#" + buttonId).click(function () {
                    if (!button.doNotClose) {
                        $modal.modal("hide");
                    }
                    if (button.onClick) button.onClick($modal);
                    else $modal.modal("hide");
                });
            });

            if (options.showCloseIconOnly) {
                $modalFooter.toggleClass("hidden", true);
            }

            if (options.destroyModalOnClose) {
                $modal.on('hidden.bs.modal', function () {
                    $modal.remove();
                });
            }

            // Fix issue where closing a modal while there was a second one open caused scroll to break
            // Bootstrap doesn't support multiple modals. See https://stackoverflow.com/a/37032284/823732
            $modal.on('hidden.bs.modal', function (e) {
                if ($('.modal:visible').length) 
                    $('body').addClass('modal-open');
            });
            

            $modal.on('shown.bs.modal', function () {
                options.onShown($modal);
            });

            $modal.modal("show");
        },
        getAlertModal: function () { return $("#TeeOhEmPopupModal"); },
        alert: function (options) {
            $.awards.popup({
                title: options.title,
                message: options.message,
                largeSize: options.largeSize,
                buttons: [{
                    text: options.okText || "Okay",
                    onClick: options.okFunction || function () { },
                    cssClass: options.buttonCssClass || "btn btn-danger"
                }],
                headerCssClass: options.headerCssClass || "bg-danger",
                bodyCssClass: options.capHeight ? "maxHeight600" : "",
                allowBackdrop: options.allowBackdrop,
                showCloseIcon: options.showCloseIcon,
                showCloseIconOnly: options.showCloseIconOnly,
                closeOnEsc : options.closeOnEsc || false,
                randomId: options.randomId,
                destroyModalOnClose: options.destroyModalOnClose,
                onShown: options.onShow || function () { }
            });
        },
        confirm: function (options) {
            $.awards.popup({
                title: options.title,
                message: options.message,
                largeSize: options.largeSize,
                headerCssClass: options.headerCssClass || "bg-danger",
                buttons: [
                {
                    text: options.cancelText || "Cancel",
                    cssClass: "btn btn-default pull-left",
                    onClick: options.cancelFunction || function () { }
                },
                {
                    text: options.okText || "Okay",
                    cssClass: "btn btn-danger",
                    onClick: options.okFunction || function () { },
                    doNotClose: options.doNotClose || false
                }],
                randomId: options.randomId,
                onShown: options.onShow || function () { }
            });
        },
        convert: {
            stringToDate: function (string) {
                var date;
                //.NET date /Date(1404967626050)/
                // REGEX: /^\/?Date\((\-?\d+)/i
                if ((matched = /^\/?Date\((\-?\d+)/i.exec(string)) !== null) {
                    date = new Date(+matched[1]);
                }
                else {
                    if (string.length == 19) {
                        // this is for UTC time without Z
                        string += "Z";
                    }
                    date = new Date(string);
                }
                return date;
            },
            dateToString: function (date, format, isUTCDate) {
                if (typeof date === "undefined" || date === null) {
                    return "";
                }
                else {

                    // date: YYYY/MM/DD
                    // datetime: YYYY/MM/DD h:mm A
                    // datetime2: hh:mm:ss a YY-MM-DD
                    if (typeof date === 'string') {
                        date = this.stringToDate(date);
                    }
                    var result = '', year, month, day, hours, minutes, seconds, isAm = true;
                    if (format === 'date' || format === 'datetime') {
                        year = date.getFullYear();
                        month = String('00' + (date.getMonth() + 1)).slice(-2);
                        day = String('00' + date.getDate()).slice(-2);

                        if (format === 'date') {
                            result = year + '/' + month + '/' + day;
                        }
                        else {
                            hours = isUTCDate ? date.getUTCHours() : date.getHours();
                            if (hours > 12) {
                                hours -= 12;
                                isAm = false;
                            }
                            minutes = String('00' + date.getUTCMinutes()).slice(-2);
                            result = year + '/' + month + '/' + day + ' ' + hours + ':' + minutes + ' ' + (isAm ? 'AM' : 'PM');
                        }
                    }
                    else if (format === 'datetime2') {
                        year = String('' + date.getFullYear()).slice(-2);
                        month = String('00' + (date.getMonth() + 1)).slice(-2);
                        day = String('00' + date.getDate()).slice(-2);

                        hours = isUTCDate ? date.getUTCHours() : date.getHours();
                        if (hours > 12) {
                            hours -= 12;
                            isAm = false;
                        }
                        hours = String('00' + hours).slice(-2);
                        minutes = String('00' + isUTCDate ? date.getUTCMinutes() : date.getMinutes()).slice(-2);
                        seconds = String('00' + isUTCDate ? date.getUTCSeconds() : date.getSeconds()).slice(-2);
                        result = hours + ':' + minutes + ':' + seconds + ' ' + (isAm ? 'AM' : 'PM') + ' ' + year + '-' + month + '-' + day;
                    }
                    return result;
                }
            }
        },
        string: {
            /**
             * Counts words of a string.
             * @param {string} input - The string for words to be counted.
             * @returns {Number} Total words.
             */
            getWordCount: function (input) {
                if ($.awards.is.nullOrEmpty(input)) { return 0; }

                input = input.replace(/(^\s*)|(\s*$)/gi, "");
                input = input.replace(/[ ]{2,}/gi, " ");
                input = input.replace(/\n /, "\n");

                var result = input.split(' ').length
                return result;
            },

            /**
             * Truncate size of a string.
             * @param {string} input - The string for words to be truncated.
             * @param {int} maxSize - truncate at this size.
             * @returns {string} Truncated String.
             */
             truncate: function (input, maxSize) {
                 return (input.length > maxSize) ? input.substr(0, maxSize - 1) + '...' : input;
             }
             
        },
        /** Misc functions - End **/

        /** Reference Data Handling - Start **/
        getReferenceDataName: function (dataItem, field) {
            var referenceDataName;
            $.each(getReferenceData(field), function (index, type) {
                if (type.Id == dataItem[field]) {
                    referenceDataName = type.Name;
                    return false;
                }
            });
            return referenceDataName || "None Selected";
        },

        dropDownEditor: function (container, options) {
            var refData = getReferenceData(options.field);
            $('<input required data-text-field="Name" data-value-field="Id" data-bind="value:' + options.field + '"/>')
				.appendTo(container)
				.kendoDropDownList({
				    autoBind: false,
				    dataSource: refData,
				    animation: false
				});
        },

        referenceData: function (obj) {
            if (typeof (getReferenceData) !== 'function') alert('getReferenceData function must be implemented');

            obj.editor = $.awards.dropDownEditor;
            obj.template = function (dataItem) { return $.awards.getReferenceDataName(dataItem, obj.field); };
            return obj;
        },
        /** Reference Data Handling - End **/

        /** DateTime string format - Start **/
        getDateTimeDisplay: function (dataItem, field) {
            return dataItem[field] ? $.awards.convert.dateToString(dataItem[field], 'datetime') : "";
        },

        dateTimeEditor: function (container, options) {
            $('<input data-bind="value:' + options.field + '"/>')
				.appendTo(container)
				.kendoDateTimePicker({
				    format: $.awards.defaults.dateTimeFormat
				});
        },

        dateTimeFormat: function (obj) {
            obj.editor = $.awards.dateTimeEditor;
            obj.template = function (dataItem) { return $.awards.getDateTimeDisplay(dataItem, obj.field) };
            return obj;
        },
        /** DateTime string format - End **/

        /** Date string format - Start **/
        getDateDisplay: function (dataItem, field) {
            return dataItem[field] ? $.awards.convert.dateToString(dataItem[field], 'date') : "";
        },

        dateEditor: function (container, options) {
            $('<input data-bind="value:' + options.field + '"/>')
				.appendTo(container)
				.kendoDatePicker({
				    format: $.awards.defaults.dateFormat
				});
        },

        dateFormat: function (obj) {
            obj.editor = $.awards.dateTimeEditor;
            obj.template = function (dataItem) { return $.awards.getDateDisplay(dataItem, obj.field) };
            return obj;
        },
        /** Date string format - End **/

        /** HTML Convertion Routines - Start **/
        encodeHTML: function (value) {
            return encodeURI(value);
        },
        decodeHTML: function (value) {
            try {
                return decodeURI(value);
            } catch (e) {
                return unescape(value);
            }
        },
        decodeEntities: function (value) {
            var doc = document.implementation.createHTMLDocument("");
            var element = doc.createElement('div');

            function getText(str) {
                element.innerHTML = str;
                str = element.textContent;
                element.textContent = '';
                return str;
            }

            function decodeHTMLEntities(str) {
                if (str && typeof str === 'string') {
                    var x = getText(str);
                    while (str !== x) {
                        str = x;
                        x = getText(x);
                    }
                    return x;
                }
            }
            return decodeHTMLEntities(value);
        },
        /** HTML Convertion Routines - End **/

        /** JCookie Implementation - Start **/
        cookieRead: function (cookieName) {
            return $.jCookie(cookieName);
        },
        cookieCreate: function (cookieName, cookieObj) {
            $.jCookie(cookieName, cookieObj)
        },
        cookieUpdate: function (cookieName, cookieObj) {
            $.jCookie(cookieName, cookieObj)
        },
        cookieDestroy: function (cookieName) {
            $.jCookie(cookieName, null);
        },
        /** JCookie Implementation - END **/
        escapeAttributeValue: function (value) {
            // As mentioned on http://api.jquery.com/category/selectors/
            return value.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g, "\\$1");
        },
        getUnique: function (list, uniqueField) {
            // return a new array;
            var result = [];
            var hashTable = {};

            $(list).each(function (index) {
                var uniqueValue = list[index][uniqueField];
                if (!hashTable[uniqueValue]) {
                    hashTable[uniqueValue] = true;
                    result.push(list[index]);
                }
            });

            return result;
        },
        linkify: function ($target) {
            if (void 0 === $target) {
                $target = $("body");
            }
            var $emails = $target.find("a").filter(function () { return this.href.match(/mailto:*/); });
            if ($emails.length) {
                $emails.each(function () {
                    var $this = $(this);
                    var text = $this.text();
                    $this.replaceWith($("<span class='linkify-email-address'/>").text(text));
                });
            }
            else {
                $emails = $(".linkify-email-address");
                $emails.each(function () {
                    var $this = $(this);
                    var text = $this.text();
                    $this.replaceWith($("<a/>").attr("href", "mailto:" + text).text(text));
                });
            }
        }
    }
})(jQuery);

Date.prototype.today = function () {
    return ((this.getDate() < 10) ? "0" : "") + this.getDate() + "/" + (((this.getMonth() + 1) < 10) ? "0" : "") + (this.getMonth() + 1) + "/" + this.getFullYear();
}
Date.prototype.timeNow = function () { return ((this.getHours() < 10) ? "0" : "") + ((this.getHours() > 12) ? (this.getHours() - 12) : this.getHours()) + ":" + ((this.getMinutes() < 10) ? "0" : "") + this.getMinutes() + ":" + ((this.getSeconds() < 10) ? "0" : "") + this.getSeconds() + ((this.getHours() > 12) ? (' PM') : ' AM'); };
Date.prototype.currentDateTime = function () {
    return new Date().today() + " " + new Date().timeNow();
};

String.prototype.format = function () {
    // usage example: '{0} is {1}'.format('DMDS', 'great');
    var res = this;
    for (var i = 0; i < arguments.length; i++) {
        res = res.replace(new RegExp("\\{" + (i) + "\\}", "g"), arguments[i]);
    }
    return res;
}

String.prototype.isNullOrEmpty = function () { return $.awards.is.nullOrEmpty(this); };
String.prototype.isNumeric = function () { return $.isNumeric(this); };
String.prototype.isAlphaNumeric = function () { return $.awards.is.alphaNumeric(this); };
String.prototype.trimIt = function () { return (typeof this === "string") ? this.replace(/\s{2,}/g, ' ').trim() : this; };
String.prototype.clean = function () { return (typeof this === "string") ? this.replace(/\s{2,}/g, ' ').trim() : this; };

(function ($) {
    $.grid = {
        init: function (options) {
            // options should have:
            // $grid
            // gridOptions
            if (options.$grid.length > 0) {
                var $grid = options.$grid;
                // we must clear the content. if not, there will be duplicated "change" events
                var $kendoGrid = $grid.data().kendoGrid;
                if ($kendoGrid) {
                    $kendoGrid.destroy();
                    $grid.empty();
                }

                if (typeof options.skipDefaultOptions === "undefined" || !options.skipDefaultOptions) {
                    options.gridOptions.filterable = {
                        operators: {
                            string: {
                                contains: "Contains"
                            }
                        },
                        extra: false
                    };

                    options.gridOptions.sortable = true;
                }
                $grid.kendoGrid(options.gridOptions);
            }
        },
        initWithSearch: function (options) {
            /// <summary>Intializes the grid with the ability to search.</summary>
            /// <param name="$grid" type="$Object"></param>
            /// <param name="gridOptions" type="Object"></param>
            /// <param name="searchPlaceholderText" type="String"></param>
            /// <param name="filters" type="Object"></param>
            /// <param name="$searchInput" type="$Object"></param>
            /// <param name="$clearSearchButton" type="$Object">Optional.</param>
            /// <param name="skipDefaultOptions" type="Object">Optional. Default: false</param>
            /// <param name="hideFilterIcons" type="Boolean">Optional. Default: true</param>
            /// <param name="retainSearch" type="Boolean">Automatically retain the search value and apply it upon reload. Optional. Default: true</param>
            /// <param name="autosaveState" type="Boolean">Save the current state of the grid to session storage on paging and search (if applicable). Optional. Default: true</param>
            /// <param name="customDeleteOptions" type="Object">
            ///     Optional. 
            ///     url: The url to send delete request to.
            ///     serverSideParameterName: The parameter name of the delete url endpoint. Ex: objectId
            ///     clientSidePropertyName: The property name of the object related to the grid row, which will be the value of serverSideParameterName. Ex: Id
            ///     True = Combine button with last column, Number = combine with cloumn n. 
            ///     combineWithColumn: True = Combine button with last column, Number = combine with cloumn n. Undefined/false = and new column
            /// </param>
            /// <param name="addTestPackageFilter" type="function">
            ///     Optional.
            ///     This function appends the toggle-test-package filter to a list of filters and
            ///     returns it in a wrapper object that can be consumed by the grid filter property.
            /// </param>

            if (typeof options === "undefined") {
                alert("you cannot init a grid without options");
                return;
            }
            if (typeof options.$grid === "undefined" ||
                     options.$grid.length == 0) {
                alert("you cannot init a grid without $grid");
                return;
            }
            var defaultOptions = {
            	searchPlaceholderText: "Search",
				clearText: "Clear",
                skipSearch: false,
                filters: function (value) {
                    return [];
                },
                hideFilterIcons: true,
                retainSearch: true,
                autosaveState: true
            };

            options = $.extend({}, defaultOptions, options);

            var $grid = options.$grid;

            if (!options.skipSearch && options.retainSearch) {
                // save the search value before the input re-created
                var $searchInput = options.$searchInput;
                if (typeof options.$searchInput === "undefined") {
                    $searchInput = $grid.find(".instantSearch");
                }
                var searchValue = $searchInput.val();

                if (!$.awards.is.nullOrEmpty(searchValue)) {
                    options.retainSearchValue = searchValue;
                }
            }

            // we must clear the content. if not, there will be duplicated "change" events
            var $kendoGrid = $grid.data().kendoGrid;
            if ($kendoGrid) {
                $kendoGrid.destroy();
                $grid.empty();
            }

            var guid = $.awards.guid(); // this is the guid for instant search

            var gridGuid = $.awards.guid(); // the grid can only have one and only one guid. this guid is for autosaveState
            if ($grid.data("gridGuid")) {
                gridGuid = $grid.data("gridGuid");
            }
            else if ($grid.data("gridguid")) {
                gridGuid = $grid.data("gridguid");
            }
            else {
                $grid.data("gridGuid", gridGuid);
            }

            if (!options.skipSearch) {
                if (typeof options.$searchInput === "undefined" || typeof options.$clearSearchButton === "undefined") {
                    if ($.awards.is.nullOrEmpty(options.searchPlaceholderText)) {
                        options.searchPlaceholderText = "Search";
                    }

                        if (typeof options.gridOptions.toolbar === "undefined")
                            options.gridOptions.toolbar = "<input class='instantSearch' data-guid='{0}' placeholder='{1}' /> <a class='clearInstantSearch btn btn-xs btn-primary' data-guid='{0}'>{2}</a>".format(guid, options.searchPlaceholderText, options.clearText);
                        else
                            options.gridOptions.toolbar.push({ template: "<input class='instantSearch' data-guid='{0}' placeholder='{1}' /> <a class='clearInstantSearch btn btn-xs btn-primary' data-guid='{0}'>{2}</a>".format(guid, options.searchPlaceholderText, options.clearText) });
                    }
                }

            if (typeof options.skipDefaultOptions === "undefined" || !options.skipDefaultOptions) {
                options.gridOptions.filterable = {
                    operators: {
                        string: {
                            contains: "Contains"
                        }
                    },
                    extra: false
                };

                options.gridOptions.sortable = {
                    mode: "multiple"
                };
            }

            if (options.customDeleteOptions) {
                var customDelete = {
                    name: "customDelete", text: "<span class='glyphicon glyphicon-trash text-danger'></span>", click: function (e) {
                        e.preventDefault();
                        var $row = $(e.currentTarget).closest("tr");
                        var dataItem = this.dataItem($row);

                        var postData = {};

                        if (options.customDeleteOptions.serverSideParameterName != undefined && options.customDeleteOptions.serverSideParameterName) {
                            postData[options.customDeleteOptions.serverSideParameterName] =
                                dataItem[options.customDeleteOptions.clientSidePropertyName];
                        } else if (options.customDeleteOptions.serverSideParameterNames != undefined && options.customDeleteOptions.serverSideParameterNames) {
                            for (let i = 0; i < options.customDeleteOptions.serverSideParameterNames.length; i++) {
                                postData[options.customDeleteOptions.serverSideParameterNames[i]] = dataItem[options.customDeleteOptions.clientSidePropertyNames[i]];
                            }
                        }

                        $.awards.confirm({
                            title: "Delete Confirmation",
                            message: "Are you sure you would like to delete this item?",
                            okFunction: function () {
                                $.ajax({
                                    url: options.customDeleteOptions.url, type: 'POST', data: postData
                                })
                                    .done(function (response) {

                                        if (response.Error) {
                                            $.awards.notify.error(response.Error);
                                            return;
                                        }

                                        var grid = $(e.currentTarget).closest('[data-role="grid"]').data("kendoGrid");

                                        grid.removeRow($row);
                                        $.awards.notify.success("Removed Successfully");
                                    })
                                    .fail(function () {
                                        $.awards.notify.error('Failed to remove. Please contact support.');
                                    });

                            },
                            okText: "Delete"
                        });
                    }
                };

                if (options.customDeleteOptions.combineWithColumn === void 0 ||
                    options.customDeleteOptions.combineWithColumn === false) {
                    options.gridOptions.columns.push({
                        command: [
                            customDelete
                        ],
                        title: " ",
                        width: 120
                    });
                }
                else {
                    var combineWithLast = options.customDeleteOptions.combineWithColumn === true;

                    if (combineWithLast) {
                        options.gridOptions.columns[options.gridOptions.columns.length - 1].command.push(customDelete);
                    }
                    else if ($.isNumeric(options.customDeleteOptions.combineWithColumn)) {
                        options.gridOptions.columns[options.customDeleteOptions.combineWithColumn].command.push(customDelete);
                    }

                }
            } // if options.customDeleteOptions

            $kendoGrid = $grid.kendoGrid(options.gridOptions);

            if (options.autosaveState) {
                $.grid.loadState({
                    cookieName: gridGuid,
                    useSessionStorage: true,
                    grid: $kendoGrid.data("kendoGrid")
                });

                var pager = $kendoGrid.data("kendoGrid").pager;
                if (typeof pager !== "undefined") {
                    pager.bind("change", function () {
                        $.grid.saveState({
                            cookieName: gridGuid,
                            useSessionStorage: true,
                            grid: $kendoGrid.data("kendoGrid")
                        });
                    });
                }

                $kendoGrid.data("kendoGrid").bind("dataBound", function (e) {
                    $.grid.saveState({
                        cookieName: gridGuid,
                        useSessionStorage: true,
                        grid: $kendoGrid.data("kendoGrid")
                    });
                });
            }

            if (options.hideFilterIcons) {
                $kendoGrid.find(".k-header").find(".k-grid-filter").hide();
            }

            // Optional field. If it is not provided, then the default behaviour is assigned
            if (!options.addTestPackageFilter) {
                options.addTestPackageFilter = function (filters) {
                    if (filters && filters.length > 0) {
                        return {
                            logic: "or",
                            filters: filters
                        };
                    }

                    return {};
                }
            }

            var filter = options.addTestPackageFilter();
            $grid.data("kendoGrid").dataSource.filter(filter);

            $kendoGrid.find(".k-grid-header").find("a.linkify").unbind().click(function () {
                $.awards.linkify($kendoGrid);
            });
            if (!options.skipSearch) {
                if (typeof options.$searchInput === "undefined" || typeof options.$clearSearchButton === "undefined") {
                    options.$searchInput = $grid.find("input.instantSearch[data-guid='{0}']".format(guid));
                    options.$clearSearchButton = $grid.find("a.clearInstantSearch[data-guid='{0}']".format(guid));
                }

                options.$searchInput.keyup(function () {
                    var value = $(this).val();
                    $grid.trigger('search', value);

                    $.awards.toggle.button({
                        $button: options.$clearSearchButton,
                        disabled: value.length === 0
                    });

                    var searchFilters = options.filters(value);
                    var filters = options.addTestPackageFilter(searchFilters);
                    $grid.data("kendoGrid").dataSource.filter(filters);

                    if (options.autosaveState) {
                        $.grid.saveState({
                            cookieName: gridGuid,
                            useSessionStorage: true,
                            grid: $kendoGrid.data("kendoGrid")
                        });
                    }
                });
                options.$clearSearchButton.click(function () {
                    $grid.data("kendoGrid").dataSource.filter({});
                    options.$searchInput.val("");
                    options.$searchInput.keyup();
                    if (typeof options.searchTextDropDownLists !== "undefined") {
                        $("[v-select-guid]").each(function () { $(this).data("kendoDropDownList").select(0) });
                        $("[v-multiselect-guid]").each(function () { $(this).data("kendoMultiSelect").value("") });
                    }
                });

                if (void 0 !== options.searchTextDropDownLists) {
                    $.each(options.searchTextDropDownLists, function (i, dropdownlist) {
                        dropdownlist.$select.attr("v-select-field", dropdownlist.field);
                        function onchange() {
                            var filters = [], value = "", field;
                            $("[v-select-guid='{0}'], [v-multiselect-guid='{0}']".format(guid)).each(function (i, e) {
                                var $this = $(e);
                                field = $this.attr("v-select-field");
                                if ($this.data("kendoMultiSelect")) {
                                    $.each($this.data("kendoMultiSelect").value(), function (i, e) {
                                        if (!$.awards.is.nullOrEmpty(e)) {
                                            filters.push({ field: field, operator: "contains", value: e });
                                        }
                                    });
                                }
                                else {
                                    value = $this.val();
                                    if (!$.awards.is.nullOrEmpty(value)) {
                                        filters.push({ field: field, operator: "contains", value: $this.find("option:selected").text() });
                                    }
                                }
                            });


                            var allFilters = options.addTestPackageFilter(filters);
                            $grid.data("kendoGrid").dataSource.filter(allFilters);
                        }
                        if (typeof dropdownlist.multiselect === "undefined") {
                            dropdownlist.$select.attr("v-select-guid", guid);
                            dropdownlist.$select.kendoDropDownList({
                                dataSource: dropdownlist.data,
                                optionLabel: void 0 === dropdownlist.optionLabel ? "-- Please Select --" : dropdownlist.optionLabel,
                                change: onchange,
                                animation: false
                            });
                        }
                        else if (dropdownlist.multiselect) {
                            dropdownlist.$select.attr("v-multiselect-guid", guid);
                            dropdownlist.$select.kendoMultiSelect({
                                dataSource: dropdownlist.data,
                                change: onchange,
                                animation: false,
                                autoClose: void 0 === dropdownlist.autoClose ? false : dropdownlist.autoClose
                            });
                        }
                    });
                }

                if (options.retainSearch && !$.awards.is.nullOrEmpty(options.retainSearchValue)) {
                    var $searchInput = options.$searchInput;
                    if (typeof options.$searchInput === "undefined") {
                        $searchInput = $grid.find(".instantSearch");
                    }
                    $searchInput.val(options.retainSearchValue);
                    if (!options.autosaveState) {
                        $searchInput.trigger("keyup");
                    }
                }


                $.awards.toggle.button({
                    $button: options.$clearSearchButton,
                    disabled: options.$searchInput.nullOrEmpty()
                }); // the clear button is hidden as default
            }

            if (options.$toggleshowtestpackages) {
                options.$toggleshowtestpackages.change(function () {
                    var searchFilters;
                    if ($searchInput.val()) {
                        searchFilters = options.filters($searchInput.val());
                    }

                    var filters = options.addTestPackageFilter(searchFilters);
                    $grid.data("kendoGrid").dataSource.filter(filters);
                    $grid.trigger('toggleTestPackages');
                });
            }
        },
        saveSelectedRow: function (options) {
            var dataRows = options.grid.items();
            var selectedRowIndex = dataRows.index(options.grid.select());

            if (typeof selectedRowIndex !== "undefined" && selectedRowIndex > -1) {
                localStorage[options.cookieName] = selectedRowIndex + 1;
            }
        },
        loadSelectedRow: function (options) {
            var cookie = localStorage[options.cookieName];
            if (typeof cookie !== "undefined") {
                options.grid.select("tr[role='row']:eq({0})".format(cookie));
            }
        },
        loadState: function (options) {
            var cookie = localStorage[options.cookieName];

            if (options.useSessionStorage) {
                cookie = sessionStorage[options.cookieName];
            }

            if (cookie) {
                var state = JSON.parse(cookie);
                if (state) {
                    if (state.filter) { // Grid has filters.

                        // Because we are serializing the state, Date values get deserialized as strings,
                        // then when you try to sort the date column, it will try to compare the Date and String
                        // which fails. To prevent this we convert all the strings back to Date.

                        if (options.grid.dataSource.options.schema.model) {
                            var fields = options.grid.dataSource.options.schema.model.fields;
                            for (var i = 0; i < state.filter.filters.length; i++) {
                                var filter = state.filter.filters[i];
                                if (filter.field in fields && fields[filter.field].type == "date") {
                                    filter.value = new Date(filter.value);
                                }
                            }
                        }

                        options.grid.dataSource.query(state);
                    }

                    if (state.group && state.group.length > 0) {
                        options.grid.dataSource.group(state.group);
                    }

                    if (state.page) {
                        options.grid.dataSource.page(state.page);
                    }

                    if (state.sort && state.sort.length > 0) {
                        options.grid.dataSource.sort(state.sort);
                    }
                    var $instantSearch = options.grid.wrapper.find(".instantSearch");
                    if (typeof state.value !== "undefined" &&
                        $instantSearch.length > 0) {
                        $instantSearch.val(state.value);
                        $instantSearch.trigger("keyup");
                    }
                }
            }
        },
        saveState: function (options) {
            var dataSource = options.grid.dataSource;

            var state = {
                page: dataSource.page(),
                pageSize: dataSource.pageSize(),
                sort: dataSource.sort(),
                group: dataSource.group(),
                filter: dataSource.filter()
            };

            if (typeof state.filter !== "undefined" && state.filter !== null) {
                var values = $.unique($.grep($.map(state.filter.filters, function (e, i) { return e.value; }), function (e, i) { return typeof e === "string"; }));
                if (values.length == 1) {
                    state.value = values[0];
                }
            }

            if (options.useSessionStorage) {
                sessionStorage[options.cookieName] = JSON.stringify(state);
            }
            else {
                localStorage[options.cookieName] = JSON.stringify(state);
            }
        },
        applyAutoSave: function (gridSelector, gridGuid) {
            // Use this method for enablind autosave on grid that are not initialized by $.grid.iniWithSearch
            var gridGuid = gridGuid || $(gridSelector).data("gridGuid");

            $.grid.loadState({
                cookieName: gridGuid,
                useSessionStorage: true,
                grid: $(gridSelector).data("kendoGrid")
            });

            var pager = $(gridSelector).data("kendoGrid").pager;
            if (typeof pager !== "undefined") {
                pager.bind("change", function () {
                    $.grid.saveState({
                        cookieName: gridGuid,
                        useSessionStorage: true,
                        grid: $(gridSelector).data("kendoGrid")
                    });
                });
            }

            $(gridSelector).data("kendoGrid").bind("dataBound", function (e) {
                $.grid.saveState({
                    cookieName: gridGuid,
                    useSessionStorage: true,
                    grid: $(gridSelector).data("kendoGrid")
                });
            });
        }
    }
    $.textbox = {
        saveState: function (options) {
            options.$input.keyup(function () {
                localStorage[options.uniqueName] = options.$input.val();
            });
        },
        loadState: function (options) {
            var value = localStorage[options.uniqueName];
            options.$input.val(value);
        }
    };
    $.dropdown = {
        saveState: function (options) {
            // you must have the following
            // - $kendodropdown
            // - uniqueId

            if (void 0 !== options.$kendodropdown && !$.awards.is.nullOrEmpty(options.uniqueId)) {
                var selectedValue = options.$kendodropdown.value();
                localStorage[options.uniqueId] = selectedValue;
            }
        },
        loadState: function (options) {
            // you must have the following
            // - $kendodropdown
            // - uniqueId

            if (void 0 !== options.$kendodropdown && !$.awards.is.nullOrEmpty(options.uniqueId)) {
                var selectedValue = localStorage[options.uniqueId];
                options.$kendodropdown.value(selectedValue);
            }
        }
    };
})(jQuery);;