TrueAchievements improver

Improves the TrueAchievements interface in various ways

当前为 2016-05-07 提交的版本,查看 最新版本

// ==UserScript==
// @author       Mobius Evalon
// @name         TrueAchievements improver
// @description  Improves the TrueAchievements interface in various ways
// @version      1.3
// @namespace    mobiusevalon.tibbius.com
// @license      Creative Commons Attribution-ShareAlike 4.0; http://creativecommons.org/licenses/by-sa/4.0/
// @require      https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js
// @require      https://code.jquery.com/ui/1.11.4/jquery-ui.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.26.0/js/jquery.tablesorter.min.js
// @include      /^https{0,1}:\/\/\w{0,}\.?trueachievements\.com.*$/
// @grant        none
// ==/UserScript==
this.$ = this.jQuery = jQuery.noConflict(true);

var chained_functions = {"tinker_tokens":function() {$("#tinker_output").val(new Date().getTokenizedOutput($("#tinker_input").val()));}};

var help_topics = {tai_longdate:"<div id='tai_help_date_tokens'><p>The letters here are tokens that expand to date information.  They use the same tokens as <a href='https://php.net/manual/en/function.date.php' target='_blank'>PHP's date() function</a>, if you're familiar with it.</p>"+
                   "<table>"+
                   "<thead><tr><th>Token</th><th>Info</th></tr></thead>"+
                   "<tbody>"+
                   "<tr><td>d</td><td>The day of the month with leading zeroes</td></tr>"+
                   "<tr><td>D</td><td>The name of the day, three letter abbreviation</td></tr>"+
                   "<tr><td>j</td><td>The day of the month, no leading zeroes</td></tr>"+
                   "<tr><td>l</td><td>The name of the day, full text</td></tr>"+
                   "<tr><td>S</td><td>Ordinal suffix for the day of the month (the 'th' in 5th or the 'st' in 1st)</td></tr>"+
                   "<tr><td>F</td><td>The name of the month, full text</td></tr>"+
                   "<tr><td>m</td><td>The month number with leading zeroes</td></tr>"+
                   "<tr><td>M</td><td>The name of the month, three letter abbreviation</td></tr>"+
                   "<tr><td>n</td><td>The month number, no leading zeroes</td></tr>"+
                   "<tr><td>Y</td><td>The year, four digits</td></tr>"+
                   "<tr><td>y</td><td>The year, two digits</td></tr>"+
                   "<tr><td>a</td><td>Lowercase meridiem (am/pm)</td></tr>"+
                   "<tr><td>A</td><td>Uppercase meridiem (AM/PM)</td></tr>"+
                   "<tr><td>g</td><td>The hour in the 12-hour meridiem rotation, no leading zeroes</td></tr>"+
                   "<tr><td>G</td><td>The hour in the 24-hour military notation, no leading zeroes</td></tr>"+
                   "<tr><td>h</td><td>The hour in the 12-hour meridiem rotation with leading zeroes</td></tr>"+
                   "<tr><td>H</td><td>The hour in the 24-hour military notation with leading zeroes</td></tr>"+
                   "<tr><td>i</td><td>Minutes with leading zeroes</td></tr>"+
                   "<tr><td>s</td><td>Seconds with leading zeroes</td></tr>"+
                   "<tr><td>[ ]</td><td>A proprietary format that 'fuzzies' the tokens inside</td></tr>"+
                   "</tbody></table>"+
                   "<p>If we assume it is currently Saturday April 30th at 1:15 PM, the token string 'D d M, H:i' would give you 'Sat 30 Apr, 13:15'.  If you use angle brackets you can fuzzy the date again.  For instance, '[D d M], H:i' would give you 'Today, 13:15'.</p>"+
                   "<p>All unrecognized letters will be left alone, so you can insert commas or other symbols as you please.</p>"+
                   "<p>You can tinker with the tokens in this textbox.  It will output the current date and time information on your system when used.</p>"+
                   "<p><input type='text' id='tinker_input'><input type='button' data-action='tinker_tokens' value='->'><input type='text' id='tinker_output' disabled='disabled'></p></div>"};

var tai_css = "#tai_help_box {background-color: #e3e3e3; color: #000; width: 350px; height: 450px; position: absolute !important; z-index: 100; display: none; border-radius: 8px; border: 2px solid #000; overflow-x: hidden; overflow-y: scroll; cursor: move;} "+
    "#tai_help_box h1 {display: block; padding: 0px; margin: 5px 0px; font-size: 125%; text-align: center;} "+
    "#tai_help_box .content {padding: 4px;} "+
    "div.spoiler {border: 1px solid #000 !important; border-radius: 5px !important;} "+
    "div.spoiler span.tai_spoiler_header {display: inline-block; width: 100%; cursor: pointer; font-weight: bold; text-align: center;} "+
    "a.tai_video_url_header {display: block; margin: 0px auto; text-align: center; font-weight: bold;} "+
    "div.Comment img.tai_permalink_icon {float: right !important; width: 16px !important; height: 16px !important; border: none !important; padding: 0px !important; margin: 8px 2px 0px 5px !important;} "+
    "#tai_flag_button {margin-left: 0px !important;} "+
    "#tai_flag_button .droparrow {margin-left: 8px;} "+
    ".tai_pagetitle {margin: 0px !important;} "+
    ".tai_won_options, #tai_filter_buttons_container {margin: 0px 0px 10px 0px !important;} "+
    "#tai_filter_buttons_container a.button {position: relative !important;} "+
    ".tai_won_options td {padding-bottom: 0px !important;} "+
    ".tai_link_label {float: none !important; display: inline-block !important; width: 40px !important; margin: 0px 10px 0px 0px !important;} "+
    ".tai_achievement_ownership_filtered {display: none !important;} "+
    ".tai_warning_panel {cursor: pointer;} "+
    "#btnFlagFilter_Options, #tai_flag_filter {z-index: 100 !important;} "+
    "#menu_click_fallthrough {position: fixed; top: 0px; left: 0px; bottom: 0px; right: 0px; min-width: 100vw; min-height: 100vh; z-index: 75; display: none;} "+
    ".tai_help_button {display: inline-block; margin: 8px 0px 0px 4px; float: left; cursor: pointer;} "+
    "#tai_help_date_tokens table {border: 1px solid #000; margin-bottom: 10px;} "+
    "#tai_help_date_tokens table thead th {font-weight: bold; background-color: #000; color: #cdcdcd;} "+
    "#tai_help_date_tokens table tbody tr td {vertical-align: middle !important;} "+
    "#tai_help_date_tokens table tbody tr td:nth-child(1) {width: 50px !important; text-align: center;} "+
    "#tai_help_date_tokens table tbody tr {border-top: 1px solid #000;} "+
    "#tai_help_date_tokens input[type=text] {width: 125px !important;} "+
    "#tai_help_box #tai_close_help {position: absolute; top: 0px; left: 0px; padding: 3px; font-wight: bold; font-size: 115%;} "+
    ".tai_hide_row {margin-left: 10px; cursor: pointer;} "+
    ".tai_gwg {background-color: #ecf198 !important;} "+
    ".tai_gold {background-color: #98a7f1 !important;} "+
    ".tai_approx {background-color: #f19898 !important;} "+
    ".tablesorter-header {cursor: pointer;} "+
    ".tablesorter-headerDesc {background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7); background-repeat: no-repeat; background-position: right;}"+
    ".tablesorter-headerAsc {background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7); background-repeat: no-repeat; background-position: right;}";

Date.prototype.short_date = true;
Date.prototype.date_time = true;

Date.prototype.getMonthString = function()
{
    switch(this.getMonth())
    {
        case 0: return "January";
        case 1: return "February";
        case 2: return "March";
        case 3: return "April";
        case 4: return "May";
        case 5: return "June";
        case 6: return "July";
        case 7: return "August";
        case 8: return "September";
        case 9: return "October";
        case 10: return "November";
        case 11: return "December";
    }
};

Date.prototype.getShortMonthString = function()
{
    return this.getMonthString().slice(0,3);
};

Date.prototype.getDayString = function()
{
    switch(this.getDay())
    {
        case 0: return "Sunday";
        case 1: return "Monday";
        case 2: return "Tuesday";
        case 3: return "Wednesday";
        case 4: return "Thursday";
        case 5: return "Friday";
        case 6: return "Saturday";
    }
};

Date.prototype.getShortDayString = function()
{
    return this.getDayString().slice(0,3);
};

Date.prototype.getTwoDigitHours = function()
{
    return zero_pad(this.getHours(),2);
};

Date.prototype.getTwoDigitMinutes = function()
{
    return zero_pad(this.getMinutes(),2);
};

Date.prototype.getTwoDigitSeconds = function()
{
    return zero_pad(this.getSeconds(),2);
};

Date.prototype.getTwoDigitDate = function()
{
    return zero_pad(this.getDate(),2);
};

Date.prototype.getShortYear = function()
{
    return (((""+this.getFullYear()).slice(-2))*1);
};

Date.prototype.getMeridiem = function()
{
    return ((this.getHours() > 11) ? "pm" : "am");
};

Date.prototype.getMeridiemHours = function()
{
    var h = this.getHours();
    if(h > 12) h -= 12;
    return h;
};

Date.prototype.getTwoDigitMeridiemHours = function()
{
    return zero_pad(this.getMeridiemHours(),2);
};

Date.prototype.adjustDate = function(n)
{
    this.setDate(this.getDate()+n);
};

Date.prototype.getDateAfterAdjustment = function(n)
{
    this.adjustDate(n);
    return this.getDate();
};

Date.prototype.getFuzzyDay = function()
{
    var d = new Date();
    if(d.getFullYear() === this.getFullYear() && d.getMonth() === this.getMonth())
    {
        if(d.getDate() === this.getDate()) return "Today";
        else if(d.getDateAfterAdjustment(1) === this.getDate()) return "Tomorrow";
        else if(d.getDateAfterAdjustment(-2) === this.getDate()) return "Yesterday";
    }
    return "";
};

Date.prototype.outputLongDate = function()
{
    return this.getTokenizedOutput(script_settings.long_date_format);
};

Date.prototype.outputShortDate = function()
{
    return this.getTokenizedOutput(script_settings.short_date_format);
};

Date.prototype.outputLongDateTime = function()
{
    return (this.outputLongDate()+", "+this.outputTime());
};

Date.prototype.outputShortDateTime = function()
{
    return (this.outputShortDate()+", "+this.outputTime());
};

Date.prototype.outputTime = function()
{
    return this.getTokenizedOutput(script_settings.time_format);
};

Date.prototype.getTokenizedOutput = function(t)
{
    var r = "",
        i = -1;
    while(i++ < t.length)
    {
        switch(t.charAt(i))
        {
            case 'd': {r += this.getTwoDigitDate(); break;}
            case 'D': {r += this.getShortDayString(); break;}
            case 'j': {r += this.getDate(); break;}
            case 'l': {r += this.getDayString(); break;}
            case 'S': {r += ordinal_suffix(this.getDate()); break;}
            case 'F': {r += this.getMonthString(); break;}
            case 'm': {r += zero_pad(this.getMonth()+1,2); break;}
            case 'M': {r += this.getShortMonthString(); break;}
            case 'n': {r += (this.getMonth()+1); break;}
            case 'Y': {r += this.getFullYear(); break;}
            case 'y': {r += this.getShortYear(); break;}
            case 'a': {r += this.getMeridiem(); break;}
            case 'A': {r += this.getMeridiem().toUpperCase(); break;}
            case 'g': {r += this.getMeridiemHours(); break;}
            case 'G': {r += this.getHours(); break;}
            case 'h': {r += this.getTwoDigitMeridiemHours(); break;}
            case 'H': {r += this.getTwoDigitHours(); break;}
            case 'i': {r += this.getTwoDigitMinutes(); break;}
            case 's': {r += this.getTwoDigitSeconds(); break;}
            case '[':
                var e = t.indexOf(']',i),
                    f = this.getFuzzyDay();
                if(e > i && f.length)
                {
                    r += f;
                    i = e;
                }
                break;
            case ']': break;
            default: {r += t.charAt(i); break;}
        }
    }
    return r;
};

Date.prototype.toString = function()
{
    var r = "";
    if(!this.short_date || script_settings.always_long_date) r += this.outputLongDate();
    else r += this.outputShortDate();

    if(this.date_time) r += (", "+this.outputTime());
    return r;
};

function datetime_master(obj)
{
    var date = new Date(),
        short = false,
        time = true;

    if(!obj.hasOwnProperty("hour") || obj.hour === undefined) {obj.hour = "00"; time = false;}
    if(!obj.hasOwnProperty("minute") || obj.minute === undefined) obj.minute = "00";

    if(!obj.hasOwnProperty("year") || obj.year === undefined) {obj.year = date.getFullYear(); short = true;}
    else if(obj.year.length === 2) obj.year = ("20"+obj.year);
    if(!obj.hasOwnProperty("month") || obj.month === undefined) obj.month = date.getShortMonthString();
    if($.type(obj.day) === "string") obj.day = obj.day.toLowerCase();
    if(!obj.hasOwnProperty("day") || obj.day === undefined || obj.day === "today") obj.day = date.getDate();
    else if(obj.day === "yesterday") obj.day = date.getDateAfterAdjustment(-1);
    else if(obj.day === "tomorrow") obj.day = date.getDateAfterAdjustment(+1);

    date = new Date(obj.month+" "+obj.day+" "+obj.year+" "+obj.hour+":"+obj.minute);
    date.short_date = short;
    date.date_time = time;

    return date;
}

function short_datetime_callback() // mon, jan 1 1900 at 00:00
{
    var len = arguments.length,
        date = datetime_master({year:arguments[len-5],month:arguments[len-6],day:(arguments[len-7]||arguments[len-8]),hour:arguments[len-4],minute:arguments[len-3]});
    return date.toString();
}

function short_date_callback() // 1 jan 1900
{
    var len = arguments.length,
        date = datetime_master({year:arguments[len-3],month:arguments[len-4],day:(arguments[len-5]||arguments[len-6])});
    return date.toString(); //date.outputShortDate();
}

function ordinal_suffix(n)
{
	n = Math.floor(n*1);

    var ord = "th";
    switch(n)
	{
		case 1: case 21: case 31:
			ord = "st";
			break;
		case 2: case 22:
			ord = "nd";
			break;
		case 3: case 23:
			ord = "rd";
			break;
	}
	return ord;
}

function zero_pad(a,l)
{
    var r = (""+a);
    while(r.length < l) r = ("0"+r);
    return r;
}

function uri()
{
	var m = window.location.href.match(/\/([\w-]*\.(?:aspx|htm))(?:\?|#|$)/i);
	if(m !== null) return m[1];
	return "";
}

function filter_settings_by_query(q)
{
    $("div#oOptionPanel div.inputform div.innerform").each(function() {
        $(this).children("div.filtered-out, div:not([class]), div[class='']").each(function() {
            if(!q.length || $(this).html().toLowerCase().indexOf(q) > -1) $(this).removeClass("filtered-out").show();
            else $(this).addClass("filtered-out").hide();
        });
        if(!q.length || $(this).children("div").not(".clearboth, .filtered-out").length) $(this).parent().show();
        else $(this).parent().hide();
    });
}

function json_obj(json)
{
    var obj;
    if(typeof json === "string")
    {
        try {obj = JSON.parse(json);}
        catch(e) {console.log("Malformed JSON object.  Error message from JSON library: ["+e.message+"]");}
    }
    return obj;
}

function localstorage_obj(key)
{
    var obj = json_obj(localStorage.getItem(key));
    if(typeof obj !== "object") localStorage.removeItem(key);
    return obj;
}

function default_settings()
{
    return {hide_ads:true,
            normalize_dates:true,
            improve_chat:true,
            session_userlinks_compare:true,
            session_hide_user_statuses:true,
            feed_permalinks:true,
            fix_spoilers:true,
            settings_page_filter:true,
            display_video_links:true,
            short_date_format:"D d M",
            long_date_format:"d M Y",
            time_format:"H:i",
            always_long_date:false,
            solution_list_filters:true,
            achievement_page_improvements:true};
}

function store_settings()
{
    localStorage.setItem("ta_improver_settings",JSON.stringify({hide_ads:checkbox("#tai_hide_ads"),
                                                                normalize_dates:checkbox("#tai_dates"),
                                                                improve_chat:checkbox("#tai_improve_chat"),
                                                                session_userlinks_compare:checkbox("#tai_session_compare"),
                                                                session_hide_user_statuses:checkbox("#tai_user_statuses"),
                                                                feed_permalinks:checkbox("#tai_permalinks"),
                                                                fix_spoilers:checkbox("#tai_spoilers"),
                                                                settings_page_filter:checkbox("#tai_filter"),
                                                                display_video_links:checkbox("#tai_video_links"),
                                                                short_date_format:$("#tai_shortdate").val(),
                                                                long_date_format:$("#tai_longdate").val(),
                                                                time_format:$("#tai_time").val(),
                                                                always_long_date:checkbox("#tai_always_longdate"),
                                                                solution_list_filters:checkbox("#tai_solution_list_filter"),
                                                                achievement_page_improvements:checkbox("#tai_improve_achievement_list")
                                                               }));
}

function checkbox(id)
{
    return ($("#divImprover "+id).prop("checked") === true);
}

function script_setting_display(id,type,value,name,tooltip)
{
    var $element;
    if(type === "checkbox") $element = $("<input/>")
        .attr({"id":id,
               "type":"checkbox"})
        .prop("checked",(value === true)); // fast short circuit.  if the value is boolean and true, the box is checked. all other circumstances evaluate to boolean false (not checked)
    if(type === "textbox") $element = $("<input/>")
        .attr({"id":id,
               "type":"text"})
        .val(value);

    var $elem = $("<div/>")
    .append($("<label/>")
            .attr("class","vlargelabel")
            .append($("<img/>")
                    .attr({"src":"/images/icons/information.png",
                           "alt":tooltip,
                           "title":tooltip})
                    .css({"width":"16px",
                          "height":"16px",
                          "margin-right":"4px"}),
                    $("<span/>")
                    .text(name)
                   ),
            $("<div/>")
            .attr("class","singleline")
            .append($element)
           )
    .after($("<div/>")
           .attr("class","clearboth")
          );
    if(help_topics.hasOwnProperty(id))
    {
        $elem.append($("<img/>")
                     .attr({"class":"tai_help_button",
                            "src":"/images/icons/helper.png"})
                     .click(function() {$("#tai_help_box")
                                        .css({"top":"15vh",
                                              "left":"25vw"})
                                        .show()
                                        .find("div.content").first().html(help_topics[id]);
                                        $("#tai_help_box").find("*[data-action]").each(function() {
                                            $(this).click(function() {
                                                chained_functions[$(this).attr("data-action")]();
                                            });
                                        });
                                       })
                    );
    }
    return $elem;
}

function intersect_arrays(s,t)
{
    var r = [];
    if($.type(s) === "array" && $.type(t) === "array")
    {
        for(var i=0;i<t.length;i++)
        {
            if(s.indexOf(t[i]) > -1) r.push(t[i]);
        }
    }
    return r;
}

function flag_filter()
{
    var filter_flags = [],
        join = $("#tai_flag_filter input[name='filter_link']:checked").val();
    $("#tai_flag_filter input[type='checkbox']:checked + div").each(function() {filter_flags.push($(this).attr("class"));});
    //console.log(join+": "+flags.join(","));
    $("div.achievementpanel").not(".tai_achievement_ownership_filtered").each(function() {var achievement_flags = [];
                                                                                          $(this).find("span.achievementtypes span").each(function() {achievement_flags.push($(this).attr("class"));});
                                                                                          if(!achievement_flags.length) achievement_flags.push("icon-information"); // unflagged achievements
                                                                                          achievement_flags = intersect_arrays(achievement_flags,filter_flags);

                                                                                          if(join === "not" && achievement_flags.length === 0) $(this).show();
                                                                                          else if(join === "or" && achievement_flags.length > 0) $(this).show();
                                                                                          else if(join === "and" && achievement_flags.length === filter_flags.length) $(this).show();
                                                                                          else $(this).hide();
                                                                                         });
}

function toggle_panel(parent,child,position)
{
    // i would love to just compute the location of the panels once and be done with it, but because of umpteen
    // situations that can change the position and scaling of the page i have to calculate a position every time
    // the panel is opened
    var $parent_elem = $(parent),
        $child_elem = $(child),
        $arrow = $parent_elem.children("span.droparrow").first();
    if($arrow.hasClass("icon-button-arrow-down"))
    {
        var pos_obj = {};
        $arrow.removeClass("icon-button-arrow-down").addClass("icon-button-arrow-up");
        if(position.x === "left") pos_obj.left = $parent_elem.position().left;
        else pos_obj.left = ($parent_elem.position().left-$child_elem.outerWidth()+$parent_elem.outerWidth());
        if(position.x === "top") pos_obj.top = ($parent_elem.position().top+$parent_elem.outerHeight());
        else pos_obj.top = ($parent_elem.position().top+$parent_elem.outerHeight());
        $("#menu_click_fallthrough").show();
        $child_elem
            .css(pos_obj)
            .show();
    }
    else
    {
        $arrow.removeClass("icon-button-arrow-up").addClass("icon-button-arrow-down");
        $("#menu_click_fallthrough").hide();
        $child_elem.hide();
    }
}

function filter_solutions(enable,type)
{
    $("table#oSolutionList tbody tr:not([nodrop])").each(function() {if(!enable) $(this).show();
                                                                     else if(type === "votes" && $(this).children().eq(9).text().trim().length) $(this).show();
                                                                     else if(type === "neg" && ($(this).children().eq(8).text().trim()*1) > ($(this).children().eq(7).text().trim()*1)) $(this).show();
                                                                     else if(type === "none" && ($(this).children().eq(8).text().trim()*1) === 0 && ($(this).children().eq(7).text().trim()*1) === 0) $(this).show();
                                                                     else $(this).hide();
                                                                    });
}

function prettynum2int(t)
{
    return(t.replace(",","")*1);
}

function table_stripes(t)
{
    $(t+" tbody tr").filter(":not([nodrop]):visible:even").removeClass("odd").addClass("even");
    $(t+" tbody tr").filter(":not([nodrop]):visible:odd").removeClass("even").addClass("odd");
}

$(document).ready(function() {
    $("head").append($("<style/>")
                     .attr("type","text/css")
                     .text(tai_css)
                    );
    $("body")
    .prepend($("<div/>") // this div is a super-simple way to handle off-panel clicks
             .attr("id","menu_click_fallthrough")
             .click(function() {$("#tai_filter_buttons_container span.icon-button-arrow-up").parent().click();}),
             $("<div/>")
             .attr("id","tai_help_box")
             .append($("<img/>")
                     .attr({"src":"/images/icons/postdelete.png",
                            "id":"tai_close_help",
                            "alt":"Close help",
                            "title":"Close help"})
                     .click(function() {$("#tai_help_box").hide();}),
                     $("<h1/>")
                     .text("TrueAchievements Improver help"),
                     $("<div/>")
                     .attr("class","content")
                    )
             .draggable()
            );

    script_settings = localstorage_obj("ta_improver_settings");
    if(typeof script_settings !== "object") script_settings = default_settings();
    else
    {
        // make sure new config options exist if the script has been updated
        var defaults = default_settings();
        $.each(defaults,function(k,v) {if(!script_settings.hasOwnProperty(k)) script_settings[k] = v;});
    }

    if(script_settings.hide_ads)
    {
        $("#topad-wrap, #divTAProHolder, #divGiftProPanel, #divBottomAds, .followuson, .internalad, .rightintergi, .sharepanel").remove();
        $("div#sidebar").children().not(".smallpanel").remove();
    }
    if(script_settings.normalize_dates)
    {
        $("td.lastpostdate, td.posted, div.info, td.time, td.sentdate, div.coveritem, td.ta, div.boostingdate, div.gamingsession h3, div.subcommentinfo, td.lastpost, div.links, #oGamer div.itemright p, td.author div.info").each(function() {
            $(this).html($(this).html().replace(/(?:on )?(?:[A-Z]{1}[a-z]{2,8}, )?(today|yesterday|tomorrow|(?:\d{1,2}) ([A-Z]{1}[a-z]{2,8}) ?(\d{2,4})?) at (\d{2}):(\d{2})/g,short_datetime_callback));
        });
        $("div.addedby, td.hwr, table.comparison td.green, .maincolumnpanel .itemright h3, #oGamer div.itemright p").each(function() {
            $(this).html($(this).html().replace(/(?:on )?(?:[A-Z]{1}[a-z]{2,8}, )?(today|yesterday|tomorrow|(\d{1,2}) ([A-Z]{1}[a-z]{2,8}) (\d{2,4}))/g,short_date_callback));
        });
    }
    // fix spoilers
    if(script_settings.fix_spoilers) $("div.spoiler").each(function() {$(this)
                                                                .children("a").first().replaceWith($("<span/>")
                                                                                                   .text("SPOILER: click to show content")
                                                                                                   .attr("class","tai_spoiler_header")
                                                                                                   .click(function() {var $span_content = $(this).siblings("span.spoiler").first();

                                                                                                                      if($span_content.css("display") === "none")
                                                                                                                      {
                                                                                                                          $span_content.show();
                                                                                                                          $(this).text("SPOILER: click to hide content");
                                                                                                                      }
                                                                                                                      else
                                                                                                                      {
                                                                                                                          $span_content.hide();
                                                                                                                          $(this).text("SPOILER: click to show content");
                                                                                                                      }
                                                                                                                     })
                                                                                                  );
                                                               });
    // give videos a visible external link so script blockers can get around a blank display
    if(script_settings.display_video_links) $("iframe[src*='youtube.com']").each(function() {var vurl = $(this).attr("src");
                                                                         vurl = ("https://www.youtube.com/watch?v="+vurl.slice(vurl.lastIndexOf("/")+1));
                                                                         $(this).parent().before($("<a/>")
                                                                                        .attr({"class":"tai_video_url_header",
                                                                                               "href":vurl,
                                                                                               "target":"_blank"})
                                                                                        .text(vurl)
                                                                                       );
    });
    // friend feed permalinks
    if(script_settings.feed_permalinks) $("#oFriendFeed div.Comment p").each(function() {$(this).prepend($("<a/>")
                                                                                         .attr({"href":("?gfcid="+$(this).parent().attr("id").slice(5)),
                                                                                                "target":"_blank"})
                                                                                         .append($("<img/>")
                                                                                                 .attr({"class":"tai_permalink_icon",
                                                                                                        "src":"/images/icons/permalink.png",
                                                                                                        "title":"Permalink",
                                                                                                        "alt":"Permalink"})
                                                                                                )
                                                                                        );
                                                                        });

    switch(uri())
    {
        case "xbox-sales.aspx":
            $("table#oSalesList")
                .prepend($("<thead/>")
                         .append($("table#oSalesList tbody tr").first())
                        )
                .find("thead tr th a").each(function() {$(this).replaceWith(document.createTextNode($(this).text()));});
            $("table#oSalesList tbody tr").each(function() {$(this).children("td").last().append($("<img/>")
                                                                                                 .attr({"src":"/images/icons/threadunsubscribe.png",
                                                                                                        "title":"Hide",
                                                                                                        "alt":"Hide",
                                                                                                        "class":"tai_hide_row"})
                                                                                                 .click(function() {$(this).parent().parent().hide();
                                                                                                                    // entirely cosmetic.  keeps the alternating row colors visibly correct as table rows are hidden
                                                                                                                    table_stripes("table#oSalesList");
                                                                                                                   })
                                                                                                );
                                                           });
            $("table#oSalesList img[src$='information.png'], table#oSalesList img[src$='information-gold.png']").each(function() {$(this).parent().attr("title",$(this).attr("title"));
                                                                                                                                  if($(this).attr("title").indexOf("Games with Gold") > -1) $(this).parent().addClass("tai_gwg");
                                                                                                                                  else if($(this).attr("title").indexOf("Gold Exclusive Sale") > -1) $(this).parent().addClass("tai_gold");
                                                                                                                                  else if($(this).attr("title").indexOf("Approximate pricing") > -1) $(this).parent().addClass("tai_approx");
                                                                                                                                  $(this).remove();});
            /*$("table#oSalesList img.hastooltip[title='Free with Games with Gold']").each(function() {$(this).parent().addClass("tai_gwg").attr("title","Games with Gold");
                                                                                                     $(this).remove();});
            $("table#oSalesList img.hastooltip[title='Gold Exclusive Sale']").each(function() {$(this).parent().addClass("tai_gold").attr("title","XBL Gold Subscription required");
                                                                                               $(this).remove();});
            $("table#oSalesList img.hastooltip[title*='Approximate pricing']").each(function() {$(this).parent().addClass("tai_approx").attr("title","Approximate pricing (whatever that means)");
                                                                                                $(this).remove();});
                                                                                                */
            $("table#oSalesList").tablesorter({
                headers:
                {
                    0:{sorter:false},
                    8:{sorter:false}
                },
                textExtraction:
                {
                    2:function(n,t,c) {return prettynum2int($(n).text().match(/([\d,]{2,6})\([\d,]{2,6}\)/i)[1]);},
                    3:function(n,t,c) {return $(n).find("img").length;},
                    7:function(n,t,c) {return new Date($(n).text().match(/([^-<]{1,})/i)[1]).getTime();}
                },
                sortAppend:
                {
                    2:[[1,'a']],
                    3:[[1,'a']],
                    4:[[1,'a']],
                    5:[[1,'a']],
                    6:[[1,'a']],
                    7:[[1,'a']],
                },
                widgets: ["zebra"],
                widgetOptions:
                {
                    zebra: ["odd","even"]
                }
            });
            break;
        case "achievements.htm":
            if(script_settings.achievement_page_improvements)
            {
                // remove default actions on the won status sorting radio buttons so this script can sort instead
                $("#rdoAllAchievements, #rdoWonAchievements, #rdoNotWonAchievements")
                    .attr("onclick","") // all three of these lines are because of old internet explorer versions
                    .prop("onclick",null)
                    .removeAttr("onclick")
                    .click(function() {var earned = ($(this).val() === "rdoAllAchievements" || $(this).val() === "rdoWonAchievements"),
                                           unearned = ($(this).val() === "rdoAllAchievements" || $(this).val() === "rdoNotWonAchievements");
                                       $("div.achievementpanel").each(function() {if((earned && $(this).hasClass("green")) || (unearned && $(this).hasClass("red"))) $(this).removeClass("tai_achievement_ownership_filtered");
                                                                                  else $(this).addClass("tai_achievement_ownership_filtered");
                                                                                  flag_filter();
                                                                                 });
                                      });
                // add the button that toggles the flag filter dropdown
                $("#btnFlagFilter")
                    .attr("onclick","")
                    .prop("onclick",null)
                    .removeAttr("onclick href")
                    .removeClass("shift_down")
                    .before($("<a/>")
                            .attr({"id":"tai_flag_button",
                                   "class":"button menubutton"})
                            .text("Filter")
                            .click(function() {toggle_panel("#tai_flag_button","#tai_flag_filter",
                                                            {x:"left",
                                                             y:"bottom"}
                                                           );
                                              })
                            .append($("<span/>")
                                    .attr("class","droparrow icon-button-arrow-down")
                                   ),
                            $("<ul/>")
                            .attr({"id":"tai_flag_filter",
                                   "class":"menuitems rightaligned filterbutton"})
                            .hide()
                           )
                    .click(function() {toggle_panel("#btnFlagFilter","#btnFlagFilter_Options",
                                                    {x:"right",
                                                     y:"bottom"}
                                                   );
                                      });
                // clone the flag filter section of the existing dropdown, then hide it so it cannot be manipulated in postback
                $("#btnFlagFilter_Options")
                    .find("div.flagfilter").parent().hide()
                    .clone().appendTo("#tai_flag_filter").show()
                    .find("*")
                    .attr("onclick","")
                    .prop("onclick",null)
                    .removeAttr("id name value onclick");
                // fix the check/uncheck all links
                // in the case of a game with either few flags or incomplete flagging, these are not present so i must add them myself
                if(!$("#tai_flag_filter li.fp h5 a").length) $("#tai_flag_filter li.fp h5").append($("<a/>")
                                                                                                   .attr("title","Select all flags")
                                                                                                   .append($("<img/>")
                                                                                                           .attr({"src":"/images/icons/selectall.png",
                                                                                                                  "width":"16",
                                                                                                                  "height":"16",
                                                                                                                  "alt":"Select all flags"})
                                                                                                          ),
                                                                                                   $("<a/>")
                                                                                                   .attr("title","Clear all flags")
                                                                                                   .append($("<img/>")
                                                                                                           .attr({"src":"/images/icons/selectnone.png",
                                                                                                                  "width":"16",
                                                                                                                  "height":"16",
                                                                                                                  "alt":"Clear all flags"})
                                                                                                          )
                                                                                                  );
                // no reason to add all this stuff above when the anchors don't exist, since i have to do this part even if they're already there anyway
                $("#tai_flag_filter a[title='Select all flags']")
                    .removeAttr("href")
                    .attr("id","tai_flags_select_all")
                    .click(function() {$("#tai_flag_filter input[type='checkbox']").prop("checked",true);});
                $("#tai_flag_filter a[title='Clear all flags']")
                    .removeAttr("href")
                    .attr("id","tai_flags_select_none")
                    .click(function() {$("#tai_flag_filter input[type='checkbox']").prop("checked",false);});
                // if there are unflagged achievements, ta puts an "unflagged" filter outside of the main flagging container that
                // does not follow the format of the remaining flags nor does it appear in the same container.  i'm redoing the
                // unflagged achievement flag where i need it in this section
                var $unflagged = $("#tai_flag_filter div.unflagged");
                if($unflagged.length)
                {
                    $("#tai_flag_filter div.flagfilter ul").append($("<li/>")
                                                                   .append($("<input/>")
                                                                           .attr({"type":"checkbox",
                                                                                  "class":"checkbox",
                                                                                  "checked":"checked"}),
                                                                           $("<div/>")
                                                                           .attr("class","icon-information"),
                                                                           $("<b/>")
                                                                           .text($unflagged.text().match(/Unflagged \((\d{1,2})\)/i)[1]),
                                                                           document.createTextNode(" Unflagged")
                                                                          )
                                                                  );
                    $unflagged.remove();
                }
                // i can't do an easy append for the NOT filter because the raw text outside of elements and floating makes it impossible,
                // so i have to clear the entire contents of this div and do it over
                var $link_flags = $("#tai_flag_filter input[type=radio]").parent();
                // i have to do this because the linking flags div is not included on a game with incomplete flagging
                if($link_flags.length) $link_flags.empty();
                else
                {
                    $link_flags = $("<div/>");
                    $("#tai_flag_filter li.fp div.flagfilter").first().after($link_flags);
                }
                $link_flags.append($("<span/>")
                                   .text("Link flags:"),
                                   $("<input/>")
                                   .attr({"type":"radio",
                                          "name":"filter_link",
                                          "id":"tai_link_or",
                                          "checked":"checked",
                                          "value":"or"}),
                                   $("<label/>")
                                   .attr({"class":"tai_link_label",
                                          "for":"tai_link_or"})
                                   .text("OR"),
                                   $("<input/>")
                                   .attr({"type":"radio",
                                          "name":"filter_link",
                                          "id":"tai_link_and",
                                          "value":"and"}),
                                   $("<label/>")
                                   .attr({"class":"tai_link_label",
                                          "for":"tai_link_and"})
                                   .text("AND"),
                                   $("<input/>")
                                   .attr({"type":"radio",
                                          "name":"filter_link",
                                          "id":"tai_link_not",
                                          "value":"not"}),
                                   $("<label/>")
                                   .attr({"class":"tai_link_label",
                                          "for":"tai_link_not"})
                                   .text("NOT")
                                  );
                // add the apply button
                $("#tai_flag_filter").append($("<li/>")
                                             .attr("class","buttons")
                                             .append($("<a/>")
                                                     .attr("class","button")
                                                     .append($("<span/>")
                                                             .attr({"class":"icon-tick",
                                                                    "title":"Apply",
                                                                    "alt":"Apply"}),
                                                             $("<span/>")
                                                             .text("Apply")
                                                            )
                                                     .click(function() {flag_filter();})
                                                    )
                                            );
                // cosmetics
                $("h1.pagetitle").first()
                    .addClass("tai_pagetitle")
                    .insertBefore("#tai_flag_button")
                    .after($("table.achievementwonoptions").first()
                           .addClass("tai_won_options"),
                           $("<div/>")
                           .attr("id","tai_filter_buttons_container")
                           .append($("#tai_flag_button, #tai_flag_filter, #btnFlagFilter, #btnFlagFilter_Options"))
                          );
                // make the warning panel for unobtainables et al. clickable and automatically filter the achievements
                var $warning_panel = $("div.warningspanel:contains(achievement)").first();
                if($warning_panel.length)
                {
                    $warning_panel
                        .addClass("tai_warning_panel")
                        .click(function() {var text = $(this).text();

                                           $("#tai_flags_select_none").click();
                                           $("#tai_link_or").click();
                                           // i have to use regex because the name of the PDU flag overlaps with both unobtainable and discontinued if i don't look for the prepended number
                                           if(/\d{1,2} Discontinued/i.test(text)) $("#tai_flag_filter div.flag-discontinued").prev("input[type='checkbox']").prop("checked",true);
                                           if(/\d{1,2} Unobtainable/i.test(text)) $("#tai_flag_filter div.flag-unobtainable").prev("input[type='checkbox']").prop("checked",true);
                                           if(/\d{1,2} Partly Discontinued\/Unobtainable/i.test(text)) $("#tai_flag_filter div.flag-partly-discontinued").prev("input[type='checkbox']").prop("checked",true);

                                           flag_filter();
                                          });
                }
            }
            break;
        case "solutions.aspx":
            if(script_settings.solution_list_filters)
            {
                $("table#oFilter tbody tr").first().after($("<tr/>")
                                                          .append($("<td/>")
                                                                  .append($("<input/>")
                                                                          .attr({"class":"checkbox",
                                                                                 "id":"tai_weekly_votes",
                                                                                 "type":"checkbox"}) // these are checkboxes because the filter needs to be able to be turned off by unchecking the active filter.  radio buttons must always have a selected button
                                                                          .click(function() {$("#tai_negative_votes, #tai_no_votes").prop("checked",false);
                                                                                             filter_solutions(($(this).prop("checked") === true),"votes");
                                                                                            }),
                                                                          $("<label/>")
                                                                          .attr({"class":"checkboxcaption",
                                                                                 "for":"tai_weekly_votes"})
                                                                          .text("Votes this week")
                                                                         ),
                                                                  $("<td/>")
                                                                  .append($("<input/>")
                                                                          .attr({"class":"checkbox",
                                                                                 "id":"tai_negative_votes",
                                                                                 "type":"checkbox"})
                                                                          .click(function() {$("#tai_weekly_votes, #tai_no_votes").prop("checked",false);
                                                                                             filter_solutions(($(this).prop("checked") === true),"neg");
                                                                                            }),
                                                                          $("<label/>")
                                                                          .attr({"class":"checkboxcaption",
                                                                                 "for":"tai_negative_votes"})
                                                                          .text("Negative vote ratio")
                                                                         ),
                                                                  $("<td/>")
                                                                  .append($("<input/>")
                                                                          .attr({"class":"checkbox",
                                                                                 "id":"tai_no_votes",
                                                                                 "type":"checkbox"})
                                                                          .click(function() {$("#tai_weekly_votes, #tai_negative_votes").prop("checked",false);
                                                                                             filter_solutions(($(this).prop("checked") === true),"none");
                                                                                            }),
                                                                          $("<label/>")
                                                                          .attr({"class":"checkboxcaption",
                                                                                 "for":"tai_no_votes"})
                                                                          .text("No votes")
                                                                         )
                                                                 )
                                                         );
                $("table#oSolutionList")
                .prepend($("<thead/>")
                         .append($("table#oSolutionList tbody tr").first())
                        )
                .find("thead tr th a").each(function() {$(this).replaceWith(document.createTextNode($(this).text()));});
                $("table#oSolutionList").tablesorter({
                    headers:
                    {
                        4:{sorter:false},
                        8:{sorter:false}
                    },
                    textExtraction:
                    {
                        1:function(n,t,c) {return $(n).find("td.game a").text();},
                        3:function(n,t,c) {return $(n).find("td.wideachievement a").text();},
                        7:function(n,t,c) {return $(n).text().length;}
                    }
                });
            }
            break;
        case "gamingsessionfeedback.aspx":
            $(".gsdisclaimer").remove();
            break;
        case "gamingsession.aspx":
            $(".gsdisclaimer").remove();

            if(script_settings.session_userlinks_compare && $("#mnuMyPages").length) // change gamertag links to compare page
            {
                var game_id = $("h4 a[title='View on session calendar']").first().attr("href"),
                    user_id = $("#mnuMyPages li a[href*='/gamerstats.aspx?gamerid=']").attr("href");
                game_id = game_id.slice(game_id.lastIndexOf("=")+1);
                user_id = user_id.slice(user_id.lastIndexOf("=")+1);

                $("#oGamingSessionGamerList td.gamer").each(function() {
                    var $gamer_anchor = $(this).children("a").first(),
                        other_id = $gamer_anchor.attr("href");
                    other_id = other_id.slice(other_id.lastIndexOf("=")+1);

                    if(other_id != user_id) $gamer_anchor.attr("href",("/comparison.aspx?gameid="+game_id+"&gamerid="+user_id+"&friendid="+other_id));
                    $gamer_anchor.attr("target","_blank");
                });
            }

            if(script_settings.session_hide_user_statuses) $("span.sitestatus").remove();
            break;
        case "customize.aspx":
            // insert the options for this script on the page
            $("#oOptionPanel")
                .before($("<div/>")
                        .attr("class","buttons")
                        .append($("<a/>")
                                .attr({"class":"button",
                                       "id":"btnSaveTop",
                                       "onclick":"Postback('btnSave_click');return false;"})
                                .append($("<img/>")
                                        .attr({"src":"/images/icons/save.png",
                                               "alt":"Save",
                                               "title":"Save"}),
                                        $("<span/>")
                                        .css("padding-left","4px")
                                        .text("Save")
                                       )
                                .click(function() {store_settings();}), // the jquery click event will fire before the inline onclick event
                                $("<div/>")
                                .attr("class","clearboth")
                               )
                       )
                .prepend($("div.informationpanel"), // because this element is appended out of order due to this script's modifications
                         $("<div/>")
                         .attr({"class":"inputform",
                                "id":"divImprover"})
                         .append($("<div/>")
                                 .attr("class","innerform")
                                 .append($("<h2/>")
                                         .text("TA Improver Script"),
                                         script_setting_display("tai_hide_ads","checkbox",script_settings.hide_ads,"Hide advertisements","This is pretty obvious."),
                                         script_setting_display("tai_dates","checkbox",script_settings.normalize_dates,"Normalize dates","TA has a bad habit of using half a dozen different date formats and further using fuzzy dates by saying something like 'tomorrow' instead of listing a calendar date.  This option sets all dates to the same format."),
                                         script_setting_display("tai_improve_chat","checkbox",script_settings.improve_chat,"Improve chat interface","Rearrange the chat interface to look better and save space."),
                                         script_setting_display("tai_session_compare","checkbox",script_settings.session_userlinks_compare,"Change user session links to compare","When clicking on a gamertag in a session roster table, this option will default the link to compare your achievements with them for that game instead of linking you to their homepage."),
                                         script_setting_display("tai_user_statuses","checkbox",script_settings.session_hide_user_statuses,"Hide user statuses in sessions","User statuses are generally just stretching the size of the table for no good reason, so using this option will hide statuses in the session roster table."),
                                         script_setting_display("tai_permalinks","checkbox",script_settings.feed_permalinks,"Friend feed permalinks","Add a permalink icon to comments on the friend feed for easily linking other people to the conversation."),
                                         script_setting_display("tai_spoilers","checkbox",script_settings.fix_spoilers,"Fix spoiler tags","This option will change spoiler tags so that the header text always remains and can be clicked to collapse the spoiler content again."),
                                         script_setting_display("tai_filter","checkbox",script_settings.settings_page_filter,"Filter settings","Adds a textbox to the top of this page to easily filter out options by search query."),
                                         script_setting_display("tai_video_links","checkbox",script_settings.display_video_links,"Video links","Display a clickable hyperlink of the video URL above it.  Most useful for those running ad/script blockers who block the YouTube domain when it's not first-party."),
                                         script_setting_display("tai_longdate","textbox",script_settings.long_date_format,"Long date format","A 'long date' is one that includes the year.  If the script finds a calendar date with an accompanying year, then it will use this format to reconfigure the output."),
                                         script_setting_display("tai_shortdate","textbox",script_settings.short_date_format,"Short date format","A 'short date' does not include the year.  Any short dates will be reconfigured using this output."),
                                         script_setting_display("tai_time","textbox",script_settings.time_format,"Time format","The format of time output to be used, if the time is included on a calendar date display."),
                                         script_setting_display("tai_always_longdate","checkbox",script_settings.always_long_date,"Always use long date","The script will not differentiate between short dates and long dates and will simply use the long date format in all circumstances."),
                                         script_setting_display("tai_solution_list_filter","checkbox",script_settings.solution_list_filters,"Solution list vote filter","I don't know about everyone else, but I check my solution list at least once a day for vote changes.  Enabling this option will add checkboxes to your list of solutions to filter for solutions with votes cast in the last week and filter for zero or negative vote ratios overall."),
                                         script_setting_display("tai_improve_achievement_list","checkbox",script_settings.achievement_page_improvements,"Improve achievement list","This will reconfigure a game's achievement list page to remove all postback to the site and instead filter achievements without reloading the page.  This option will also add a NOT filter.")
                                        ),
                                 $("<div/>")
                                 .attr("class","clearboth")
                                )
                        );
            $("#btnCancel").remove(); // the cancel button doesn't even do anything
            $("#btnSave").click(function() {store_settings();});
            // this page has become ridiculously bloated so this simple search filter helps quickly narrow relevant options down
            if(script_settings.settings_page_filter) $("div#main h1.pagetitle")
                .css("display","inline-block")
                .after($("<img/>")
                       .attr({"src":"/images/icons/information.png",
                              "alt":"Quickly find relevant options you're looking for by typing search text in the box, then hitting Enter/Return or clicking the Find button.",
                              "title":"Quickly find relevant options you're looking for by typing search text in the box, then hitting Enter/Return or clicking the Find button."})
                       .css("margin-left","8px"),
                       $("<input/>")
                       .attr({"type":"text",
                              "id":"filter-text"})
                       .css({"margin-left":"8px",
                             "margin-bottom":"-2px"})
                       .keyup(function(e) {if(e.which === 13 || !$(this).val().length) $("#execute-filter").click();}),
                       $("<input/>")
                       .attr({"type":"button",
                              "value":"Find",
                              "class":"button",
                              "id":"execute-filter"})
                       .css("margin-left","8px")
                       .click(function() {filter_settings_by_query($("#filter-text").val());})
                      );
            break;
        case "chat.aspx":
            if(script_settings.improve_chat)
            {
                // this whole section is overriding the default styling of the page when viewing the chatroom to change a whole
                // bunch of things, including:
                // # changing the font of the whole chat interface
                // # extending the height of the userlist to be the same as the chatbox
                // # collapses vertical space to fit the entire chat on one screen without scrolling
                // # extending the width of the input box
                // # giving the timestamp a fixed width
                // # giving the gamertag a fixed width
                // # positioning the buttons we'll be adding after the text input later
                // # preventing long words (spam) from adding horizontal scrolling
                // # moves the clear chat button out of the display box and puts it next to the input box
                // # removes the large footer for the chat guidelines and makes it a tiny button by the input box instead
                // # removes the "TrueAchievements Chat" page header

                // this section moves the clear chat button and creates a new rules button to the right of the input box at the bottom
                $("#btnClearChat")
                    .insertBefore($("#divChatKey"))
                    .after($("<a/>")
                           .attr({"href":"chatpolicy.aspx",
                                  "target":"_blank"})
                           .append($("<img/>")
                                   .attr({"src":"/images/itemflags/MainStoryline.png",
                                          "id":"btnChatRules",
                                          "title":"Chat guidelines",
                                          "alt":"Chat guidelines"})
                                  )
                          );
                $("#divChatKey, #divChatInformation, h1.pagetitle, #footer-wrap").remove();

                $("head").append($("<style/>")
                                 .attr("type","text/css")
                                 .text("div#divChatHolder {font-family: 'Droid Sans Mono',monospace !important} "+
                                       "div#divChatList {width: 175px !important; height: 450px !important;}" +
                                       "div#divChatBody {margin-right: 190px !important; height: 450px !important; overflow-wrap: break-word !important;} "+
                                       "input#txtChatMessage {width: 720px !important;} "+
                                       "span.chattime {display: inline-block !important; width: 65px !important; font-style: normal !important;} "+
                                       "span.gamertag {display: inline-block !important; width: 105px !important;} "+
                                       "a#btnClearChat {position: relative !important; top: -4px !important; right: auto !important; padding-right: 8px !important;} "+
                                       "img#btnChatRules {position: relative !important; top: -4px !important;} "+
                                       "div#main-holder {padding-bottom: 0 !important;} "+
                                       "div#main {padding: 10px 10px 0px 10px !important; min-height: 0 !important;} "+
                                       "div#page-wrap {padding-bottom: 0 !important;} "+
                                       "div#page {min-height: 0 !important;} ")
                            );
            }
            break;
    }
});