﻿/*
* jQuery Plugin: Tokenizing Autocomplete Text Entry
* Version 1.6.0
*
* Copyright (c) 2009 James Smith (http://loopj.com)
* Licensed jointly under the GPL and MIT licenses,
* choose which one suits your project best!
*
*/

(function ($) {
    // Default settings
    var DEFAULT_SETTINGS = {
        // Search settings
        method: "GET",
        contentType: "json",
        queryParam: "q",
        searchDelay: 300,
        minChars: 1,
        propertyToSearch: "name",
        jsonContainer: null,

        // Display settings
        hintText: "Type in a search term",
        noResultsText: "No results",
        searchingText: "Searching...",
        deleteText: "&times;",
        animateDropdown: true,

        // Tokenization settings
        tokenLimit: null,
        tokenDelimiter: ",",
        preventDuplicates: false,

        // Output settings
        tokenValue: "id",

        // Prepopulation settings
        prePopulate: null,
        processPrePopulate: false,

        // Manipulation settings
        idPrefix: "token-input-",

        // Formatters
        resultsFormatter: function (item) { return "<li>" + item[this.propertyToSearch] + "</li>" },
        tokenFormatter: function (item) { return "<li><p>" + item[this.propertyToSearch] + "</p></li>" },

        // Callbacks
        onResult: null,
        onAdd: null,
        onDelete: null,
        onReady: null,
        formatQuery: null
    };

    // Default classes to use when theming
    var DEFAULT_CLASSES = {
        tokenList: "token-input-list",
        token: "token-input-token",
        tokenDelete: "token-input-delete-token",
        selectedToken: "token-input-selected-token",
        highlightedToken: "token-input-highlighted-token",
        dropdown: "token-input-dropdown",
        dropdownItem: "token-input-dropdown-item",
        dropdownItem2: "token-input-dropdown-item2",
        selectedDropdownItem: "token-input-selected-dropdown-item",
        inputToken: "token-input-input-token"
    };

    // Input box position "enum"
    var POSITION = {
        BEFORE: 0,
        AFTER: 1,
        END: 2
    };

    // Keys "enum"
    var KEY = {
        BACKSPACE: 8,
        TAB: 9,
        ENTER: 13,
        ESCAPE: 27,
        SPACE: 32,
        PAGE_UP: 33,
        PAGE_DOWN: 34,
        END: 35,
        HOME: 36,
        LEFT: 37,
        UP: 38,
        RIGHT: 39,
        DOWN: 40,
        NUMPAD_ENTER: 108,
        COMMA: 188
    };

    // Additional public (exposed) methods
    var methods = {
        init: function (url_or_data_or_function, options) {
            var settings = $.extend({}, DEFAULT_SETTINGS, options || {});

            return this.each(function () {
                $(this).data("tokenInputObject", new $.TokenList(this, url_or_data_or_function, settings));
            });
        },
        clear: function () {
            this.data("tokenInputObject").clear();
            return this;
        },
        add: function (item) {
            this.data("tokenInputObject").add(item);
            return this;
        },
        remove: function (item) {
            this.data("tokenInputObject").remove(item);
            return this;
        },
        get: function () {
            return this.data("tokenInputObject").getTokens();
        },
        val: function (val) {
            return this.data("tokenInputObject").setInput(val);
        }
    }

    // Expose the .tokenInput function to jQuery as a plugin
    $.fn.tokenInput = function (method) {
        // Method calling and initialization logic
        if (methods[method]) {
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
        } else {
            return methods.init.apply(this, arguments);
        }
    };

    // TokenList class for each input
    $.TokenList = function (input, url_or_data, settings) {
        //
        // Initialization
        //

        // Configure the data source
        if ($.type(url_or_data) === "string" || $.type(url_or_data) === "function") {
            // Set the url to query against
            settings.url = url_or_data;

            // If the URL is a function, evaluate it here to do our initalization work
            var url = computeURL();

            // Make a smart guess about cross-domain if it wasn't explicitly specified
            if (settings.crossDomain === undefined) {
                if (url.indexOf("://") === -1) {
                    settings.crossDomain = false;
                } else {
                    settings.crossDomain = (location.href.split(/\/+/g)[1] !== url.split(/\/+/g)[1]);
                }
            }
        } else if (typeof (url_or_data) === "object") {
            // Set the local data to search through
            settings.local_data = url_or_data;
        }

        // Build class names
        if (settings.classes) {
            // Use custom class names
            settings.classes = $.extend({}, DEFAULT_CLASSES, settings.classes);
        } else if (settings.theme) {
            // Use theme-suffixed default class names
            settings.classes = {};
            $.each(DEFAULT_CLASSES, function (key, value) {
                settings.classes[key] = value + "-" + settings.theme;
            });
        } else {
            settings.classes = DEFAULT_CLASSES;
        }


        // Save the tokens
        var saved_tokens = [];

        // Keep track of the number of tokens in the list
        var token_count = 0;

        // Basic cache to save on db hits
        var cache = new $.TokenList.Cache();

        // Keep track of the timeout, old vals
        var timeout;
        var input_val;

        // Create a new text input an attach keyup events
        var input_box = $("<input type=\"text\"  autocomplete=\"off\">")
        .css({
            outline: "none"
        })
        .attr("id", settings.idPrefix + input.id)
        .focus(function () {
            if (settings.tokenLimit === null || settings.tokenLimit !== token_count) {
                show_dropdown_hint();
            }
        })
        .blur(function () {
            
            hide_dropdown();
            $(this).val("");
        })
        .bind("keyup keydown blur update", resize_input)
        .keydown(function (event) {
            var previous_token;
            var next_token;

            switch (event.keyCode) {
                case KEY.LEFT:
                case KEY.RIGHT:
                case KEY.UP:
                case KEY.DOWN:
                    if (!$(this).val()) {
                        previous_token = input_token.prev();
                        next_token = input_token.next();

                        if ((previous_token.length && previous_token.get(0) === selected_token) || (next_token.length && next_token.get(0) === selected_token)) {
                            // Check if there is a previous/next token and it is selected
                            if (event.keyCode === KEY.LEFT || event.keyCode === KEY.UP) {
                                deselect_token($(selected_token), POSITION.BEFORE);
                            } else {
                                deselect_token($(selected_token), POSITION.AFTER);
                            }
                        } else if ((event.keyCode === KEY.LEFT || event.keyCode === KEY.UP) && previous_token.length) {
                            // We are moving left, select the previous token if it exists
                            select_token($(previous_token.get(0)));
                        } else if ((event.keyCode === KEY.RIGHT || event.keyCode === KEY.DOWN) && next_token.length) {
                            // We are moving right, select the next token if it exists
                            select_token($(next_token.get(0)));
                        }
                    } else {
                        var dropdown_item = null;

                        if (event.keyCode === KEY.DOWN || event.keyCode === KEY.RIGHT) {
                            dropdown_item = $(selected_dropdown_item).next();
                        } else {
                            dropdown_item = $(selected_dropdown_item).prev();
                        }

                        if (dropdown_item.length) {
                            select_dropdown_item(dropdown_item);
                        }
                        return false;
                    }
                    break;

                case KEY.BACKSPACE:
                    previous_token = input_token.prev();

                    if (!$(this).val().length) {
                        if (selected_token) {
                            delete_token($(selected_token));
                            hidden_input.change();
                        } else if (previous_token.length) {
                            select_token($(previous_token.get(0)));
                        }

                        return false;
                    } else if ($(this).val().length === 1) {
                        hide_dropdown();
                    } else {
                        // set a timeout just long enough to let this function finish.
                        setTimeout(function () { do_search(); }, 5);
                    }
                    break;

                case KEY.TAB:
                case KEY.ENTER:
                case KEY.NUMPAD_ENTER:
                case KEY.COMMA:
                    if (selected_dropdown_item) {
                        add_token($(selected_dropdown_item).data("tokeninput"));
                        hidden_input.change();
                        return false;
                    }
                    break;

                case KEY.ESCAPE:
                    hide_dropdown();
                    return true;

                default:
                    if (String.fromCharCode(event.which)) {
                        // set a timeout just long enough to let this function finish.
                        setTimeout(function () { do_search(); }, 5);
                    }
                    break;
            }
        });

        // Keep a reference to the original input box
        var hidden_input = $(input)
                           .hide()
                           .val("")
                           .focus(function () {
                               input_box.focus();
                           })
                           .blur(function () {
                               input_box.blur();
                           });

        // Keep a reference to the selected token and dropdown item
        var selected_token = null;
        var selected_token_index = 0;
        var selected_dropdown_item = null;

        // The list to store the token items in
        var token_list = $("<ul />")
        .addClass(settings.classes.tokenList)
        .click(function (event) {
            var li = $(event.target).closest("li");
            if (li && li.get(0) && $.data(li.get(0), "tokeninput")) {
                toggle_select_token(li);
            } else {
                // Deselect selected token
                if (selected_token) {
                    deselect_token($(selected_token), POSITION.END);
                }

                // Focus input box
                input_box.focus();
            }
        })
        .mouseover(function (event) {
            var li = $(event.target).closest("li");
            if (li && selected_token !== this) {
                li.addClass(settings.classes.highlightedToken);
            }
        })
        .mouseout(function (event) {
            var li = $(event.target).closest("li");
            if (li && selected_token !== this) {
                li.removeClass(settings.classes.highlightedToken);
            }
        })
        .insertBefore(hidden_input);

        // The token holding the input box
        var input_token = $("<li />")
        .addClass(settings.classes.inputToken)
        .appendTo(token_list)
        .append(input_box);

        // The list to store the dropdown items in        
        var dropdown = $("<div>")
        .addClass(settings.classes.dropdown)
        .appendTo("body")
        .hide();

        // Magic element to help us resize the text input
        var input_resizer = $("<tester/>")
        .insertAfter(input_box)
        .css({
            position: "absolute",
            top: -9999,
            left: -9999,
            width: "auto",
            fontSize: input_box.css("fontSize"),
            fontFamily: input_box.css("fontFamily"),
            fontWeight: input_box.css("fontWeight"),
            letterSpacing: input_box.css("letterSpacing"),
            whiteSpace: "nowrap"
        });

        // Pre-populate list if items exist
        hidden_input.val("");
        var li_data = settings.prePopulate || hidden_input.data("pre");
        if (settings.processPrePopulate && $.isFunction(settings.onResult)) {
            li_data = settings.onResult.call(hidden_input, li_data);
        }
        if (li_data && li_data.length) {
            $.each(li_data, function (index, value) {
                insert_token(value);
                checkTokenLimit();
            });
        }

        // Initialization is done
        if ($.isFunction(settings.onReady)) {
            settings.onReady.call();
        }

        //
        // Public functions
        //

        this.clear = function () {
            token_list.children("li").each(function () {
                if ($(this).children("input").length === 0) {
                    delete_token($(this));
                }
            });
        }

        this.add = function (item) {
            add_token(item);
        }

        this.setInput = function (val) {

            input_box.val(val);
            return do_search();
        }

        this.remove = function (item) {
            token_list.children("li").each(function () {
                if ($(this).children("input").length === 0) {
                    var currToken = $(this).data("tokeninput");
                    var match = true;
                    for (var prop in item) {
                        if (item[prop] !== currToken[prop]) {
                            match = false;
                            break;
                        }
                    }
                    if (match) {
                        delete_token($(this));
                    }
                }
            });
        }

        this.getTokens = function () {
            return saved_tokens;
        }

        //
        // Private functions
        //

        function checkTokenLimit() {
            if (settings.tokenLimit !== null && token_count >= settings.tokenLimit) {
                input_box.hide();
                hide_dropdown();
                return;
            }
        }

        function resize_input() {
            if (input_val === (input_val = input_box.val())) { return; }

            // Enter new content into resizer and resize input accordingly
            var escaped = input_val.replace(/&/g, '&amp;').replace(/\s/g, ' ').replace(/</g, '&lt;').replace(/>/g, '&gt;');
            input_resizer.html(escaped);
            input_box.width(input_resizer.width() + 30);
        }

        function is_printable_character(keycode) {
            return ((keycode >= 48 && keycode <= 90) ||     // 0-1a-z
                (keycode >= 96 && keycode <= 111) ||    // numpad 0-9 + - / * .
                (keycode >= 186 && keycode <= 192) ||   // ; = , - . / ^
                (keycode >= 219 && keycode <= 222));    // ( \ ) '
        }

        // Inner function to a token to the list
        function insert_token(item) {
            var this_token = settings.tokenFormatter(item);
            this_token = $(this_token)
          .addClass(settings.classes.token)
          .insertBefore(input_token);

            // The 'delete token' button
            $("<span>" + settings.deleteText + "</span>")
            .addClass(settings.classes.tokenDelete)
            .appendTo(this_token)
            .click(function () {
                delete_token($(this).parent());
                hidden_input.change();
                return false;
            });

            // Store data on the token
            var token_data = { "id": item.id };
            token_data[settings.propertyToSearch] = item[settings.propertyToSearch];
            $.data(this_token.get(0), "tokeninput", item);

            // Save this token for duplicate checking
            saved_tokens = saved_tokens.slice(0, selected_token_index).concat([token_data]).concat(saved_tokens.slice(selected_token_index));
            selected_token_index++;

            // Update the hidden input
            update_hidden_input(saved_tokens, hidden_input);

            token_count += 1;

            // Check the token limit
            if (settings.tokenLimit !== null && token_count >= settings.tokenLimit) {
                input_box.hide();
                hide_dropdown();
            }

            return this_token;
        }

        // Add a token to the token list based on user input
        function add_token(item) {
            var callback = settings.onAdd;

            // See if the token already exists and select it if we don't want duplicates
            if (token_count > 0 && settings.preventDuplicates) {
                var found_existing_token = null;
                token_list.children().each(function () {
                    var existing_token = $(this);
                    var existing_data = $.data(existing_token.get(0), "tokeninput");
                    if (existing_data && existing_data.id === item.id) {
                        found_existing_token = existing_token;
                        return false;
                    }
                });

                if (found_existing_token) {
                    select_token(found_existing_token);
                    input_token.insertAfter(found_existing_token);
                    input_box.focus();
                    return;
                }
            }

            // Insert the new tokens
            if (settings.tokenLimit == null || token_count < settings.tokenLimit) {
                insert_token(item);
                checkTokenLimit();
            }

            // Clear input box
            input_box.val("");

            // Don't show the help dropdown, they've got the idea
            hide_dropdown();

            // Execute the onAdd callback if defined
            if ($.isFunction(callback)) {
                callback.call(hidden_input, item);
            }
        }

        // Select a token in the token list
        function select_token(token) {
            token.addClass(settings.classes.selectedToken);
            selected_token = token.get(0);

            // Hide input box
            input_box.val("");

            // Hide dropdown if it is visible (eg if we clicked to select token)
            hide_dropdown();
        }

        // Deselect a token in the token list
        function deselect_token(token, position) {
            token.removeClass(settings.classes.selectedToken);
            selected_token = null;

            if (position === POSITION.BEFORE) {
                input_token.insertBefore(token);
                selected_token_index--;
            } else if (position === POSITION.AFTER) {
                input_token.insertAfter(token);
                selected_token_index++;
            } else {
                input_token.appendTo(token_list);
                selected_token_index = token_count;
            }

            // Show the input box and give it focus again
            input_box.focus();
        }

        // Toggle selection of a token in the token list
        function toggle_select_token(token) {
            var previous_selected_token = selected_token;

            if (selected_token) {
                deselect_token($(selected_token), POSITION.END);
            }

            if (previous_selected_token === token.get(0)) {
                deselect_token(token, POSITION.END);
            } else {
                select_token(token);
            }
        }

        // Delete a token from the token list
        function delete_token(token) {
            // Remove the id from the saved list
            var token_data = $.data(token.get(0), "tokeninput");
            var callback = settings.onDelete;

            var index = token.prevAll().length;
            if (index > selected_token_index) index--;

            // Delete the token
            token.remove();
            selected_token = null;

            // Show the input box and give it focus again
            input_box.focus();

            // Remove this token from the saved list
            saved_tokens = saved_tokens.slice(0, index).concat(saved_tokens.slice(index + 1));
            if (index < selected_token_index) selected_token_index--;

            // Update the hidden input
            update_hidden_input(saved_tokens, hidden_input);

            token_count -= 1;

            if (settings.tokenLimit !== null) {
                input_box
                .show()
                .val("")
                .focus();
            }

            // Execute the onDelete callback if defined
            if ($.isFunction(callback)) {
                callback.call(hidden_input, token_data);
            }
        }

        // Update the hidden input box value
        function update_hidden_input(saved_tokens, hidden_input) {
            var token_values = $.map(saved_tokens, function (el) {
                return el[settings.tokenValue];
            });
            hidden_input.val(token_values.join(settings.tokenDelimiter));

        }

        // Hide and clear the results dropdown
        function hide_dropdown() {
            dropdown.hide().empty();
            selected_dropdown_item = null;
        }

        function show_dropdown() {
            dropdown
            .css({
                position: "absolute",
                top: $(token_list).offset().top + $(token_list).outerHeight(),
                left: $(token_list).offset().left,
                zindex: 999
            })
            .show();
        }

        function show_dropdown_searching() {
            if (settings.searchingText) {
                dropdown.html("<p>" + settings.searchingText + "</p>");
                show_dropdown();
            }
        }

        function show_dropdown_hint() {
            if (settings.hintText) {
                dropdown.html("<p>" + settings.hintText + "</p>");
                show_dropdown();
            }
        }

        // Highlight the query part of the search term
        function highlight_term(value, term) {
            return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<b>$1</b>");
        }

        function find_value_and_highlight_term(template, value, term) {
            return template.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + value + ")(?![^<>]*>)(?![^&;]+;)", "g"), highlight_term(value, term));
        }

        // Populate the results dropdown with some results
        function populate_dropdown(query, results) {
            if (results && results.length) {
                dropdown.empty();
                var dropdown_ul = $("<ul>")
                .appendTo(dropdown)
                .mouseover(function (event) {
                    select_dropdown_item($(event.target).closest("li"));
                })
                .mousedown(function (event) {
                    add_token($(event.target).closest("li").data("tokeninput"));
                    hidden_input.change();
                    return false;
                })
                .hide();

                $.each(results, function (index, value) {
                    var this_li = settings.resultsFormatter(value);

                    this_li = find_value_and_highlight_term(this_li, value[settings.propertyToSearch], query);

                    this_li = $(this_li).appendTo(dropdown_ul);

                    if (index % 2) {
                        this_li.addClass(settings.classes.dropdownItem);
                    } else {
                        this_li.addClass(settings.classes.dropdownItem2);
                    }

                    if (index === 0) {
                        select_dropdown_item(this_li);
                    }

                    $.data(this_li.get(0), "tokeninput", value);
                });

                show_dropdown();
                
                if (settings.animateDropdown) {
                    dropdown_ul.slideDown("fast");
                } else {
                    
                    dropdown_ul.show();
                }
            } else {
                if (settings.noResultsText) {
                    dropdown.html("<p>" + settings.noResultsText + "</p>");
                    show_dropdown();
                }
            }
        }

        // Highlight an item in the results dropdown
        function select_dropdown_item(item) {
            if (item) {
                if (selected_dropdown_item) {
                    deselect_dropdown_item($(selected_dropdown_item));
                }

                item.addClass(settings.classes.selectedDropdownItem);
                selected_dropdown_item = item.get(0);
            }
        }

        // Remove highlighting from an item in the results dropdown
        function deselect_dropdown_item(item) {
            item.removeClass(settings.classes.selectedDropdownItem);
            selected_dropdown_item = null;
        }

        // Do a search and show the "searching" dropdown if the input is longer
        // than settings.minChars
        function do_search() {
            var query = input_box.val().toLowerCase();

            if (query && query.length) {
                if (selected_token) {
                    deselect_token($(selected_token), POSITION.AFTER);
                }

                if (query.length >= settings.minChars) {
                    show_dropdown_searching();
                    clearTimeout(timeout);

                    timeout = setTimeout(function () {
                        run_search(query);
                    }, settings.searchDelay);
                } else {
                    hide_dropdown();
                }
            }
        }

        //Format the query
        function formatQuery(query) {
            if (settings.formatQuery)
                return settings.formatQuery(query);
            return query;
        }

        // Do the actual search
        function run_search(query) {
            var cache_key = query + computeURL();
            var cached_results = cache.get(cache_key);
            if (cached_results) {
                populate_dropdown(query, cached_results);
            } else {
                // Are we doing an ajax search or local data search?
                if (settings.url) {
                    var url = computeURL();
                    // Extract exisiting get params
                    var ajax_params = {};
                    ajax_params.data = {};
                    if (url.indexOf("?") > -1) {
                        var parts = url.split("?");
                        ajax_params.url = parts[0];

                        var param_array = parts[1].split("&");
                        $.each(param_array, function (index, value) {
                            var kv = value.split("=");
                            ajax_params.data[kv[0]] = kv[1];
                        });
                    } else {
                        ajax_params.url = url;
                    }

                    // Prepare the request
                    ajax_params.data[settings.queryParam] = formatQuery(query);
                    ajax_params.type = settings.method;
                    ajax_params.dataType = settings.contentType;
                    if (settings.crossDomain) {
                        ajax_params.dataType = "jsonp";

                    }

                    // Attach the success callback
                    ajax_params.success = function (results) {

                        if ($.isFunction(settings.onResult)) {
                            results = settings.onResult.call(hidden_input, results);
                        }
                        cache.add(cache_key, settings.jsonContainer ? results[settings.jsonContainer] : results);

                        // only populate the dropdown if the results are associated with the active search query
                        if (input_box.val().toLowerCase() === query) {
                            populate_dropdown(query, settings.jsonContainer ? results[settings.jsonContainer] : results);
                        }
                    };

                    // Make the request
                    $.ajax(ajax_params);
                } else if (settings.local_data) {
                    // Do the search through local data
                    var results = $.grep(settings.local_data, function (row) {
                        return row[settings.propertyToSearch].toLowerCase().indexOf(query.toLowerCase()) > -1;
                    });

                    if ($.isFunction(settings.onResult)) {
                        results = settings.onResult.call(hidden_input, results);
                    }
                    cache.add(cache_key, results);
                    populate_dropdown(query, results);
                }
            }
        }

        // compute the dynamic URL
        function computeURL() {
            var url = settings.url;
            if (typeof settings.url == 'function') {
                url = settings.url.call();
            }
            return url;
        }
    };

    // Really basic cache for the results
    $.TokenList.Cache = function (options) {
        var settings = $.extend({
            max_size: 500
        }, options);

        var data = {};
        var size = 0;

        var flush = function () {
            data = {};
            size = 0;
        };

        this.add = function (query, results) {
            if (size > settings.max_size) {
                flush();
            }

            if (!data[query]) {
                size += 1;
            }

            data[query] = results;
        };

        this.get = function (query) {
            return data[query];
        };
    };
} (jQuery));


/**
* Version: 1.0 Alpha-1 
* Build Date: 13-Nov-2007
* Copyright (c) 2006-2007, Coolite Inc. (http://www.coolite.com/). All rights reserved.
* License: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/. 
* Website: http://www.datejs.com/ or http://www.coolite.com/datejs/
*/
Date.CultureInfo = { name: "en-US", englishName: "English (United States)", nativeName: "English (United States)", dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], abbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], shortestDayNames: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"], firstLetterDayNames: ["S", "M", "T", "W", "T", "F", "S"], monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], amDesignator: "AM", pmDesignator: "PM", firstDayOfWeek: 0, twoDigitYearMax: 2029, dateElementOrder: "mdy", formatPatterns: { shortDate: "M/d/yyyy", longDate: "dddd, MMMM dd, yyyy", shortTime: "h:mm tt", longTime: "h:mm:ss tt", fullDateTime: "dddd, MMMM dd, yyyy h:mm:ss tt", sortableDateTime: "yyyy-MM-ddTHH:mm:ss", universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ", rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT", monthDay: "MMMM dd", yearMonth: "MMMM, yyyy" }, regexPatterns: { jan: /^jan(uary)?/i, feb: /^feb(ruary)?/i, mar: /^mar(ch)?/i, apr: /^apr(il)?/i, may: /^may/i, jun: /^jun(e)?/i, jul: /^jul(y)?/i, aug: /^aug(ust)?/i, sep: /^sep(t(ember)?)?/i, oct: /^oct(ober)?/i, nov: /^nov(ember)?/i, dec: /^dec(ember)?/i, sun: /^su(n(day)?)?/i, mon: /^mo(n(day)?)?/i, tue: /^tu(e(s(day)?)?)?/i, wed: /^we(d(nesday)?)?/i, thu: /^th(u(r(s(day)?)?)?)?/i, fri: /^fr(i(day)?)?/i, sat: /^sa(t(urday)?)?/i, future: /^next/i, past: /^last|past|prev(ious)?/i, add: /^(\+|after|from)/i, subtract: /^(\-|before|ago)/i, yesterday: /^yesterday/i, today: /^t(oday)?/i, tomorrow: /^tomorrow/i, now: /^n(ow)?/i, millisecond: /^ms|milli(second)?s?/i, second: /^sec(ond)?s?/i, minute: /^min(ute)?s?/i, hour: /^h(ou)?rs?/i, week: /^w(ee)?k/i, month: /^m(o(nth)?s?)?/i, day: /^d(ays?)?/i, year: /^y((ea)?rs?)?/i, shortMeridian: /^(a|p)/i, longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i, timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt)/i, ordinalSuffix: /^\s*(st|nd|rd|th)/i, timeContext: /^\s*(\:|a|p)/i }, abbreviatedTimeZoneStandard: { GMT: "-000", EST: "-0400", CST: "-0500", MST: "-0600", PST: "-0700" }, abbreviatedTimeZoneDST: { GMT: "-000", EDT: "-0500", CDT: "-0600", MDT: "-0700", PDT: "-0800"} };
Date.getMonthNumberFromName = function (name) {
    var n = Date.CultureInfo.monthNames, m = Date.CultureInfo.abbreviatedMonthNames, s = name.toLowerCase(); for (var i = 0; i < n.length; i++) { if (n[i].toLowerCase() == s || m[i].toLowerCase() == s) { return i; } }
    return -1;
}; Date.getDayNumberFromName = function (name) {
    var n = Date.CultureInfo.dayNames, m = Date.CultureInfo.abbreviatedDayNames, o = Date.CultureInfo.shortestDayNames, s = name.toLowerCase(); for (var i = 0; i < n.length; i++) { if (n[i].toLowerCase() == s || m[i].toLowerCase() == s) { return i; } }
    return -1;
}; Date.isLeapYear = function (year) { return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0)); }; Date.getDaysInMonth = function (year, month) { return [31, (Date.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]; }; Date.getTimezoneOffset = function (s, dst) { return (dst || false) ? Date.CultureInfo.abbreviatedTimeZoneDST[s.toUpperCase()] : Date.CultureInfo.abbreviatedTimeZoneStandard[s.toUpperCase()]; }; Date.getTimezoneAbbreviation = function (offset, dst) {
    var n = (dst || false) ? Date.CultureInfo.abbreviatedTimeZoneDST : Date.CultureInfo.abbreviatedTimeZoneStandard, p; for (p in n) { if (n[p] === offset) { return p; } }
    return null;
}; Date.prototype.clone = function () { return new Date(this.getTime()); }; Date.prototype.compareTo = function (date) {
    if (isNaN(this)) { throw new Error(this); }
    if (date instanceof Date && !isNaN(date)) { return (this > date) ? 1 : (this < date) ? -1 : 0; } else { throw new TypeError(date); } 
}; Date.prototype.equals = function (date) { return (this.compareTo(date) === 0); }; Date.prototype.between = function (start, end) { var t = this.getTime(); return t >= start.getTime() && t <= end.getTime(); }; Date.prototype.addMilliseconds = function (value) { this.setMilliseconds(this.getMilliseconds() + value); return this; }; Date.prototype.addSeconds = function (value) { return this.addMilliseconds(value * 1000); }; Date.prototype.addMinutes = function (value) { return this.addMilliseconds(value * 60000); }; Date.prototype.addHours = function (value) { return this.addMilliseconds(value * 3600000); }; Date.prototype.addDays = function (value) { return this.addMilliseconds(value * 86400000); }; Date.prototype.addWeeks = function (value) { return this.addMilliseconds(value * 604800000); }; Date.prototype.addMonths = function (value) { var n = this.getDate(); this.setDate(1); this.setMonth(this.getMonth() + value); this.setDate(Math.min(n, this.getDaysInMonth())); return this; }; Date.prototype.addYears = function (value) { return this.addMonths(value * 12); }; Date.prototype.add = function (config) {
    if (typeof config == "number") { this._orient = config; return this; }
    var x = config; if (x.millisecond || x.milliseconds) { this.addMilliseconds(x.millisecond || x.milliseconds); }
    if (x.second || x.seconds) { this.addSeconds(x.second || x.seconds); }
    if (x.minute || x.minutes) { this.addMinutes(x.minute || x.minutes); }
    if (x.hour || x.hours) { this.addHours(x.hour || x.hours); }
    if (x.month || x.months) { this.addMonths(x.month || x.months); }
    if (x.year || x.years) { this.addYears(x.year || x.years); }
    if (x.day || x.days) { this.addDays(x.day || x.days); }
    return this;
}; Date._validate = function (value, min, max, name) {
    if (typeof value != "number") { throw new TypeError(value + " is not a Number."); } else if (value < min || value > max) { throw new RangeError(value + " is not a valid value for " + name + "."); }
    return true;
}; Date.validateMillisecond = function (n) { return Date._validate(n, 0, 999, "milliseconds"); }; Date.validateSecond = function (n) { return Date._validate(n, 0, 59, "seconds"); }; Date.validateMinute = function (n) { return Date._validate(n, 0, 59, "minutes"); }; Date.validateHour = function (n) { return Date._validate(n, 0, 23, "hours"); }; Date.validateDay = function (n, year, month) { return Date._validate(n, 1, Date.getDaysInMonth(year, month), "days"); }; Date.validateMonth = function (n) { return Date._validate(n, 0, 11, "months"); }; Date.validateYear = function (n) { return Date._validate(n, 1, 9999, "seconds"); }; Date.prototype.set = function (config) {
    var x = config; if (!x.millisecond && x.millisecond !== 0) { x.millisecond = -1; }
    if (!x.second && x.second !== 0) { x.second = -1; }
    if (!x.minute && x.minute !== 0) { x.minute = -1; }
    if (!x.hour && x.hour !== 0) { x.hour = -1; }
    if (!x.day && x.day !== 0) { x.day = -1; }
    if (!x.month && x.month !== 0) { x.month = -1; }
    if (!x.year && x.year !== 0) { x.year = -1; }
    if (x.millisecond != -1 && Date.validateMillisecond(x.millisecond)) { this.addMilliseconds(x.millisecond - this.getMilliseconds()); }
    if (x.second != -1 && Date.validateSecond(x.second)) { this.addSeconds(x.second - this.getSeconds()); }
    if (x.minute != -1 && Date.validateMinute(x.minute)) { this.addMinutes(x.minute - this.getMinutes()); }
    if (x.hour != -1 && Date.validateHour(x.hour)) { this.addHours(x.hour - this.getHours()); }
    if (x.month !== -1 && Date.validateMonth(x.month)) { this.addMonths(x.month - this.getMonth()); }
    if (x.year != -1 && Date.validateYear(x.year)) { this.addYears(x.year - this.getFullYear()); }
    if (x.day != -1 && Date.validateDay(x.day, this.getFullYear(), this.getMonth())) { this.addDays(x.day - this.getDate()); }
    if (x.timezone) { this.setTimezone(x.timezone); }
    if (x.timezoneOffset) { this.setTimezoneOffset(x.timezoneOffset); }
    return this;
}; Date.prototype.clearTime = function () { this.setHours(0); this.setMinutes(0); this.setSeconds(0); this.setMilliseconds(0); return this; }; Date.prototype.isLeapYear = function () { var y = this.getFullYear(); return (((y % 4 === 0) && (y % 100 !== 0)) || (y % 400 === 0)); }; Date.prototype.isWeekday = function () { return !(this.is().sat() || this.is().sun()); }; Date.prototype.getDaysInMonth = function () { return Date.getDaysInMonth(this.getFullYear(), this.getMonth()); }; Date.prototype.moveToFirstDayOfMonth = function () { return this.set({ day: 1 }); }; Date.prototype.moveToLastDayOfMonth = function () { return this.set({ day: this.getDaysInMonth() }); }; Date.prototype.moveToDayOfWeek = function (day, orient) { var diff = (day - this.getDay() + 7 * (orient || +1)) % 7; return this.addDays((diff === 0) ? diff += 7 * (orient || +1) : diff); }; Date.prototype.moveToMonth = function (month, orient) { var diff = (month - this.getMonth() + 12 * (orient || +1)) % 12; return this.addMonths((diff === 0) ? diff += 12 * (orient || +1) : diff); }; Date.prototype.getDayOfYear = function () { return Math.floor((this - new Date(this.getFullYear(), 0, 1)) / 86400000); }; Date.prototype.getWeekOfYear = function (firstDayOfWeek) {
    var y = this.getFullYear(), m = this.getMonth(), d = this.getDate(); var dow = firstDayOfWeek || Date.CultureInfo.firstDayOfWeek; var offset = 7 + 1 - new Date(y, 0, 1).getDay(); if (offset == 8) { offset = 1; }
    var daynum = ((Date.UTC(y, m, d, 0, 0, 0) - Date.UTC(y, 0, 1, 0, 0, 0)) / 86400000) + 1; var w = Math.floor((daynum - offset + 7) / 7); if (w === dow) { y--; var prevOffset = 7 + 1 - new Date(y, 0, 1).getDay(); if (prevOffset == 2 || prevOffset == 8) { w = 53; } else { w = 52; } }
    return w;
}; Date.prototype.isDST = function () { console.log('isDST'); return this.toString().match(/(E|C|M|P)(S|D)T/)[2] == "D"; }; Date.prototype.getTimezone = function () { return Date.getTimezoneAbbreviation(this.getUTCOffset, this.isDST()); }; Date.prototype.setTimezoneOffset = function (s) { var here = this.getTimezoneOffset(), there = Number(s) * -6 / 10; this.addMinutes(there - here); return this; }; Date.prototype.setTimezone = function (s) { return this.setTimezoneOffset(Date.getTimezoneOffset(s)); }; Date.prototype.getUTCOffset = function () { var n = this.getTimezoneOffset() * -10 / 6, r; if (n < 0) { r = (n - 10000).toString(); return r[0] + r.substr(2); } else { r = (n + 10000).toString(); return "+" + r.substr(1); } }; Date.prototype.getDayName = function (abbrev) { return abbrev ? Date.CultureInfo.abbreviatedDayNames[this.getDay()] : Date.CultureInfo.dayNames[this.getDay()]; }; Date.prototype.getMonthName = function (abbrev) { return abbrev ? Date.CultureInfo.abbreviatedMonthNames[this.getMonth()] : Date.CultureInfo.monthNames[this.getMonth()]; }; Date.prototype._toString = Date.prototype.toString; Date.prototype.toString = function (format) { var self = this; var p = function p(s) { return (s.toString().length == 1) ? "0" + s : s; }; return format ? format.replace(/dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?/g, function (format) { switch (format) { case "hh": return p(self.getHours() < 13 ? self.getHours() : (self.getHours() - 12)); case "h": return self.getHours() < 13 ? self.getHours() : (self.getHours() - 12); case "HH": return p(self.getHours()); case "H": return self.getHours(); case "mm": return p(self.getMinutes()); case "m": return self.getMinutes(); case "ss": return p(self.getSeconds()); case "s": return self.getSeconds(); case "yyyy": return self.getFullYear(); case "yy": return self.getFullYear().toString().substring(2, 4); case "dddd": return self.getDayName(); case "ddd": return self.getDayName(true); case "dd": return p(self.getDate()); case "d": return self.getDate().toString(); case "MMMM": return self.getMonthName(); case "MMM": return self.getMonthName(true); case "MM": return p((self.getMonth() + 1)); case "M": return self.getMonth() + 1; case "t": return self.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1); case "tt": return self.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator; case "zzz": case "zz": case "z": return ""; } }) : this._toString(); };
Date.now = function () { return new Date(); }; Date.today = function () { return Date.now().clearTime(); }; Date.prototype._orient = +1; Date.prototype.next = function () { this._orient = +1; return this; }; Date.prototype.last = Date.prototype.prev = Date.prototype.previous = function () { this._orient = -1; return this; }; Date.prototype._is = false; Date.prototype.is = function () { this._is = true; return this; }; Number.prototype._dateElement = "day"; Number.prototype.fromNow = function () { var c = {}; c[this._dateElement] = this; return Date.now().add(c); }; Number.prototype.ago = function () { var c = {}; c[this._dateElement] = this * -1; return Date.now().add(c); }; (function () {
    var $D = Date.prototype, $N = Number.prototype; var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/), mx = ("january february march april may june july august september october november december").split(/\s/), px = ("Millisecond Second Minute Hour Day Week Month Year").split(/\s/), de; var df = function (n) {
        return function () {
            if (this._is) { this._is = false; return this.getDay() == n; }
            return this.moveToDayOfWeek(n, this._orient);
        };
    }; for (var i = 0; i < dx.length; i++) { $D[dx[i]] = $D[dx[i].substring(0, 3)] = df(i); }
    var mf = function (n) {
        return function () {
            if (this._is) { this._is = false; return this.getMonth() === n; }
            return this.moveToMonth(n, this._orient);
        };
    }; for (var j = 0; j < mx.length; j++) { $D[mx[j]] = $D[mx[j].substring(0, 3)] = mf(j); }
    var ef = function (j) {
        return function () {
            if (j.substring(j.length - 1) != "s") { j += "s"; }
            return this["add" + j](this._orient);
        };
    }; var nf = function (n) { return function () { this._dateElement = n; return this; }; }; for (var k = 0; k < px.length; k++) { de = px[k].toLowerCase(); $D[de] = $D[de + "s"] = ef(px[k]); $N[de] = $N[de + "s"] = nf(de); } 
} ()); Date.prototype.toJSONString = function () { return this.toString("yyyy-MM-ddThh:mm:ssZ"); }; Date.prototype.toShortDateString = function () { return this.toString(Date.CultureInfo.formatPatterns.shortDatePattern); }; Date.prototype.toLongDateString = function () { return this.toString(Date.CultureInfo.formatPatterns.longDatePattern); }; Date.prototype.toShortTimeString = function () { return this.toString(Date.CultureInfo.formatPatterns.shortTimePattern); }; Date.prototype.toLongTimeString = function () { return this.toString(Date.CultureInfo.formatPatterns.longTimePattern); }; Date.prototype.getOrdinal = function () { switch (this.getDate()) { case 1: case 21: case 31: return "st"; case 2: case 22: return "nd"; case 3: case 23: return "rd"; default: return "th"; } };
(function () {
    Date.Parsing = { Exception: function (s) { this.message = "Parse error at '" + s.substring(0, 10) + " ...'"; } }; var $P = Date.Parsing; var _ = $P.Operators = { rtoken: function (r) { return function (s) { var mx = s.match(r); if (mx) { return ([mx[0], s.substring(mx[0].length)]); } else { throw new $P.Exception(s); } }; }, token: function (s) { return function (s) { return _.rtoken(new RegExp("^\s*" + s + "\s*"))(s); }; }, stoken: function (s) { return _.rtoken(new RegExp("^" + s)); }, until: function (p) {
        return function (s) {
            var qx = [], rx = null; while (s.length) {
                try { rx = p.call(this, s); } catch (e) { qx.push(rx[0]); s = rx[1]; continue; }
                break;
            }
            return [qx, s];
        };
    }, many: function (p) {
        return function (s) {
            var rx = [], r = null; while (s.length) {
                try { r = p.call(this, s); } catch (e) { return [rx, s]; }
                rx.push(r[0]); s = r[1];
            }
            return [rx, s];
        };
    }, optional: function (p) {
        return function (s) {
            var r = null; try { r = p.call(this, s); } catch (e) { return [null, s]; }
            return [r[0], r[1]];
        };
    }, not: function (p) {
        return function (s) {
            try { p.call(this, s); } catch (e) { return [null, s]; }
            throw new $P.Exception(s);
        };
    }, ignore: function (p) { return p ? function (s) { var r = null; r = p.call(this, s); return [null, r[1]]; } : null; }, product: function () {
        var px = arguments[0], qx = Array.prototype.slice.call(arguments, 1), rx = []; for (var i = 0; i < px.length; i++) { rx.push(_.each(px[i], qx)); }
        return rx;
    }, cache: function (rule) {
        var cache = {}, r = null; return function (s) {
            try { r = cache[s] = (cache[s] || rule.call(this, s)); } catch (e) { r = cache[s] = e; }
            if (r instanceof $P.Exception) { throw r; } else { return r; } 
        };
    }, any: function () {
        var px = arguments; return function (s) {
            var r = null; for (var i = 0; i < px.length; i++) {
                if (px[i] == null) { continue; }
                try { r = (px[i].call(this, s)); } catch (e) { r = null; }
                if (r) { return r; } 
            }
            throw new $P.Exception(s);
        };
    }, each: function () {
        var px = arguments; return function (s) {
            var rx = [], r = null; for (var i = 0; i < px.length; i++) {
                if (px[i] == null) { continue; }
                try { r = (px[i].call(this, s)); } catch (e) { throw new $P.Exception(s); }
                rx.push(r[0]); s = r[1];
            }
            return [rx, s];
        };
    }, all: function () { var px = arguments, _ = _; return _.each(_.optional(px)); }, sequence: function (px, d, c) {
        d = d || _.rtoken(/^\s*/); c = c || null; if (px.length == 1) { return px[0]; }
        return function (s) {
            var r = null, q = null; var rx = []; for (var i = 0; i < px.length; i++) {
                try { r = px[i].call(this, s); } catch (e) { break; }
                rx.push(r[0]); try { q = d.call(this, r[1]); } catch (ex) { q = null; break; }
                s = q[1];
            }
            if (!r) { throw new $P.Exception(s); }
            if (q) { throw new $P.Exception(q[1]); }
            if (c) { try { r = c.call(this, r[1]); } catch (ey) { throw new $P.Exception(r[1]); } }
            return [rx, (r ? r[1] : s)];
        };
    }, between: function (d1, p, d2) { d2 = d2 || d1; var _fn = _.each(_.ignore(d1), p, _.ignore(d2)); return function (s) { var rx = _fn.call(this, s); return [[rx[0][0], r[0][2]], rx[1]]; }; }, list: function (p, d, c) { d = d || _.rtoken(/^\s*/); c = c || null; return (p instanceof Array ? _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) : _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c))); }, set: function (px, d, c) {
        d = d || _.rtoken(/^\s*/); c = c || null; return function (s) {
            var r = null, p = null, q = null, rx = null, best = [[], s], last = false; for (var i = 0; i < px.length; i++) {
                q = null; p = null; r = null; last = (px.length == 1); try { r = px[i].call(this, s); } catch (e) { continue; }
                rx = [[r[0]], r[1]]; if (r[1].length > 0 && !last) { try { q = d.call(this, r[1]); } catch (ex) { last = true; } } else { last = true; }
                if (!last && q[1].length === 0) { last = true; }
                if (!last) {
                    var qx = []; for (var j = 0; j < px.length; j++) { if (i != j) { qx.push(px[j]); } }
                    p = _.set(qx, d).call(this, q[1]); if (p[0].length > 0) { rx[0] = rx[0].concat(p[0]); rx[1] = p[1]; } 
                }
                if (rx[1].length < best[1].length) { best = rx; }
                if (best[1].length === 0) { break; } 
            }
            if (best[0].length === 0) { return best; }
            if (c) {
                try { q = c.call(this, best[1]); } catch (ey) { throw new $P.Exception(best[1]); }
                best[1] = q[1];
            }
            return best;
        };
    }, forward: function (gr, fname) { return function (s) { return gr[fname].call(this, s); }; }, replace: function (rule, repl) { return function (s) { var r = rule.call(this, s); return [repl, r[1]]; }; }, process: function (rule, fn) { return function (s) { var r = rule.call(this, s); return [fn.call(this, r[0]), r[1]]; }; }, min: function (min, rule) {
        return function (s) {
            var rx = rule.call(this, s); if (rx[0].length < min) { throw new $P.Exception(s); }
            return rx;
        };
    } 
    }; var _generator = function (op) {
        return function () {
            var args = null, rx = []; if (arguments.length > 1) { args = Array.prototype.slice.call(arguments); } else if (arguments[0] instanceof Array) { args = arguments[0]; }
            if (args) { for (var i = 0, px = args.shift(); i < px.length; i++) { args.unshift(px[i]); rx.push(op.apply(null, args)); args.shift(); return rx; } } else { return op.apply(null, arguments); } 
        };
    }; var gx = "optional not ignore cache".split(/\s/); for (var i = 0; i < gx.length; i++) { _[gx[i]] = _generator(_[gx[i]]); }
    var _vector = function (op) { return function () { if (arguments[0] instanceof Array) { return op.apply(null, arguments[0]); } else { return op.apply(null, arguments); } }; }; var vx = "each any all".split(/\s/); for (var j = 0; j < vx.length; j++) { _[vx[j]] = _vector(_[vx[j]]); } 
} ()); (function () {
    var flattenAndCompact = function (ax) {
        var rx = []; for (var i = 0; i < ax.length; i++) { if (ax[i] instanceof Array) { rx = rx.concat(flattenAndCompact(ax[i])); } else { if (ax[i]) { rx.push(ax[i]); } } }
        return rx;
    }; Date.Grammar = {}; Date.Translator = { hour: function (s) { return function () { this.hour = Number(s); }; }, minute: function (s) { return function () { this.minute = Number(s); }; }, second: function (s) { return function () { this.second = Number(s); }; }, meridian: function (s) { return function () { this.meridian = s.slice(0, 1).toLowerCase(); }; }, timezone: function (s) { return function () { var n = s.replace(/[^\d\+\-]/g, ""); if (n.length) { this.timezoneOffset = Number(n); } else { this.timezone = s.toLowerCase(); } }; }, day: function (x) { var s = x[0]; return function () { this.day = Number(s.match(/\d+/)[0]); }; }, month: function (s) { return function () { this.month = ((s.length == 3) ? Date.getMonthNumberFromName(s) : (Number(s) - 1)); }; }, year: function (s) { return function () { var n = Number(s); this.year = ((s.length > 2) ? n : (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900))); }; }, rday: function (s) { return function () { switch (s) { case "yesterday": this.days = -1; break; case "tomorrow": this.days = 1; break; case "today": this.days = 0; break; case "now": this.days = 0; this.now = true; break; } }; }, finishExact: function (x) {
        x = (x instanceof Array) ? x : [x]; var now = new Date(); this.year = now.getFullYear(); this.month = now.getMonth(); this.day = 1; this.hour = 0; this.minute = 0; this.second = 0; for (var i = 0; i < x.length; i++) { if (x[i]) { x[i].call(this); } }
        this.hour = (this.meridian == "p" && this.hour < 13) ? this.hour + 12 : this.hour; if (this.day > Date.getDaysInMonth(this.year, this.month)) { throw new RangeError(this.day + " is not a valid value for days."); }
        var r = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second); if (this.timezone) { r.set({ timezone: this.timezone }); } else if (this.timezoneOffset) { r.set({ timezoneOffset: this.timezoneOffset }); }
        return r;
    }, finish: function (x) {
        x = (x instanceof Array) ? flattenAndCompact(x) : [x]; if (x.length === 0) { return null; }
        for (var i = 0; i < x.length; i++) { if (typeof x[i] == "function") { x[i].call(this); } }
        if (this.now) { return new Date(); }
        var today = Date.today(); var method = null; var expression = !!(this.days != null || this.orient || this.operator); if (expression) {
            var gap, mod, orient; orient = ((this.orient == "past" || this.operator == "subtract") ? -1 : 1); if (this.weekday) { this.unit = "day"; gap = (Date.getDayNumberFromName(this.weekday) - today.getDay()); mod = 7; this.days = gap ? ((gap + (orient * mod)) % mod) : (orient * mod); }
            if (this.month) { this.unit = "month"; gap = (this.month - today.getMonth()); mod = 12; this.months = gap ? ((gap + (orient * mod)) % mod) : (orient * mod); this.month = null; }
            if (!this.unit) { this.unit = "day"; }
            if (this[this.unit + "s"] == null || this.operator != null) {
                if (!this.value) { this.value = 1; }
                if (this.unit == "week") { this.unit = "day"; this.value = this.value * 7; }
                this[this.unit + "s"] = this.value * orient;
            }
            return today.add(this);
        } else {
            if (this.meridian && this.hour) { this.hour = (this.hour < 13 && this.meridian == "p") ? this.hour + 12 : this.hour; }
            if (this.weekday && !this.day) { this.day = (today.addDays((Date.getDayNumberFromName(this.weekday) - today.getDay()))).getDate(); }
            if (this.month && !this.day) { this.day = 1; }
            return today.set(this);
        } 
    } 
    }; var _ = Date.Parsing.Operators, g = Date.Grammar, t = Date.Translator, _fn; g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/); g.timePartDelimiter = _.stoken(":"); g.whiteSpace = _.rtoken(/^\s*/); g.generalDelimiter = _.rtoken(/^(([\s\,]|at|on)+)/); var _C = {}; g.ctoken = function (keys) {
        var fn = _C[keys]; if (!fn) {
            var c = Date.CultureInfo.regexPatterns; var kx = keys.split(/\s+/), px = []; for (var i = 0; i < kx.length; i++) { px.push(_.replace(_.rtoken(c[kx[i]]), kx[i])); }
            fn = _C[keys] = _.any.apply(null, px);
        }
        return fn;
    }; g.ctoken2 = function (key) { return _.rtoken(Date.CultureInfo.regexPatterns[key]); }; g.h = _.cache(_.process(_.rtoken(/^(0[0-9]|1[0-2]|[1-9])/), t.hour)); g.hh = _.cache(_.process(_.rtoken(/^(0[0-9]|1[0-2])/), t.hour)); g.H = _.cache(_.process(_.rtoken(/^([0-1][0-9]|2[0-3]|[0-9])/), t.hour)); g.HH = _.cache(_.process(_.rtoken(/^([0-1][0-9]|2[0-3])/), t.hour)); g.m = _.cache(_.process(_.rtoken(/^([0-5][0-9]|[0-9])/), t.minute)); g.mm = _.cache(_.process(_.rtoken(/^[0-5][0-9]/), t.minute)); g.s = _.cache(_.process(_.rtoken(/^([0-5][0-9]|[0-9])/), t.second)); g.ss = _.cache(_.process(_.rtoken(/^[0-5][0-9]/), t.second)); g.hms = _.cache(_.sequence([g.H, g.mm, g.ss], g.timePartDelimiter)); g.t = _.cache(_.process(g.ctoken2("shortMeridian"), t.meridian)); g.tt = _.cache(_.process(g.ctoken2("longMeridian"), t.meridian)); g.z = _.cache(_.process(_.rtoken(/^(\+|\-)?\s*\d\d\d\d?/), t.timezone)); g.zz = _.cache(_.process(_.rtoken(/^(\+|\-)\s*\d\d\d\d/), t.timezone)); g.zzz = _.cache(_.process(g.ctoken2("timezone"), t.timezone)); g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([g.tt, g.zzz])); g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix); g.d = _.cache(_.process(_.each(_.rtoken(/^([0-2]\d|3[0-1]|\d)/), _.optional(g.ctoken2("ordinalSuffix"))), t.day)); g.dd = _.cache(_.process(_.each(_.rtoken(/^([0-2]\d|3[0-1])/), _.optional(g.ctoken2("ordinalSuffix"))), t.day)); g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"), function (s) { return function () { this.weekday = s; }; })); g.M = _.cache(_.process(_.rtoken(/^(1[0-2]|0\d|\d)/), t.month)); g.MM = _.cache(_.process(_.rtoken(/^(1[0-2]|0\d)/), t.month)); g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month)); g.y = _.cache(_.process(_.rtoken(/^(\d\d?)/), t.year)); g.yy = _.cache(_.process(_.rtoken(/^(\d\d)/), t.year)); g.yyy = _.cache(_.process(_.rtoken(/^(\d\d?\d?\d?)/), t.year)); g.yyyy = _.cache(_.process(_.rtoken(/^(\d\d\d\d)/), t.year)); _fn = function () { return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext"))); }; g.day = _fn(g.d, g.dd); g.month = _fn(g.M, g.MMM); g.year = _fn(g.yyyy, g.yy); g.orientation = _.process(g.ctoken("past future"), function (s) { return function () { this.orient = s; }; }); g.operator = _.process(g.ctoken("add subtract"), function (s) { return function () { this.operator = s; }; }); g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday); g.unit = _.process(g.ctoken("minute hour day week month year"), function (s) { return function () { this.unit = s; }; }); g.value = _.process(_.rtoken(/^\d\d?(st|nd|rd|th)?/), function (s) { return function () { this.value = s.replace(/\D/g, ""); }; }); g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM]); _fn = function () { return _.set(arguments, g.datePartDelimiter); }; g.mdy = _fn(g.ddd, g.month, g.day, g.year); g.ymd = _fn(g.ddd, g.year, g.month, g.day); g.dmy = _fn(g.ddd, g.day, g.month, g.year); g.date = function (s) { return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s)); }; g.format = _.process(_.many(_.any(_.process(_.rtoken(/^(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/), function (fmt) { if (g[fmt]) { return g[fmt]; } else { throw Date.Parsing.Exception(fmt); } }), _.process(_.rtoken(/^[^dMyhHmstz]+/), function (s) { return _.ignore(_.stoken(s)); }))), function (rules) { return _.process(_.each.apply(null, rules), t.finishExact); }); var _F = {}; var _get = function (f) { return _F[f] = (_F[f] || g.format(f)[0]); }; g.formats = function (fx) {
        if (fx instanceof Array) {
            var rx = []; for (var i = 0; i < fx.length; i++) { rx.push(_get(fx[i])); }
            return _.any.apply(null, rx);
        } else { return _get(fx); } 
    }; g._formats = g.formats(["yyyy-MM-ddTHH:mm:ss", "ddd, MMM dd, yyyy H:mm:ss tt", "ddd MMM d yyyy HH:mm:ss zzz", "d"]); g._start = _.process(_.set([g.date, g.time, g.expression], g.generalDelimiter, g.whiteSpace), t.finish); g.start = function (s) {
        try { var r = g._formats.call({}, s); if (r[1].length === 0) { return r; } } catch (e) { }
        return g._start.call({}, s);
    };
} ()); Date._parse = Date.parse; Date.parse = function (s) {
    var r = null; if (!s) { return null; }
    try { r = Date.Grammar.start.call({}, s); } catch (e) { return null; }
    return ((r[1].length === 0) ? r[0] : null);
}; Date.getParseFunction = function (fx) {
    var fn = Date.Grammar.formats(fx); return function (s) {
        var r = null; try { r = fn.call({}, s); } catch (e) { return null; }
        return ((r[1].length === 0) ? r[0] : null);
    };
}; Date.parseExact = function (s, fx) { return Date.getParseFunction(fx)(s); };




/*
* jQuery history plugin
* 
* The MIT License
* 
* Copyright (c) 2006-2009 Taku Sano (Mikage Sawatari)
* Copyright (c) 2010 Takayuki Miwa
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* 
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

(function ($) {
    var locationWrapper = {
        put: function (hash, win) {
            (win || window).location.hash = this.encoder(hash);
        },
        get: function (win) {
            var hash = ((win || window).location.hash).replace(/^#/, '');
            try {
                return $.browser.mozilla ? hash : decodeURIComponent(hash);
            }
            catch (error) {
                return hash;
            }
        },
        encoder: encodeURIComponent
    };

    var iframeWrapper = {
        id: "__jQuery_history",
        init: function () {
            var html = '<iframe id="' + this.id + '" style="display:none" src="javascript:false;" />';
            $("body").prepend(html);
            return this;
        },
        _document: function () {
            return $("#" + this.id)[0].contentWindow.document;
        },
        put: function (hash) {
            var doc = this._document();
            doc.open();
            doc.close();
            locationWrapper.put(hash, doc);
        },
        get: function () {
            return locationWrapper.get(this._document());
        }
    };

    function initObjects(options) {
        options = $.extend({
            unescape: false
        }, options || {});

        locationWrapper.encoder = encoder(options.unescape);

        function encoder(unescape_) {
            if (unescape_ === true) {
                return function (hash) { return hash; };
            }
            if (typeof unescape_ == "string" &&
               (unescape_ = partialDecoder(unescape_.split("")))
               || typeof unescape_ == "function") {
                return function (hash) { return unescape_(encodeURIComponent(hash)); };
            }
            return encodeURIComponent;
        }

        function partialDecoder(chars) {
            var re = new RegExp($.map(chars, encodeURIComponent).join("|"), "ig");
            return function (enc) { return enc.replace(re, decodeURIComponent); };
        }
    }

    var implementations = {};

    implementations.base = {
        callback: undefined,
        type: undefined,

        check: function () { },
        load: function (hash) { },
        init: function (callback, options) {
            initObjects(options);
            self.callback = callback;
            self._options = options;
            self._init();
        },

        _init: function () { },
        _options: {}
    };

    implementations.timer = {
        _appState: undefined,
        _init: function () {
            var current_hash = locationWrapper.get();
            self._appState = current_hash;
            self.callback(current_hash);
            setInterval(self.check, 100);
        },
        check: function () {
            var current_hash = locationWrapper.get();
            if (current_hash != self._appState) {
                self._appState = current_hash;
                self.callback(current_hash);
            }
        },
        load: function (hash) {
            if (hash != self._appState) {
                locationWrapper.put(hash);
                self._appState = hash;
                self.callback(hash);
            }
        }
    };

    implementations.iframeTimer = {
        _appState: undefined,
        _init: function () {
            var current_hash = locationWrapper.get();
            self._appState = current_hash;
            iframeWrapper.init().put(current_hash);
            self.callback(current_hash);
            setInterval(self.check, 100);
        },
        check: function () {
            var iframe_hash = iframeWrapper.get(),
                location_hash = locationWrapper.get();

            if (location_hash != iframe_hash) {
                if (location_hash == self._appState) {    // user used Back or Forward button
                    self._appState = iframe_hash;
                    locationWrapper.put(iframe_hash);
                    self.callback(iframe_hash);
                } else {                              // user loaded new bookmark
                    self._appState = location_hash;
                    iframeWrapper.put(location_hash);
                    self.callback(location_hash);
                }
            }
        },
        load: function (hash) {
            if (hash != self._appState) {
                locationWrapper.put(hash);
                iframeWrapper.put(hash);
                self._appState = hash;
                self.callback(hash);
            }
        }
    };

    implementations.hashchangeEvent = {
        _init: function () {
            self.callback(locationWrapper.get());
            $(window).bind('hashchange', self.check);
        },
        check: function () {
            self.callback(locationWrapper.get());
        },
        load: function (hash) {
            locationWrapper.put(hash);
        }
    };

    var self = $.extend({}, implementations.base);

    if ($.browser.msie && ($.browser.version < 8 || document.documentMode < 8)) {
        self.type = 'iframeTimer';
    } else if ("onhashchange" in window) {
        self.type = 'hashchangeEvent';
    } else {
        self.type = 'timer';
    }

    $.extend(self, implementations[self.type]);
    $.history = self;
})(jQuery);


/*BEGIN HINT PLUGIN*/
jQuery.fn.hint = function (blurClass) {
    if (!blurClass) {
        blurClass = 'blur';
    }

    return this.each(function () {
        // get jQuery version of 'this'
        var $input = jQuery(this),

        // capture the rest of the variable to allow for reuse
      title = $input.attr('title'),
      type = ($input.attr('data-type') || $input.attr('type')),
      $form = jQuery(this.form),
      $win = jQuery(window);

        function remove() {
            if ($input.val() === title && $input.hasClass(blurClass)) {
                $input.val('').removeClass(blurClass);
                
            }
        }

        // only apply logic if the element has the attribute
        if (title) {
            // on blur, set value to title attr if text is blank
            $input.blur(function () {
                if (this.value === '') {
                    $input.val(title).addClass(blurClass);
                    
                }
            }).focus(remove).blur(); // now change all inputs to title

            // clear the pre-defined text when form is submitted
            $form.submit(remove);
            $win.unload(remove); // handles Firefox's autocomplete
        }
    });
};
/*END HINT PLUGIN*/


/*BEGIN JQUERY FLASH PLUGIN*/
// jQuery SWFObject v1.1.1 MIT/GPL @jon_neal
// http://jquery.thewikies.com/swfobject

(function ($, flash, Plugin) {
    var OBJECT = 'object',
		ENCODE = true;

    function _compareArrayIntegers(a, b) {
        var x = (a[0] || 0) - (b[0] || 0);

        return x > 0 || (
			!x &&
			a.length > 0 &&
			_compareArrayIntegers(a.slice(1), b.slice(1))
		);
    }

    function _objectToArguments(obj) {
        if (typeof obj != OBJECT) {
            return obj;
        }

        var arr = [],
			str = '';

        for (var i in obj) {
            if (typeof obj[i] == OBJECT) {
                str = _objectToArguments(obj[i]);
            }
            else {
                str = [i, (ENCODE) ? encodeURI(obj[i]) : obj[i]].join('=');
            }

            arr.push(str);
        }

        return arr.join('&');
    }

    function _objectFromObject(obj) {
        var arr = [];

        for (var i in obj) {
            if (obj[i]) {
                arr.push([i, '="', obj[i], '"'].join(''));
            }
        }

        return arr.join(' ');
    }

    function _paramsFromObject(obj) {
        var arr = [];

        for (var i in obj) {
            arr.push([
				'<param name="', i,
				'" value="', _objectToArguments(obj[i]), '" />'
			].join(''));
        }

        return arr.join('');
    }

    try {
        var flashVersion = Plugin.description || (function () {
            return (
				new Plugin('ShockwaveFlash.ShockwaveFlash')
			).GetVariable('$version');
        } ())
    }
    catch (e) {
        flashVersion = 'Unavailable';
    }

    var flashVersionMatchVersionNumbers = flashVersion.match(/\d+/g) || [0];

    $[flash] = {
        available: flashVersionMatchVersionNumbers[0] > 0,

        activeX: Plugin && !Plugin.name,

        version: {
            original: flashVersion,
            array: flashVersionMatchVersionNumbers,
            string: flashVersionMatchVersionNumbers.join('.'),
            major: parseInt(flashVersionMatchVersionNumbers[0], 10) || 0,
            minor: parseInt(flashVersionMatchVersionNumbers[1], 10) || 0,
            release: parseInt(flashVersionMatchVersionNumbers[2], 10) || 0
        },

        hasVersion: function (version) {
            var versionArray = (/string|number/.test(typeof version))
				? version.toString().split('.')
				: (/object/.test(typeof version))
					? [version.major, version.minor]
					: version || [0, 0];

            return _compareArrayIntegers(
				flashVersionMatchVersionNumbers,
				versionArray
			);
        },

        encodeParams: true,

        expressInstall: 'expressInstall.swf',
        expressInstallIsActive: false,

        create: function (obj) {
            var instance = this;

            if (
				!obj.swf ||
				instance.expressInstallIsActive ||
				(!instance.available && !obj.hasVersionFail)
			) {
                return false;
            }

            if (!instance.hasVersion(obj.hasVersion || 1)) {
                instance.expressInstallIsActive = true;

                if (typeof obj.hasVersionFail == 'function') {
                    if (!obj.hasVersionFail.apply(obj)) {
                        return false;
                    }
                }

                obj = {
                    swf: obj.expressInstall || instance.expressInstall,
                    height: 137,
                    width: 214,
                    flashvars: {
                        MMredirectURL: location.href,
                        MMplayerType: (instance.activeX)
							? 'ActiveX' : 'PlugIn',
                        MMdoctitle: document.title.slice(0, 47) +
							' - Flash Player Installation'
                    }
                };
            }

            attrs = {
                data: obj.swf,
                type: 'application/x-shockwave-flash',
                id: obj.id || 'flash_' + Math.floor(Math.random() * 999999999),
                width: obj.width || 320,
                height: obj.height || 180,
                style: obj.style || ''
            };

            ENCODE = typeof obj.useEncode !== 'undefined' ? obj.useEncode : instance.encodeParams;

            obj.movie = obj.swf;
            obj.wmode = obj.wmode || 'opaque';

            delete obj.fallback;
            delete obj.hasVersion;
            delete obj.hasVersionFail;
            delete obj.height;
            delete obj.id;
            delete obj.swf;
            delete obj.useEncode;
            delete obj.width;

            var flashContainer = document.createElement('div');

            flashContainer.innerHTML = [
				'<object ', _objectFromObject(attrs), '>',
				_paramsFromObject(obj),
				'</object>'
			].join('');

            return flashContainer.firstChild;
        }
    };

    $.fn[flash] = function (options) {
        var $this = this.find(OBJECT).andSelf().filter(OBJECT);

        if (/string|object/.test(typeof options)) {
            this.each(
				function () {
				    var $this = $(this),
						flashObject;

				    options = (typeof options == OBJECT) ? options : {
				        swf: options
				    };

				    options.fallback = this;

				    flashObject = $[flash].create(options);

				    if (flashObject) {
				        $this.children().remove();

				        $this.html(flashObject);
				    }
				}
			);
        }

        if (typeof options == 'function') {
            $this.each(
				function () {
				    var instance = this,
					jsInteractionTimeoutMs = 'jsInteractionTimeoutMs';

				    instance[jsInteractionTimeoutMs] =
						instance[jsInteractionTimeoutMs] || 0;

				    if (instance[jsInteractionTimeoutMs] < 660) {
				        if (instance.clientWidth || instance.clientHeight) {
				            options.call(instance);
				        }
				        else {
				            setTimeout(
								function () {
								    $(instance)[flash](options);
								},
								instance[jsInteractionTimeoutMs] + 66
							);
				        }
				    }
				}
			);
        }

        return $this;
    };
} (
	jQuery,
	'flash',
	navigator.plugins['Shockwave Flash'] || window.ActiveXObject
));

/*END JQUERY FLASH PLUGIN*/



/*CUSTOM VIDEO PLUGIN*/
var VideoState = {
    PLAYING: 1,
    PAUSED: 2,
    STOPPED: 3,
    BUFFERING: 4,
    ERROR: 5
};

function Video(argObj) {

    this.marker = 0;
    this.loaded = 0;
    this.length = 0;
    this.state = VideoState.PLAY;
    this.reportedHalf = false;
    this.reportedWhole = false;
    this.started = false;
    this.videoSrc = argObj.src;

    this.videoName = "Video";

    if (argObj.videoName)
        this.videoName = argObj.videoName;

    this.targetStyle = null;

    for (var i in Video.defaults)
        this[i] = Video.defaults[i];

    for (var i in argObj)
        this[i] = argObj[i];

    if (this.target == null)
        this.target = $("<div id='js-video-wrapper'>").appendTo(document);



    $(this.target).empty();

    if (argObj.h1) {

        $(this.target).append("<div class='video-wrapper'><h3 class='video-title'>" + argObj.h1 + "</h3><div class='vid-target'></div></div>");
        this.target = $(this.target).find(".vid-target");
    }

    if ($.flash.available) {

        $(this.target).flash({
            swf: "media/swf/PQVideo.swf",
            width: this.width,
            height: this.height,
            flashvars: {
                src: "../mov/flv/" + this.videoSrc + ".flv",
                width: this.width,
                height: this.height,
                videoName: this.videoName,
                autoplay: this.autoPlay,
                skin: "media/swf/SkinOverPlayStopSeekMuteVol.swf"
            },
            wmode: "transparent"
        });

    } else if (Video.supportsVideo()) {

        var vid = $("<video />").appendTo(this.target);

        if (Parcel.Browser.flag == "Android")
            $(vid).click(function () { this.play(); });

        if (this.autoPlay)
            $(vid).attr("autoplay", "autoplay");

        $(vid).attr("controls", "controls");
        $(vid).attr("width", this.width);
        $(vid).attr("height", this.height);



        var src;
        src = $("<source />").appendTo($(vid));
        $(src).attr("src", "media/mov/ogg/" + this.videoSrc + ".ogv");
        $(src).attr("type", "video/ogg");
        $(src).attr("codecs", "theora, vorbis");
        $(src).attr("error", "alert('error FF');");
        //$(src).attr("poster", "Media/Img/content/widgets/loadingLG.gif")

        src = $("<source />").appendTo($(vid));
        $(src).attr("src", "media/mov/mp4/" + this.videoSrc + ".mp4");
        //$(src).attr("type", "video/mp4");
        //$(src).attr("codecs", "avc1.42E01E, mp4a.40.2");
        $(vid).get(0).videoObj = this;
        $(vid).get(0).addEventListener("play", this.onPlay);
        $(vid).get(0).addEventListener("pause", this.onPause);
        $(vid).get(0).addEventListener("seeked", this.onSeek);
        $(vid).get(0).addEventListener("volumechange", this.onVolume);
        //$(vid).get(0).addEventListener("ontimeupdate", this.onTime);
        //$(vid).get(0).addEventListener("onended", this.onEnded);

        //Event.addEnterFrame(this.onTime, $(vid).get(0), "frame" + this.videoName);

        //$(src).attr("type", "video/mp4");
        //$(src).attr("codecs", "avc1.42E01E, mp4a.40.2");

    }



    return this;
}

Video.defaults = {
    target: null,
    src: "notfound",
    width: 640,
    height: 480,
    autoPlay: true
};

Video.supportsVideo = function () {
    return !!document.createElement('video').canPlayType;
}


Video.prototype.play = function (timeCode) {
    if (!timeCode)
        timeCode = 0;
}

Video.prototype.seek = function (timeCode) {
    if (!timeCode)
        return;
}

Video.prototype.stop = function () {

}

Video.prototype.pause = function () {

}

Video.prototype.volume = function (set) {

}

Video.prototype.mute = function (toggle) {

}

/*
video begin: _gaq.push(['gatt._trackEvent','video player','video start','[VIDEO NAME]']);
video end: _gaq.push(['gatt._trackEvent','video player','video end',[VIDEO NAME]);
video pause: _gaq.push(['gatt._trackEvent','video player','pause',[VIDEO NAME]);
video mute: _gaq.push(['gatt._trackEvent','video player','mute',[VIDEO NAME]);
video 50% complete: _gaq.push(['gatt._trackEvent','video player','50% complete',[VIDEO NAME]);
flash player in use: _gaq.push(['gatt._trackEvent','video player','flash player',[VIDEO NAME]);
*/

Video.prototype.onPlay = function (e) {
    var self = this;
    if (!this.sdTool)
        self = e.target.videoObj;
    if (!self.started)
        self.sdTool("video start");
    self.started = true;
}

Video.prototype.onSeek = function (e) {

}

Video.prototype.onEnded = function (e) {
    var self = this;
    if (!this.sdTool)
        self = e.target.videoObj;
    self.reportedWhole = true;
    self.sdTool("video end");
}

Video.prototype.onTime = function (e) {
    var self = this;
    if (!this.sdTool)
        self = e.target.videoObj;
    if (!self.started)
        return;
    var vid = e.target;
    if (!self.reportedHalf && e.target.currentTime / e.target.duration > .5)
        self.onHalf(e);
    if (!self.reportedWhole && e.target.currentTime / e.target.duration > .99)
        self.onEnded(e);
}

Video.prototype.onHalf = function (e) {
    var self = this;
    if (!this.sdTool)
        self = e.target.videoObj;
    self.reportedHalf = true;
    self.sdTool("50% complete");
}

Video.prototype.onPause = function (e) {
    var self = this;
    if (!this.sdTool)
        self = e.target.videoObj;
    self.sdTool("pause");
}
Video.prototype.onMute = function (e) {
    var self = this;
    if (!this.sdTool)
        self = e.target.videoObj;
    self.sdTool("mute");
}

Video.prototype.onVolume = function (e) {
    var self = this;
    if (!this.sdTool)
        self = e.target.videoObj;
    if (e.target.volume == 0 || e.target.muted)
        self.onMute(e);
}
Video.prototype.sdTool = function (event) {
    //if (console)
    return;
    //console.log(event+":"+this.videoName);
    _gaq.push(['gatt._trackEvent', 'video player', event, this.videoName]);
}
Video.currentVideo = null;
Video.swf= function (src, width, height, name, h1) {
    
    if (!width)
        width = 640;
    if (!height)
        height = 480;

    if (!name)
        name = src;

    if (!Video.supportsVideo())
        height -= 20;



    $.fancybox({
        content: " ",
        width: width,
        height: height,
        margin: 10,
        padding: 5,
        autoDimensions: false,
        autoScale: false,
        //title: h1,
        //titlePosition:"over",
        onComplete: function () {

            $("#fancybox-content").flash({
                swf: src,
                width: width,
                height: height,                
                wmode: "transparent"
            });

            
        },
        onCleanup: function () {
            $("#fancybox-content").empty();
            $("#fancybox-content").html(" ");
        }
    });
}


Video.box = function (src, width, height, name, h1) {

    if (!width)
        width = 800;
    if (!height)
        height = 600;

    if (!name)
        name = src;

    if (!Video.supportsVideo())
        height -= 20;

    if (src == "pq-home-final" && !$.flash.available) {
        width = 480;
        height = 270;

    }

    $.fancybox({
        content: " ",
        width: width,
        height: height,
        margin: 10,
        padding: 5,
        autoDimensions: false,
        autoScale: false,
        //titlePosition:"over",
        onComplete: function () {

            Video.currentVideo = new Video({ target: $("#fancybox-content"), src: src, autoPlay: true, height: height, width: width, videoName: name, h1: h1 });
        },
        onCleanup: function () {
            $("#fancybox-content").empty();
            $("#fancybox-content").html(" ");
        }
    });
}

Video.swfFirst = function (src, width, height, name, h1,skipHtmlVideo) {

    if ($.flash.available) {

        src = "media/swf/" + src + ".swf";
        window.open("/" + src, "flashtutorial", "", true);
        //Video.swf(src, width, height, name, h1);

    } else if (!skipHtmlVideo) {

        Video.box(src);
    }

};
/*END CUSTOM VIDEO*/



/*
* FancyBox - jQuery Plugin
* Simple and fancy lightbox alternative
*
* Examples and documentation at: http://fancybox.net
*
* Copyright (c) 2008 - 2010 Janis Skarnelis
* That said, it is hardly a one-person project. Many people have submitted bugs, code, and offered their advice freely. Their support is greatly appreciated.
*
* Version: 1.3.4 (11/11/2010)
* Requires: jQuery v1.3+
*
* Dual licensed under the MIT and GPL licenses:
*   http://www.opensource.org/licenses/mit-license.php
*   http://www.gnu.org/licenses/gpl.html
*/

;     (function ($) {
    var tmp, loading, overlay, wrap, outer, content, close, title, nav_left, nav_right,

		selectedIndex = 0, selectedOpts = {}, selectedArray = [], currentIndex = 0, currentOpts = {}, currentArray = [],

		ajaxLoader = null, imgPreloader = new Image(), imgRegExp = /\.(jpg|gif|png|bmp|jpeg)(.*)?$/i, swfRegExp = /[^\.]\.(swf)\s*$/i,

		loadingTimer, loadingFrame = 1,

		titleHeight = 0, titleStr = '', start_pos, final_pos, busy = false, fx = $.extend($('<div/>')[0], { prop: 0 }),

		isIE6 = $.browser.msie && $.browser.version < 7 && !window.XMLHttpRequest,

    /*
    * Private methods 
    */

		_abort = function () {
		    loading.hide();

		    imgPreloader.onerror = imgPreloader.onload = null;

		    if (ajaxLoader) {
		        ajaxLoader.abort();
		    }

		    tmp.empty();
		},

		_error = function () {
		    if (false === selectedOpts.onError(selectedArray, selectedIndex, selectedOpts)) {
		        loading.hide();
		        busy = false;
		        return;
		    }

		    selectedOpts.titleShow = false;

		    selectedOpts.width = 'auto';
		    selectedOpts.height = 'auto';

		    tmp.html('<p id="fancybox-error">The requested content cannot be loaded.<br />Please try again later.</p>');

		    _process_inline();
		},

		_start = function () {
		    var obj = selectedArray[selectedIndex],
				href,
				type,
				title,
				str,
				emb,
				ret;

		    _abort();

		    selectedOpts = $.extend({}, $.fn.fancybox.defaults, (typeof $(obj).data('fancybox') == 'undefined' ? selectedOpts : $(obj).data('fancybox')));

		    ret = selectedOpts.onStart(selectedArray, selectedIndex, selectedOpts);

		    if (ret === false) {
		        busy = false;
		        return;
		    } else if (typeof ret == 'object') {
		        selectedOpts = $.extend(selectedOpts, ret);
		    }

		    title = selectedOpts.title || (obj.nodeName ? $(obj).attr('title') : obj.title) || '';

		    if (obj.nodeName && !selectedOpts.orig) {
		        selectedOpts.orig = $(obj).children("img:first").length ? $(obj).children("img:first") : $(obj);
		    }

		    if (title === '' && selectedOpts.orig && selectedOpts.titleFromAlt) {
		        title = selectedOpts.orig.attr('alt');
		    }

		    href = selectedOpts.href || (obj.nodeName ? $(obj).attr('href') : obj.href) || null;

		    if ((/^(?:javascript)/i).test(href) || href == '#') {
		        href = null;
		    }

		    if (selectedOpts.type) {
		        type = selectedOpts.type;

		        if (!href) {
		            href = selectedOpts.content;
		        }

		    } else if (selectedOpts.content) {
		        type = 'html';

		    } else if (href) {
		        if (href.match(imgRegExp)) {
		            type = 'image';

		        } else if (href.match(swfRegExp)) {
		            type = 'swf';

		        } else if ($(obj).hasClass("iframe")) {
		            type = 'iframe';

		        } else if (href.indexOf("#") === 0) {
		            type = 'inline';

		        } else {
		            type = 'ajax';
		        }
		    }

		    if (!type) {
		        _error();
		        return;
		    }

		    if (type == 'inline') {
		        obj = href.substr(href.indexOf("#"));
		        type = $(obj).length > 0 ? 'inline' : 'ajax';
		    }

		    selectedOpts.type = type;
		    selectedOpts.href = href;
		    selectedOpts.title = title;

		    if (selectedOpts.autoDimensions) {
		        if (selectedOpts.type == 'html' || selectedOpts.type == 'inline' || selectedOpts.type == 'ajax') {
		            selectedOpts.width = 'auto';
		            selectedOpts.height = 'auto';
		        } else {
		            selectedOpts.autoDimensions = false;
		        }
		    }

		    if (selectedOpts.modal) {
		        selectedOpts.overlayShow = true;
		        selectedOpts.hideOnOverlayClick = false;
		        selectedOpts.hideOnContentClick = false;
		        selectedOpts.enableEscapeButton = false;
		        selectedOpts.showCloseButton = false;
		    }

		    selectedOpts.padding = parseInt(selectedOpts.padding, 10);
		    selectedOpts.margin = parseInt(selectedOpts.margin, 10);

		    tmp.css('padding', (selectedOpts.padding + selectedOpts.margin));

		    $('.fancybox-inline-tmp').unbind('fancybox-cancel').bind('fancybox-change', function () {
		        $(this).replaceWith(content.children());
		    });

		    switch (type) {
		        case 'html':
		            tmp.html(selectedOpts.content);
		            _process_inline();
		            break;

		        case 'inline':
		            if ($(obj).parent().is('#fancybox-content') === true) {
		                busy = false;
		                return;
		            }

		            $('<div class="fancybox-inline-tmp" />')
						.hide()
						.insertBefore($(obj))
						.bind('fancybox-cleanup', function () {
						    $(this).replaceWith(content.children());
						}).bind('fancybox-cancel', function () {
						    $(this).replaceWith(tmp.children());
						});

		            $(obj).appendTo(tmp);

		            _process_inline();
		            break;

		        case 'image':
		            busy = false;

		            $.fancybox.showActivity();

		            imgPreloader = new Image();

		            imgPreloader.onerror = function () {
		                _error();
		            };

		            imgPreloader.onload = function () {
		                busy = true;

		                imgPreloader.onerror = imgPreloader.onload = null;

		                _process_image();
		            };

		            imgPreloader.src = href;
		            break;

		        case 'swf':
		            selectedOpts.scrolling = 'no';

		            str = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="' + selectedOpts.width + '" height="' + selectedOpts.height + '"><param name="movie" value="' + href + '"></param>';
		            emb = '';

		            $.each(selectedOpts.swf, function (name, val) {
		                str += '<param name="' + name + '" value="' + val + '"></param>';
		                emb += ' ' + name + '="' + val + '"';
		            });

		            str += '<embed src="' + href + '" type="application/x-shockwave-flash" width="' + selectedOpts.width + '" height="' + selectedOpts.height + '"' + emb + '></embed></object>';

		            tmp.html(str);

		            _process_inline();
		            break;

		        case 'ajax':
		            busy = false;

		            $.fancybox.showActivity();

		            selectedOpts.ajax.win = selectedOpts.ajax.success;

		            ajaxLoader = $.ajax($.extend({}, selectedOpts.ajax, {
		                url: href,
		                data: selectedOpts.ajax.data || {},
		                error: function (XMLHttpRequest, textStatus, errorThrown) {
		                    if (XMLHttpRequest.status > 0) {
		                        _error();
		                    }
		                },
		                success: function (data, textStatus, XMLHttpRequest) {
		                    var o = typeof XMLHttpRequest == 'object' ? XMLHttpRequest : ajaxLoader;
		                    if (o.status == 200) {
		                        if (typeof selectedOpts.ajax.win == 'function') {
		                            ret = selectedOpts.ajax.win(href, data, textStatus, XMLHttpRequest);

		                            if (ret === false) {
		                                loading.hide();
		                                return;
		                            } else if (typeof ret == 'string' || typeof ret == 'object') {
		                                data = ret;
		                            }
		                        }

		                        tmp.html(data);
		                        _process_inline();
		                    }
		                }
		            }));

		            break;

		        case 'iframe':
		            _show();
		            break;
		    }
		},

		_process_inline = function () {
		    var 
				w = selectedOpts.width,
				h = selectedOpts.height;

		    if (w.toString().indexOf('%') > -1) {
		        w = parseInt(($(window).width() - (selectedOpts.margin * 2)) * parseFloat(w) / 100, 10) + 'px';

		    } else {
		        w = w == 'auto' ? 'auto' : w + 'px';
		    }

		    if (h.toString().indexOf('%') > -1) {
		        h = parseInt(($(window).height() - (selectedOpts.margin * 2)) * parseFloat(h) / 100, 10) + 'px';

		    } else {
		        h = h == 'auto' ? 'auto' : h + 'px';
		    }

		    tmp.wrapInner('<div style="width:' + w + ';height:' + h + ';overflow: ' + (selectedOpts.scrolling == 'auto' ? 'auto' : (selectedOpts.scrolling == 'yes' ? 'scroll' : 'hidden')) + ';position:relative;"></div>');

		    selectedOpts.width = tmp.width();
		    selectedOpts.height = tmp.height();

		    _show();
		},

		_process_image = function () {
		    selectedOpts.width = imgPreloader.width;
		    selectedOpts.height = imgPreloader.height;

		    $("<img />").attr({
		        'id': 'fancybox-img',
		        'src': imgPreloader.src,
		        'alt': selectedOpts.title
		    }).appendTo(tmp);

		    _show();
		},

		_show = function () {
		    var pos, equal;

		    loading.hide();

		    if (wrap.is(":visible") && false === currentOpts.onCleanup(currentArray, currentIndex, currentOpts)) {
		        $.event.trigger('fancybox-cancel');

		        busy = false;
		        return;
		    }

		    busy = true;

		    $(content.add(overlay)).unbind();

		    $(window).unbind("resize.fb scroll.fb");
		    $(document).unbind('keydown.fb');

		    if (wrap.is(":visible") && currentOpts.titlePosition !== 'outside') {
		        wrap.css('height', wrap.height());
		    }

		    currentArray = selectedArray;
		    currentIndex = selectedIndex;
		    currentOpts = selectedOpts;

		    if (currentOpts.overlayShow) {
		        overlay.css({
		            'background-color': currentOpts.overlayColor,
		            'opacity': currentOpts.overlayOpacity,
		            'cursor': currentOpts.hideOnOverlayClick ? 'pointer' : 'auto',
		            'height': $(document).height()
		        });

		        if (!overlay.is(':visible')) {
		            if (isIE6) {
		                $('select:not(#fancybox-tmp select)').filter(function () {
		                    return this.style.visibility !== 'hidden';
		                }).css({ 'visibility': 'hidden' }).one('fancybox-cleanup', function () {
		                    this.style.visibility = 'inherit';
		                });
		            }

		            overlay.show();
		        }
		    } else {
		        overlay.hide();
		    }

		    final_pos = _get_zoom_to();

		    _process_title();

		    if (wrap.is(":visible")) {
		        $(close.add(nav_left).add(nav_right)).hide();

		        pos = wrap.position(),

				start_pos = {
				    top: pos.top,
				    left: pos.left,
				    width: wrap.width(),
				    height: wrap.height()
				};

		        equal = (start_pos.width == final_pos.width && start_pos.height == final_pos.height);

		        content.fadeTo(currentOpts.changeFade, 0.3, function () {
		            var finish_resizing = function () {
		                content.html(tmp.contents()).fadeTo(currentOpts.changeFade, 1, _finish);
		            };

		            $.event.trigger('fancybox-change');

		            content
						.empty()
						.removeAttr('filter')
						.css({
						    'border-width': currentOpts.padding,
						    'width': final_pos.width - currentOpts.padding * 2,
						    'height': selectedOpts.autoDimensions ? 'auto' : final_pos.height - titleHeight - currentOpts.padding * 2
						});

		            if (equal) {
		                finish_resizing();

		            } else {
		                fx.prop = 0;

		                $(fx).animate({ prop: 1 }, {
		                    duration: currentOpts.changeSpeed,
		                    easing: currentOpts.easingChange,
		                    step: _draw,
		                    complete: finish_resizing
		                });
		            }
		        });

		        return;
		    }

            

		    wrap.removeAttr("style");

		    content.css('border-width', currentOpts.padding);

		    if (currentOpts.transitionIn == 'elastic') {
		        start_pos = _get_zoom_from();

		        content.html(tmp.contents());

		        wrap.show();

		        if (currentOpts.opacity) {
		            final_pos.opacity = 0;
		        }

		        fx.prop = 0;

		        $(fx).animate({ prop: 1 }, {
		            duration: currentOpts.speedIn,
		            easing: currentOpts.easingIn,
		            step: _draw,
		            complete: _finish
		        });

		        return;
		    }

		    if (currentOpts.titlePosition == 'inside' && titleHeight > 0) {
		        title.show();
		    }

		    content
				.css({
				    'width': final_pos.width - currentOpts.padding * 2,
				    'height': selectedOpts.autoDimensions ? 'auto' : final_pos.height - titleHeight - currentOpts.padding * 2
				})
				.html(tmp.contents());

		    wrap
				.css(final_pos)
				.fadeIn(currentOpts.transitionIn == 'none' ? 0 : currentOpts.speedIn, _finish);
		},

		_format_title = function (title) {
		    if (title && title.length) {
		        if (currentOpts.titlePosition == 'float') {
		            return '<table id="fancybox-title-float-wrap" cellpadding="0" cellspacing="0"><tr><td id="fancybox-title-float-left"></td><td id="fancybox-title-float-main">' + title + '</td><td id="fancybox-title-float-right"></td></tr></table>';
		        }

		        return '<div id="fancybox-title-' + currentOpts.titlePosition + '">' + title + '</div>';
		    }

		    return false;
		},

		_process_title = function () {
		    titleStr = currentOpts.title || '';
		    titleHeight = 0;

		    title
				.empty()
				.removeAttr('style')
				.removeClass();

		    if (currentOpts.titleShow === false) {
		        title.hide();
		        return;
		    }

		    titleStr = $.isFunction(currentOpts.titleFormat) ? currentOpts.titleFormat(titleStr, currentArray, currentIndex, currentOpts) : _format_title(titleStr);

		    if (!titleStr || titleStr === '') {
		        title.hide();
		        return;
		    }

		    title
				.addClass('fancybox-title-' + currentOpts.titlePosition)
				.html(titleStr)
				.appendTo('body')
				.show();

		    switch (currentOpts.titlePosition) {
		        case 'inside':
		            title
						.css({
						    'width': final_pos.width - (currentOpts.padding * 2),
						    'marginLeft': currentOpts.padding,
						    'marginRight': currentOpts.padding
						});

		            titleHeight = title.outerHeight(true);

		            title.appendTo(outer);

		            final_pos.height += titleHeight;
		            break;

		        case 'over':
		            title
						.css({
						    'marginLeft': currentOpts.padding,
						    'width': final_pos.width - (currentOpts.padding * 2),
						    'bottom': currentOpts.padding
						})
						.appendTo(outer);
		            break;

		        case 'float':
		            title
						.css('left', parseInt((title.width() - final_pos.width - 40) / 2, 10) * -1)
						.appendTo(wrap);
		            break;

		        default:
		            title
						.css({
						    'width': final_pos.width - (currentOpts.padding * 2),
						    'paddingLeft': currentOpts.padding,
						    'paddingRight': currentOpts.padding
						})
						.appendTo(wrap);
		            break;
		    }

		    title.hide();
		},

		_set_navigation = function () {
		    if (currentOpts.enableEscapeButton || currentOpts.enableKeyboardNav) {
		        $(document).bind('keydown.fb', function (e) {
		            if (e.keyCode == 27 && currentOpts.enableEscapeButton) {
		                e.preventDefault();
		                $.fancybox.close();

		            } else if ((e.keyCode == 37 || e.keyCode == 39) && currentOpts.enableKeyboardNav && e.target.tagName !== 'INPUT' && e.target.tagName !== 'TEXTAREA' && e.target.tagName !== 'SELECT') {
		                e.preventDefault();
		                $.fancybox[e.keyCode == 37 ? 'prev' : 'next']();
		            }
		        });
		    }

		    if (!currentOpts.showNavArrows) {
		        nav_left.hide();
		        nav_right.hide();
		        return;
		    }

		    if ((currentOpts.cyclic && currentArray.length > 1) || currentIndex !== 0) {
		        nav_left.show();
		    }

		    if ((currentOpts.cyclic && currentArray.length > 1) || currentIndex != (currentArray.length - 1)) {
		        nav_right.show();
		    }
		},

		_finish = function () {
		    if (!$.support.opacity) {
		        content.get(0).style.removeAttribute('filter');
		        wrap.get(0).style.removeAttribute('filter');
		    }

		    if (selectedOpts.autoDimensions) {
		        content.css('height', 'auto');
		    }

		    wrap.css('height', 'auto');

		    if (titleStr && titleStr.length) {
		        title.show();
		    }

		    if (currentOpts.showCloseButton) {
		        close.show();
		    }

		    _set_navigation();

		    if (currentOpts.hideOnContentClick) {
		        content.bind('click', $.fancybox.close);
		    }

		    if (currentOpts.hideOnOverlayClick) {
		        overlay.bind('click', $.fancybox.close);
		    }

		    $(window).bind("resize.fb", $.fancybox.resize);

		    if (currentOpts.centerOnScroll) {
		        $(window).bind("scroll.fb", $.fancybox.center);
		    }

		    if (currentOpts.type == 'iframe') {
                //MATT EDIT this whole block
                if(currentOpts.href.indexOf('?')==-1)
                    currentOpts.href+="?";
                else
                    currentOpts.href+="&";
                currentOpts.href+= ('p=' + encodeURIComponent(document.location));

		        $('<iframe id="fancybox-frame" name="fancybox-frame' + new Date().getTime() + '" frameborder="0" hspace="0" ' + ($.browser.msie ? 'allowtransparency="true""' : '') + ' scrolling="' + selectedOpts.scrolling + '" src="' + currentOpts.href + '"></iframe>').appendTo(content);
		    }

		    wrap.show();

		    busy = false;

		    $.fancybox.center();

		    currentOpts.onComplete(currentArray, currentIndex, currentOpts);

		    _preload_images();
		},

		_preload_images = function () {
		    var href,
				objNext;

		    if ((currentArray.length - 1) > currentIndex) {
		        href = currentArray[currentIndex + 1].href;

		        if (typeof href !== 'undefined' && href.match(imgRegExp)) {
		            objNext = new Image();
		            objNext.src = href;
		        }
		    }

		    if (currentIndex > 0) {
		        href = currentArray[currentIndex - 1].href;

		        if (typeof href !== 'undefined' && href.match(imgRegExp)) {
		            objNext = new Image();
		            objNext.src = href;
		        }
		    }
		},

		_draw = function (pos) {
		    var dim = {
		        width: parseInt(start_pos.width + (final_pos.width - start_pos.width) * pos, 10),
		        height: parseInt(start_pos.height + (final_pos.height - start_pos.height) * pos, 10),

		        top: parseInt(start_pos.top + (final_pos.top - start_pos.top) * pos, 10),
		        left: parseInt(start_pos.left + (final_pos.left - start_pos.left) * pos, 10)
		    };

		    if (typeof final_pos.opacity !== 'undefined') {
		        dim.opacity = pos < 0.5 ? 0.5 : pos;
		    }

		    wrap.css(dim);

		    content.css({
		        'width': dim.width - currentOpts.padding * 2,
		        'height': dim.height - (titleHeight * pos) - currentOpts.padding * 2
		    });
		},

		_get_viewport = function () {
		    return [
				$(window).width() - (currentOpts.margin * 2),
                //MATT EDIT
				$(window).height() - (currentOpts.margin * 2)-100,
				$(document).scrollLeft() + currentOpts.margin,
				$(document).scrollTop() + currentOpts.margin
			];
		},

		_get_zoom_to = function () {
		    var view = _get_viewport(),
				to = {},
				resize = currentOpts.autoScale,
				double_padding = currentOpts.padding * 2,
				ratio;

		    if (currentOpts.width.toString().indexOf('%') > -1) {
		        to.width = parseInt((view[0] * parseFloat(currentOpts.width)) / 100, 10);
		    } else {
		        to.width = currentOpts.width + double_padding;
		    }

		    if (currentOpts.height.toString().indexOf('%') > -1) {
		        to.height = parseInt((view[1] * parseFloat(currentOpts.height)) / 100, 10);
		    } else {
		        to.height = currentOpts.height + double_padding;
		    }

		    if (resize && (to.width > view[0] || to.height > view[1])) {
		        if (selectedOpts.type == 'image' || selectedOpts.type == 'swf') {
		            ratio = (currentOpts.width) / (currentOpts.height);

		            if ((to.width) > view[0]) {
		                to.width = view[0];
		                to.height = parseInt(((to.width - double_padding) / ratio) + double_padding, 10);
		            }

		            if ((to.height) > view[1]) {
		                to.height = view[1];
		                to.width = parseInt(((to.height - double_padding) * ratio) + double_padding, 10);
		            }

		        } else {
		            to.width = Math.min(to.width, view[0]);
		            to.height = Math.min(to.height, view[1]);
		        }
		    }

		    to.top = parseInt(Math.max(view[3] - 20, view[3] + ((view[1] - to.height - 40) * 0.5)), 10);
		    to.left = parseInt(Math.max(view[2] - 20, view[2] + ((view[0] - to.width - 40) * 0.5)), 10);

		    return to;
		},

		_get_obj_pos = function (obj) {
		    var pos = obj.offset();

		    pos.top += parseInt(obj.css('paddingTop'), 10) || 0;
		    pos.left += parseInt(obj.css('paddingLeft'), 10) || 0;

		    pos.top += parseInt(obj.css('border-top-width'), 10) || 0;
		    pos.left += parseInt(obj.css('border-left-width'), 10) || 0;

		    pos.width = obj.width();
		    pos.height = obj.height();

		    return pos;
		},

		_get_zoom_from = function () {
		    var orig = selectedOpts.orig ? $(selectedOpts.orig) : false,
				from = {},
				pos,
				view;

		    if (orig && orig.length) {
		        pos = _get_obj_pos(orig);

		        from = {
		            width: pos.width + (currentOpts.padding * 2),
		            height: pos.height + (currentOpts.padding * 2),
		            top: pos.top - currentOpts.padding - 20,
		            left: pos.left - currentOpts.padding - 20
		        };

		    } else {
		        view = _get_viewport();

		        from = {
		            width: currentOpts.padding * 2,
		            height: currentOpts.padding * 2,
		            top: parseInt(view[3] + view[1] * 0.5, 10),
		            left: parseInt(view[2] + view[0] * 0.5, 10)
		        };
		    }

		    return from;
		},

		_animate_loading = function () {
		    if (!loading.is(':visible')) {
		        clearInterval(loadingTimer);
		        return;
		    }

		    $('div', loading).css('top', (loadingFrame * -40) + 'px');

		    loadingFrame = (loadingFrame + 1) % 12;
		};

    /*
    * Public methods 
    */

    $.fn.fancybox = function (options) {
        if (!$(this).length) {
            return this;
        }

        $(this)
			.data('fancybox', $.extend({}, options, ($.metadata ? $(this).metadata() : {})))
			.unbind('click.fb')
			.bind('click.fb', function (e) {
			    e.preventDefault();

			    if (busy) {
			        return;
			    }

			    busy = true;

			    $(this).blur();

			    selectedArray = [];
			    selectedIndex = 0;

			    var rel = $(this).attr('rel') || '';

			    if (!rel || rel == '' || rel === 'nofollow') {
			        selectedArray.push(this);

			    } else {
			        selectedArray = $("a[rel=" + rel + "], area[rel=" + rel + "]");
			        selectedIndex = selectedArray.index(this);
			    }

			    _start();

			    return;
			});

        return this;
    };

    $.fancybox = function (obj) {
        var opts;

        if (busy) {
            return;
        }

        busy = true;
        opts = typeof arguments[1] !== 'undefined' ? arguments[1] : {};

        selectedArray = [];
        selectedIndex = parseInt(opts.index, 10) || 0;

        if ($.isArray(obj)) {
            for (var i = 0, j = obj.length; i < j; i++) {
                if (typeof obj[i] == 'object') {
                    $(obj[i]).data('fancybox', $.extend({}, opts, obj[i]));
                } else {
                    obj[i] = $({}).data('fancybox', $.extend({ content: obj[i] }, opts));
                }
            }

            selectedArray = jQuery.merge(selectedArray, obj);

        } else {
            if (typeof obj == 'object') {
                $(obj).data('fancybox', $.extend({}, opts, obj));
            } else {
                obj = $({}).data('fancybox', $.extend({ content: obj }, opts));
            }

            selectedArray.push(obj);
        }

        if (selectedIndex > selectedArray.length || selectedIndex < 0) {
            selectedIndex = 0;
        }

        _start();
    };

    $.fancybox.showActivity = function () {
        clearInterval(loadingTimer);

        loading.show();
        loadingTimer = setInterval(_animate_loading, 66);
    };

    $.fancybox.hideActivity = function () {
        loading.hide();
    };

    $.fancybox.next = function () {
        return $.fancybox.pos(currentIndex + 1);
    };

    $.fancybox.prev = function () {
        return $.fancybox.pos(currentIndex - 1);
    };

    $.fancybox.pos = function (pos) {
        if (busy) {
            return;
        }

        pos = parseInt(pos);

        selectedArray = currentArray;

        if (pos > -1 && pos < currentArray.length) {
            selectedIndex = pos;
            _start();

        } else if (currentOpts.cyclic && currentArray.length > 1) {
            selectedIndex = pos >= currentArray.length ? 0 : currentArray.length - 1;
            _start();
        }

        return;
    };

    $.fancybox.cancel = function () {
        if (busy) {
            return;
        }

        busy = true;

        $.event.trigger('fancybox-cancel');

        _abort();

        selectedOpts.onCancel(selectedArray, selectedIndex, selectedOpts);

        busy = false;
    };

    // Note: within an iframe use - parent.$.fancybox.close();
    $.fancybox.close = function () {
        if (busy || wrap.is(':hidden')) {
            return;
        }

        busy = true;

        if (currentOpts && false === currentOpts.onCleanup(currentArray, currentIndex, currentOpts)) {
            busy = false;
            return;
        }

        _abort();

        $(close.add(nav_left).add(nav_right)).hide();

        $(content.add(overlay)).unbind();

        $(window).unbind("resize.fb scroll.fb");
        $(document).unbind('keydown.fb');

        content.find('iframe').attr('src', isIE6 && /^https/i.test(window.location.href || '') ? 'javascript:void(false)' : 'about:blank');

        if (currentOpts.titlePosition !== 'inside') {
            title.empty();
        }

        wrap.stop();

        function _cleanup() {
            overlay.fadeOut('fast');

            title.empty().hide();
            wrap.hide();

            $.event.trigger('fancybox-cleanup');

            content.empty();

            currentOpts.onClosed(currentArray, currentIndex, currentOpts);

            currentArray = selectedOpts = [];
            currentIndex = selectedIndex = 0;
            currentOpts = selectedOpts = {};

            busy = false;
        }

        if (currentOpts.transitionOut == 'elastic') {
            start_pos = _get_zoom_from();

            var pos = wrap.position();

            final_pos = {
                top: pos.top,
                left: pos.left,
                width: wrap.width(),
                height: wrap.height()
            };

            if (currentOpts.opacity) {
                final_pos.opacity = 1;
            }

            title.empty().hide();

            fx.prop = 1;

            $(fx).animate({ prop: 0 }, {
                duration: currentOpts.speedOut,
                easing: currentOpts.easingOut,
                step: _draw,
                complete: _cleanup
            });

        } else {
            wrap.fadeOut(currentOpts.transitionOut == 'none' ? 0 : currentOpts.speedOut, _cleanup);
        }
    };

    $.fancybox.resize = function () {
        if (overlay.is(':visible')) {
            overlay.css('height', $(document).height());
        }

        $.fancybox.center(true);
    };

    $.fancybox.center = function () {
        var view, align;

        if (busy) {
            return;
        }

        align = arguments[0] === true ? 1 : 0;
        view = _get_viewport();

        if (!align && (wrap.width() > view[0] || wrap.height() > view[1])) {
            return;
        }

        wrap
			.stop()
			.animate({
			    'top': parseInt(Math.max(view[3] - 20, view[3] + ((view[1] - content.height() - 40) * 0.5) - currentOpts.padding)),
			    'left': parseInt(Math.max(view[2] - 20, view[2] + ((view[0] - content.width() - 40) * 0.5) - currentOpts.padding))
			}, typeof arguments[0] == 'number' ? arguments[0] : 200);
    };

    $.fancybox.init = function () {
        if ($("#fancybox-wrap").length) {
            return;
        }

        $('body').append(
			tmp = $('<div id="fancybox-tmp"></div>'),
			loading = $('<div id="fancybox-loading"><div></div></div>'),
			overlay = $('<div id="fancybox-overlay"></div>'),
			wrap = $('<div id="fancybox-wrap"></div>')
		);

        outer = $('<div id="fancybox-outer" class="rounded shadow"></div>').appendTo(wrap);

        outer.append(
			content = $('<div id="fancybox-content" class="rounded"></div>'),
			close = $('<a id="fancybox-close"></a>'),
			title = $('<div id="fancybox-title"></div>'),

			nav_left = $('<a href="javascript:;" id="fancybox-left"><span class="fancy-ico" id="fancybox-left-ico"></span></a>'),
			nav_right = $('<a href="javascript:;" id="fancybox-right"><span class="fancy-ico" id="fancybox-right-ico"></span></a>')
		);

        close.click($.fancybox.close);
        loading.click($.fancybox.cancel);

        nav_left.click(function (e) {
            e.preventDefault();
            $.fancybox.prev();
        });

        nav_right.click(function (e) {
            e.preventDefault();
            $.fancybox.next();
        });

        if ($.fn.mousewheel) {
            wrap.bind('mousewheel.fb', function (e, delta) {
                if (busy) {
                    e.preventDefault();

                } else if ($(e.target).get(0).clientHeight == 0 || $(e.target).get(0).scrollHeight === $(e.target).get(0).clientHeight) {
                    e.preventDefault();
                    $.fancybox[delta > 0 ? 'prev' : 'next']();
                }
            });
        }

        if (!$.support.opacity) {
            wrap.addClass('fancybox-ie');
        }

        if (isIE6) {
            loading.addClass('fancybox-ie6');
            wrap.addClass('fancybox-ie6');

            $('<iframe id="fancybox-hide-sel-frame" src="' + (/^https/i.test(window.location.href || '') ? 'javascript:void(false)' : 'about:blank') + '" scrolling="no" border="0" frameborder="0" tabindex="-1"></iframe>').prependTo(outer);
        }
    };

    $.fn.fancybox.defaults = {
        padding: 10,
        margin: 40,
        opacity: false,
        modal: false,
        cyclic: false,
        scrolling: 'auto', // 'auto', 'yes' or 'no'
        style:"",

        width: 560,
        height: 340,

        autoScale: true,
        autoDimensions: true,
        centerOnScroll: false,

        ajax: {},
        swf: { wmode: 'transparent' },

        hideOnOverlayClick: true,
        hideOnContentClick: false,

        overlayShow: true,
        overlayOpacity: 0.6,
        overlayColor: '#000',

        titleShow: true,
        titlePosition: 'float', // 'float', 'outside', 'inside' or 'over'
        titleFormat: null,
        titleFromAlt: false,

        transitionIn: 'fade', // 'elastic', 'fade' or 'none'
        transitionOut: 'fade', // 'elastic', 'fade' or 'none'

        speedIn: 300,
        speedOut: 300,

        changeSpeed: 300,
        changeFade: 'fast',

        easingIn: 'swing',
        easingOut: 'swing',

        showCloseButton: true,
        showNavArrows: true,
        enableEscapeButton: true,
        enableKeyboardNav: true,

        onStart: function () { },
        onCancel: function () { },
        onComplete: function () { },
        onCleanup: function () { },
        onClosed: function () { },
        onError: function () { }
    };

    $(document).ready(function () {
        $.fancybox.init();
    });

})(jQuery);



