﻿/*
* jquery.radius.js
* Uses DD_roundies and SVG_roundies libraries to provide border radius styling in IE 6,7,8 and Opera, 
* including correct positioning of legend elements within styled fieldset elements.
*
* Tested with Opera 10.0 - IE 6,7,8 - FireFox 3.5 - Safari 4.0.3 (all on Windows XP)
*
* Author: Richard Collette
* Email: rcollette ~ a ~ yawho.com (obfuscated to prevent spam)
* Version: 0.0.1
*
* Usage:
* jQuery(selector).radius({legendExpression:"selector",radius{topleft:"8px",topright:"8px",bottomleft:"8px",bottomright:"8px",all:"8px"}});
* 
* configuration values are optional except for Opera where the radius configuration value must be set. In all other major browsers, the element's
* current border radius attribute is used.
* legendExpression defaults to "legend:first".
*
* Includes a custom jQuery selector :hasBorderRadius to select elements which have a non-zero radius CSS attribute. This, does not work with Opera as if version 10.0
MIT License

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 config,
    configRadius,
    configHasRadius,
    px = "px",
    zpx = "0px",
    cssRadiusAttributes = { standards: {
        topleft: "border-top-left-radius",
        topright: "border-top-right-radius",
        bottomleft: "border-bottom-left-radius",
        bottomright: "border-bottom-right-radius",
        all: "border-radius"
    },
        mozilla: {
            topleft: "-moz-border-radius-topleft",
            topright: "-moz-border-radius-topright",
            bottomleft: "-moz-border-radius-bottomleft",
            bottomright: "-moz-border-radius-bottomright",
            all: "-moz-border-radius"
        },
        webkit: {
            topleft: "-webkit-border-top-left-radius",
            topright: "-webkit-border-top-right-radius",
            bottomleft: "-webkit-border-bottom-left-radius",
            bottomright: "-webkit-border-bottom-right-radius",
            all: "-webkit-border-radius"
        }
    };

    //Extend the jQuery selection mechanism so that elements can be selected which have a border radius.
    //This doesn't work with Opera though because no element can have a border radius.
    $.extend($.expr[':'], {
        hasBorderRadius: _hasRadius
    });

    //public functions
    $.fn.radius = function(settings) {
        config = { legendExpression: "legend:first",  //The expression used to locate a child element of the radiused element which acts as the legend.
            radius: { topleft: null,  //The border radius to use in Opera.
                topright: null,
                bottomleft: null,
                bottomright: null,
                all: null
            }
        };
        //update the default settings
        if (settings) $.extend(config, settings);
        //If opera, create the set of radius attributes one time for the function call.
        _setConfigRadius();
        //Process each element
        this.each(function() {
            _radiusElement(this);
        });
        return this;
    }

    //private methods

    function _setConfigRadius() {
        if (!_hasRadiusSupport() && _isSVGBrowser()) {
            //No ability to read non-standard CSS attribute values in opera so the values must come from configuration settings passed in.
            //They only need to be set once per function call.
            configRadius = config.radius;
            configRadius = {
                topleft: !(value = configRadius.topleft) ? zpx : value,
                topright: !(value = configRadius.topright) ? zpx : value,
                bottomright: !(value = configRadius.bottomright) ? zpx : value,
                bottomleft: !(value = configRadius.bottomleft) ? zpx : value
            };
            if (configRadius && _hasNoSize(configRadius.topleft) && _hasNoSize(configRadius.topright) && _hasNoSize(configRadius.bottomleft) && _hasNoSize(configRadius.bottomright)) {
                if (!_hasNoSize(configRadius.all)) {
                    configRadius.topleft = configRadius.all;
                    configRadius.topright = configRadius.all;
                    configRadius.bottomleft = configRadius.all;
                    configRadius.bottomright = configRadius.all;
                    configHasRadius = true;
                } else configHasRadius = false;
            } else configHasRadius = true;
        }
    }

    function _hasRadiusSupport() {
        if (typeof _hasRadiusSupport.supported == "undefined") {
            var s = document.body.style;
            if (s.BorderRadius !== undefined || s.MozBorderRadius !== undefined || s.WebkitBorderRadius !== undefined || s.OBorderRadius !== undefined || s.KhtmlBorderRadius !== undefined) {
                _hasRadiusSupport.supported = true;
            } else _hasRadiusSupport.supported = false;
        }
        return _hasRadiusSupport.supported;
    }

    function _isVMLBrowser() {
        if (typeof _isVMLBrowser.supported == "undefined") {
            var a = document.body.appendChild(document.createElement('div'));
            a.innerHTML = '<v:shape id="vml_flag1" adj="1" />';
            var b = a.firstChild;
            b.style.behavior = "url(#default#VML)";
            _isVMLBrowser.supported = b ? typeof b.adj == "object" : true;
            a.parentNode.removeChild(a);
        }
        return _isVMLBrowser.supported;
    }

    function _isSVGBrowser() {
        if (typeof _isSVGBrowser.supported == "undefined") {
            _isSVGBrowser.supported = document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1")

        }
        return _isSVGBrowser.supported;
    }

    function _radiusElement(element) {
        var container = $(element),
        legend;
        if (!_hasRadiusSupport() && (_isVMLBrowser() || _isSVGBrowser())) {
            var radius = _getRadius(container);
            if (radius) {
                if (_isVMLBrowser()) {
                    DD_roundies.addRuleToElement(element, radius.topleft + " " + radius.topright + " " + radius.bottomright + " " + radius.bottomleft);
                } else {
                    SVG_roundies.addRuleToElement(element, radius.topleft + " " + radius.topright + " " + radius.bottomright + " " + radius.bottomleft);
                }
            }
        }
        var isFieldSet = element.tagName == "FIELDSET";
        legend = container.children(config.legendExpression);
        if ((!isFieldSet || !_hasRadiusSupport()) && legend && legend.length > 0) {
            _formatLegend(container, legend);
        }
    };

    function _formatLegend(container, legend) {
        var legendHeight = legend.outerHeight(true);
        //_addLegendResizeHandler(container, legend);
        //The legend height will be zero if not currently displayed.  The property change handler will recalc as needed.
        if (legendHeight == 0) return;
        var halfHeight = Math.round(.5 * legendHeight),
        width = _intOrZero(container.css("border-top-width")),
        legendTop = Math.round((.5 * (legendHeight - width))),
        isFieldSet = container.tagName == "FIELDSET";
        if (!isFieldSet || $.browser.msie) {
            if (legend.css("height") == "auto" && legendHeight < width) legend.css("height", width);
        }
        if ($.browser.msie) {
            legendTop -= width;
        }
        container.css({ "position": "relative",
            "top": halfHeight
        });
        legend.css({ "position": "absolute",
            "top": -1 * legendTop + px
        });
        //Insert a placeholder div with a height equal to the portion of the legend that is inside the frameset.
        var placeHolder = legend[0].radiusplaceholder;
        if (!placeHolder) {
            //create a new div element
            //insert it as the first element of the fieldset
            //inline the style so that stylesheets will not impact it
            placeHolder = $('<div style="border:none 0px;margin:0px;padding:0px;position:static;background:transparent;"/>');
            legend.after(placeHolder);
            //store a reference to the element so that we don't create it multiple times.            
            legend[0].radiusplaceholder = placeHolder
        }
        //set the height of the placeholder
        //The height of the div must place the bottom edge of the div at the bottom edge of the legend.
        var bottomEdgeOfLegend = legend.offset().top + legendHeight,
        heightOfPlaceHolder = bottomEdgeOfLegend - placeHolder.offset().top;
        heightOfPlaceHolder = Math.max(0, heightOfPlaceHolder);
        if (heightOfPlaceHolder == 0) {
            placeHolder.css("display", "none");
        } else {
            placeHolder.css("display", "block");
            placeHolder.height(heightOfPlaceHolder);
        }
    }

    function _addLegendResizeHandler(container, legend) {
        if (legend[0].radius_listenerAttached) return;
        legend[0].radius_listenerAttached = true;
        //TODO: resize is not called except in IE6 and IE7.
        legend.resize(function() { _formatLegend(container, legend); });
    }

    function _intOrZero(value) {
        try {
            var valueLocal = parseInt(value);
            if (isNaN(valueLocal)) {
                return 0;
            } else return valueLocal;
        } catch (e) {
            return 0;
        }
    }

    function _hasRadius(e, val) {
        var je = $(e)
        for (var key in cssRadiusAttributes) {
            var cssPositionSet = cssRadiusAttributes[key];
            for (var position in cssPositionSet) {
                var value = _intOrZero(je.css(cssPositionSet[position]));
                if (!_hasNoSize(value)) return true;
            }
        }
        return false;
    }

    function _getRadius(container) {
        var radius;
        if (_hasRadiusSupport() || _isVMLBrowser())
            for (var key in cssRadiusAttributes) {
            var cssPositionSet = cssRadiusAttributes[key],
                value;
            radius = {
                topleft: !(value = container.css(cssPositionSet.topleft)) ? zpx : value,
                topright: !(value = container.css(cssPositionSet.topright)) ? zpx : value,
                bottomright: !(value = container.css(cssPositionSet.bottomright)) ? zpx : value,
                bottomleft: !(value = container.css(cssPositionSet.bottomleft)) ? zpx : value
            };
            if (_hasNoSize(radius.topleft) && _hasNoSize(radius.topright) && _hasNoSize(radius.bottomleft) && _hasNoSize(radius.bottomright)) {
                //If no size, try to see if there is a common size
                if (cssPositionSet.all) {
                    value = container.css(cssPositionSet.all);
                    if (value) {
                        radius.topleft = value;
                        radius.topright = value;
                        radius.bottomleft = value;
                        radius.bottomright = value;
                        return radius;
                    }
                }
            } else {
                return radius;
            }
        }
        //No values were found, check if this is an SVG enabled browser and if so, use radius values passed in configuration if any.
        if (_isSVGBrowser() && configHasRadius) return configRadius;
        return radius;
    };

    function _hasNoSize(value) {
        if (!value || value == "auto" || value == zpx || value == "0em" || value == "" || value == 0) {
            return true;
        } else {
            return false;
        }
    };


    /**
    * DD_roundies, this adds rounded-corner CSS in standard browsers and VML sublayers in IE that accomplish a similar appearance when comparing said browsers.
    * Author: Drew Diller
    * Email: drew.diller@gmail.com
    * URL: http://www.dillerdesign.com/experiment/DD_roundies/
    * Version: 0.0.2a
    * Licensed under the MIT License: http://dillerdesign.com/experiment/DD_roundies/#license
    *
    * Usage:
    * DD_roundies.addRule('#doc .container', '10px 5px'); // selector and multiple radii
    * DD_roundies.addRule('.box', 5, true); // selector, radius, and optional addition of border-radius code for standard browsers.
    * 
    * Just want the PNG fixing effect for IE6, and don't want to also use the DD_belatedPNG library?  Don't give any additional arguments after the CSS selector.
    * DD_roundies.addRule('.your .example img');
    **/
    var DD_roundies = {

        ns: 'DD_roundies',

        IE6: false,
        IE7: false,
        IE8: false,
        IEversion: function() {
            if (document.documentMode != 8 && document.namespaces && !document.namespaces[this.ns]) {
                this.IE6 = true;
                this.IE7 = true;
            }
            else if (document.documentMode == 8) {
                this.IE8 = true;
            }
        },
        querySelector: document.querySelectorAll,
        selectorsToProcess: [],
        imgSize: {},

        createVmlNameSpace: function() { /* enable VML */
            if (this.IE6 || this.IE7) {
                document.namespaces.add(this.ns, 'urn:schemas-microsoft-com:vml');
            }
            if (this.IE8) {
                document.writeln('<?import namespace="' + this.ns + '" implementation="#default#VML" ?>');
            }
        },

        createVmlStyleSheet: function() { /* style VML, enable behaviors */
            /*
            Just in case lots of other developers have added
            lots of other stylesheets using document.createStyleSheet
            and hit the 31-limit mark, let's not use that method!
            further reading: http://msdn.microsoft.com/en-us/library/ms531194(VS.85).aspx
            */
            var style = document.createElement('style');
            document.documentElement.firstChild.insertBefore(style, document.documentElement.firstChild.firstChild);
            if (style.styleSheet) { /* IE */
                try {
                    var styleSheet = style.styleSheet;
                    styleSheet.addRule(this.ns + '\\:*', '{behavior:url(#default#VML)}');
                    this.styleSheet = styleSheet;
                } catch (err) { }
            }
            else {
                this.styleSheet = style;
            }
        },

        /**
        * Method to use from afar - refer to it whenever.
        * Example for IE only: DD_roundies.addRule('div.boxy_box', '10px 5px');
        * Example for IE, Firefox, and WebKit: DD_roundies.addRule('div.boxy_box', '10px 5px', true);
        * @param {String} selector - REQUIRED - a CSS selector, such as '#doc .container'
        * @param {Integer} radius - REQUIRED - the desired radius for the box corners
        * @param {Boolean} standards - OPTIONAL - true if you also wish to output -moz-border-radius/-webkit-border-radius/border-radius declarations
        **/
        addRule: function(selector, rad, standards) {
            //MOD: calcRad was factored into a separate function.
            rad = this.calcRad(rad);
            if (this.styleSheet) {
                if (this.styleSheet.addRule) { /* IE */
                    var selectors = selector.split(','); /* multiple selectors supported, no need for multiple calls to this anymore */
                    for (var i = 0; i < selectors.length; i++) {
                        this.styleSheet.addRule(selectors[i], 'behavior:expression(DD_roundies.roundify.call(this, [' + rad.join(',') + ']))'); /* seems to execute the function without adding it to the stylesheet - interesting... */
                    }
                }
                else if (standards) {
                    var moz_implementation = rad.join('px ') + 'px';
                    this.styleSheet.appendChild(document.createTextNode(selector + ' {border-radius:' + moz_implementation + '; -moz-border-radius:' + moz_implementation + ';}'));
                    this.styleSheet.appendChild(document.createTextNode(selector + ' {-webkit-border-top-left-radius:' + rad[0] + 'px ' + rad[0] + 'px; -webkit-border-top-right-radius:' + rad[1] + 'px ' + rad[1] + 'px; -webkit-border-bottom-right-radius:' + rad[2] + 'px ' + rad[2] + 'px; -webkit-border-bottom-left-radius:' + rad[3] + 'px ' + rad[3] + 'px;}'));
                }
            }
            else if (this.IE8) {
                this.selectorsToProcess.push({ 'selector': selector, 'radii': rad });
            }
        },

        /*MOD: factored out function to use with addRuleToElement*/
        calcRad: function(rad) {
            if (typeof rad == 'undefined' || rad === null) {
                rad = 0;
            }
            if (rad.constructor.toString().search('Array') == -1) {
                rad = rad.toString().replace(/[^0-9 ]/g, '').split(' ');
            }
            for (var i = 0; i < 4; i++) {
                rad[i] = (!rad[i] && rad[i] !== 0) ? rad[Math.max((i - 2), 0)] : rad[i];
            }
            return rad;
        },

        /*MOD: function that enables jQuery element selection */
        addRuleToElement: function(element, rad) {
            var radLocal = this.calcRad(rad);
            DD_roundies.roundify.call(element, radLocal);
        },

        readPropertyChanges: function(el) {
            switch (event.propertyName) {
                case 'style.border':
                case 'style.borderWidth':
                case 'style.padding':
                    this.applyVML(el);
                    break;
                case 'style.borderColor':
                    this.vmlStrokeColor(el);
                    break;
                case 'style.backgroundColor':
                case 'style.backgroundPosition':
                case 'style.backgroundRepeat':
                    this.applyVML(el);
                    break;
                case 'style.display':
                    el.vmlBox.style.display = (el.style.display == 'none' || el.style.visibility == 'hidden') ? 'none' : 'block';
                    break;
                case 'style.filter':
                    this.vmlOpacity(el);
                    break;
                case 'style.zIndex':
                    el.vmlBox.style.zIndex = el.style.zIndex;
                    break;
            }
        },

        applyVML: function(el) {
            el.runtimeStyle.cssText = '';
            this.vmlFill(el);
            this.vmlStrokeColor(el);
            this.vmlStrokeWeight(el);
            this.vmlOffsets(el);
            this.vmlPath(el);
            this.nixBorder(el);
            this.vmlOpacity(el);
        },

        vmlOpacity: function(el) {
            if (el.currentStyle.filter.search('lpha') != -1) {
                var trans = el.currentStyle.filter;
                trans = parseInt(trans.substring(trans.lastIndexOf('=') + 1, trans.lastIndexOf(')')), 10) / 100;
                for (var v in el.vml) {
                    el.vml[v].filler.opacity = trans;
                }
            }
        },

        vmlFill: function(el) {
            if (!el.currentStyle) {
                return;
            } else {
                var elStyle = el.currentStyle;
            }
            el.runtimeStyle.backgroundColor = '';
            el.runtimeStyle.backgroundImage = '';
            var noColor = (elStyle.backgroundColor == 'transparent');
            var noImg = true;
            if (elStyle.backgroundImage != 'none' || el.isImg) {
                if (!el.isImg) {
                    el.vmlBg = elStyle.backgroundImage;
                    el.vmlBg = el.vmlBg.substr(5, el.vmlBg.lastIndexOf('")') - 5);
                }
                else {
                    el.vmlBg = el.src;
                }
                var lib = this;
                if (!lib.imgSize[el.vmlBg]) { /* determine size of loaded image */
                    var img = document.createElement('img');
                    img.attachEvent('onload', function() {
                        this.width = this.offsetWidth; /* weird cache-busting requirement! */
                        this.height = this.offsetHeight;
                        lib.vmlOffsets(el);
                    });
                    img.className = lib.ns + '_sizeFinder';
                    img.runtimeStyle.cssText = 'behavior:none; position:absolute; top:-10000px; left:-10000px; border:none;'; /* make sure to set behavior to none to prevent accidental matching of the helper elements! */
                    img.src = el.vmlBg;
                    img.removeAttribute('width');
                    img.removeAttribute('height');
                    document.body.insertBefore(img, document.body.firstChild);
                    lib.imgSize[el.vmlBg] = img;
                }
                el.vml.image.filler.src = el.vmlBg;
                noImg = false;
            }
            el.vml.image.filled = !noImg;
            el.vml.image.fillcolor = 'none';
            el.vml.color.filled = !noColor;
            el.vml.color.fillcolor = elStyle.backgroundColor;
            el.runtimeStyle.backgroundImage = 'none';
            el.runtimeStyle.backgroundColor = 'transparent';
        },

        vmlStrokeColor: function(el) {
            el.vml.stroke.fillcolor = el.currentStyle.borderColor;
        },

        vmlStrokeWeight: function(el) {
            var borders = ['Top', 'Right', 'Bottom', 'Left'];
            el.bW = {};
            for (var b = 0; b < 4; b++) {
                el.bW[borders[b]] = parseInt(el.currentStyle['border' + borders[b] + 'Width'], 10) || 0;
            }
        },

        vmlOffsets: function(el) {
            var dims = ['Left', 'Top', 'Width', 'Height'];
            for (var d = 0; d < 4; d++) {
                el.dim[dims[d]] = el['offset' + dims[d]];
            }
            var assign = function(obj, topLeft) {
                obj.style.left = (topLeft ? 0 : el.dim.Left) + 'px';
                obj.style.top = (topLeft ? 0 : el.dim.Top) + 'px';
                obj.style.width = el.dim.Width + 'px';
                obj.style.height = el.dim.Height + 'px';
            };
            for (var v in el.vml) {
                var mult = (v == 'image') ? 1 : 2;
                el.vml[v].coordsize = (el.dim.Width * mult) + ', ' + (el.dim.Height * mult);
                assign(el.vml[v], true);
            }
            assign(el.vmlBox, false);

            if (DD_roundies.IE8) {
                el.vml.stroke.style.margin = '-1px';
                if (typeof el.bW == 'undefined') {
                    this.vmlStrokeWeight(el);
                }
                el.vml.color.style.margin = (el.bW.Top - 1) + 'px ' + (el.bW.Left - 1) + 'px';
            }
        },

        vmlPath: function(el) {
            var coords = function(direction, w, h, r, aL, aT, mult) {
                var cmd = direction ? ['m', 'qy', 'l', 'qx', 'l', 'qy', 'l', 'qx', 'l'] : ['qx', 'l', 'qy', 'l', 'qx', 'l', 'qy', 'l', 'm']; /* whoa */
                aL *= mult;
                aT *= mult;
                w *= mult;
                h *= mult;
                var R = r.slice(); /* do not affect original array */
                for (var i = 0; i < 4; i++) {
                    R[i] *= mult;
                    R[i] = Math.min(w / 2, h / 2, R[i]); /* make sure you do not get funky shapes - pick the smallest: half of the width, half of the height, or current value */
                }
                var coords = [
				cmd[0] + Math.floor(0 + aL) + ',' + Math.floor(R[0] + aT),
				cmd[1] + Math.floor(R[0] + aL) + ',' + Math.floor(0 + aT),
				cmd[2] + Math.ceil(w - R[1] + aL) + ',' + Math.floor(0 + aT),
				cmd[3] + Math.ceil(w + aL) + ',' + Math.floor(R[1] + aT),
				cmd[4] + Math.ceil(w + aL) + ',' + Math.ceil(h - R[2] + aT),
				cmd[5] + Math.ceil(w - R[2] + aL) + ',' + Math.ceil(h + aT),
				cmd[6] + Math.floor(R[3] + aL) + ',' + Math.ceil(h + aT),
				cmd[7] + Math.floor(0 + aL) + ',' + Math.ceil(h - R[3] + aT),
				cmd[8] + Math.floor(0 + aL) + ',' + Math.floor(R[0] + aT)
			];
                if (!direction) {
                    coords.reverse();
                }
                var path = coords.join('');
                return path;
            };

            if (typeof el.bW == 'undefined') {
                this.vmlStrokeWeight(el);
            }
            var bW = el.bW;
            var rad = el.DD_radii.slice();

            /* determine outer curves */
            var outer = coords(true, el.dim.Width, el.dim.Height, rad, 0, 0, 2);

            /* determine inner curves */
            rad[0] -= Math.max(bW.Left, bW.Top);
            rad[1] -= Math.max(bW.Top, bW.Right);
            rad[2] -= Math.max(bW.Right, bW.Bottom);
            rad[3] -= Math.max(bW.Bottom, bW.Left);
            for (var i = 0; i < 4; i++) {
                rad[i] = Math.max(rad[i], 0);
            }
            var inner = coords(false, el.dim.Width - bW.Left - bW.Right, el.dim.Height - bW.Top - bW.Bottom, rad, bW.Left, bW.Top, 2);
            var image = coords(true, el.dim.Width - bW.Left - bW.Right + 1, el.dim.Height - bW.Top - bW.Bottom + 1, rad, bW.Left, bW.Top, 1);

            /* apply huge path string */
            el.vml.color.path = inner;
            el.vml.image.path = image;
            el.vml.stroke.path = outer + inner;

            this.clipImage(el);
        },

        nixBorder: function(el) {
            var s = el.currentStyle;
            var sides = ['Top', 'Left', 'Right', 'Bottom'];
            for (var i = 0; i < 4; i++) {
                el.runtimeStyle['padding' + sides[i]] = (parseInt(s['padding' + sides[i]], 10) || 0) + (parseInt(s['border' + sides[i] + 'Width'], 10) || 0) + 'px';
            }
            el.runtimeStyle.border = 'none';
        },

        clipImage: function(el) {
            var lib = DD_roundies;
            if (!el.vmlBg || !lib.imgSize[el.vmlBg]) {
                return;
            }
            var thisStyle = el.currentStyle;
            var bg = { 'X': 0, 'Y': 0 };
            var figurePercentage = function(axis, position) {
                var fraction = true;
                switch (position) {
                    case 'left':
                    case 'top':
                        bg[axis] = 0;
                        break;
                    case 'center':
                        bg[axis] = 0.5;
                        break;
                    case 'right':
                    case 'bottom':
                        bg[axis] = 1;
                        break;
                    default:
                        if (position.search('%') != -1) {
                            bg[axis] = parseInt(position, 10) * 0.01;
                        }
                        else {
                            fraction = false;
                        }
                }
                var horz = (axis == 'X');
                bg[axis] = Math.ceil(fraction ? ((el.dim[horz ? 'Width' : 'Height'] - (el.bW[horz ? 'Left' : 'Top'] + el.bW[horz ? 'Right' : 'Bottom'])) * bg[axis]) - (lib.imgSize[el.vmlBg][horz ? 'width' : 'height'] * bg[axis]) : parseInt(position, 10));
                bg[axis] += 1;
            };
            for (var b in bg) {
                figurePercentage(b, thisStyle['backgroundPosition' + b]);
            }
            el.vml.image.filler.position = (bg.X / (el.dim.Width - el.bW.Left - el.bW.Right + 1)) + ',' + (bg.Y / (el.dim.Height - el.bW.Top - el.bW.Bottom + 1));
            var bgR = thisStyle.backgroundRepeat;
            var c = { 'T': 1, 'R': el.dim.Width + 1, 'B': el.dim.Height + 1, 'L': 1 }; /* these are defaults for repeat of any kind */
            var altC = { 'X': { 'b1': 'L', 'b2': 'R', 'd': 'Width' }, 'Y': { 'b1': 'T', 'b2': 'B', 'd': 'Height'} };
            if (bgR != 'repeat') {
                c = { 'T': (bg.Y), 'R': (bg.X + lib.imgSize[el.vmlBg].width), 'B': (bg.Y + lib.imgSize[el.vmlBg].height), 'L': (bg.X) }; /* these are defaults for no-repeat - clips down to the image location */
                if (bgR.search('repeat-') != -1) { /* now let's revert to dC for repeat-x or repeat-y */
                    var v = bgR.split('repeat-')[1].toUpperCase();
                    c[altC[v].b1] = 1;
                    c[altC[v].b2] = el.dim[altC[v].d] + 1;
                }
                if (c.B > el.dim.Height) {
                    c.B = el.dim.Height + 1;
                }
            }
            el.vml.image.style.clip = 'rect(' + c.T + 'px ' + c.R + 'px ' + c.B + 'px ' + c.L + 'px)';
        },

        pseudoClass: function(el) {
            var self = this;
            setTimeout(function() { /* would not work as intended without setTimeout */
                self.applyVML(el);
            }, 1);
        },

        reposition: function(el) {
            this.vmlOffsets(el);
            this.vmlPath(el);
        },

        roundify: function(rad) {
            this.style.behavior = 'none';
            if (!this.currentStyle) {
                return;
            }
            else {
                var thisStyle = this.currentStyle;
            }
            var allowed = { BODY: false, TABLE: false, TR: false, TD: false, SELECT: false, OPTION: false, TEXTAREA: false };
            if (allowed[this.nodeName] === false) { /* elements not supported yet */
                return;
            }
            var self = this; /* who knows when you might need a setTimeout */
            var lib = DD_roundies;
            this.DD_radii = rad;
            this.dim = {};

            /* attach handlers */
            var handlers = { resize: 'reposition', move: 'reposition' };
            if (this.nodeName == 'A') {
                var moreForAs = { mouseleave: 'pseudoClass', mouseenter: 'pseudoClass', focus: 'pseudoClass', blur: 'pseudoClass' };
                for (var a in moreForAs) {
                    handlers[a] = moreForAs[a];
                }
            }
            for (var h in handlers) {
                this.attachEvent('on' + h, function() {
                    lib[handlers[h]](self);
                });
            }
            this.attachEvent('onpropertychange', function() {
                lib.readPropertyChanges(self);
            });

            /* ensure that this elent and its parent is given hasLayout (needed for accurate positioning) */
            var giveLayout = function(el) {
                el.style.zoom = 1;
                if (el.currentStyle.position == 'static') {
                    el.style.position = 'relative';
                }
            };
            giveLayout(this.offsetParent);
            giveLayout(this);

            /* create vml elements */
            this.vmlBox = document.createElement('ignore'); /* IE8 really wants to be encased in a wrapper element for the VML to work, and I don't want to disturb getElementsByTagName('div') - open to suggestion on how to do this differently */
            this.vmlBox.runtimeStyle.cssText = 'behavior:none; position:absolute; margin:0; padding:0; border:0; background:none;'; /* super important - if something accidentally matches this (you yourseld did this once, Drew), you'll get infinitely-created elements and a frozen browser! */
            this.vmlBox.style.zIndex = thisStyle.zIndex;
            this.vmlBox.style.display = (thisStyle.display == 'none' || thisStyle.visibility == 'hidden') ? 'none' : 'block';
            this.vml = { 'color': true, 'image': true, 'stroke': true };
            for (var v in this.vml) {
                this.vml[v] = document.createElement(lib.ns + ':shape');
                this.vml[v].filler = document.createElement(lib.ns + ':fill');
                this.vml[v].appendChild(this.vml[v].filler);
                this.vml[v].stroked = false;
                this.vml[v].style.position = 'absolute';
                this.vml[v].style.zIndex = thisStyle.zIndex;
                this.vml[v].coordorigin = '1,1';
                this.vmlBox.appendChild(this.vml[v]);
            }
            this.vml.image.fillcolor = 'none';
            this.vml.image.filler.type = 'tile';
            this.parentNode.insertBefore(this.vmlBox, this);

            this.isImg = false;
            if (this.nodeName == 'IMG') {
                this.isImg = true;
                this.style.visibility = 'hidden';
            }

            setTimeout(function() {
                lib.applyVML(self);
            }, 1);
        }

    };

    try {
        document.execCommand("BackgroundImageCache", false, true);
    } catch (err) { }
    DD_roundies.IEversion();
    DD_roundies.createVmlNameSpace();
    DD_roundies.createVmlStyleSheet();

    if (DD_roundies.IE8 && document.attachEvent && DD_roundies.querySelector) {
        document.attachEvent('onreadystatechange', function() {
            if (document.readyState == 'complete') {
                var selectors = DD_roundies.selectorsToProcess;
                var length = selectors.length;
                var delayedCall = function(node, radii, index) {
                    setTimeout(function() {
                        DD_roundies.roundify.call(node, radii);
                    }, index * 100);
                };
                for (var i = 0; i < length; i++) {
                    var results = document.querySelectorAll(selectors[i].selector);
                    var rLength = results.length;
                    for (var r = 0; r < rLength; r++) {
                        if (results[r].nodeName != 'INPUT') { /* IE8 doesn't like to do this to inputs yet */
                            delayedCall(results[r], selectors[i].radii, r);
                        }
                    }
                }
            }
        });
    }

    /*!
    * SVG_roundies dynamically creates SVG graphics to make boxes look like as if they have rounded corners.
    * Adapted from DD_roundies: http://dillerdesign.com/experiment/DD_roundies/
    *
    * Author: Boris Schaeling
    * Email: boris@highscore.de
    * URL: http://www.highscore.de/SVG_roundies/
    * Version: 0.0.2a
    *
    * Licensed under the MIT License: http://www.highscore.de/SVG_roundies/#license
    * Copyright (c) 2008-2009 Drew Diller, Boris Schaeling
    *
    * Usage:
    * SVG_roundies.addRule('p', '10px 5px'); // tag name and multiple radii
    */

    var SVG_roundies = {

        ns: 'SVG_roundies',
        imgSize: {},

        /* reset querySelectorAll to document.querySelectorAll if you know your browsers support it */
        querySelectorAll: function(selector) {
            return document.getElementsByTagName(selector);
        },

        /*
        * Method to use from afar - refer to it whenever.
        * Example: SVG_roundies.addRule('p', '10px 5px');
        * @param {String} tag - REQUIRED - a tag name, such as 'p'
        * @param {String} radii - REQUIRED - the desired radii for the box corners
        */
        addRule: function(selector, rad) {
            //MOD: calcRad was factored into a separate function.
            rad = this.calcRad(rad);
            var selectors = selector.split(',');
            for (var i = 0; i < selectors.length; i++) {
                var els = this.querySelectorAll(selector);
                for (var j = 0; j < els.length; j++) {
                    this.roundify(els[j], rad);
                }
            }
        },

        //MOD: calcRad was factored into a separate function.
        calcRad: function(rad) {
            if (typeof rad == 'undefined' || rad === null) {
                rad = 0;
            }
            if (rad.constructor.toString().search('Array') == -1) {
                rad = rad.toString().replace(/[^0-9 ]/g, '').split(' ');
            }
            for (var i = 0; i < 4; i++) {
                rad[i] = (!rad[i] && rad[i] !== 0) ? rad[Math.max((i - 2), 0)] : rad[i];
            }
            return rad;
        },

        /*MOD: function that enables jQuery element selection */
        addRuleToElement: function(element, rad) {
            var radLocal = this.calcRad(rad);
            SVG_roundies.roundify(element, radLocal);
        },

        /* equivalent to IE's runtimeStyle */
        runtimeStyle: function(el) {
            var compStyle = document.defaultView.getComputedStyle(el, null);
            if (el.SVG_roundies.v === undefined) {
                el.SVG_roundies.v = {};
            }
            /*MOD: Check that background color is not transparent from a previous call */
            var backgroundColor = compStyle.getPropertyValue('background-color')
            if (el.SVG_roundies.v.bgColor === undefined || el.SVG_roundies.v.bgColor != backgroundColor && backgroundColor != "transparent") {
                el.SVG_roundies.v.bgColor = backgroundColor;
            }
            if (el.SVG_roundies.v.bgImage === undefined || el.SVG_roundies.v.bgImage != compStyle.getPropertyValue('background-image')) {
                el.SVG_roundies.v.bgImage = compStyle.getPropertyValue('background-image');
            }
            /* Firefox doesn't like border-color */
            /*MOD: Check that border color is not transparent from a previous call */
            var borderColor = compStyle.getPropertyValue('border-left-color')
            if (el.SVG_roundies.v.borderColor === undefined || el.SVG_roundies.v.borderColor != borderColor && borderColor != 'transparent') {
                el.SVG_roundies.v.borderColor = borderColor;
            }
        },

        readPropertyChanges: function(evt) {
            var el = evt.target;
            /*MOD: Don't filter event handling to just the current target.  Rounded parent nodes need to update their size.*/
            if (evt.attrName == 'style' && typeof (el.SVG_roundies) !== "undefined" && el.SVG_roundies != null) {
                /*
                * As in Firefox prevValue and newValue are the same (see https://bugzilla.mozilla.org/show_bug.cgi?id=338679)
                * and as it's very difficult to find the difference between the previous and the new style in Opera, too,
                * this is a brute force approach.
                */
                /*MOD: update zIndex and display style properties to match the rounded element.*/
                var svgStyle = el.SVG_roundies.svg.style;
                var value = el.style.zIndex,
                svgValue = svgStyle.zIndex;
                this.runtimeStyle(el);
                if (svgValue != value) {
                    svgStyle.zIndex = value;
                }
                value = el.style.display;
                svgValue = svgStyle.display;
                if (svgValue != value) {
                    svgStyle.display = value;
                }
                this.applySVG(el);
            }
        },

        applySVG: function(el) {
            this.removeEventListeners(el);
            this.svgFill(el);
            this.svgStrokeColor(el);
            this.svgStrokeWeight(el);
            this.svgOffsets(el);
            this.svgPath(el);
            this.svgOpacity(el);
            this.addEventListeners(el);
        },

        /* <p style="opacity: 0.5"> */
        svgOpacity: function(el) {
            var compStyle = document.defaultView.getComputedStyle(el, null);
            el.SVG_roundies.svg.setAttribute('opacity', compStyle.getPropertyValue('opacity'));
        },

        /* <p style="background-color: #FF0000"> or <p style="background-image: url(foo.png)> or <img src="foo.png"> */
        svgFill: function(el) {
            el.style.setProperty('background-color', 'transparent', null);
            if (el.SVG_roundies.v.bgImage != 'none' || el.SVG_roundies.isImg) {
                var initImage = function(lib, el, img) {
                    var defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
                    var pattern = document.createElementNS('http://www.w3.org/2000/svg', 'pattern');
                    pattern.setAttribute('patternUnits', 'userSpaceOnUse');
                    pattern.setAttribute('width', img.offsetWidth + 'px');
                    pattern.setAttribute('height', img.offsetHeight + 'px');
                    var id = lib.ns + '_' + img.getAttribute('src').replace(/\W/g, '');
                    pattern.setAttribute('id', id);
                    el.SVG_roundies.paths.color.setAttribute('fill', 'url(#' + id + ')');
                    var image = document.createElementNS('http://www.w3.org/2000/svg', 'image');
                    image.setAttributeNS('http://www.w3.org/1999/xlink', 'href', img.getAttribute('src'));
                    image.setAttribute('width', img.offsetWidth + 'px');
                    image.setAttribute('height', img.offsetHeight + 'px');
                    pattern.appendChild(image);
                    defs.appendChild(pattern);
                    el.SVG_roundies.svg.appendChild(defs);
                }
                var lib = this;
                if (el.SVG_roundies.isImg) {
                    initImage(lib, el, el);
                } else {
                    var bg;
                    el.style.setProperty('background-image', 'none', null);
                    var url = el.SVG_roundies.v.bgImage;
                    bg = url.substring(4, url.length - 1);
                    if (bg[0] == '"' || bg[0] == '\'') {
                        bg = bg.substring(1, bg.length - 1);
                    }
                    if (this.imgSize[bg] === undefined) {
                        var img = document.createElement('img');
                        img.addEventListener('load', function() {
                            initImage(lib, el, img);
                        }, false);
                        img.style.setProperty('position', 'absolute', null);
                        img.style.setProperty('top', '-10000px', null);
                        img.style.setProperty('left', '-10000px', null);
                        img.setAttribute('src', bg);
                        document.body.insertBefore(img, document.body.firstChild);
                        this.imgSize[bg] = img;
                    } else {
                        initImage(lib, el, this.imgSize[bg]);
                    }
                }
            }
            else {
                el.SVG_roundies.paths.color.setAttribute('fill', (el.SVG_roundies.v.bgColor == 'transparent') ? 'none' : el.SVG_roundies.v.bgColor);
            }
        },

        /* <p style="border-color: 0000FF"> */
        svgStrokeColor: function(el) {
            el.style.setProperty('border-color', 'transparent', null);
            el.SVG_roundies.paths.stroke.setAttribute('fill', el.SVG_roundies.v.borderColor);
        },

        /* <p style="border-width: 5px"> */
        svgStrokeWeight: function(el) {
            var compStyle = document.defaultView.getComputedStyle(el, null);
            var borders = ['top', 'right', 'bottom', 'left'];
            el.SVG_roundies.bW = [];
            for (var b = 0; b < 4; b++) {
                el.SVG_roundies.bW[borders[b]] = parseInt(compStyle.getPropertyValue('border-' + borders[b] + '-width'), 10) || 0;
            }
        },

        svgOffsets: function(el) {
            var dims = ['Left', 'Top', 'Width', 'Height'];
            el.SVG_roundies.dim = [];
            for (var d = 0; d < 4; d++) {
                el.SVG_roundies.dim[dims[d]] = el['offset' + dims[d]];
            }
            var assign = function(obj) {
                obj.style.setProperty('left', el.SVG_roundies.dim.Left + 'px', null);
                obj.style.setProperty('top', el.SVG_roundies.dim.Top + 'px', null);
                obj.style.setProperty('width', el.SVG_roundies.dim.Width + 'px', null);
                obj.style.setProperty('height', el.SVG_roundies.dim.Height + 'px', null);
            };
            assign(el.SVG_roundies.svg);
        },

        svgPath: function(el) {
            var coords = function(direction, w, h, r, aL, aT) {
                var R = r.slice(); /* do not affect original array */
                for (var i = 0; i < 4; i++) {
                    R[i] = Math.min(w / 2, h / 2, R[i]); /* make sure you do not get funky shapes - pick the smallest: half of the width, half of the height, or current value */
                }
                /*MOD: Coords declaration moved out of if scope.*/
                var coords;
                if (direction) {
                    /*MOD: Visual Studio complains about cmd being declared twice in both if and else scope.  Changed to cmdDir*/
                    var cmdDir = ['M', 'A', 'L', 'A', 'L', 'A', 'L', 'A', 'L'];
                    coords = [
					cmdDir[0] + Math.floor(0 + aL) + ',' + Math.floor(R[0] + aT),
					cmdDir[1] + R[0] + ',' + R[0] + ' 0 0 1 ' + Math.floor(R[0] + aL) + ',' + Math.floor(0 + aT),
					cmdDir[2] + Math.ceil(w - R[1] + aL) + ',' + Math.floor(0 + aT),
					cmdDir[3] + R[1] + ',' + R[1] + ' 0 0 1 ' + Math.ceil(w + aL) + ',' + Math.floor(R[1] + aT),
					cmdDir[4] + Math.ceil(w + aL) + ',' + Math.ceil(h - R[2] + aT),
					cmdDir[5] + R[2] + ',' + R[2] + ' 0 0 1 ' + Math.ceil(w - R[2] + aL) + ',' + Math.ceil(h + aT),
					cmdDir[6] + Math.floor(R[3] + aL) + ',' + Math.ceil(h + aT),
					cmdDir[7] + R[3] + ',' + R[3] + ' 0 0 1 ' + Math.floor(0 + aL) + ',' + Math.ceil(h - R[3] + aT),
					cmdDir[8] + Math.floor(0 + aL) + ',' + Math.floor(R[0] + aT)
				];
                } else {
                    var cmd = ['A', 'L', 'A', 'L', 'A', 'L', 'A', 'L', 'M'];
                    /*MOD: Coords declaration moved out of if scope.*/
                    coords = [
					cmd[0] + R[0] + ',' + R[0] + ' 0 0 0 ' + Math.floor(0 + aL) + ',' + Math.floor(R[0] + aT),
					cmd[1] + Math.floor(R[0] + aL) + ',' + Math.floor(0 + aT),
					cmd[2] + R[1] + ',' + R[1] + ' 0 0 0 ' + Math.ceil(w - R[1] + aL) + ',' + Math.floor(0 + aT),
					cmd[3] + Math.ceil(w + aL) + ',' + Math.floor(R[1] + aT),
					cmd[4] + R[2] + ',' + R[2] + ' 0 0 0 ' + Math.ceil(w + aL) + ',' + Math.ceil(h - R[2] + aT),
					cmd[5] + Math.ceil(w - R[2] + aL) + ',' + Math.ceil(h + aT),
					cmd[6] + R[3] + ',' + R[3] + ' 0 0 0 ' + Math.floor(R[3] + aL) + ',' + Math.ceil(h + aT),
					cmd[7] + Math.floor(0 + aL) + ',' + Math.ceil(h - R[3] + aT),
					cmd[8] + Math.floor(0 + aL) + ',' + Math.floor(R[0] + aT)
				];
                    coords.reverse();
                }
                var path = coords.join('');
                return path;
            };

            var bW = el.SVG_roundies.bW;
            var rad = el.SVG_roundies.radii.slice();

            /* determine outer curves */
            var outer = coords(true, el.SVG_roundies.dim.Width, el.SVG_roundies.dim.Height, rad, 0, 0);

            /* determine inner curves */
            rad[0] -= Math.max(bW.left, bW.top);
            rad[1] -= Math.max(bW.top, bW.right);
            rad[2] -= Math.max(bW.right, bW.bottom);
            rad[3] -= Math.max(bW.bottom, bW.left);
            for (var i = 0; i < 4; i++) {
                rad[i] = Math.max(rad[i], 0);
            }
            var inner = coords(false, el.SVG_roundies.dim.Width - bW.left - bW.right, el.SVG_roundies.dim.Height - bW.top - bW.bottom, rad, bW.left, bW.top);

            /* apply huge path string */
            el.SVG_roundies.paths.color.setAttribute('d', inner);
            el.SVG_roundies.paths.stroke.setAttribute('d', outer + inner);
        },

        reposition: function(el) {
            this.svgOffsets(el);
            this.svgPath(el);
        },

        addEventListeners: function(el) {
            if (el.handlers === undefined) {
                el.handlers = [];
                var lib = SVG_roundies;
                var handlers = { resize: 'reposition' };
                for (var h in handlers) {
                    var handler = function() {
                        lib[handlers[h]](el);
                    };
                    if (h == 'resize') {
                        window.addEventListener(h, handler, false); /* resize is only fired for the entire window */
                    } else {
                        el.addEventListener(h, handler, false);
                    }
                    el.handlers.push({ type: h, listener: handler });
                }
                /*MOD: Visual Studio complains about handler var already being declared in for loop scope changed variable to handler2*/
                var handler2 = function(evt) {
                    lib.readPropertyChanges(evt);
                };
                el.addEventListener('DOMAttrModified', handler2, false); /* doesn't fire in Safari 4 Public Beta if an existing attribute is changed */
                //MOD: We also need to handle dom events in the offset parent in case the offsetParent moves.
                el.offsetParent.addEventListener('DOMAttryModified', handler2, false);
                el.handlers.push({ type: 'DOMAttrModified', listener: handler2 });
            }
        },

        removeEventListeners: function(el) {
            if (el.handlers !== undefined) {
                for (var i = 0; i < el.handlers.length; i++) {
                    var handler = el.handlers[i];
                    if (handler.type == 'resize') {
                        window.removeEventListener(handler.type, handler.listener, false);
                    } else {
                        el.removeEventListener(handler.type, handler.listener, false);
                    }
                }
                delete el.handlers;
            }
        },

        roundify: function(el, rad) {
            var lib = SVG_roundies;
            el.SVG_roundies = {};
            el.SVG_roundies.radii = rad;

            var allowed = { TABLE: false, TR: false, TD: false, OPTION: false };
            if (allowed[el.nodeName] === false) { /* elements not supported */
                return;
            }

            /* save style properties which will be overriden */
            this.runtimeStyle(el);

            /* create svg elements */
            var compStyle = document.defaultView.getComputedStyle(el, null);
            el.SVG_roundies.svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
            el.SVG_roundies.svg.style.setProperty('position', 'absolute', null);
            el.SVG_roundies.svg.style.setProperty('z-index', compStyle.getPropertyValue('z-index'), null);
            /*MOD: Set the display property*/
            el.SVG_roundies.svg.style.setProperty('display', ((compStyle.display == 'none' || compStyle.visibility == 'hidden') ? 'none' : 'block'), null);
            el.SVG_roundies.paths = {};

            el.SVG_roundies.paths.color = document.createElementNS('http://www.w3.org/2000/svg', 'path');
            el.SVG_roundies.svg.appendChild(el.SVG_roundies.paths.color);

            el.SVG_roundies.paths.stroke = document.createElementNS('http://www.w3.org/2000/svg', 'path');
            el.SVG_roundies.svg.appendChild(el.SVG_roundies.paths.stroke);

            el.parentNode.insertBefore(el.SVG_roundies.svg, el);

            /* position element to move it to front (otherwise it's hidden by the SVG graphic) */
            if (compStyle.getPropertyValue('position') == 'static') {
                el.style.setProperty('position', 'relative', null);
            }

            el.SVG_roundies.isImg = false;
            if (el.nodeName == 'IMG') {
                el.SVG_roundies.isImg = true;
                el.style.setProperty('visibility', 'hidden', null);
            }

            setTimeout(function() {
                lib.applySVG(el);
            }, 1);
        }

    };



})(jQuery);