//jQuery URL
//jQuery.url=function(){var segments={};var parsed={};var options={url:window.location,strictMode:false,key:["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],q:{name:"queryKey",parser:/(?:^|&)([^&=]*)=?([^&]*)/g},parser:{strict:/^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,loose:/^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/}};var parseUri=function(){str=decodeURI(options.url);var m=options.parser[options.strictMode?"strict":"loose"].exec(str);var uri={};var i=14;while(i--){uri[options.key[i]]=m[i]||""}uri[options.q.name]={};uri[options.key[12]].replace(options.q.parser,function($0,$1,$2){if($1){uri[options.q.name][$1]=$2}});return uri};var key=function(key){if(!parsed.length){setUp()}if(key=="base"){if(parsed.port!==null&&parsed.port!==""){return parsed.protocol+"://"+parsed.host+":"+parsed.port+"/"}else{return parsed.protocol+"://"+parsed.host+"/"}}return(parsed[key]==="")?null:parsed[key]};var param=function(item){if(!parsed.length){setUp()}return(parsed.queryKey[item]===null)?null:parsed.queryKey[item]};var setUp=function(){parsed=parseUri();getSegments()};var getSegments=function(){var p=parsed.path;segments=[];segments=parsed.path.length==1?{}:(p.charAt(p.length-1)=="/"?p.substring(1,p.length-1):path=p.substring(1)).split("/")};return{setMode:function(mode){strictMode=mode=="strict"?true:false;return this},setUrl:function(newUri){options.url=newUri===undefined?window.location:newUri;setUp();return this},segment:function(pos){if(!parsed.length){setUp()}if(pos===undefined){return segments.length}return(segments[pos]===""||segments[pos]===undefined)?null:segments[pos]},attr:key,param:param}}();

// JQuery URL Parser
// Written by Mark Perkins, mark@allmarkedup.com
// License: http://unlicense.org/ (i.e. do what you want with it!)

jQuery.url = function()
{
	var segments = {};
	
	var parsed = {};
	
	/**
    * Options object. Only the URI and strictMode values can be changed via the setters below.
    */
  	var options = {
	
		url : window.location, // default URI is the page in which the script is running
		
		strictMode: false, // 'loose' parsing by default
	
		key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"], // keys available to query 
		
		q: {
			name: "queryKey",
			parser: /(?:^|&)([^&=]*)=?([^&]*)/g
		},
		
		parser: {
			strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,  //less intuitive, more accurate to the specs
			loose:  /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/ // more intuitive, fails on relative paths and deviates from specs
		}
		
	};
	
    /**
     * Deals with the parsing of the URI according to the regex above.
 	 * Written by Steven Levithan - see credits at top.
     */		
	var parseUri = function()
	{
		str = decodeURI( window.location );
		
		var m = options.parser[ options.strictMode ? "strict" : "loose" ].exec( str );
		var uri = {};
		var i = 14;

		while ( i-- ) {
			uri[ options.key[i] ] = m[i] || "";
		}

		uri[ options.q.name ] = {};
		uri[ options.key[12] ].replace( options.q.parser, function ( $0, $1, $2 ) {
			if ($1) {
				uri[options.q.name][$1] = $2;
			}
		});

		return uri;
	};

    /**
     * Returns the value of the passed in key from the parsed URI.
  	 * 
	 * @param string key The key whose value is required
     */		
	var key = function( key )
	{
		if ( jQuery.isEmptyObject(parsed) )
		{
			setUp(); // if the URI has not been parsed yet then do this first...	
		} 
		if ( key == "base" )
		{
			if ( parsed.port !== null && parsed.port !== "" )
			{
				return parsed.protocol+"://"+parsed.host+":"+parsed.port+"/";	
			}
			else
			{
				return parsed.protocol+"://"+parsed.host+"/";
			}
		}
	
		return ( parsed[key] === "" ) ? null : parsed[key];
	};
	
	/**
     * Returns the value of the required query string parameter.
  	 * 
	 * @param string item The parameter whose value is required
     */		
	var param = function( item )
	{
		if ( jQuery.isEmptyObject(parsed) )
		{
			setUp(); // if the URI has not been parsed yet then do this first...	
		}
		return ( parsed.queryKey[item] === null ) ? null : parsed.queryKey[item];
	};

    /**
     * 'Constructor' (not really!) function.
     *  Called whenever the URI changes to kick off re-parsing of the URI and splitting it up into segments. 
     */	
	var setUp = function()
	{
		parsed = parseUri();
		
		getSegments();	
	};
	
    /**
     * Splits up the body of the URI into segments (i.e. sections delimited by '/')
     */
	var getSegments = function()
	{
		var p = parsed.path;
		segments = []; // clear out segments array
		segments = parsed.path.length == 1 ? {} : ( p.charAt( p.length - 1 ) == "/" ? p.substring( 1, p.length - 1 ) : path = p.substring( 1 ) ).split("/");
	};
	
	return {
		
	    /**
	     * Sets the parsing mode - either strict or loose. Set to loose by default.
	     *
	     * @param string mode The mode to set the parser to. Anything apart from a value of 'strict' will set it to loose!
	     */
		setMode : function( mode )
		{
			options.strictMode = mode == "strict" ? true : false;
			return this;
		},
		
		/**
	     * Sets URI to parse if you don't want to to parse the current page's URI.
		 * Calling the function with no value for newUri resets it to the current page's URI.
	     *
	     * @param string newUri The URI to parse.
	     */		
		setUrl : function( newUri )
		{
			options.url = newUri === undefined ? window.location : newUri;
			setUp();
			return this;
		},		
		
		/**
	     * Returns the value of the specified URI segment. Segments are numbered from 1 to the number of segments.
		 * For example the URI http://test.com/about/company/ segment(1) would return 'about'.
		 *
		 * If no integer is passed into the function it returns the number of segments in the URI.
	     *
	     * @param int pos The position of the segment to return. Can be empty.
	     */	
		segment : function( pos )
		{
			if ( jQuery.isEmptyObject(parsed) )
			{
				setUp(); // if the URI has not been parsed yet then do this first...	
			} 
			if ( pos === undefined )
			{
				return segments.length;
			}
			return ( segments[pos] === "" || segments[pos] === undefined ) ? null : segments[pos];
		},
		
		attr : key, // provides public access to private 'key' function - see above
		
		param : param // provides public access to private 'param' function - see above
		
	};
	
}();

/**
 * Cookie plugin
 *
 * Copyright (c) 2006 Klaus Hartl (stilbuero.de)
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 *
 */

/**
 * Create a cookie with the given name and value and other optional parameters.
 *
 * @example $.cookie('the_cookie', 'the_value');
 * @desc Set the value of a cookie.
 * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true });
 * @desc Create a cookie with all available options.
 * @example $.cookie('the_cookie', 'the_value');
 * @desc Create a session cookie.
 * @example $.cookie('the_cookie', null);
 * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain
 *       used when the cookie was set.
 *
 * @param String name The name of the cookie.
 * @param String value The value of the cookie.
 * @param Object options An object literal containing key/value pairs to provide optional cookie attributes.
 * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.
 *                             If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
 *                             If set to null or omitted, the cookie will be a session cookie and will not be retained
 *                             when the the browser exits.
 * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie).
 * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).
 * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will
 *                        require a secure protocol (like HTTPS).
 * @type undefined
 *
 * @name $.cookie
 * @cat Plugins/Cookie
 * @author Klaus Hartl/klaus.hartl@stilbuero.de
 */

/**
 * Get the value of a cookie with the given name.
 *
 * @example $.cookie('the_cookie');
 * @desc Get the value of a cookie.
 *
 * @param String name The name of the cookie.
 * @return The value of the cookie.
 * @type String
 *
 * @name $.cookie
 * @cat Plugins/Cookie
 * @author Klaus Hartl/klaus.hartl@stilbuero.de
 */
jQuery.cookie = function(name, value, options) {
    if (typeof value != 'undefined') { // name and value given, set cookie
        options = options || {};
        if (value === null) {
            value = '';
            options.expires = -1;
        }
        var expires = '';
        if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
            var date;
            if (typeof options.expires == 'number') {
                date = new Date();
                date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
            } else {
                date = options.expires;
            }
            expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
        }
        // CAUTION: Needed to parenthesize options.path and options.domain
        // in the following expressions, otherwise they evaluate to undefined
        // in the packed version for some reason...
        var path = options.path ? '; path=' + (options.path) : '';
        var domain = options.domain ? '; domain=' + (options.domain) : '';
        var secure = options.secure ? '; secure' : '';
        document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
    } else { // only name given, get cookie
        var cookieValue = null;
        if (document.cookie && document.cookie != '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = jQuery.trim(cookies[i]);
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) == (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }
};

/*
 * jQuery sprintf - perl based functionallity for sprintf and friends.
 *
 * Copyright 2008 Carl Furstenberg
 *
 * Released under GPL, BSD, or MIT license.
 * ---------------------------------------------------------------------------
 *  GPL:
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Copyright (c) The Regents of the University of California.
 * All rights reserved.
 *
 * ---------------------------------------------------------------------------
 *  BSD:
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * 
 * ---------------------------------------------------------------------------
 *  MIT:
 *
 * 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.
 * 
 * ---------------------------------------------------------------------------
 *
 *  Version: 0.0.6
 */

/** 
 * Inserts the arguments into the format and returns the formated string
 *
 * @example alert($.vsprintf( "%s %s", [ "Hello", "world" ] ));
 *
 * @param String format the format to use
 * @param Array args the arguments to insert into the format
 * @return String the formated string
 */
jQuery.vsprintf = function jQuery_vsprintf( format, args ) {
    if( format == null ) {
        throw "Not enough arguments for vsprintf";
    }
    if( args == null ) {
        args = [];
    }

    function _sprintf_format( type, value, flags ) {

        // Similar to how perl printf works
        if( value == undefined ) {
            if( type == 's' ) {
                return '';
            } else {
                return '0';
            }
        }

        var result;
        var prefix = '';
        var fill = '';
        var fillchar = ' ';
        if( flags['short'] || flags['long'] || flags['long_long'] ) {
            /* This is pretty ugly, but as JS ignores bit lengths except 
             * somewhat when working with bit operators. 
             * So we fake a bit :) */
            switch( type ) {
            case 'e':
            case 'f':
            case 'G':
            case 'E':
            case 'G':
            case 'd': /* signed */
                if( flags['short'] ) {
                    if( value >= 32767 ) {
                        value = 32767;
                    } else if( value <= -32767-1 ) {
                        value = -32767-1;
                    }
                } else if ( flags['long'] ) {
                    if( value >= 2147483647 ) {
                        value = 2147483647;
                    } else if( value <= -2147483647-1 ) {
                        value = -2147483647-1;
                    }
                } else /*if ( flags['long_long'] )*/ {
                    if( value >= 9223372036854775807 ) {
                        value = 9223372036854775807;
                    } else if( value <= -9223372036854775807-1 ) {
                        value = -9223372036854775807-1;
                    }
                }
                break;
            case 'X':
            case 'B':
            case 'u':
            case 'o':
            case 'x': 
            case 'b': /* unsigned */
                if( value < 0 ) {
                    /* Pretty ugly, but one only solution */
                    value = Math.abs( value ) - 1;
                }
                if( flags['short'] ) {
                    if( value >= 65535 ) {
                        value = 65535;
                    } 
                } else if ( flags['long'] ) {
                    if( value >= 4294967295 ) {
                        value = 4294967295;
                    } 

                } else /*if ( flags['long_long'] )*/ {
                    if( value >= 18446744073709551615 ) {
                        value = 18446744073709551615;
                    } 

                }
                break;
            }
        }
        switch( type ) {
        case 'c':
            result = String.fromCharCode( parseInt( value ) );
            break;
        case 's':
            result = value.toString();
            break;
        case 'd':
            result = (new Number( parseInt( value ) ) ).toString();
            break;
        case 'u':
            result = (new Number( parseInt( value ) ) ).toString();
            break;
        case 'o':
            result = (new Number( parseInt( value ) ) ).toString(8);
            break;
        case 'x':
            result = (new Number( parseInt( value ) ) ).toString(16);
            break;
        case 'B':
        case 'b':
            result = (new Number( parseInt( value ) ) ).toString(2);
            break;
        case 'e':
            var digits = flags['precision'] ? flags['precision'] : 6;
            result = (new Number( value ) ).toExponential( digits ).toString();
            break;
        case 'f':
            var digits = flags['precision'] ? flags['precision'] : 6;
            result = (new Number( value ) ).toFixed( digits ).toString();
            break;
        case 'g':
            var digits = flags['precision'] ? flags['precision'] : 6;
            result = (new Number( value ) ).toPrecision( digits ).toString();
            break;
        case 'X':
            result = (new Number( parseInt( value ) ) ).toString(16).toUpperCase();
            break;
        case 'E':
            var digits = flags['precision'] ? flags['precision'] : 6;
            result = (new Number( value ) ).toExponential( digits ).toString().toUpperCase();
            break;
        case 'G':
            var digits = flags['precision'] ? flags['precision'] : 6;
            result = (new Number( value ) ).toPrecision( digits ).toString().toUpperCase();
            break;
        }

        if(flags['+'] && parseFloat( value ) > 0 && ['d','e','f','g','E','G'].indexOf(type) != -1 ) {
            prefix = '+';
        }

        if(flags[' '] && parseFloat( value ) > 0 && ['d','e','f','g','E','G'].indexOf(type) != -1 ) {
            prefix = ' ';
        }

        if( flags['#'] && parseInt( value ) != 0 ) {
            switch(type) {
            case 'o':
                prefix = '0';
                break;
            case 'x':
            case 'X':
                prefix = '0x';
                break;
            case 'b':
                prefix = '0b';
                break;
            case 'B':
                prefix = '0B';
                break;
            }
        }

        if( flags['0'] && !flags['-'] ) {
            fillchar = '0';
        }

        if( flags['width'] && flags['width'] > ( result.length + prefix.length ) ) {
            var tofill = flags['width'] - result.length - prefix.length;
            for( var i = 0; i < tofill; ++i ) {
                fill += fillchar;
            }
        }

        if( flags['-'] && !flags['0'] ) {
            result += fill;
        } else {
            result = fill + result;
        }

        return prefix + result;
    };

    var result = "";

    var index = 0;
    var current_index = 0;
    var flags = {
        'long': false,
        'short': false,
        'long_long': false
    };
    var in_operator = false;
    var relative = false;
    var precision = false;
    var fixed = false;
    var vector = false;
    var bitwidth = false;
    var vector_delimiter = '.';

    for( var i = 0; i < format.length; ++i ) {
        var current_char = format.charAt(i);
        if( in_operator ) {
            // backward compat
            switch( current_char ) {
            case 'i':
                current_char = 'd';
                break;
            case 'D':
                flags['long'] = true;
                current_char = 'd';
                break;
            case 'U':
                flags['long'] = true;
                current_char = 'u';
                break;
            case 'O':
                flags['long'] = true;
                current_char = 'o';
                break;
            case 'F':
                current_char = 'f';
                break;
            }
            switch( current_char ) {
            case 'c':
            case 's':
            case 'd':
            case 'u':
            case 'o':
            case 'x':
            case 'e':
            case 'f':
            case 'g':
            case 'X':
            case 'E':
            case 'G':
            case 'b':
            case 'B':
                var value = args[current_index];
                if( vector ) {
                    var fixed_value = value;
                    if( value instanceof Array ) {
                        // if the value is an array, assume to work on it directly
                        fixed_value = value;
                    } else if ( typeof(value) == 'string' || value instanceof String ) {
                        // normal behavour, assume string is a bitmap
                        fixed_value = value.split('').map( function( value ) { return value.charCodeAt(); } );
                    } else if ( ( typeof(value) == 'number' || value instanceof Number ) && flags['bitwidth'] ) {
                        // if we defined a width, assume we want to vectorize the bits directly
                        fixed_value = [];
                        do {
                            fixed_value.unshift( value & ~(~0 << flags['bitwidth'] ) );
                        } while( value >>>= flags['bitwidth'] );
                    } else {
                        fixed_value = value.toString().split('').map( function( value ) { return value.charCodeAt(); } );

                    }
                    result += fixed_value.map( function( value ) {
                            return _sprintf_format( current_char, value, flags );
                        }).join( vector_delimiter );
                } else {
                    result += _sprintf_format( current_char, value, flags );
                }
                if( !fixed ) {
                    ++index;
                }
                current_index = index;
                flags = {};
                relative = false;
                in_operator = false;
                precision = false;
                fixed = false;
                vector = false;
                bitwidth = false;
                vector_delimiter = '.';
                break;
            case 'v':
                vector = true;
                break;
            case ' ':
            case '0':
            case '-':
            case '+':
            case '#':
                flags[current_char] = true;
                break;
            case '*':
                relative = true;
                break;
            case '.':
                precision = true;
                break;
            case '@':
                bitwidth = true;
                break;
            case 'l':
                if( flags['long'] ) {
                    flags['long_long'] = true;
                    flags['long'] = false;
                } else {
                    flags['long'] = true;
                    flags['long_long'] = false;
                }
                flags['short'] = false;
                break;
            case 'q':
            case 'L':
                flags['long_long'] = true;
                flags['long'] = false;
                flags['short'] = false;
                break;
            case 'h':
                flags['short'] = true;
                flags['long'] = false;
                flags['long_long'] = false;
                break;
            }
            if( /\d/.test( current_char ) ) {
                var num = parseInt( format.substr( i ) );
                var len = num.toString().length;
                i += len - 1;
                var next = format.charAt( i  + 1 );
                if( next == '$' ) {
                    if( num < 0 || num > args.length ) {
                        throw "out of bound";
                    }
                    if( relative ) {
                        if( precision ) {
                            flags['precision'] = args[num - 1];
                            precision = false;
                        } else if( format.charAt( i + 2 ) == 'v' ) {
                            vector_delimiter = args[num - 1];
                        }else {
                            flags['width'] = args[num - 1];
                        }
                        relative = false;
                    } else {
                        fixed = true;
                        current_index = num - 1;
                    }
                    ++i;
                } else if( precision ) {
                    flags['precision'] = num;
                    precision = false;
                } else if( bitwidth ) {
                    flags['bitwidth'] = num;
                    bitwidth = false;
                } else {
                    flags['width'] = num;
                }
            } else if ( relative && !/\d/.test( format.charAt( i + 1 ) ) ) {
                if( precision ) {
                    flags['precision'] = args[current_index];
                    precision = false;
                } else if( format.charAt( i + 1 ) == 'v' ) {
                    vector_delimiter = args[current_index];
                } else {
                    flags['width'] = args[current_index];
                }
                ++index;
                if( !fixed ) {
                    current_index++;
                }
                relative = false;
            }
        } else {
            if( current_char == '%' ) {
                // If the next character is an %, then we have an escaped %, 
                // we'll take this as an exception to the normal lookup, as
                // we don't want/need to process this.
                if( format.charAt(i+1) == '%' ) {
                    result += '%';
                    ++i;
                    continue;
                }
                in_operator = true;
                continue;
            } else {
                result += current_char;
                continue;
            }
        }
    }
    return result;
};

/** 
 * Inserts the arguments into the format and returns the formated string
 *
 * @example alert($.sprintf( "%s %s", "Hello", "world" ));
 *
 * @param String format the format to use
 * @param Object args... the arguments to insert into the format
 * @return String the formated string
 */

jQuery.sprintf = function jQuery_sprintf() {
    if( arguments.length == 0 ) {
        throw "Not enough arguments for sprintf";
    }

    var args = Array.prototype.slice.call(arguments);
    var format = args.shift();

    return jQuery.vsprintf( format, args ); 
};

/** 
 * Inserts the arguments into the format and appends the formated string
 * to the objects in question.
 *
 * @example $('p').printf( "%d <strong>%s</strong>", 2, "world" );
 *
 * @before <p>Hello</p>
 *
 * @after <p>Hello2 <strong>world</strong></p>
 *
 * @param String format the format to use
 * @param Object args... the arguments to insert into the format
 */

jQuery.fn.printf = function jQuery_fn_printf() {
    if( arguments.length == 0 ) {
        throw "Not enough arguments for sprintf";
    }
    var args = Array.prototype.slice.call(arguments);
    var format = args.shift();

    return this.append( jQuery.vsprintf( format, args ) );
};

/** 
 * Inserts the arguments into the format and appends the formated string
 * to the objects in question.
 *
 * @example $('p').vprintf( "%d <strong>%s</strong>", [ 2, "world" ] );
 *
 * @before <p>Hello</p>
 *
 * @after <p>Hello2 <strong>world</strong></p>
 *
 * @param String format the format to use
 * @param Array args the arguments to insert into the format
 */
jQuery.fn.vprintf = function jQuery_fn_vprintf( format, args ) {
    if( arguments.length == 0 ) {
        throw "Not enough arguments for sprintf";
    }

    return this.append( jQuery.vsprintf( format, args  ) );
};

/** 
 * Formats the objects html in question and replaces the content 
 * with the formated content
 *
 * @example $('p').vformat( [ "Hello", "world" ] );
 *
 * @before <p>%s %s</p>
 *
 * @after <p>Hello world</p>
 *
 * @param Array args the arguments to insert into the format
 */

jQuery.fn.vformat = function jQuery_fn_vformat( args ) {
    if( arguments.length == 0 ) {
        throw "Not enough arguments for sprintf";
    }
    return this.each( function() { 
            self = jQuery(this);
            self.html(  jQuery.vsprintf( self.html(), args ) )
        }
    ); 
}

/** 
 * Formats the objects html in question and replaces the content 
 * with the formated content
 *
 * @example $('p').format( "Hello", "world" );
 *
 * @before <p>%s %s</p>
 *
 * @after <p>Hello world</p>
 *
 * @param Object args... the arguments to insert into the format
 */
jQuery.fn.format = function jQuery_fn_format() {
    if( arguments.length == 0 ) {
        throw "Not enough arguments for sprintf";
    }
    var args = Array.prototype.slice.call(arguments);
    return this.each( function() { 
            self = jQuery(this);
            self.html(  jQuery.vsprintf( self.html(), args ) )
        }
    ); 
}

/** 
 * Inserts the arguments into the format and prints formated string 
 * to console or dump
 *
 * @example $.printf( "%s %s", "Hello", "world" );
 *
 * @param String format the format to use
 * @param Object args... the arguments to insert into the format
 */
jQuery.printf = function jQuery_printf() {
    if( arguments.length == 0 ) {
        throw "Not enough arguments for sprintf";
    }
    var args = Array.prototype.slice.call(arguments);
    var format = args.shift();
    var ret = jQuery.vsprintf( format, args );

    if( window.console ) {
        window.console.info( ret );
    } else {
        window.dump( ret ); 
    }
};
/** 
 * Inserts the arguments into the format and prints formated string 
 * to console or dump
 *
 * @example $.vprintf( "%s %s", [ "Hello", "world" ] );
 *
 * @param String format the format to use
 * @param Array args the arguments to insert into the format
 */
jQuery.vprintf = function jQuery_vprintf( format, args ) {
    if( arguments.length == 0 ) {
        throw "Not enough arguments for sprintf";
    }
    var ret = jQuery.vsprintf( format, args );

    if( window.console ) {
        window.console.info( ret );
    } else {
        window.dump( ret ); 
    }
};

