text: /*
   * jQuery sprintf - perl based functionallity for sprintf and friends.
   *
   * Copyright © 2008 Carl Fürstenberg
   *
   * 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 ); 
  	}
  
  };
  
  