" && !rtbody.test( elem ) ?
+ tmp :
+ 0;
+
+ j = elem && elem.childNodes.length;
+ while ( j-- ) {
+ if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) {
+ elem.removeChild( tbody );
+ }
+ }
+ }
+
+ jQuery.merge( nodes, tmp.childNodes );
+
+ // Fix #12392 for WebKit and IE > 9
+ tmp.textContent = "";
+
+ // Fix #12392 for oldIE
+ while ( tmp.firstChild ) {
+ tmp.removeChild( tmp.firstChild );
+ }
+
+ // Remember the top-level container for proper cleanup
+ tmp = safe.lastChild;
+ }
+ }
+ }
+
+ // Fix #11356: Clear elements from fragment
+ if ( tmp ) {
+ safe.removeChild( tmp );
+ }
+
+ // Reset defaultChecked for any radios and checkboxes
+ // about to be appended to the DOM in IE 6/7 (#8060)
+ if ( !jQuery.support.appendChecked ) {
+ jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked );
+ }
+
+ i = 0;
+ while ( (elem = nodes[ i++ ]) ) {
+
+ // #4087 - If origin and destination elements are the same, and this is
+ // that element, do not do anything
+ if ( selection && jQuery.inArray( elem, selection ) !== -1 ) {
+ continue;
+ }
+
+ contains = jQuery.contains( elem.ownerDocument, elem );
+
+ // Append to fragment
+ tmp = getAll( safe.appendChild( elem ), "script" );
+
+ // Preserve script evaluation history
+ if ( contains ) {
+ setGlobalEval( tmp );
+ }
+
+ // Capture executables
+ if ( scripts ) {
+ j = 0;
+ while ( (elem = tmp[ j++ ]) ) {
+ if ( rscriptType.test( elem.type || "" ) ) {
+ scripts.push( elem );
+ }
+ }
+ }
+ }
+
+ tmp = null;
+
+ return safe;
+ },
+
+ cleanData: function( elems, /* internal */ acceptData ) {
+ var data, id, elem, type,
+ i = 0,
+ internalKey = jQuery.expando,
+ cache = jQuery.cache,
+ deleteExpando = jQuery.support.deleteExpando,
+ special = jQuery.event.special;
+
+ for ( ; (elem = elems[i]) != null; i++ ) {
+
+ if ( acceptData || jQuery.acceptData( elem ) ) {
+
+ id = elem[ internalKey ];
+ data = id && cache[ id ];
+
+ if ( data ) {
+ if ( data.events ) {
+ for ( type in data.events ) {
+ if ( special[ type ] ) {
+ jQuery.event.remove( elem, type );
+
+ // This is a shortcut to avoid jQuery.event.remove's overhead
+ } else {
+ jQuery.removeEvent( elem, type, data.handle );
+ }
+ }
+ }
+
+ // Remove cache only if it was not already removed by jQuery.event.remove
+ if ( cache[ id ] ) {
+
+ delete cache[ id ];
+
+ // IE does not allow us to delete expando properties from nodes,
+ // nor does it have a removeAttribute function on Document nodes;
+ // we must handle all of these cases
+ if ( deleteExpando ) {
+ delete elem[ internalKey ];
+
+ } else if ( typeof elem.removeAttribute !== "undefined" ) {
+ elem.removeAttribute( internalKey );
+
+ } else {
+ elem[ internalKey ] = null;
+ }
+
+ core_deletedIds.push( id );
+ }
+ }
+ }
+ }
+ }
+});
+var curCSS, getStyles, iframe,
+ ralpha = /alpha\([^)]*\)/i,
+ ropacity = /opacity\s*=\s*([^)]*)/,
+ rposition = /^(top|right|bottom|left)$/,
+ // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
+ // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
+ rdisplayswap = /^(none|table(?!-c[ea]).+)/,
+ rmargin = /^margin/,
+ rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ),
+ rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ),
+ rrelNum = new RegExp( "^([+-])=(" + core_pnum + ")", "i" ),
+ elemdisplay = { BODY: "block" },
+
+ cssShow = { position: "absolute", visibility: "hidden", display: "block" },
+ cssNormalTransform = {
+ letterSpacing: 0,
+ fontWeight: 400
+ },
+
+ cssExpand = [ "Top", "Right", "Bottom", "Left" ],
+ cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
+
+// return a css property mapped to a potentially vendor prefixed property
+function vendorPropName( style, name ) {
+
+ // shortcut for names that are not vendor prefixed
+ if ( name in style ) {
+ return name;
+ }
+
+ // check for vendor prefixed names
+ var capName = name.charAt(0).toUpperCase() + name.slice(1),
+ origName = name,
+ i = cssPrefixes.length;
+
+ while ( i-- ) {
+ name = cssPrefixes[ i ] + capName;
+ if ( name in style ) {
+ return name;
+ }
+ }
+
+ return origName;
+}
+
+function isHidden( elem, el ) {
+ // isHidden might be called from jQuery#filter function;
+ // in that case, element will be second argument
+ elem = el || elem;
+ return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
+}
+
+function showHide( elements, show ) {
+ var elem,
+ values = [],
+ index = 0,
+ length = elements.length;
+
+ for ( ; index < length; index++ ) {
+ elem = elements[ index ];
+ if ( !elem.style ) {
+ continue;
+ }
+ values[ index ] = jQuery._data( elem, "olddisplay" );
+ if ( show ) {
+ // Reset the inline display of this element to learn if it is
+ // being hidden by cascaded rules or not
+ if ( !values[ index ] && elem.style.display === "none" ) {
+ elem.style.display = "";
+ }
+
+ // Set elements which have been overridden with display: none
+ // in a stylesheet to whatever the default browser style is
+ // for such an element
+ if ( elem.style.display === "" && isHidden( elem ) ) {
+ values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) );
+ }
+ } else if ( !values[ index ] && !isHidden( elem ) ) {
+ jQuery._data( elem, "olddisplay", jQuery.css( elem, "display" ) );
+ }
+ }
+
+ // Set the display of most of the elements in a second loop
+ // to avoid the constant reflow
+ for ( index = 0; index < length; index++ ) {
+ elem = elements[ index ];
+ if ( !elem.style ) {
+ continue;
+ }
+ if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
+ elem.style.display = show ? values[ index ] || "" : "none";
+ }
+ }
+
+ return elements;
+}
+
+jQuery.fn.extend({
+ css: function( name, value ) {
+ return jQuery.access( this, function( elem, name, value ) {
+ var styles, len,
+ map = {},
+ i = 0;
+
+ if ( jQuery.isArray( name ) ) {
+ styles = getStyles( elem );
+ len = name.length;
+
+ for ( ; i < len; i++ ) {
+ map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
+ }
+
+ return map;
+ }
+
+ return value !== undefined ?
+ jQuery.style( elem, name, value ) :
+ jQuery.css( elem, name );
+ }, name, value, arguments.length > 1 );
+ },
+ show: function() {
+ return showHide( this, true );
+ },
+ hide: function() {
+ return showHide( this );
+ },
+ toggle: function( state ) {
+ var bool = typeof state === "boolean";
+
+ return this.each(function() {
+ if ( bool ? state : isHidden( this ) ) {
+ jQuery( this ).show();
+ } else {
+ jQuery( this ).hide();
+ }
+ });
+ }
+});
+
+jQuery.extend({
+ // Add in style property hooks for overriding the default
+ // behavior of getting and setting a style property
+ cssHooks: {
+ opacity: {
+ get: function( elem, computed ) {
+ if ( computed ) {
+ // We should always get a number back from opacity
+ var ret = curCSS( elem, "opacity" );
+ return ret === "" ? "1" : ret;
+ }
+ }
+ }
+ },
+
+ // Exclude the following css properties to add px
+ cssNumber: {
+ "columnCount": true,
+ "fillOpacity": true,
+ "fontWeight": true,
+ "lineHeight": true,
+ "opacity": true,
+ "orphans": true,
+ "widows": true,
+ "zIndex": true,
+ "zoom": true
+ },
+
+ // Add in properties whose names you wish to fix before
+ // setting or getting the value
+ cssProps: {
+ // normalize float css property
+ "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
+ },
+
+ // Get and set the style property on a DOM Node
+ style: function( elem, name, value, extra ) {
+ // Don't set styles on text and comment nodes
+ if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
+ return;
+ }
+
+ // Make sure that we're working with the right name
+ var ret, type, hooks,
+ origName = jQuery.camelCase( name ),
+ style = elem.style;
+
+ name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
+
+ // gets hook for the prefixed version
+ // followed by the unprefixed version
+ hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+ // Check if we're setting a value
+ if ( value !== undefined ) {
+ type = typeof value;
+
+ // convert relative number strings (+= or -=) to relative numbers. #7345
+ if ( type === "string" && (ret = rrelNum.exec( value )) ) {
+ value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
+ // Fixes bug #9237
+ type = "number";
+ }
+
+ // Make sure that NaN and null values aren't set. See: #7116
+ if ( value == null || type === "number" && isNaN( value ) ) {
+ return;
+ }
+
+ // If a number was passed in, add 'px' to the (except for certain CSS properties)
+ if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
+ value += "px";
+ }
+
+ // Fixes #8908, it can be done more correctly by specifing setters in cssHooks,
+ // but it would mean to define eight (for every problematic property) identical functions
+ if ( !jQuery.support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) {
+ style[ name ] = "inherit";
+ }
+
+ // If a hook was provided, use that value, otherwise just set the specified value
+ if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
+
+ // Wrapped to prevent IE from throwing errors when 'invalid' values are provided
+ // Fixes bug #5509
+ try {
+ style[ name ] = value;
+ } catch(e) {}
+ }
+
+ } else {
+ // If a hook was provided get the non-computed value from there
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
+ return ret;
+ }
+
+ // Otherwise just get the value from the style object
+ return style[ name ];
+ }
+ },
+
+ css: function( elem, name, extra, styles ) {
+ var val, num, hooks,
+ origName = jQuery.camelCase( name );
+
+ // Make sure that we're working with the right name
+ name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
+
+ // gets hook for the prefixed version
+ // followed by the unprefixed version
+ hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+ // If a hook was provided get the computed value from there
+ if ( hooks && "get" in hooks ) {
+ val = hooks.get( elem, true, extra );
+ }
+
+ // Otherwise, if a way to get the computed value exists, use that
+ if ( val === undefined ) {
+ val = curCSS( elem, name, styles );
+ }
+
+ //convert "normal" to computed value
+ if ( val === "normal" && name in cssNormalTransform ) {
+ val = cssNormalTransform[ name ];
+ }
+
+ // Return, converting to number if forced or a qualifier was provided and val looks numeric
+ if ( extra ) {
+ num = parseFloat( val );
+ return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
+ }
+ return val;
+ },
+
+ // A method for quickly swapping in/out CSS properties to get correct calculations
+ swap: function( elem, options, callback, args ) {
+ var ret, name,
+ old = {};
+
+ // Remember the old values, and insert the new ones
+ for ( name in options ) {
+ old[ name ] = elem.style[ name ];
+ elem.style[ name ] = options[ name ];
+ }
+
+ ret = callback.apply( elem, args || [] );
+
+ // Revert the old values
+ for ( name in options ) {
+ elem.style[ name ] = old[ name ];
+ }
+
+ return ret;
+ }
+});
+
+// NOTE: we've included the "window" in window.getComputedStyle
+// because jsdom on node.js will break without it.
+if ( window.getComputedStyle ) {
+ getStyles = function( elem ) {
+ return window.getComputedStyle( elem, null );
+ };
+
+ curCSS = function( elem, name, _computed ) {
+ var width, minWidth, maxWidth,
+ computed = _computed || getStyles( elem ),
+
+ // getPropertyValue is only needed for .css('filter') in IE9, see #12537
+ ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined,
+ style = elem.style;
+
+ if ( computed ) {
+
+ if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
+ ret = jQuery.style( elem, name );
+ }
+
+ // A tribute to the "awesome hack by Dean Edwards"
+ // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right
+ // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
+ // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
+ if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
+
+ // Remember the original values
+ width = style.width;
+ minWidth = style.minWidth;
+ maxWidth = style.maxWidth;
+
+ // Put in the new values to get a computed value out
+ style.minWidth = style.maxWidth = style.width = ret;
+ ret = computed.width;
+
+ // Revert the changed values
+ style.width = width;
+ style.minWidth = minWidth;
+ style.maxWidth = maxWidth;
+ }
+ }
+
+ return ret;
+ };
+} else if ( document.documentElement.currentStyle ) {
+ getStyles = function( elem ) {
+ return elem.currentStyle;
+ };
+
+ curCSS = function( elem, name, _computed ) {
+ var left, rs, rsLeft,
+ computed = _computed || getStyles( elem ),
+ ret = computed ? computed[ name ] : undefined,
+ style = elem.style;
+
+ // Avoid setting ret to empty string here
+ // so we don't default to auto
+ if ( ret == null && style && style[ name ] ) {
+ ret = style[ name ];
+ }
+
+ // From the awesome hack by Dean Edwards
+ // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
+
+ // If we're not dealing with a regular pixel number
+ // but a number that has a weird ending, we need to convert it to pixels
+ // but not position css attributes, as those are proportional to the parent element instead
+ // and we can't measure the parent instead because it might trigger a "stacking dolls" problem
+ if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {
+
+ // Remember the original values
+ left = style.left;
+ rs = elem.runtimeStyle;
+ rsLeft = rs && rs.left;
+
+ // Put in the new values to get a computed value out
+ if ( rsLeft ) {
+ rs.left = elem.currentStyle.left;
+ }
+ style.left = name === "fontSize" ? "1em" : ret;
+ ret = style.pixelLeft + "px";
+
+ // Revert the changed values
+ style.left = left;
+ if ( rsLeft ) {
+ rs.left = rsLeft;
+ }
+ }
+
+ return ret === "" ? "auto" : ret;
+ };
+}
+
+function setPositiveNumber( elem, value, subtract ) {
+ var matches = rnumsplit.exec( value );
+ return matches ?
+ // Guard against undefined "subtract", e.g., when used as in cssHooks
+ Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
+ value;
+}
+
+function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
+ var i = extra === ( isBorderBox ? "border" : "content" ) ?
+ // If we already have the right measurement, avoid augmentation
+ 4 :
+ // Otherwise initialize for horizontal or vertical properties
+ name === "width" ? 1 : 0,
+
+ val = 0;
+
+ for ( ; i < 4; i += 2 ) {
+ // both box models exclude margin, so add it if we want it
+ if ( extra === "margin" ) {
+ val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
+ }
+
+ if ( isBorderBox ) {
+ // border-box includes padding, so remove it if we want content
+ if ( extra === "content" ) {
+ val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+ }
+
+ // at this point, extra isn't border nor margin, so remove border
+ if ( extra !== "margin" ) {
+ val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+ }
+ } else {
+ // at this point, extra isn't content, so add padding
+ val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+
+ // at this point, extra isn't content nor padding, so add border
+ if ( extra !== "padding" ) {
+ val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+ }
+ }
+ }
+
+ return val;
+}
+
+function getWidthOrHeight( elem, name, extra ) {
+
+ // Start with offset property, which is equivalent to the border-box value
+ var valueIsBorderBox = true,
+ val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
+ styles = getStyles( elem ),
+ isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
+
+ // some non-html elements return undefined for offsetWidth, so check for null/undefined
+ // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
+ // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
+ if ( val <= 0 || val == null ) {
+ // Fall back to computed then uncomputed css if necessary
+ val = curCSS( elem, name, styles );
+ if ( val < 0 || val == null ) {
+ val = elem.style[ name ];
+ }
+
+ // Computed unit is not pixels. Stop here and return.
+ if ( rnumnonpx.test(val) ) {
+ return val;
+ }
+
+ // we need the check for style in case a browser which returns unreliable values
+ // for getComputedStyle silently falls back to the reliable elem.style
+ valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] );
+
+ // Normalize "", auto, and prepare for extra
+ val = parseFloat( val ) || 0;
+ }
+
+ // use the active box-sizing model to add/subtract irrelevant styles
+ return ( val +
+ augmentWidthOrHeight(
+ elem,
+ name,
+ extra || ( isBorderBox ? "border" : "content" ),
+ valueIsBorderBox,
+ styles
+ )
+ ) + "px";
+}
+
+// Try to determine the default display value of an element
+function css_defaultDisplay( nodeName ) {
+ var doc = document,
+ display = elemdisplay[ nodeName ];
+
+ if ( !display ) {
+ display = actualDisplay( nodeName, doc );
+
+ // If the simple way fails, read from inside an iframe
+ if ( display === "none" || !display ) {
+ // Use the already-created iframe if possible
+ iframe = ( iframe ||
+ jQuery("")
+ .css( "cssText", "display:block !important" )
+ ).appendTo( doc.documentElement );
+
+ // Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
+ doc = ( iframe[0].contentWindow || iframe[0].contentDocument ).document;
+ doc.write("");
+ doc.close();
+
+ display = actualDisplay( nodeName, doc );
+ iframe.detach();
+ }
+
+ // Store the correct default display
+ elemdisplay[ nodeName ] = display;
+ }
+
+ return display;
+}
+
+// Called ONLY from within css_defaultDisplay
+function actualDisplay( name, doc ) {
+ var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
+ display = jQuery.css( elem[0], "display" );
+ elem.remove();
+ return display;
+}
+
+jQuery.each([ "height", "width" ], function( i, name ) {
+ jQuery.cssHooks[ name ] = {
+ get: function( elem, computed, extra ) {
+ if ( computed ) {
+ // certain elements can have dimension info if we invisibly show them
+ // however, it must have a current display style that would benefit from this
+ return elem.offsetWidth === 0 && rdisplayswap.test( jQuery.css( elem, "display" ) ) ?
+ jQuery.swap( elem, cssShow, function() {
+ return getWidthOrHeight( elem, name, extra );
+ }) :
+ getWidthOrHeight( elem, name, extra );
+ }
+ },
+
+ set: function( elem, value, extra ) {
+ var styles = extra && getStyles( elem );
+ return setPositiveNumber( elem, value, extra ?
+ augmentWidthOrHeight(
+ elem,
+ name,
+ extra,
+ jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
+ styles
+ ) : 0
+ );
+ }
+ };
+});
+
+if ( !jQuery.support.opacity ) {
+ jQuery.cssHooks.opacity = {
+ get: function( elem, computed ) {
+ // IE uses filters for opacity
+ return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
+ ( 0.01 * parseFloat( RegExp.$1 ) ) + "" :
+ computed ? "1" : "";
+ },
+
+ set: function( elem, value ) {
+ var style = elem.style,
+ currentStyle = elem.currentStyle,
+ opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
+ filter = currentStyle && currentStyle.filter || style.filter || "";
+
+ // IE has trouble with opacity if it does not have layout
+ // Force it by setting the zoom level
+ style.zoom = 1;
+
+ // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
+ // if value === "", then remove inline opacity #12685
+ if ( ( value >= 1 || value === "" ) &&
+ jQuery.trim( filter.replace( ralpha, "" ) ) === "" &&
+ style.removeAttribute ) {
+
+ // Setting style.filter to null, "" & " " still leave "filter:" in the cssText
+ // if "filter:" is present at all, clearType is disabled, we want to avoid this
+ // style.removeAttribute is IE Only, but so apparently is this code path...
+ style.removeAttribute( "filter" );
+
+ // if there is no filter style applied in a css rule or unset inline opacity, we are done
+ if ( value === "" || currentStyle && !currentStyle.filter ) {
+ return;
+ }
+ }
+
+ // otherwise, set new filter values
+ style.filter = ralpha.test( filter ) ?
+ filter.replace( ralpha, opacity ) :
+ filter + " " + opacity;
+ }
+ };
+}
+
+// These hooks cannot be added until DOM ready because the support test
+// for it is not run until after DOM ready
+jQuery(function() {
+ if ( !jQuery.support.reliableMarginRight ) {
+ jQuery.cssHooks.marginRight = {
+ get: function( elem, computed ) {
+ if ( computed ) {
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+ // Work around by temporarily setting element display to inline-block
+ return jQuery.swap( elem, { "display": "inline-block" },
+ curCSS, [ elem, "marginRight" ] );
+ }
+ }
+ };
+ }
+
+ // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
+ // getComputedStyle returns percent when specified for top/left/bottom/right
+ // rather than make the css module depend on the offset module, we just check for it here
+ if ( !jQuery.support.pixelPosition && jQuery.fn.position ) {
+ jQuery.each( [ "top", "left" ], function( i, prop ) {
+ jQuery.cssHooks[ prop ] = {
+ get: function( elem, computed ) {
+ if ( computed ) {
+ computed = curCSS( elem, prop );
+ // if curCSS returns percentage, fallback to offset
+ return rnumnonpx.test( computed ) ?
+ jQuery( elem ).position()[ prop ] + "px" :
+ computed;
+ }
+ }
+ };
+ });
+ }
+
+});
+
+if ( jQuery.expr && jQuery.expr.filters ) {
+ jQuery.expr.filters.hidden = function( elem ) {
+ return ( elem.offsetWidth === 0 && elem.offsetHeight === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
+ };
+
+ jQuery.expr.filters.visible = function( elem ) {
+ return !jQuery.expr.filters.hidden( elem );
+ };
+}
+
+// These hooks are used by animate to expand properties
+jQuery.each({
+ margin: "",
+ padding: "",
+ border: "Width"
+}, function( prefix, suffix ) {
+ jQuery.cssHooks[ prefix + suffix ] = {
+ expand: function( value ) {
+ var i = 0,
+ expanded = {},
+
+ // assumes a single number if not a string
+ parts = typeof value === "string" ? value.split(" ") : [ value ];
+
+ for ( ; i < 4; i++ ) {
+ expanded[ prefix + cssExpand[ i ] + suffix ] =
+ parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
+ }
+
+ return expanded;
+ }
+ };
+
+ if ( !rmargin.test( prefix ) ) {
+ jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
+ }
+});
+var r20 = /%20/g,
+ rbracket = /\[\]$/,
+ rCRLF = /\r?\n/g,
+ rsubmitterTypes = /^(?:submit|button|image|reset)$/i,
+ rsubmittable = /^(?:input|select|textarea|keygen)/i;
+
+jQuery.fn.extend({
+ serialize: function() {
+ return jQuery.param( this.serializeArray() );
+ },
+ serializeArray: function() {
+ return this.map(function(){
+ // Can add propHook for "elements" to filter or add form elements
+ var elements = jQuery.prop( this, "elements" );
+ return elements ? jQuery.makeArray( elements ) : this;
+ })
+ .filter(function(){
+ var type = this.type;
+ // Use .is(":disabled") so that fieldset[disabled] works
+ return this.name && !jQuery( this ).is( ":disabled" ) &&
+ rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
+ ( this.checked || !manipulation_rcheckableType.test( type ) );
+ })
+ .map(function( i, elem ){
+ var val = jQuery( this ).val();
+
+ return val == null ?
+ null :
+ jQuery.isArray( val ) ?
+ jQuery.map( val, function( val ){
+ return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ }) :
+ { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ }).get();
+ }
+});
+
+//Serialize an array of form elements or a set of
+//key/values into a query string
+jQuery.param = function( a, traditional ) {
+ var prefix,
+ s = [],
+ add = function( key, value ) {
+ // If value is a function, invoke it and return its value
+ value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
+ s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
+ };
+
+ // Set traditional to true for jQuery <= 1.3.2 behavior.
+ if ( traditional === undefined ) {
+ traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
+ }
+
+ // If an array was passed in, assume that it is an array of form elements.
+ if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
+ // Serialize the form elements
+ jQuery.each( a, function() {
+ add( this.name, this.value );
+ });
+
+ } else {
+ // If traditional, encode the "old" way (the way 1.3.2 or older
+ // did it), otherwise encode params recursively.
+ for ( prefix in a ) {
+ buildParams( prefix, a[ prefix ], traditional, add );
+ }
+ }
+
+ // Return the resulting serialization
+ return s.join( "&" ).replace( r20, "+" );
+};
+
+function buildParams( prefix, obj, traditional, add ) {
+ var name;
+
+ if ( jQuery.isArray( obj ) ) {
+ // Serialize array item.
+ jQuery.each( obj, function( i, v ) {
+ if ( traditional || rbracket.test( prefix ) ) {
+ // Treat each array item as a scalar.
+ add( prefix, v );
+
+ } else {
+ // Item is non-scalar (array or object), encode its numeric index.
+ buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
+ }
+ });
+
+ } else if ( !traditional && jQuery.type( obj ) === "object" ) {
+ // Serialize object item.
+ for ( name in obj ) {
+ buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
+ }
+
+ } else {
+ // Serialize scalar item.
+ add( prefix, obj );
+ }
+}
+var
+ // Document location
+ ajaxLocParts,
+ ajaxLocation,
+
+ ajax_nonce = jQuery.now(),
+
+ ajax_rquery = /\?/,
+ rhash = /#.*$/,
+ rts = /([?&])_=[^&]*/,
+ rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
+ // #7653, #8125, #8152: local protocol detection
+ rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
+ rnoContent = /^(?:GET|HEAD)$/,
+ rprotocol = /^\/\//,
+ rurl = /^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,
+
+ // Keep a copy of the old load method
+ _load = jQuery.fn.load,
+
+ /* Prefilters
+ * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
+ * 2) These are called:
+ * - BEFORE asking for a transport
+ * - AFTER param serialization (s.data is a string if s.processData is true)
+ * 3) key is the dataType
+ * 4) the catchall symbol "*" can be used
+ * 5) execution will start with transport dataType and THEN continue down to "*" if needed
+ */
+ prefilters = {},
+
+ /* Transports bindings
+ * 1) key is the dataType
+ * 2) the catchall symbol "*" can be used
+ * 3) selection will start with transport dataType and THEN go to "*" if needed
+ */
+ transports = {},
+
+ // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
+ allTypes = "*/".concat("*");
+
+// #8138, IE may throw an exception when accessing
+// a field from window.location if document.domain has been set
+try {
+ ajaxLocation = location.href;
+} catch( e ) {
+ // Use the href attribute of an A element
+ // since IE will modify it given document.location
+ ajaxLocation = document.createElement( "a" );
+ ajaxLocation.href = "";
+ ajaxLocation = ajaxLocation.href;
+}
+
+// Segment location into parts
+ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
+
+// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
+function addToPrefiltersOrTransports( structure ) {
+
+ // dataTypeExpression is optional and defaults to "*"
+ return function( dataTypeExpression, func ) {
+
+ if ( typeof dataTypeExpression !== "string" ) {
+ func = dataTypeExpression;
+ dataTypeExpression = "*";
+ }
+
+ var dataType,
+ i = 0,
+ dataTypes = dataTypeExpression.toLowerCase().match( core_rnotwhite ) || [];
+
+ if ( jQuery.isFunction( func ) ) {
+ // For each dataType in the dataTypeExpression
+ while ( (dataType = dataTypes[i++]) ) {
+ // Prepend if requested
+ if ( dataType[0] === "+" ) {
+ dataType = dataType.slice( 1 ) || "*";
+ (structure[ dataType ] = structure[ dataType ] || []).unshift( func );
+
+ // Otherwise append
+ } else {
+ (structure[ dataType ] = structure[ dataType ] || []).push( func );
+ }
+ }
+ }
+ };
+}
+
+// Base inspection function for prefilters and transports
+function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
+
+ var inspected = {},
+ seekingTransport = ( structure === transports );
+
+ function inspect( dataType ) {
+ var selected;
+ inspected[ dataType ] = true;
+ jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
+ var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
+ if( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
+ options.dataTypes.unshift( dataTypeOrTransport );
+ inspect( dataTypeOrTransport );
+ return false;
+ } else if ( seekingTransport ) {
+ return !( selected = dataTypeOrTransport );
+ }
+ });
+ return selected;
+ }
+
+ return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
+}
+
+// A special extend for ajax options
+// that takes "flat" options (not to be deep extended)
+// Fixes #9887
+function ajaxExtend( target, src ) {
+ var key, deep,
+ flatOptions = jQuery.ajaxSettings.flatOptions || {};
+
+ for ( key in src ) {
+ if ( src[ key ] !== undefined ) {
+ ( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];
+ }
+ }
+ if ( deep ) {
+ jQuery.extend( true, target, deep );
+ }
+
+ return target;
+}
+
+jQuery.fn.load = function( url, params, callback ) {
+ if ( typeof url !== "string" && _load ) {
+ return _load.apply( this, arguments );
+ }
+
+ var selector, type, response,
+ self = this,
+ off = url.indexOf(" ");
+
+ if ( off >= 0 ) {
+ selector = url.slice( off, url.length );
+ url = url.slice( 0, off );
+ }
+
+ // If it's a function
+ if ( jQuery.isFunction( params ) ) {
+
+ // We assume that it's the callback
+ callback = params;
+ params = undefined;
+
+ // Otherwise, build a param string
+ } else if ( params && typeof params === "object" ) {
+ type = "POST";
+ }
+
+ // If we have elements to modify, make the request
+ if ( self.length > 0 ) {
+ jQuery.ajax({
+ url: url,
+
+ // if "type" variable is undefined, then "GET" method will be used
+ type: type,
+ dataType: "html",
+ data: params
+ }).done(function( responseText ) {
+
+ // Save response for use in complete callback
+ response = arguments;
+
+ self.html( selector ?
+
+ // If a selector was specified, locate the right elements in a dummy div
+ // Exclude scripts to avoid IE 'Permission Denied' errors
+ jQuery("").append( jQuery.parseHTML( responseText ) ).find( selector ) :
+
+ // Otherwise use the full result
+ responseText );
+
+ }).complete( callback && function( jqXHR, status ) {
+ self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
+ });
+ }
+
+ return this;
+};
+
+// Attach a bunch of functions for handling common AJAX events
+jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ){
+ jQuery.fn[ type ] = function( fn ){
+ return this.on( type, fn );
+ };
+});
+
+jQuery.each( [ "get", "post" ], function( i, method ) {
+ jQuery[ method ] = function( url, data, callback, type ) {
+ // shift arguments if data argument was omitted
+ if ( jQuery.isFunction( data ) ) {
+ type = type || callback;
+ callback = data;
+ data = undefined;
+ }
+
+ return jQuery.ajax({
+ url: url,
+ type: method,
+ dataType: type,
+ data: data,
+ success: callback
+ });
+ };
+});
+
+jQuery.extend({
+
+ // Counter for holding the number of active queries
+ active: 0,
+
+ // Last-Modified header cache for next request
+ lastModified: {},
+ etag: {},
+
+ ajaxSettings: {
+ url: ajaxLocation,
+ type: "GET",
+ isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
+ global: true,
+ processData: true,
+ async: true,
+ contentType: "application/x-www-form-urlencoded; charset=UTF-8",
+ /*
+ timeout: 0,
+ data: null,
+ dataType: null,
+ username: null,
+ password: null,
+ cache: null,
+ throws: false,
+ traditional: false,
+ headers: {},
+ */
+
+ accepts: {
+ "*": allTypes,
+ text: "text/plain",
+ html: "text/html",
+ xml: "application/xml, text/xml",
+ json: "application/json, text/javascript"
+ },
+
+ contents: {
+ xml: /xml/,
+ html: /html/,
+ json: /json/
+ },
+
+ responseFields: {
+ xml: "responseXML",
+ text: "responseText"
+ },
+
+ // Data converters
+ // Keys separate source (or catchall "*") and destination types with a single space
+ converters: {
+
+ // Convert anything to text
+ "* text": window.String,
+
+ // Text to html (true = no transformation)
+ "text html": true,
+
+ // Evaluate text as a json expression
+ "text json": jQuery.parseJSON,
+
+ // Parse text as xml
+ "text xml": jQuery.parseXML
+ },
+
+ // For options that shouldn't be deep extended:
+ // you can add your own custom options here if
+ // and when you create one that shouldn't be
+ // deep extended (see ajaxExtend)
+ flatOptions: {
+ url: true,
+ context: true
+ }
+ },
+
+ // Creates a full fledged settings object into target
+ // with both ajaxSettings and settings fields.
+ // If target is omitted, writes into ajaxSettings.
+ ajaxSetup: function( target, settings ) {
+ return settings ?
+
+ // Building a settings object
+ ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
+
+ // Extending ajaxSettings
+ ajaxExtend( jQuery.ajaxSettings, target );
+ },
+
+ ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
+ ajaxTransport: addToPrefiltersOrTransports( transports ),
+
+ // Main method
+ ajax: function( url, options ) {
+
+ // If url is an object, simulate pre-1.5 signature
+ if ( typeof url === "object" ) {
+ options = url;
+ url = undefined;
+ }
+
+ // Force options to be an object
+ options = options || {};
+
+ var transport,
+ // URL without anti-cache param
+ cacheURL,
+ // Response headers
+ responseHeadersString,
+ responseHeaders,
+ // timeout handle
+ timeoutTimer,
+ // Cross-domain detection vars
+ parts,
+ // To know if global events are to be dispatched
+ fireGlobals,
+ // Loop variable
+ i,
+ // Create the final options object
+ s = jQuery.ajaxSetup( {}, options ),
+ // Callbacks context
+ callbackContext = s.context || s,
+ // Context for global events is callbackContext if it is a DOM node or jQuery collection
+ globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
+ jQuery( callbackContext ) :
+ jQuery.event,
+ // Deferreds
+ deferred = jQuery.Deferred(),
+ completeDeferred = jQuery.Callbacks("once memory"),
+ // Status-dependent callbacks
+ statusCode = s.statusCode || {},
+ // Headers (they are sent all at once)
+ requestHeaders = {},
+ requestHeadersNames = {},
+ // The jqXHR state
+ state = 0,
+ // Default abort message
+ strAbort = "canceled",
+ // Fake xhr
+ jqXHR = {
+ readyState: 0,
+
+ // Builds headers hashtable if needed
+ getResponseHeader: function( key ) {
+ var match;
+ if ( state === 2 ) {
+ if ( !responseHeaders ) {
+ responseHeaders = {};
+ while ( (match = rheaders.exec( responseHeadersString )) ) {
+ responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
+ }
+ }
+ match = responseHeaders[ key.toLowerCase() ];
+ }
+ return match == null ? null : match;
+ },
+
+ // Raw string
+ getAllResponseHeaders: function() {
+ return state === 2 ? responseHeadersString : null;
+ },
+
+ // Caches the header
+ setRequestHeader: function( name, value ) {
+ var lname = name.toLowerCase();
+ if ( !state ) {
+ name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
+ requestHeaders[ name ] = value;
+ }
+ return this;
+ },
+
+ // Overrides response content-type header
+ overrideMimeType: function( type ) {
+ if ( !state ) {
+ s.mimeType = type;
+ }
+ return this;
+ },
+
+ // Status-dependent callbacks
+ statusCode: function( map ) {
+ var code;
+ if ( map ) {
+ if ( state < 2 ) {
+ for ( code in map ) {
+ // Lazy-add the new callback in a way that preserves old ones
+ statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
+ }
+ } else {
+ // Execute the appropriate callbacks
+ jqXHR.always( map[ jqXHR.status ] );
+ }
+ }
+ return this;
+ },
+
+ // Cancel the request
+ abort: function( statusText ) {
+ var finalText = statusText || strAbort;
+ if ( transport ) {
+ transport.abort( finalText );
+ }
+ done( 0, finalText );
+ return this;
+ }
+ };
+
+ // Attach deferreds
+ deferred.promise( jqXHR ).complete = completeDeferred.add;
+ jqXHR.success = jqXHR.done;
+ jqXHR.error = jqXHR.fail;
+
+ // Remove hash character (#7531: and string promotion)
+ // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
+ // Handle falsy url in the settings object (#10093: consistency with old signature)
+ // We also use the url parameter if available
+ s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
+
+ // Alias method option to type as per ticket #12004
+ s.type = options.method || options.type || s.method || s.type;
+
+ // Extract dataTypes list
+ s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( core_rnotwhite ) || [""];
+
+ // A cross-domain request is in order when we have a protocol:host:port mismatch
+ if ( s.crossDomain == null ) {
+ parts = rurl.exec( s.url.toLowerCase() );
+ s.crossDomain = !!( parts &&
+ ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
+ ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
+ ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) )
+ );
+ }
+
+ // Convert data if not already a string
+ if ( s.data && s.processData && typeof s.data !== "string" ) {
+ s.data = jQuery.param( s.data, s.traditional );
+ }
+
+ // Apply prefilters
+ inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
+
+ // If request was aborted inside a prefilter, stop there
+ if ( state === 2 ) {
+ return jqXHR;
+ }
+
+ // We can fire global events as of now if asked to
+ fireGlobals = s.global;
+
+ // Watch for a new set of requests
+ if ( fireGlobals && jQuery.active++ === 0 ) {
+ jQuery.event.trigger("ajaxStart");
+ }
+
+ // Uppercase the type
+ s.type = s.type.toUpperCase();
+
+ // Determine if request has content
+ s.hasContent = !rnoContent.test( s.type );
+
+ // Save the URL in case we're toying with the If-Modified-Since
+ // and/or If-None-Match header later on
+ cacheURL = s.url;
+
+ // More options handling for requests with no content
+ if ( !s.hasContent ) {
+
+ // If data is available, append data to url
+ if ( s.data ) {
+ cacheURL = ( s.url += ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
+ // #9682: remove data so that it's not used in an eventual retry
+ delete s.data;
+ }
+
+ // Add anti-cache in url if needed
+ if ( s.cache === false ) {
+ s.url = rts.test( cacheURL ) ?
+
+ // If there is already a '_' parameter, set its value
+ cacheURL.replace( rts, "$1_=" + ajax_nonce++ ) :
+
+ // Otherwise add one to the end
+ cacheURL + ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ajax_nonce++;
+ }
+ }
+
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+ if ( s.ifModified ) {
+ if ( jQuery.lastModified[ cacheURL ] ) {
+ jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
+ }
+ if ( jQuery.etag[ cacheURL ] ) {
+ jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
+ }
+ }
+
+ // Set the correct header, if data is being sent
+ if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
+ jqXHR.setRequestHeader( "Content-Type", s.contentType );
+ }
+
+ // Set the Accepts header for the server, depending on the dataType
+ jqXHR.setRequestHeader(
+ "Accept",
+ s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
+ s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
+ s.accepts[ "*" ]
+ );
+
+ // Check for headers option
+ for ( i in s.headers ) {
+ jqXHR.setRequestHeader( i, s.headers[ i ] );
+ }
+
+ // Allow custom headers/mimetypes and early abort
+ if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
+ // Abort if not done already and return
+ return jqXHR.abort();
+ }
+
+ // aborting is no longer a cancellation
+ strAbort = "abort";
+
+ // Install callbacks on deferreds
+ for ( i in { success: 1, error: 1, complete: 1 } ) {
+ jqXHR[ i ]( s[ i ] );
+ }
+
+ // Get transport
+ transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
+
+ // If no transport, we auto-abort
+ if ( !transport ) {
+ done( -1, "No Transport" );
+ } else {
+ jqXHR.readyState = 1;
+
+ // Send global event
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
+ }
+ // Timeout
+ if ( s.async && s.timeout > 0 ) {
+ timeoutTimer = setTimeout(function() {
+ jqXHR.abort("timeout");
+ }, s.timeout );
+ }
+
+ try {
+ state = 1;
+ transport.send( requestHeaders, done );
+ } catch ( e ) {
+ // Propagate exception as error if not done
+ if ( state < 2 ) {
+ done( -1, e );
+ // Simply rethrow otherwise
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ // Callback for when everything is done
+ function done( status, nativeStatusText, responses, headers ) {
+ var isSuccess, success, error, response, modified,
+ statusText = nativeStatusText;
+
+ // Called once
+ if ( state === 2 ) {
+ return;
+ }
+
+ // State is "done" now
+ state = 2;
+
+ // Clear timeout if it exists
+ if ( timeoutTimer ) {
+ clearTimeout( timeoutTimer );
+ }
+
+ // Dereference transport for early garbage collection
+ // (no matter how long the jqXHR object will be used)
+ transport = undefined;
+
+ // Cache response headers
+ responseHeadersString = headers || "";
+
+ // Set readyState
+ jqXHR.readyState = status > 0 ? 4 : 0;
+
+ // Get response data
+ if ( responses ) {
+ response = ajaxHandleResponses( s, jqXHR, responses );
+ }
+
+ // If successful, handle type chaining
+ if ( status >= 200 && status < 300 || status === 304 ) {
+
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+ if ( s.ifModified ) {
+ modified = jqXHR.getResponseHeader("Last-Modified");
+ if ( modified ) {
+ jQuery.lastModified[ cacheURL ] = modified;
+ }
+ modified = jqXHR.getResponseHeader("etag");
+ if ( modified ) {
+ jQuery.etag[ cacheURL ] = modified;
+ }
+ }
+
+ // If not modified
+ if ( status === 304 ) {
+ isSuccess = true;
+ statusText = "notmodified";
+
+ // If we have data
+ } else {
+ isSuccess = ajaxConvert( s, response );
+ statusText = isSuccess.state;
+ success = isSuccess.data;
+ error = isSuccess.error;
+ isSuccess = !error;
+ }
+ } else {
+ // We extract error from statusText
+ // then normalize statusText and status for non-aborts
+ error = statusText;
+ if ( status || !statusText ) {
+ statusText = "error";
+ if ( status < 0 ) {
+ status = 0;
+ }
+ }
+ }
+
+ // Set data for the fake xhr object
+ jqXHR.status = status;
+ jqXHR.statusText = ( nativeStatusText || statusText ) + "";
+
+ // Success/Error
+ if ( isSuccess ) {
+ deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
+ } else {
+ deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
+ }
+
+ // Status-dependent callbacks
+ jqXHR.statusCode( statusCode );
+ statusCode = undefined;
+
+ if ( fireGlobals ) {
+ globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
+ [ jqXHR, s, isSuccess ? success : error ] );
+ }
+
+ // Complete
+ completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
+
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
+ // Handle the global AJAX counter
+ if ( !( --jQuery.active ) ) {
+ jQuery.event.trigger("ajaxStop");
+ }
+ }
+ }
+
+ return jqXHR;
+ },
+
+ getScript: function( url, callback ) {
+ return jQuery.get( url, undefined, callback, "script" );
+ },
+
+ getJSON: function( url, data, callback ) {
+ return jQuery.get( url, data, callback, "json" );
+ }
+});
+
+/* Handles responses to an ajax request:
+ * - sets all responseXXX fields accordingly
+ * - finds the right dataType (mediates between content-type and expected dataType)
+ * - returns the corresponding response
+ */
+function ajaxHandleResponses( s, jqXHR, responses ) {
+
+ var ct, type, finalDataType, firstDataType,
+ contents = s.contents,
+ dataTypes = s.dataTypes,
+ responseFields = s.responseFields;
+
+ // Fill responseXXX fields
+ for ( type in responseFields ) {
+ if ( type in responses ) {
+ jqXHR[ responseFields[type] ] = responses[ type ];
+ }
+ }
+
+ // Remove auto dataType and get content-type in the process
+ while( dataTypes[ 0 ] === "*" ) {
+ dataTypes.shift();
+ if ( ct === undefined ) {
+ ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
+ }
+ }
+
+ // Check if we're dealing with a known content-type
+ if ( ct ) {
+ for ( type in contents ) {
+ if ( contents[ type ] && contents[ type ].test( ct ) ) {
+ dataTypes.unshift( type );
+ break;
+ }
+ }
+ }
+
+ // Check to see if we have a response for the expected dataType
+ if ( dataTypes[ 0 ] in responses ) {
+ finalDataType = dataTypes[ 0 ];
+ } else {
+ // Try convertible dataTypes
+ for ( type in responses ) {
+ if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
+ finalDataType = type;
+ break;
+ }
+ if ( !firstDataType ) {
+ firstDataType = type;
+ }
+ }
+ // Or just use first one
+ finalDataType = finalDataType || firstDataType;
+ }
+
+ // If we found a dataType
+ // We add the dataType to the list if needed
+ // and return the corresponding response
+ if ( finalDataType ) {
+ if ( finalDataType !== dataTypes[ 0 ] ) {
+ dataTypes.unshift( finalDataType );
+ }
+ return responses[ finalDataType ];
+ }
+}
+
+// Chain conversions given the request and the original response
+function ajaxConvert( s, response ) {
+
+ var conv, conv2, current, tmp,
+ converters = {},
+ i = 0,
+ // Work with a copy of dataTypes in case we need to modify it for conversion
+ dataTypes = s.dataTypes.slice(),
+ prev = dataTypes[ 0 ];
+
+ // Apply the dataFilter if provided
+ if ( s.dataFilter ) {
+ response = s.dataFilter( response, s.dataType );
+ }
+
+ // Create converters map with lowercased keys
+ if ( dataTypes[ 1 ] ) {
+ for ( conv in s.converters ) {
+ converters[ conv.toLowerCase() ] = s.converters[ conv ];
+ }
+ }
+
+ // Convert to each sequential dataType, tolerating list modification
+ for ( ; (current = dataTypes[++i]); ) {
+
+ // There's only work to do if current dataType is non-auto
+ if ( current !== "*" ) {
+
+ // Convert response if prev dataType is non-auto and differs from current
+ if ( prev !== "*" && prev !== current ) {
+
+ // Seek a direct converter
+ conv = converters[ prev + " " + current ] || converters[ "* " + current ];
+
+ // If none found, seek a pair
+ if ( !conv ) {
+ for ( conv2 in converters ) {
+
+ // If conv2 outputs current
+ tmp = conv2.split(" ");
+ if ( tmp[ 1 ] === current ) {
+
+ // If prev can be converted to accepted input
+ conv = converters[ prev + " " + tmp[ 0 ] ] ||
+ converters[ "* " + tmp[ 0 ] ];
+ if ( conv ) {
+ // Condense equivalence converters
+ if ( conv === true ) {
+ conv = converters[ conv2 ];
+
+ // Otherwise, insert the intermediate dataType
+ } else if ( converters[ conv2 ] !== true ) {
+ current = tmp[ 0 ];
+ dataTypes.splice( i--, 0, current );
+ }
+
+ break;
+ }
+ }
+ }
+ }
+
+ // Apply converter (if not an equivalence)
+ if ( conv !== true ) {
+
+ // Unless errors are allowed to bubble, catch and return them
+ if ( conv && s["throws"] ) {
+ response = conv( response );
+ } else {
+ try {
+ response = conv( response );
+ } catch ( e ) {
+ return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
+ }
+ }
+ }
+ }
+
+ // Update prev for next iteration
+ prev = current;
+ }
+ }
+
+ return { state: "success", data: response };
+}
+// Install script dataType
+jQuery.ajaxSetup({
+ accepts: {
+ script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
+ },
+ contents: {
+ script: /(?:java|ecma)script/
+ },
+ converters: {
+ "text script": function( text ) {
+ jQuery.globalEval( text );
+ return text;
+ }
+ }
+});
+
+// Handle cache's special case and global
+jQuery.ajaxPrefilter( "script", function( s ) {
+ if ( s.cache === undefined ) {
+ s.cache = false;
+ }
+ if ( s.crossDomain ) {
+ s.type = "GET";
+ s.global = false;
+ }
+});
+
+// Bind script tag hack transport
+jQuery.ajaxTransport( "script", function(s) {
+
+ // This transport only deals with cross domain requests
+ if ( s.crossDomain ) {
+
+ var script,
+ head = document.head || jQuery("head")[0] || document.documentElement;
+
+ return {
+
+ send: function( _, callback ) {
+
+ script = document.createElement("script");
+
+ script.async = true;
+
+ if ( s.scriptCharset ) {
+ script.charset = s.scriptCharset;
+ }
+
+ script.src = s.url;
+
+ // Attach handlers for all browsers
+ script.onload = script.onreadystatechange = function( _, isAbort ) {
+
+ if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
+
+ // Handle memory leak in IE
+ script.onload = script.onreadystatechange = null;
+
+ // Remove the script
+ if ( script.parentNode ) {
+ script.parentNode.removeChild( script );
+ }
+
+ // Dereference the script
+ script = null;
+
+ // Callback if not abort
+ if ( !isAbort ) {
+ callback( 200, "success" );
+ }
+ }
+ };
+
+ // Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending
+ // Use native DOM manipulation to avoid our domManip AJAX trickery
+ head.insertBefore( script, head.firstChild );
+ },
+
+ abort: function() {
+ if ( script ) {
+ script.onload( undefined, true );
+ }
+ }
+ };
+ }
+});
+var oldCallbacks = [],
+ rjsonp = /(=)\?(?=&|$)|\?\?/;
+
+// Default jsonp settings
+jQuery.ajaxSetup({
+ jsonp: "callback",
+ jsonpCallback: function() {
+ var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( ajax_nonce++ ) );
+ this[ callback ] = true;
+ return callback;
+ }
+});
+
+// Detect, normalize options and install callbacks for jsonp requests
+jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
+
+ var callbackName, overwritten, responseContainer,
+ jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
+ "url" :
+ typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data"
+ );
+
+ // Handle iff the expected data type is "jsonp" or we have a parameter to set
+ if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
+
+ // Get callback name, remembering preexisting value associated with it
+ callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
+ s.jsonpCallback() :
+ s.jsonpCallback;
+
+ // Insert callback into url or form data
+ if ( jsonProp ) {
+ s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
+ } else if ( s.jsonp !== false ) {
+ s.url += ( ajax_rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
+ }
+
+ // Use data converter to retrieve json after script execution
+ s.converters["script json"] = function() {
+ if ( !responseContainer ) {
+ jQuery.error( callbackName + " was not called" );
+ }
+ return responseContainer[ 0 ];
+ };
+
+ // force json dataType
+ s.dataTypes[ 0 ] = "json";
+
+ // Install callback
+ overwritten = window[ callbackName ];
+ window[ callbackName ] = function() {
+ responseContainer = arguments;
+ };
+
+ // Clean-up function (fires after converters)
+ jqXHR.always(function() {
+ // Restore preexisting value
+ window[ callbackName ] = overwritten;
+
+ // Save back as free
+ if ( s[ callbackName ] ) {
+ // make sure that re-using the options doesn't screw things around
+ s.jsonpCallback = originalSettings.jsonpCallback;
+
+ // save the callback name for future use
+ oldCallbacks.push( callbackName );
+ }
+
+ // Call if it was a function and we have a response
+ if ( responseContainer && jQuery.isFunction( overwritten ) ) {
+ overwritten( responseContainer[ 0 ] );
+ }
+
+ responseContainer = overwritten = undefined;
+ });
+
+ // Delegate to script
+ return "script";
+ }
+});
+var xhrCallbacks, xhrSupported,
+ xhrId = 0,
+ // #5280: Internet Explorer will keep connections alive if we don't abort on unload
+ xhrOnUnloadAbort = window.ActiveXObject && function() {
+ // Abort all pending requests
+ var key;
+ for ( key in xhrCallbacks ) {
+ xhrCallbacks[ key ]( undefined, true );
+ }
+ };
+
+// Functions to create xhrs
+function createStandardXHR() {
+ try {
+ return new window.XMLHttpRequest();
+ } catch( e ) {}
+}
+
+function createActiveXHR() {
+ try {
+ return new window.ActiveXObject("Microsoft.XMLHTTP");
+ } catch( e ) {}
+}
+
+// Create the request object
+// (This is still attached to ajaxSettings for backward compatibility)
+jQuery.ajaxSettings.xhr = window.ActiveXObject ?
+ /* Microsoft failed to properly
+ * implement the XMLHttpRequest in IE7 (can't request local files),
+ * so we use the ActiveXObject when it is available
+ * Additionally XMLHttpRequest can be disabled in IE7/IE8 so
+ * we need a fallback.
+ */
+ function() {
+ return !this.isLocal && createStandardXHR() || createActiveXHR();
+ } :
+ // For all other browsers, use the standard XMLHttpRequest object
+ createStandardXHR;
+
+// Determine support properties
+xhrSupported = jQuery.ajaxSettings.xhr();
+jQuery.support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
+xhrSupported = jQuery.support.ajax = !!xhrSupported;
+
+// Create transport if the browser can provide an xhr
+if ( xhrSupported ) {
+
+ jQuery.ajaxTransport(function( s ) {
+ // Cross domain only allowed if supported through XMLHttpRequest
+ if ( !s.crossDomain || jQuery.support.cors ) {
+
+ var callback;
+
+ return {
+ send: function( headers, complete ) {
+
+ // Get a new xhr
+ var handle, i,
+ xhr = s.xhr();
+
+ // Open the socket
+ // Passing null username, generates a login popup on Opera (#2865)
+ if ( s.username ) {
+ xhr.open( s.type, s.url, s.async, s.username, s.password );
+ } else {
+ xhr.open( s.type, s.url, s.async );
+ }
+
+ // Apply custom fields if provided
+ if ( s.xhrFields ) {
+ for ( i in s.xhrFields ) {
+ xhr[ i ] = s.xhrFields[ i ];
+ }
+ }
+
+ // Override mime type if needed
+ if ( s.mimeType && xhr.overrideMimeType ) {
+ xhr.overrideMimeType( s.mimeType );
+ }
+
+ // X-Requested-With header
+ // For cross-domain requests, seeing as conditions for a preflight are
+ // akin to a jigsaw puzzle, we simply never set it to be sure.
+ // (it can always be set on a per-request basis or even using ajaxSetup)
+ // For same-domain requests, won't change header if already provided.
+ if ( !s.crossDomain && !headers["X-Requested-With"] ) {
+ headers["X-Requested-With"] = "XMLHttpRequest";
+ }
+
+ // Need an extra try/catch for cross domain requests in Firefox 3
+ try {
+ for ( i in headers ) {
+ xhr.setRequestHeader( i, headers[ i ] );
+ }
+ } catch( err ) {}
+
+ // Do send the request
+ // This may raise an exception which is actually
+ // handled in jQuery.ajax (so no try/catch here)
+ xhr.send( ( s.hasContent && s.data ) || null );
+
+ // Listener
+ callback = function( _, isAbort ) {
+
+ var status,
+ statusText,
+ responseHeaders,
+ responses,
+ xml;
+
+ // Firefox throws exceptions when accessing properties
+ // of an xhr when a network error occurred
+ // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
+ try {
+
+ // Was never called and is aborted or complete
+ if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
+
+ // Only called once
+ callback = undefined;
+
+ // Do not keep as active anymore
+ if ( handle ) {
+ xhr.onreadystatechange = jQuery.noop;
+ if ( xhrOnUnloadAbort ) {
+ delete xhrCallbacks[ handle ];
+ }
+ }
+
+ // If it's an abort
+ if ( isAbort ) {
+ // Abort it manually if needed
+ if ( xhr.readyState !== 4 ) {
+ xhr.abort();
+ }
+ } else {
+ responses = {};
+ status = xhr.status;
+ xml = xhr.responseXML;
+ responseHeaders = xhr.getAllResponseHeaders();
+
+ // Construct response list
+ if ( xml && xml.documentElement /* #4958 */ ) {
+ responses.xml = xml;
+ }
+
+ // When requesting binary data, IE6-9 will throw an exception
+ // on any attempt to access responseText (#11426)
+ if ( typeof xhr.responseText === "string" ) {
+ responses.text = xhr.responseText;
+ }
+
+ // Firefox throws an exception when accessing
+ // statusText for faulty cross-domain requests
+ try {
+ statusText = xhr.statusText;
+ } catch( e ) {
+ // We normalize with Webkit giving an empty statusText
+ statusText = "";
+ }
+
+ // Filter status for non standard behaviors
+
+ // If the request is local and we have data: assume a success
+ // (success with no data won't get notified, that's the best we
+ // can do given current implementations)
+ if ( !status && s.isLocal && !s.crossDomain ) {
+ status = responses.text ? 200 : 404;
+ // IE - #1450: sometimes returns 1223 when it should be 204
+ } else if ( status === 1223 ) {
+ status = 204;
+ }
+ }
+ }
+ } catch( firefoxAccessException ) {
+ if ( !isAbort ) {
+ complete( -1, firefoxAccessException );
+ }
+ }
+
+ // Call complete if needed
+ if ( responses ) {
+ complete( status, statusText, responses, responseHeaders );
+ }
+ };
+
+ if ( !s.async ) {
+ // if we're in sync mode we fire the callback
+ callback();
+ } else if ( xhr.readyState === 4 ) {
+ // (IE6 & IE7) if it's in cache and has been
+ // retrieved directly we need to fire the callback
+ setTimeout( callback );
+ } else {
+ handle = ++xhrId;
+ if ( xhrOnUnloadAbort ) {
+ // Create the active xhrs callbacks list if needed
+ // and attach the unload handler
+ if ( !xhrCallbacks ) {
+ xhrCallbacks = {};
+ jQuery( window ).unload( xhrOnUnloadAbort );
+ }
+ // Add to list of active xhrs callbacks
+ xhrCallbacks[ handle ] = callback;
+ }
+ xhr.onreadystatechange = callback;
+ }
+ },
+
+ abort: function() {
+ if ( callback ) {
+ callback( undefined, true );
+ }
+ }
+ };
+ }
+ });
+}
+var fxNow, timerId,
+ rfxtypes = /^(?:toggle|show|hide)$/,
+ rfxnum = new RegExp( "^(?:([+-])=|)(" + core_pnum + ")([a-z%]*)$", "i" ),
+ rrun = /queueHooks$/,
+ animationPrefilters = [ defaultPrefilter ],
+ tweeners = {
+ "*": [function( prop, value ) {
+ var end, unit,
+ tween = this.createTween( prop, value ),
+ parts = rfxnum.exec( value ),
+ target = tween.cur(),
+ start = +target || 0,
+ scale = 1,
+ maxIterations = 20;
+
+ if ( parts ) {
+ end = +parts[2];
+ unit = parts[3] || ( jQuery.cssNumber[ prop ] ? "" : "px" );
+
+ // We need to compute starting value
+ if ( unit !== "px" && start ) {
+ // Iteratively approximate from a nonzero starting point
+ // Prefer the current property, because this process will be trivial if it uses the same units
+ // Fallback to end or a simple constant
+ start = jQuery.css( tween.elem, prop, true ) || end || 1;
+
+ do {
+ // If previous iteration zeroed out, double until we get *something*
+ // Use a string for doubling factor so we don't accidentally see scale as unchanged below
+ scale = scale || ".5";
+
+ // Adjust and apply
+ start = start / scale;
+ jQuery.style( tween.elem, prop, start + unit );
+
+ // Update scale, tolerating zero or NaN from tween.cur()
+ // And breaking the loop if scale is unchanged or perfect, or if we've just had enough
+ } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
+ }
+
+ tween.unit = unit;
+ tween.start = start;
+ // If a +=/-= token was provided, we're doing a relative animation
+ tween.end = parts[1] ? start + ( parts[1] + 1 ) * end : end;
+ }
+ return tween;
+ }]
+ };
+
+// Animations created synchronously will run synchronously
+function createFxNow() {
+ setTimeout(function() {
+ fxNow = undefined;
+ });
+ return ( fxNow = jQuery.now() );
+}
+
+function createTweens( animation, props ) {
+ jQuery.each( props, function( prop, value ) {
+ var collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
+ index = 0,
+ length = collection.length;
+ for ( ; index < length; index++ ) {
+ if ( collection[ index ].call( animation, prop, value ) ) {
+
+ // we're done with this property
+ return;
+ }
+ }
+ });
+}
+
+function Animation( elem, properties, options ) {
+ var result,
+ stopped,
+ index = 0,
+ length = animationPrefilters.length,
+ deferred = jQuery.Deferred().always( function() {
+ // don't match elem in the :animated selector
+ delete tick.elem;
+ }),
+ tick = function() {
+ if ( stopped ) {
+ return false;
+ }
+ var currentTime = fxNow || createFxNow(),
+ remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
+ // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
+ temp = remaining / animation.duration || 0,
+ percent = 1 - temp,
+ index = 0,
+ length = animation.tweens.length;
+
+ for ( ; index < length ; index++ ) {
+ animation.tweens[ index ].run( percent );
+ }
+
+ deferred.notifyWith( elem, [ animation, percent, remaining ]);
+
+ if ( percent < 1 && length ) {
+ return remaining;
+ } else {
+ deferred.resolveWith( elem, [ animation ] );
+ return false;
+ }
+ },
+ animation = deferred.promise({
+ elem: elem,
+ props: jQuery.extend( {}, properties ),
+ opts: jQuery.extend( true, { specialEasing: {} }, options ),
+ originalProperties: properties,
+ originalOptions: options,
+ startTime: fxNow || createFxNow(),
+ duration: options.duration,
+ tweens: [],
+ createTween: function( prop, end ) {
+ var tween = jQuery.Tween( elem, animation.opts, prop, end,
+ animation.opts.specialEasing[ prop ] || animation.opts.easing );
+ animation.tweens.push( tween );
+ return tween;
+ },
+ stop: function( gotoEnd ) {
+ var index = 0,
+ // if we are going to the end, we want to run all the tweens
+ // otherwise we skip this part
+ length = gotoEnd ? animation.tweens.length : 0;
+ if ( stopped ) {
+ return this;
+ }
+ stopped = true;
+ for ( ; index < length ; index++ ) {
+ animation.tweens[ index ].run( 1 );
+ }
+
+ // resolve when we played the last frame
+ // otherwise, reject
+ if ( gotoEnd ) {
+ deferred.resolveWith( elem, [ animation, gotoEnd ] );
+ } else {
+ deferred.rejectWith( elem, [ animation, gotoEnd ] );
+ }
+ return this;
+ }
+ }),
+ props = animation.props;
+
+ propFilter( props, animation.opts.specialEasing );
+
+ for ( ; index < length ; index++ ) {
+ result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
+ if ( result ) {
+ return result;
+ }
+ }
+
+ createTweens( animation, props );
+
+ if ( jQuery.isFunction( animation.opts.start ) ) {
+ animation.opts.start.call( elem, animation );
+ }
+
+ jQuery.fx.timer(
+ jQuery.extend( tick, {
+ elem: elem,
+ anim: animation,
+ queue: animation.opts.queue
+ })
+ );
+
+ // attach callbacks from options
+ return animation.progress( animation.opts.progress )
+ .done( animation.opts.done, animation.opts.complete )
+ .fail( animation.opts.fail )
+ .always( animation.opts.always );
+}
+
+function propFilter( props, specialEasing ) {
+ var index, name, easing, value, hooks;
+
+ // camelCase, specialEasing and expand cssHook pass
+ for ( index in props ) {
+ name = jQuery.camelCase( index );
+ easing = specialEasing[ name ];
+ value = props[ index ];
+ if ( jQuery.isArray( value ) ) {
+ easing = value[ 1 ];
+ value = props[ index ] = value[ 0 ];
+ }
+
+ if ( index !== name ) {
+ props[ name ] = value;
+ delete props[ index ];
+ }
+
+ hooks = jQuery.cssHooks[ name ];
+ if ( hooks && "expand" in hooks ) {
+ value = hooks.expand( value );
+ delete props[ name ];
+
+ // not quite $.extend, this wont overwrite keys already present.
+ // also - reusing 'index' from above because we have the correct "name"
+ for ( index in value ) {
+ if ( !( index in props ) ) {
+ props[ index ] = value[ index ];
+ specialEasing[ index ] = easing;
+ }
+ }
+ } else {
+ specialEasing[ name ] = easing;
+ }
+ }
+}
+
+jQuery.Animation = jQuery.extend( Animation, {
+
+ tweener: function( props, callback ) {
+ if ( jQuery.isFunction( props ) ) {
+ callback = props;
+ props = [ "*" ];
+ } else {
+ props = props.split(" ");
+ }
+
+ var prop,
+ index = 0,
+ length = props.length;
+
+ for ( ; index < length ; index++ ) {
+ prop = props[ index ];
+ tweeners[ prop ] = tweeners[ prop ] || [];
+ tweeners[ prop ].unshift( callback );
+ }
+ },
+
+ prefilter: function( callback, prepend ) {
+ if ( prepend ) {
+ animationPrefilters.unshift( callback );
+ } else {
+ animationPrefilters.push( callback );
+ }
+ }
+});
+
+function defaultPrefilter( elem, props, opts ) {
+ /*jshint validthis:true */
+ var index, prop, value, length, dataShow, toggle, tween, hooks, oldfire,
+ anim = this,
+ style = elem.style,
+ orig = {},
+ handled = [],
+ hidden = elem.nodeType && isHidden( elem );
+
+ // handle queue: false promises
+ if ( !opts.queue ) {
+ hooks = jQuery._queueHooks( elem, "fx" );
+ if ( hooks.unqueued == null ) {
+ hooks.unqueued = 0;
+ oldfire = hooks.empty.fire;
+ hooks.empty.fire = function() {
+ if ( !hooks.unqueued ) {
+ oldfire();
+ }
+ };
+ }
+ hooks.unqueued++;
+
+ anim.always(function() {
+ // doing this makes sure that the complete handler will be called
+ // before this completes
+ anim.always(function() {
+ hooks.unqueued--;
+ if ( !jQuery.queue( elem, "fx" ).length ) {
+ hooks.empty.fire();
+ }
+ });
+ });
+ }
+
+ // height/width overflow pass
+ if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
+ // Make sure that nothing sneaks out
+ // Record all 3 overflow attributes because IE does not
+ // change the overflow attribute when overflowX and
+ // overflowY are set to the same value
+ opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
+
+ // Set display property to inline-block for height/width
+ // animations on inline elements that are having width/height animated
+ if ( jQuery.css( elem, "display" ) === "inline" &&
+ jQuery.css( elem, "float" ) === "none" ) {
+
+ // inline-level elements accept inline-block;
+ // block-level elements need to be inline with layout
+ if ( !jQuery.support.inlineBlockNeedsLayout || css_defaultDisplay( elem.nodeName ) === "inline" ) {
+ style.display = "inline-block";
+
+ } else {
+ style.zoom = 1;
+ }
+ }
+ }
+
+ if ( opts.overflow ) {
+ style.overflow = "hidden";
+ if ( !jQuery.support.shrinkWrapBlocks ) {
+ anim.done(function() {
+ style.overflow = opts.overflow[ 0 ];
+ style.overflowX = opts.overflow[ 1 ];
+ style.overflowY = opts.overflow[ 2 ];
+ });
+ }
+ }
+
+
+ // show/hide pass
+ for ( index in props ) {
+ value = props[ index ];
+ if ( rfxtypes.exec( value ) ) {
+ delete props[ index ];
+ toggle = toggle || value === "toggle";
+ if ( value === ( hidden ? "hide" : "show" ) ) {
+ continue;
+ }
+ handled.push( index );
+ }
+ }
+
+ length = handled.length;
+ if ( length ) {
+ dataShow = jQuery._data( elem, "fxshow" ) || jQuery._data( elem, "fxshow", {} );
+ if ( "hidden" in dataShow ) {
+ hidden = dataShow.hidden;
+ }
+
+ // store state if its toggle - enables .stop().toggle() to "reverse"
+ if ( toggle ) {
+ dataShow.hidden = !hidden;
+ }
+ if ( hidden ) {
+ jQuery( elem ).show();
+ } else {
+ anim.done(function() {
+ jQuery( elem ).hide();
+ });
+ }
+ anim.done(function() {
+ var prop;
+ jQuery._removeData( elem, "fxshow" );
+ for ( prop in orig ) {
+ jQuery.style( elem, prop, orig[ prop ] );
+ }
+ });
+ for ( index = 0 ; index < length ; index++ ) {
+ prop = handled[ index ];
+ tween = anim.createTween( prop, hidden ? dataShow[ prop ] : 0 );
+ orig[ prop ] = dataShow[ prop ] || jQuery.style( elem, prop );
+
+ if ( !( prop in dataShow ) ) {
+ dataShow[ prop ] = tween.start;
+ if ( hidden ) {
+ tween.end = tween.start;
+ tween.start = prop === "width" || prop === "height" ? 1 : 0;
+ }
+ }
+ }
+ }
+}
+
+function Tween( elem, options, prop, end, easing ) {
+ return new Tween.prototype.init( elem, options, prop, end, easing );
+}
+jQuery.Tween = Tween;
+
+Tween.prototype = {
+ constructor: Tween,
+ init: function( elem, options, prop, end, easing, unit ) {
+ this.elem = elem;
+ this.prop = prop;
+ this.easing = easing || "swing";
+ this.options = options;
+ this.start = this.now = this.cur();
+ this.end = end;
+ this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
+ },
+ cur: function() {
+ var hooks = Tween.propHooks[ this.prop ];
+
+ return hooks && hooks.get ?
+ hooks.get( this ) :
+ Tween.propHooks._default.get( this );
+ },
+ run: function( percent ) {
+ var eased,
+ hooks = Tween.propHooks[ this.prop ];
+
+ if ( this.options.duration ) {
+ this.pos = eased = jQuery.easing[ this.easing ](
+ percent, this.options.duration * percent, 0, 1, this.options.duration
+ );
+ } else {
+ this.pos = eased = percent;
+ }
+ this.now = ( this.end - this.start ) * eased + this.start;
+
+ if ( this.options.step ) {
+ this.options.step.call( this.elem, this.now, this );
+ }
+
+ if ( hooks && hooks.set ) {
+ hooks.set( this );
+ } else {
+ Tween.propHooks._default.set( this );
+ }
+ return this;
+ }
+};
+
+Tween.prototype.init.prototype = Tween.prototype;
+
+Tween.propHooks = {
+ _default: {
+ get: function( tween ) {
+ var result;
+
+ if ( tween.elem[ tween.prop ] != null &&
+ (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
+ return tween.elem[ tween.prop ];
+ }
+
+ // passing a non empty string as a 3rd parameter to .css will automatically
+ // attempt a parseFloat and fallback to a string if the parse fails
+ // so, simple values such as "10px" are parsed to Float.
+ // complex values such as "rotate(1rad)" are returned as is.
+ result = jQuery.css( tween.elem, tween.prop, "auto" );
+ // Empty strings, null, undefined and "auto" are converted to 0.
+ return !result || result === "auto" ? 0 : result;
+ },
+ set: function( tween ) {
+ // use step hook for back compat - use cssHook if its there - use .style if its
+ // available and use plain properties where available
+ if ( jQuery.fx.step[ tween.prop ] ) {
+ jQuery.fx.step[ tween.prop ]( tween );
+ } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
+ jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
+ } else {
+ tween.elem[ tween.prop ] = tween.now;
+ }
+ }
+ }
+};
+
+// Remove in 2.0 - this supports IE8's panic based approach
+// to setting things on disconnected nodes
+
+Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
+ set: function( tween ) {
+ if ( tween.elem.nodeType && tween.elem.parentNode ) {
+ tween.elem[ tween.prop ] = tween.now;
+ }
+ }
+};
+
+jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
+ var cssFn = jQuery.fn[ name ];
+ jQuery.fn[ name ] = function( speed, easing, callback ) {
+ return speed == null || typeof speed === "boolean" ?
+ cssFn.apply( this, arguments ) :
+ this.animate( genFx( name, true ), speed, easing, callback );
+ };
+});
+
+jQuery.fn.extend({
+ fadeTo: function( speed, to, easing, callback ) {
+
+ // show any hidden elements after setting opacity to 0
+ return this.filter( isHidden ).css( "opacity", 0 ).show()
+
+ // animate to the value specified
+ .end().animate({ opacity: to }, speed, easing, callback );
+ },
+ animate: function( prop, speed, easing, callback ) {
+ var empty = jQuery.isEmptyObject( prop ),
+ optall = jQuery.speed( speed, easing, callback ),
+ doAnimation = function() {
+ // Operate on a copy of prop so per-property easing won't be lost
+ var anim = Animation( this, jQuery.extend( {}, prop ), optall );
+ doAnimation.finish = function() {
+ anim.stop( true );
+ };
+ // Empty animations, or finishing resolves immediately
+ if ( empty || jQuery._data( this, "finish" ) ) {
+ anim.stop( true );
+ }
+ };
+ doAnimation.finish = doAnimation;
+
+ return empty || optall.queue === false ?
+ this.each( doAnimation ) :
+ this.queue( optall.queue, doAnimation );
+ },
+ stop: function( type, clearQueue, gotoEnd ) {
+ var stopQueue = function( hooks ) {
+ var stop = hooks.stop;
+ delete hooks.stop;
+ stop( gotoEnd );
+ };
+
+ if ( typeof type !== "string" ) {
+ gotoEnd = clearQueue;
+ clearQueue = type;
+ type = undefined;
+ }
+ if ( clearQueue && type !== false ) {
+ this.queue( type || "fx", [] );
+ }
+
+ return this.each(function() {
+ var dequeue = true,
+ index = type != null && type + "queueHooks",
+ timers = jQuery.timers,
+ data = jQuery._data( this );
+
+ if ( index ) {
+ if ( data[ index ] && data[ index ].stop ) {
+ stopQueue( data[ index ] );
+ }
+ } else {
+ for ( index in data ) {
+ if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
+ stopQueue( data[ index ] );
+ }
+ }
+ }
+
+ for ( index = timers.length; index--; ) {
+ if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
+ timers[ index ].anim.stop( gotoEnd );
+ dequeue = false;
+ timers.splice( index, 1 );
+ }
+ }
+
+ // start the next in the queue if the last step wasn't forced
+ // timers currently will call their complete callbacks, which will dequeue
+ // but only if they were gotoEnd
+ if ( dequeue || !gotoEnd ) {
+ jQuery.dequeue( this, type );
+ }
+ });
+ },
+ finish: function( type ) {
+ if ( type !== false ) {
+ type = type || "fx";
+ }
+ return this.each(function() {
+ var index,
+ data = jQuery._data( this ),
+ queue = data[ type + "queue" ],
+ hooks = data[ type + "queueHooks" ],
+ timers = jQuery.timers,
+ length = queue ? queue.length : 0;
+
+ // enable finishing flag on private data
+ data.finish = true;
+
+ // empty the queue first
+ jQuery.queue( this, type, [] );
+
+ if ( hooks && hooks.cur && hooks.cur.finish ) {
+ hooks.cur.finish.call( this );
+ }
+
+ // look for any active animations, and finish them
+ for ( index = timers.length; index--; ) {
+ if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
+ timers[ index ].anim.stop( true );
+ timers.splice( index, 1 );
+ }
+ }
+
+ // look for any animations in the old queue and finish them
+ for ( index = 0; index < length; index++ ) {
+ if ( queue[ index ] && queue[ index ].finish ) {
+ queue[ index ].finish.call( this );
+ }
+ }
+
+ // turn off finishing flag
+ delete data.finish;
+ });
+ }
+});
+
+// Generate parameters to create a standard animation
+function genFx( type, includeWidth ) {
+ var which,
+ attrs = { height: type },
+ i = 0;
+
+ // if we include width, step value is 1 to do all cssExpand values,
+ // if we don't include width, step value is 2 to skip over Left and Right
+ includeWidth = includeWidth? 1 : 0;
+ for( ; i < 4 ; i += 2 - includeWidth ) {
+ which = cssExpand[ i ];
+ attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
+ }
+
+ if ( includeWidth ) {
+ attrs.opacity = attrs.width = type;
+ }
+
+ return attrs;
+}
+
+// Generate shortcuts for custom animations
+jQuery.each({
+ slideDown: genFx("show"),
+ slideUp: genFx("hide"),
+ slideToggle: genFx("toggle"),
+ fadeIn: { opacity: "show" },
+ fadeOut: { opacity: "hide" },
+ fadeToggle: { opacity: "toggle" }
+}, function( name, props ) {
+ jQuery.fn[ name ] = function( speed, easing, callback ) {
+ return this.animate( props, speed, easing, callback );
+ };
+});
+
+jQuery.speed = function( speed, easing, fn ) {
+ var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
+ complete: fn || !fn && easing ||
+ jQuery.isFunction( speed ) && speed,
+ duration: speed,
+ easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
+ };
+
+ opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
+ opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
+
+ // normalize opt.queue - true/undefined/null -> "fx"
+ if ( opt.queue == null || opt.queue === true ) {
+ opt.queue = "fx";
+ }
+
+ // Queueing
+ opt.old = opt.complete;
+
+ opt.complete = function() {
+ if ( jQuery.isFunction( opt.old ) ) {
+ opt.old.call( this );
+ }
+
+ if ( opt.queue ) {
+ jQuery.dequeue( this, opt.queue );
+ }
+ };
+
+ return opt;
+};
+
+jQuery.easing = {
+ linear: function( p ) {
+ return p;
+ },
+ swing: function( p ) {
+ return 0.5 - Math.cos( p*Math.PI ) / 2;
+ }
+};
+
+jQuery.timers = [];
+jQuery.fx = Tween.prototype.init;
+jQuery.fx.tick = function() {
+ var timer,
+ timers = jQuery.timers,
+ i = 0;
+
+ fxNow = jQuery.now();
+
+ for ( ; i < timers.length; i++ ) {
+ timer = timers[ i ];
+ // Checks the timer has not already been removed
+ if ( !timer() && timers[ i ] === timer ) {
+ timers.splice( i--, 1 );
+ }
+ }
+
+ if ( !timers.length ) {
+ jQuery.fx.stop();
+ }
+ fxNow = undefined;
+};
+
+jQuery.fx.timer = function( timer ) {
+ if ( timer() && jQuery.timers.push( timer ) ) {
+ jQuery.fx.start();
+ }
+};
+
+jQuery.fx.interval = 13;
+
+jQuery.fx.start = function() {
+ if ( !timerId ) {
+ timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
+ }
+};
+
+jQuery.fx.stop = function() {
+ clearInterval( timerId );
+ timerId = null;
+};
+
+jQuery.fx.speeds = {
+ slow: 600,
+ fast: 200,
+ // Default speed
+ _default: 400
+};
+
+// Back Compat <1.8 extension point
+jQuery.fx.step = {};
+
+if ( jQuery.expr && jQuery.expr.filters ) {
+ jQuery.expr.filters.animated = function( elem ) {
+ return jQuery.grep(jQuery.timers, function( fn ) {
+ return elem === fn.elem;
+ }).length;
+ };
+}
+jQuery.fn.offset = function( options ) {
+ if ( arguments.length ) {
+ return options === undefined ?
+ this :
+ this.each(function( i ) {
+ jQuery.offset.setOffset( this, options, i );
+ });
+ }
+
+ var docElem, win,
+ box = { top: 0, left: 0 },
+ elem = this[ 0 ],
+ doc = elem && elem.ownerDocument;
+
+ if ( !doc ) {
+ return;
+ }
+
+ docElem = doc.documentElement;
+
+ // Make sure it's not a disconnected DOM node
+ if ( !jQuery.contains( docElem, elem ) ) {
+ return box;
+ }
+
+ // If we don't have gBCR, just use 0,0 rather than error
+ // BlackBerry 5, iOS 3 (original iPhone)
+ if ( typeof elem.getBoundingClientRect !== "undefined" ) {
+ box = elem.getBoundingClientRect();
+ }
+ win = getWindow( doc );
+ return {
+ top: box.top + ( win.pageYOffset || docElem.scrollTop ) - ( docElem.clientTop || 0 ),
+ left: box.left + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 )
+ };
+};
+
+jQuery.offset = {
+
+ setOffset: function( elem, options, i ) {
+ var position = jQuery.css( elem, "position" );
+
+ // set position first, in-case top/left are set even on static elem
+ if ( position === "static" ) {
+ elem.style.position = "relative";
+ }
+
+ var curElem = jQuery( elem ),
+ curOffset = curElem.offset(),
+ curCSSTop = jQuery.css( elem, "top" ),
+ curCSSLeft = jQuery.css( elem, "left" ),
+ calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
+ props = {}, curPosition = {}, curTop, curLeft;
+
+ // need to be able to calculate position if either top or left is auto and position is either absolute or fixed
+ if ( calculatePosition ) {
+ curPosition = curElem.position();
+ curTop = curPosition.top;
+ curLeft = curPosition.left;
+ } else {
+ curTop = parseFloat( curCSSTop ) || 0;
+ curLeft = parseFloat( curCSSLeft ) || 0;
+ }
+
+ if ( jQuery.isFunction( options ) ) {
+ options = options.call( elem, i, curOffset );
+ }
+
+ if ( options.top != null ) {
+ props.top = ( options.top - curOffset.top ) + curTop;
+ }
+ if ( options.left != null ) {
+ props.left = ( options.left - curOffset.left ) + curLeft;
+ }
+
+ if ( "using" in options ) {
+ options.using.call( elem, props );
+ } else {
+ curElem.css( props );
+ }
+ }
+};
+
+
+jQuery.fn.extend({
+
+ position: function() {
+ if ( !this[ 0 ] ) {
+ return;
+ }
+
+ var offsetParent, offset,
+ parentOffset = { top: 0, left: 0 },
+ elem = this[ 0 ];
+
+ // fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is it's only offset parent
+ if ( jQuery.css( elem, "position" ) === "fixed" ) {
+ // we assume that getBoundingClientRect is available when computed position is fixed
+ offset = elem.getBoundingClientRect();
+ } else {
+ // Get *real* offsetParent
+ offsetParent = this.offsetParent();
+
+ // Get correct offsets
+ offset = this.offset();
+ if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
+ parentOffset = offsetParent.offset();
+ }
+
+ // Add offsetParent borders
+ parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
+ parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
+ }
+
+ // Subtract parent offsets and element margins
+ // note: when an element has margin: auto the offsetLeft and marginLeft
+ // are the same in Safari causing offset.left to incorrectly be 0
+ return {
+ top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
+ left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true)
+ };
+ },
+
+ offsetParent: function() {
+ return this.map(function() {
+ var offsetParent = this.offsetParent || document.documentElement;
+ while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position") === "static" ) ) {
+ offsetParent = offsetParent.offsetParent;
+ }
+ return offsetParent || document.documentElement;
+ });
+ }
+});
+
+
+// Create scrollLeft and scrollTop methods
+jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) {
+ var top = /Y/.test( prop );
+
+ jQuery.fn[ method ] = function( val ) {
+ return jQuery.access( this, function( elem, method, val ) {
+ var win = getWindow( elem );
+
+ if ( val === undefined ) {
+ return win ? (prop in win) ? win[ prop ] :
+ win.document.documentElement[ method ] :
+ elem[ method ];
+ }
+
+ if ( win ) {
+ win.scrollTo(
+ !top ? val : jQuery( win ).scrollLeft(),
+ top ? val : jQuery( win ).scrollTop()
+ );
+
+ } else {
+ elem[ method ] = val;
+ }
+ }, method, val, arguments.length, null );
+ };
+});
+
+function getWindow( elem ) {
+ return jQuery.isWindow( elem ) ?
+ elem :
+ elem.nodeType === 9 ?
+ elem.defaultView || elem.parentWindow :
+ false;
+}
+// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
+jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
+ jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
+ // margin is only for outerHeight, outerWidth
+ jQuery.fn[ funcName ] = function( margin, value ) {
+ var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
+ extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
+
+ return jQuery.access( this, function( elem, type, value ) {
+ var doc;
+
+ if ( jQuery.isWindow( elem ) ) {
+ // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
+ // isn't a whole lot we can do. See pull request at this URL for discussion:
+ // https://github.com/jquery/jquery/pull/764
+ return elem.document.documentElement[ "client" + name ];
+ }
+
+ // Get document width or height
+ if ( elem.nodeType === 9 ) {
+ doc = elem.documentElement;
+
+ // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest
+ // unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it.
+ return Math.max(
+ elem.body[ "scroll" + name ], doc[ "scroll" + name ],
+ elem.body[ "offset" + name ], doc[ "offset" + name ],
+ doc[ "client" + name ]
+ );
+ }
+
+ return value === undefined ?
+ // Get width or height on the element, requesting but not forcing parseFloat
+ jQuery.css( elem, type, extra ) :
+
+ // Set width or height on the element
+ jQuery.style( elem, type, value, extra );
+ }, type, chainable ? margin : undefined, chainable, null );
+ };
+ });
+});
+// Limit scope pollution from any deprecated API
+// (function() {
+
+// })();
+// Expose jQuery to the global object
+window.jQuery = window.$ = jQuery;
+
+// Expose jQuery as an AMD module, but only for AMD loaders that
+// understand the issues with loading multiple versions of jQuery
+// in a page that all might call define(). The loader will indicate
+// they have special allowances for multiple jQuery versions by
+// specifying define.amd.jQuery = true. Register as a named module,
+// since jQuery can be concatenated with other files that may use define,
+// but not use a proper concatenation script that understands anonymous
+// AMD modules. A named AMD is safest and most robust way to register.
+// Lowercase jquery is used because AMD module names are derived from
+// file names, and jQuery is normally delivered in a lowercase file name.
+// Do this after creating the global so that if an AMD module wants to call
+// noConflict to hide this version of jQuery, it will work.
+if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
+ define( "jquery", [], function () { return jQuery; } );
+}
+
+})( window );
diff --git a/js/tagcanvas.js b/js/tagcanvas.js
new file mode 100644
index 0000000..80866a2
--- /dev/null
+++ b/js/tagcanvas.js
@@ -0,0 +1,2243 @@
+/**
+ * Copyright (C) 2010-2015 Graham Breach
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+/**
+ * TagCanvas 2.9
+ * For more information, please contact
+ */
+(function(){
+"use strict";
+var i, j, abs = Math.abs, sin = Math.sin, cos = Math.cos, max = Math.max,
+ min = Math.min, ceil = Math.ceil, sqrt = Math.sqrt, pow = Math.pow,
+ hexlookup3 = {}, hexlookup2 = {}, hexlookup1 = {
+ 0:"0,", 1:"17,", 2:"34,", 3:"51,", 4:"68,", 5:"85,",
+ 6:"102,", 7:"119,", 8:"136,", 9:"153,", a:"170,", A:"170,",
+ b:"187,", B:"187,", c:"204,", C:"204,", d:"221,", D:"221,",
+ e:"238,", E:"238,", f:"255,", F:"255,"
+ }, Oproto, Tproto, TCproto, Mproto, Vproto, TSproto, TCVproto,
+ doc = document, ocanvas, handlers = {};
+for(i = 0; i < 256; ++i) {
+ j = i.toString(16);
+ if(i < 16)
+ j = '0' + j;
+ hexlookup2[j] = hexlookup2[j.toUpperCase()] = i.toString() + ',';
+}
+function Defined(d) {
+ return typeof d != 'undefined';
+}
+function IsObject(o) {
+ return typeof o == 'object' && o != null;
+}
+function Clamp(v, mn, mx) {
+ return isNaN(v) ? mx : min(mx, max(mn, v));
+}
+function Nop() {
+ return false;
+}
+function TimeNow() {
+ return new Date().valueOf();
+}
+function SortList(l, f) {
+ var nl = [], tl = l.length, i;
+ for(i = 0; i < tl; ++i)
+ nl.push(l[i]);
+ nl.sort(f);
+ return nl;
+}
+function Shuffle(a) {
+ var i = a.length-1, t, p;
+ while(i) {
+ p = ~~(Math.random()*i);
+ t = a[i];
+ a[i] = a[p];
+ a[p] = t;
+ --i;
+ }
+}
+function Vector(x, y, z) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+}
+Vproto = Vector.prototype;
+Vproto.length = function() {
+ return sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
+};
+Vproto.dot = function(v) {
+ return this.x * v.x + this.y * v.y + this.z * v.z;
+};
+Vproto.cross = function(v) {
+ var x = this.y * v.z - this.z * v.y,
+ y = this.z * v.x - this.x * v.z,
+ z = this.x * v.y - this.y * v.x;
+ return new Vector(x, y, z);
+};
+Vproto.angle = function(v) {
+ var dot = this.dot(v), ac;
+ if(dot == 0)
+ return Math.PI / 2.0;
+ ac = dot / (this.length() * v.length());
+ if(ac >= 1)
+ return 0;
+ if(ac <= -1)
+ return Math.PI;
+ return Math.acos(ac);
+};
+Vproto.unit = function() {
+ var l = this.length();
+ return new Vector(this.x / l, this.y / l, this.z / l);
+};
+function MakeVector(lg, lt) {
+ lt = lt * Math.PI / 180;
+ lg = lg * Math.PI / 180;
+ var x = sin(lg) * cos(lt), y = -sin(lt), z = -cos(lg) * cos(lt);
+ return new Vector(x, y, z);
+}
+function Matrix(a) {
+ this[1] = {1: a[0], 2: a[1], 3: a[2]};
+ this[2] = {1: a[3], 2: a[4], 3: a[5]};
+ this[3] = {1: a[6], 2: a[7], 3: a[8]};
+}
+Mproto = Matrix.prototype;
+Matrix.Identity = function() {
+ return new Matrix([1,0,0, 0,1,0, 0,0,1]);
+};
+Matrix.Rotation = function(angle, u) {
+ var sina = sin(angle), cosa = cos(angle), mcos = 1 - cosa;
+ return new Matrix([
+ cosa + pow(u.x, 2) * mcos, u.x * u.y * mcos - u.z * sina, u.x * u.z * mcos + u.y * sina,
+ u.y * u.x * mcos + u.z * sina, cosa + pow(u.y, 2) * mcos, u.y * u.z * mcos - u.x * sina,
+ u.z * u.x * mcos - u.y * sina, u.z * u.y * mcos + u.x * sina, cosa + pow(u.z, 2) * mcos
+ ]);
+}
+Mproto.mul = function(m) {
+ var a = [], i, j, mmatrix = (m.xform ? 1 : 0);
+ for(i = 1; i <= 3; ++i)
+ for(j = 1; j <= 3; ++j) {
+ if(mmatrix)
+ a.push(this[i][1] * m[1][j] +
+ this[i][2] * m[2][j] +
+ this[i][3] * m[3][j]);
+ else
+ a.push(this[i][j] * m);
+ }
+ return new Matrix(a);
+};
+Mproto.xform = function(p) {
+ var a = {}, x = p.x, y = p.y, z = p.z;
+ a.x = x * this[1][1] + y * this[2][1] + z * this[3][1];
+ a.y = x * this[1][2] + y * this[2][2] + z * this[3][2];
+ a.z = x * this[1][3] + y * this[2][3] + z * this[3][3];
+ return a;
+};
+function PointsOnSphere(n,xr,yr,zr,magic) {
+ var i, y, r, phi, pts = [], off = 2/n, inc;
+ inc = Math.PI * (3 - sqrt(5) + (parseFloat(magic) ? parseFloat(magic) : 0));
+ for(i = 0; i < n; ++i) {
+ y = i * off - 1 + (off / 2);
+ r = sqrt(1 - y*y);
+ phi = i * inc;
+ pts.push([cos(phi) * r * xr, y * yr, sin(phi) * r * zr]);
+ }
+ return pts;
+}
+function Cylinder(n,o,xr,yr,zr,magic) {
+ var phi, pts = [], off = 2/n, inc, i, j, k, l;
+ inc = Math.PI * (3 - sqrt(5) + (parseFloat(magic) ? parseFloat(magic) : 0));
+ for(i = 0; i < n; ++i) {
+ j = i * off - 1 + (off / 2);
+ phi = i * inc;
+ k = cos(phi);
+ l = sin(phi);
+ pts.push(o ? [j * xr, k * yr, l * zr] : [k * xr, j * yr, l * zr]);
+ }
+ return pts;
+}
+function Ring(o, n, xr, yr, zr, j) {
+ var phi, pts = [], inc = Math.PI * 2 / n, i, k, l;
+ for(i = 0; i < n; ++i) {
+ phi = i * inc;
+ k = cos(phi);
+ l = sin(phi);
+ pts.push(o ? [j * xr, k * yr, l * zr] : [k * xr, j * yr, l * zr]);
+ }
+ return pts;
+}
+function PointsOnCylinderV(n,xr,yr,zr,m) { return Cylinder(n, 0, xr, yr, zr, m) }
+function PointsOnCylinderH(n,xr,yr,zr,m) { return Cylinder(n, 1, xr, yr, zr, m) }
+function PointsOnRingV(n, xr, yr, zr, offset) {
+ offset = isNaN(offset) ? 0 : offset * 1;
+ return Ring(0, n, xr, yr, zr, offset);
+}
+function PointsOnRingH(n, xr, yr, zr, offset) {
+ offset = isNaN(offset) ? 0 : offset * 1;
+ return Ring(1, n, xr, yr, zr, offset);
+}
+function CentreImage(t) {
+ var i = new Image;
+ i.onload = function() {
+ var dx = i.width / 2, dy = i.height / 2;
+ t.centreFunc = function(c, w, h, cx, cy) {
+ c.setTransform(1, 0, 0, 1, 0, 0);
+ c.globalAlpha = 1;
+ c.drawImage(i, cx - dx, cy - dy);
+ };
+ };
+ i.src = t.centreImage;
+}
+function SetAlpha(c,a) {
+ var d = c, p1, p2, ae = (a*1).toPrecision(3) + ')';
+ if(c[0] === '#') {
+ if(!hexlookup3[c])
+ if(c.length === 4)
+ hexlookup3[c] = 'rgba(' + hexlookup1[c[1]] + hexlookup1[c[2]] + hexlookup1[c[3]];
+ else
+ hexlookup3[c] = 'rgba(' + hexlookup2[c.substr(1,2)] + hexlookup2[c.substr(3,2)] + hexlookup2[c.substr(5,2)];
+ d = hexlookup3[c] + ae;
+ } else if(c.substr(0,4) === 'rgb(' || c.substr(0,4) === 'hsl(') {
+ d = (c.replace('(','a(').replace(')', ',' + ae));
+ } else if(c.substr(0,5) === 'rgba(' || c.substr(0,5) === 'hsla(') {
+ p1 = c.lastIndexOf(',') + 1, p2 = c.indexOf(')');
+ a *= parseFloat(c.substring(p1,p2));
+ d = c.substr(0,p1) + a.toPrecision(3) + ')';
+ }
+ return d;
+}
+function NewCanvas(w,h) {
+ // if using excanvas, give up now
+ if(window.G_vmlCanvasManager)
+ return null;
+ var c = doc.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ return c;
+}
+// I think all browsers pass this test now...
+function ShadowAlphaBroken() {
+ var cv = NewCanvas(3,3), c, i;
+ if(!cv)
+ return false;
+ c = cv.getContext('2d');
+ c.strokeStyle = '#000';
+ c.shadowColor = '#fff';
+ c.shadowBlur = 3;
+ c.globalAlpha = 0;
+ c.strokeRect(2,2,2,2);
+ c.globalAlpha = 1;
+ i = c.getImageData(2,2,1,1);
+ cv = null;
+ return (i.data[0] > 0);
+}
+function SetGradient(c, l, o, g) {
+ var gd = c.createLinearGradient(0, 0, l, 0), i;
+ for(i in g)
+ gd.addColorStop(1 - i, g[i]);
+ c.fillStyle = gd;
+ c.fillRect(0, o, l, 1);
+}
+function FindGradientColour(tc, p, r) {
+ var l = 1024, h = 1, gl = tc.weightGradient, cv, c, i, d;
+ if(tc.gCanvas) {
+ c = tc.gCanvas.getContext('2d');
+ h = tc.gCanvas.height;
+ } else {
+ if(IsObject(gl[0]))
+ h = gl.length;
+ else
+ gl = [gl];
+ tc.gCanvas = cv = NewCanvas(l, h);
+ if(!cv)
+ return null;
+ c = cv.getContext('2d');
+ for(i = 0; i < h; ++i)
+ SetGradient(c, l, i, gl[i]);
+ }
+ r = max(min(r || 0, h - 1), 0);
+ d = c.getImageData(~~((l - 1) * p), r, 1, 1).data;
+ return 'rgba(' + d[0] + ',' + d[1] + ',' + d[2] + ',' + (d[3]/255) + ')';
+}
+function TextSet(ctxt, font, colour, strings, padx, pady, shadowColour,
+ shadowBlur, shadowOffsets, maxWidth, widths, align) {
+ var xo = padx + (shadowBlur || 0) +
+ (shadowOffsets.length && shadowOffsets[0] < 0 ? abs(shadowOffsets[0]) : 0),
+ yo = pady + (shadowBlur || 0) +
+ (shadowOffsets.length && shadowOffsets[1] < 0 ? abs(shadowOffsets[1]) : 0), i, xc;
+ ctxt.font = font;
+ ctxt.textBaseline = 'top';
+ ctxt.fillStyle = colour;
+ shadowColour && (ctxt.shadowColor = shadowColour);
+ shadowBlur && (ctxt.shadowBlur = shadowBlur);
+ shadowOffsets.length && (ctxt.shadowOffsetX = shadowOffsets[0],
+ ctxt.shadowOffsetY = shadowOffsets[1]);
+ for(i = 0; i < strings.length; ++i) {
+ xc = 0;
+ if(widths) {
+ if('right' == align) {
+ xc = maxWidth - widths[i];
+ } else if('centre' == align) {
+ xc = (maxWidth - widths[i]) / 2;
+ }
+ }
+ ctxt.fillText(strings[i], xo + xc, yo);
+ yo += parseInt(font);
+ }
+}
+function RRect(c, x, y, w, h, r, s) {
+ if(r) {
+ c.beginPath();
+ c.moveTo(x, y + h - r);
+ c.arcTo(x, y, x + r, y, r);
+ c.arcTo(x + w, y, x + w, y + r, r);
+ c.arcTo(x + w, y + h, x + w - r, y + h, r);
+ c.arcTo(x, y + h, x, y + h - r, r);
+ c.closePath();
+ c[s ? 'stroke' : 'fill']();
+ } else {
+ c[s ? 'strokeRect' : 'fillRect'](x, y, w, h);
+ }
+}
+function TextCanvas(strings, font, w, h, maxWidth, stringWidths, align, valign,
+ scale) {
+ this.strings = strings;
+ this.font = font;
+ this.width = w;
+ this.height = h;
+ this.maxWidth = maxWidth;
+ this.stringWidths = stringWidths;
+ this.align = align;
+ this.valign = valign;
+ this.scale = scale;
+}
+TCVproto = TextCanvas.prototype;
+TCVproto.SetImage = function(image, w, h, position, padding, align, valign,
+ scale) {
+ this.image = image;
+ this.iwidth = w * this.scale;
+ this.iheight = h * this.scale;
+ this.ipos = position;
+ this.ipad = padding * this.scale;
+ this.iscale = scale;
+ this.ialign = align;
+ this.ivalign = valign;
+};
+TCVproto.Align = function(size, space, a) {
+ var pos = 0;
+ if(a == 'right' || a == 'bottom')
+ pos = space - size;
+ else if(a != 'left' && a != 'top')
+ pos = (space - size) / 2;
+ return pos;
+};
+TCVproto.Create = function(colour, bgColour, bgOutline, bgOutlineThickness,
+ shadowColour, shadowBlur, shadowOffsets, padding, radius) {
+ var cv, cw, ch, c, x1, x2, y1, y2, offx, offy, ix, iy, iw, ih, rr,
+ sox = abs(shadowOffsets[0]), soy = abs(shadowOffsets[1]), shadowcv, shadowc;
+ padding = max(padding, sox + shadowBlur, soy + shadowBlur);
+ x1 = 2 * (padding + bgOutlineThickness);
+ y1 = 2 * (padding + bgOutlineThickness);
+ cw = this.width + x1;
+ ch = this.height + y1;
+ offx = offy = padding + bgOutlineThickness;
+
+ if(this.image) {
+ ix = iy = padding + bgOutlineThickness;
+ iw = this.iwidth;
+ ih = this.iheight;
+ if(this.ipos == 'top' || this.ipos == 'bottom') {
+ if(iw < this.width)
+ ix += this.Align(iw, this.width, this.ialign);
+ else
+ offx += this.Align(this.width, iw, this.align);
+ if(this.ipos == 'top')
+ offy += ih + this.ipad;
+ else
+ iy += this.height + this.ipad;
+ cw = max(cw, iw + x1);
+ ch += ih + this.ipad;
+ } else {
+ if(ih < this.height)
+ iy += this.Align(ih, this.height, this.ivalign);
+ else
+ offy += this.Align(this.height, ih, this.valign);
+ if(this.ipos == 'right')
+ ix += this.width + this.ipad;
+ else
+ offx += iw + this.ipad;
+ cw += iw + this.ipad;
+ ch = max(ch, ih + y1);
+ }
+ }
+
+ cv = NewCanvas(cw, ch);
+ if(!cv)
+ return null;
+ x1 = y1 = bgOutlineThickness / 2;
+ x2 = cw - bgOutlineThickness;
+ y2 = ch - bgOutlineThickness;
+ rr = min(radius, x2 / 2, y2 / 2);
+ c = cv.getContext('2d');
+ if(bgColour) {
+ c.fillStyle = bgColour;
+ RRect(c, x1, y1, x2, y2, rr);
+ }
+ if(bgOutlineThickness) {
+ c.strokeStyle = bgOutline;
+ c.lineWidth = bgOutlineThickness;
+ RRect(c, x1, y1, x2, y2, rr, true);
+ }
+ if(shadowBlur || sox || soy) {
+ // use a transparent canvas to draw on
+ shadowcv = NewCanvas(cw, ch);
+ if(shadowcv) {
+ shadowc = c;
+ c = shadowcv.getContext('2d');
+ }
+ }
+
+ // don't use TextSet shadow support because it adds space for shadow
+ TextSet(c, this.font, colour, this.strings, offx, offy, 0, 0, [],
+ this.maxWidth, this.stringWidths, this.align);
+
+ if(this.image)
+ c.drawImage(this.image, ix, iy, iw, ih);
+
+ if(shadowc) {
+ // draw the text and image with the added shadow
+ c = shadowc;
+ shadowColour && (c.shadowColor = shadowColour);
+ shadowBlur && (c.shadowBlur = shadowBlur);
+ c.shadowOffsetX = shadowOffsets[0];
+ c.shadowOffsetY = shadowOffsets[1];
+ c.drawImage(shadowcv, 0, 0);
+ }
+ return cv;
+};
+function ExpandImage(i, w, h) {
+ var cv = NewCanvas(w, h), c;
+ if(!cv)
+ return null;
+ c = cv.getContext('2d');
+ c.drawImage(i, (w - i.width) / 2, (h - i.height) / 2);
+ return cv;
+}
+function ScaleImage(i, w, h) {
+ var cv = NewCanvas(w, h), c;
+ if(!cv)
+ return null;
+ c = cv.getContext('2d');
+ c.drawImage(i, 0, 0, w, h);
+ return cv;
+}
+function AddBackgroundToImage(i, w, h, scale, colour, othickness, ocolour,
+ padding, radius, ofill) {
+ var cw = w + ((2 * padding) + othickness) * scale,
+ ch = h + ((2 * padding) + othickness) * scale,
+ cv = NewCanvas(cw, ch), c, x1, y1, x2, y2, ocanvas, cc, rr;
+ if(!cv)
+ return null;
+ othickness *= scale;
+ radius *= scale;
+ x1 = y1 = othickness / 2;
+ x2 = cw - othickness;
+ y2 = ch - othickness;
+ padding = (padding * scale) + x1; // add space for outline
+ c = cv.getContext('2d');
+ rr = min(radius, x2 / 2, y2 / 2);
+ if(colour) {
+ c.fillStyle = colour;
+ RRect(c, x1, y1, x2, y2, rr);
+ }
+ if(othickness) {
+ c.strokeStyle = ocolour;
+ c.lineWidth = othickness;
+ RRect(c, x1, y1, x2, y2, rr, true);
+ }
+
+ if(ofill) {
+ // use compositing to colour in the image and border
+ ocanvas = NewCanvas(cw, ch);
+ cc = ocanvas.getContext('2d');
+ cc.drawImage(i, padding, padding, w, h);
+ cc.globalCompositeOperation = 'source-in';
+ cc.fillStyle = ocolour;
+ cc.fillRect(0, 0, cw, ch);
+ cc.globalCompositeOperation = 'destination-over';
+ cc.drawImage(cv, 0, 0);
+ cc.globalCompositeOperation = 'source-over';
+ c.drawImage(ocanvas, 0, 0);
+ } else {
+ c.drawImage(i, padding, padding, i.width, i.height);
+ }
+ return {image: cv, width: cw / scale, height: ch / scale};
+}
+/**
+ * Rounds off the corners of an image
+ */
+function RoundImage(i, r, iw, ih, s) {
+ var cv, c, r1 = parseFloat(r), l = max(iw, ih);
+ cv = NewCanvas(iw, ih);
+ if(!cv)
+ return null;
+ if(r.indexOf('%') > 0)
+ r1 = l * r1 / 100;
+ else
+ r1 = r1 * s;
+ c = cv.getContext('2d');
+ c.globalCompositeOperation = 'source-over';
+ c.fillStyle = '#fff';
+ if(r1 >= l/2) {
+ r1 = min(iw,ih) / 2;
+ c.beginPath();
+ c.moveTo(iw/2,ih/2);
+ c.arc(iw/2,ih/2,r1,0,2*Math.PI,false);
+ c.fill();
+ c.closePath();
+ } else {
+ r1 = min(iw/2,ih/2,r1);
+ RRect(c, 0, 0, iw, ih, r1, true);
+ c.fill();
+ }
+ c.globalCompositeOperation = 'source-in';
+ c.drawImage(i, 0, 0, iw, ih);
+ return cv;
+}
+/**
+ * Creates a new canvas containing the image and its shadow
+ * Returns an object containing the image and its dimensions at z=0
+ */
+function AddShadowToImage(i, w, h, scale, sc, sb, so) {
+ var sw = abs(so[0]), sh = abs(so[1]),
+ cw = w + (sw > sb ? sw + sb : sb * 2) * scale,
+ ch = h + (sh > sb ? sh + sb : sb * 2) * scale,
+ xo = scale * ((sb || 0) + (so[0] < 0 ? sw : 0)),
+ yo = scale * ((sb || 0) + (so[1] < 0 ? sh : 0)), cv, c;
+ cv = NewCanvas(cw, ch);
+ if(!cv)
+ return null;
+ c = cv.getContext('2d');
+ sc && (c.shadowColor = sc);
+ sb && (c.shadowBlur = sb * scale);
+ so && (c.shadowOffsetX = so[0] * scale, c.shadowOffsetY = so[1] * scale);
+ c.drawImage(i, xo, yo, w, h);
+ return {image: cv, width: cw / scale, height: ch / scale};
+}
+function FindTextBoundingBox(s,f,ht) {
+ var w = parseInt(s.toString().length * ht), h = parseInt(ht * 2 * s.length),
+ cv = NewCanvas(w,h), c, idata, w1, h1, x, y, i, ex;
+ if(!cv)
+ return null;
+ c = cv.getContext('2d');
+ c.fillStyle = '#000';
+ c.fillRect(0,0,w,h);
+ TextSet(c,ht + 'px ' + f,'#fff',s,0,0,0,0,[],'centre')
+
+ idata = c.getImageData(0,0,w,h);
+ w1 = idata.width; h1 = idata.height;
+ ex = {
+ min: { x: w1, y: h1 },
+ max: { x: -1, y: -1 }
+ };
+ for(y = 0; y < h1; ++y) {
+ for(x = 0; x < w1; ++x) {
+ i = (y * w1 + x) * 4;
+ if(idata.data[i+1] > 0) {
+ if(x < ex.min.x) ex.min.x = x;
+ if(x > ex.max.x) ex.max.x = x;
+ if(y < ex.min.y) ex.min.y = y;
+ if(y > ex.max.y) ex.max.y = y;
+ }
+ }
+ }
+ // device pixels might not be css pixels
+ if(w1 != w) {
+ ex.min.x *= (w / w1);
+ ex.max.x *= (w / w1);
+ }
+ if(h1 != h) {
+ ex.min.y *= (w / h1);
+ ex.max.y *= (w / h1);
+ }
+
+ cv = null;
+ return ex;
+}
+function FixFont(f) {
+ return "'" + f.replace(/(\'|\")/g,'').replace(/\s*,\s*/g, "', '") + "'";
+}
+function AddHandler(h,f,e) {
+ e = e || doc;
+ if(e.addEventListener)
+ e.addEventListener(h,f,false);
+ else
+ e.attachEvent('on' + h, f);
+}
+function RemoveHandler(h,f,e) {
+ e = e || doc;
+ if(e.removeEventListener)
+ e.removeEventListener(h, f);
+ else
+ e.detachEvent('on' + h, f);
+}
+function AddImage(i, o, t, tc) {
+ var s = tc.imageScale, mscale, ic, bc, oc, iw, ih;
+ // image not loaded, wait for image onload
+ if(!o.complete)
+ return AddHandler('load',function() { AddImage(i,o,t,tc); }, o);
+ if(!i.complete)
+ return AddHandler('load',function() { AddImage(i,o,t,tc); }, i);
+
+ // Yes, this does look like nonsense, but it makes sure that both the
+ // width and height are actually set and not just calculated. This is
+ // required to keep proportional sizes when the images are hidden, so
+ // the images can be used again for another cloud.
+ o.width = o.width;
+ o.height = o.height;
+
+ if(s) {
+ i.width = o.width * s;
+ i.height = o.height * s;
+ }
+ // the standard width of the image, with imageScale applied
+ t.iw = i.width;
+ t.ih = i.height;
+ if(tc.txtOpt) {
+ ic = i;
+ mscale = tc.zoomMax * tc.txtScale;
+ iw = t.iw * mscale;
+ ih = t.ih * mscale;
+ if(iw < o.naturalWidth || ih < o.naturalHeight) {
+ ic = ScaleImage(i, iw, ih);
+ if(ic)
+ t.fimage = ic;
+ } else {
+ iw = t.iw;
+ ih = t.ih;
+ mscale = 1;
+ }
+ if(parseFloat(tc.imageRadius))
+ t.image = t.fimage = i = RoundImage(t.image, tc.imageRadius, iw, ih, mscale);
+ if(!t.HasText()) {
+ if(tc.shadow) {
+ ic = AddShadowToImage(t.image, iw, ih, mscale, tc.shadow, tc.shadowBlur,
+ tc.shadowOffset);
+ if(ic) {
+ t.fimage = ic.image;
+ t.w = ic.width;
+ t.h = ic.height;
+ }
+ }
+ if(tc.bgColour || tc.bgOutlineThickness) {
+ bc = tc.bgColour == 'tag' ? GetProperty(t.a, 'background-color') :
+ tc.bgColour;
+ oc = tc.bgOutline == 'tag' ? GetProperty(t.a, 'color') :
+ (tc.bgOutline || tc.textColour);
+ iw = t.fimage.width;
+ ih = t.fimage.height;
+ if(tc.outlineMethod == 'colour') {
+ // create the outline version first, using the current image state
+ ic = AddBackgroundToImage(t.fimage, iw, ih, mscale, bc,
+ tc.bgOutlineThickness, t.outline.colour, tc.padding, tc.bgRadius, 1);
+ if(ic)
+ t.oimage = ic.image;
+ }
+ ic = AddBackgroundToImage(t.fimage, iw, ih, mscale, bc,
+ tc.bgOutlineThickness, oc, tc.padding, tc.bgRadius);
+ if(ic) {
+ t.fimage = ic.image;
+ t.w = ic.width;
+ t.h = ic.height;
+ }
+ }
+ if(tc.outlineMethod == 'size') {
+ if(tc.outlineIncrease > 0) {
+ t.iw += 2 * tc.outlineIncrease;
+ t.ih += 2 * tc.outlineIncrease;
+ iw = mscale * t.iw;
+ ih = mscale * t.ih;
+ ic = ScaleImage(t.fimage, iw, ih);
+ t.oimage = ic;
+ t.fimage = ExpandImage(t.fimage, t.oimage.width, t.oimage.height);
+ } else {
+ iw = mscale * (t.iw + (2 * tc.outlineIncrease));
+ ih = mscale * (t.ih + (2 * tc.outlineIncrease));
+ ic = ScaleImage(t.fimage, iw, ih);
+ t.oimage = ExpandImage(ic, t.fimage.width, t.fimage.height);
+ }
+ }
+ }
+ }
+ t.Init();
+}
+function GetProperty(e,p) {
+ var dv = doc.defaultView, pc = p.replace(/\-([a-z])/g,function(a){return a.charAt(1).toUpperCase()});
+ return (dv && dv.getComputedStyle && dv.getComputedStyle(e,null).getPropertyValue(p)) ||
+ (e.currentStyle && e.currentStyle[pc]);
+}
+function FindWeight(a, wFrom, tHeight) {
+ var w = 1, p;
+ if(wFrom) {
+ w = 1 * (a.getAttribute(wFrom) || tHeight);
+ } else if(p = GetProperty(a,'font-size')) {
+ w = (p.indexOf('px') > -1 && p.replace('px','') * 1) ||
+ (p.indexOf('pt') > -1 && p.replace('pt','') * 1.25) ||
+ p * 3.3;
+ }
+ return w;
+}
+function EventToCanvasId(e) {
+ return e.target && Defined(e.target.id) ? e.target.id :
+ e.srcElement.parentNode.id;
+}
+function EventXY(e, c) {
+ var xy, p, xmul = parseInt(GetProperty(c, 'width')) / c.width,
+ ymul = parseInt(GetProperty(c, 'height')) / c.height;
+ if(Defined(e.offsetX)) {
+ xy = {x: e.offsetX, y: e.offsetY};
+ } else {
+ p = AbsPos(c.id);
+ if(Defined(e.changedTouches))
+ e = e.changedTouches[0];
+ if(e.pageX)
+ xy = {x: e.pageX - p.x, y: e.pageY - p.y};
+ }
+ if(xy && xmul && ymul) {
+ xy.x /= xmul;
+ xy.y /= ymul;
+ }
+ return xy;
+}
+function MouseOut(e) {
+ var cv = e.target || e.fromElement.parentNode, tc = TagCanvas.tc[cv.id];
+ if(tc) {
+ tc.mx = tc.my = -1;
+ tc.UnFreeze();
+ tc.EndDrag();
+ }
+}
+function MouseMove(e) {
+ var i, t = TagCanvas, tc, p, tg = EventToCanvasId(e);
+ for(i in t.tc) {
+ tc = t.tc[i];
+ if(tc.tttimer) {
+ clearTimeout(tc.tttimer);
+ tc.tttimer = null;
+ }
+ }
+ if(tg && t.tc[tg]) {
+ tc = t.tc[tg];
+ if(p = EventXY(e, tc.canvas)) {
+ tc.mx = p.x;
+ tc.my = p.y;
+ tc.Drag(e, p);
+ }
+ tc.drawn = 0;
+ }
+}
+function MouseDown(e) {
+ var t = TagCanvas, cb = doc.addEventListener ? 0 : 1,
+ tg = EventToCanvasId(e);
+ if(tg && e.button == cb && t.tc[tg]) {
+ t.tc[tg].BeginDrag(e);
+ }
+}
+function MouseUp(e) {
+ var t = TagCanvas, cb = doc.addEventListener ? 0 : 1,
+ tg = EventToCanvasId(e), tc;
+ if(tg && e.button == cb && t.tc[tg]) {
+ tc = t.tc[tg];
+ MouseMove(e);
+ if(!tc.EndDrag() && !tc.touchState)
+ tc.Clicked(e);
+ }
+}
+function TouchDown(e) {
+ var tg = EventToCanvasId(e), tc = (tg && TagCanvas.tc[tg]), p;
+ if(tc && e.changedTouches) {
+ if(e.touches.length == 1 && tc.touchState == 0) {
+ tc.touchState = 1;
+ tc.BeginDrag(e);
+ if(p = EventXY(e, tc.canvas)) {
+ tc.mx = p.x;
+ tc.my = p.y;
+ tc.drawn = 0;
+ }
+ } else if(e.targetTouches.length == 2 && tc.pinchZoom) {
+ tc.touchState = 3;
+ tc.EndDrag();
+ tc.BeginPinch(e);
+ } else {
+ tc.EndDrag();
+ tc.EndPinch();
+ tc.touchState = 0;
+ }
+ }
+}
+function TouchUp(e) {
+ var tg = EventToCanvasId(e), tc = (tg && TagCanvas.tc[tg]);
+ if(tc && e.changedTouches) {
+ switch(tc.touchState) {
+ case 1:
+ tc.Draw();
+ tc.Clicked();
+ break;
+ case 2:
+ tc.EndDrag();
+ break;
+ case 3:
+ tc.EndPinch();
+ }
+ tc.touchState = 0;
+ }
+}
+function TouchMove(e) {
+ var i, t = TagCanvas, tc, p, tg = EventToCanvasId(e);
+ for(i in t.tc) {
+ tc = t.tc[i];
+ if(tc.tttimer) {
+ clearTimeout(tc.tttimer);
+ tc.tttimer = null;
+ }
+ }
+ tc = (tg && t.tc[tg]);
+ if(tc && e.changedTouches && tc.touchState) {
+ switch(tc.touchState) {
+ case 1:
+ case 2:
+ if(p = EventXY(e, tc.canvas)) {
+ tc.mx = p.x;
+ tc.my = p.y;
+ if(tc.Drag(e, p))
+ tc.touchState = 2;
+ }
+ break;
+ case 3:
+ tc.Pinch(e);
+ }
+ tc.drawn = 0;
+ }
+}
+function MouseWheel(e) {
+ var t = TagCanvas, tg = EventToCanvasId(e);
+ if(tg && t.tc[tg]) {
+ e.cancelBubble = true;
+ e.returnValue = false;
+ e.preventDefault && e.preventDefault();
+ t.tc[tg].Wheel((e.wheelDelta || e.detail) > 0);
+ }
+}
+function Scroll(e) {
+ var i, t = TagCanvas;
+ clearTimeout(t.scrollTimer);
+ for(i in t.tc) {
+ t.tc[i].Pause();
+ }
+ t.scrollTimer = setTimeout(function() {
+ var i, t = TagCanvas;
+ for(i in t.tc) {
+ t.tc[i].Resume();
+ }
+ }, t.scrollPause);
+}
+function DrawCanvas() {
+ DrawCanvasRAF(TimeNow());
+}
+function DrawCanvasRAF(t) {
+ var tc = TagCanvas.tc, i;
+ TagCanvas.NextFrame(TagCanvas.interval);
+ t = t || TimeNow();
+ for(i in tc)
+ tc[i].Draw(t);
+}
+function AbsPos(id) {
+ var e = doc.getElementById(id), r = e.getBoundingClientRect(),
+ dd = doc.documentElement, b = doc.body, w = window,
+ xs = w.pageXOffset || dd.scrollLeft,
+ ys = w.pageYOffset || dd.scrollTop,
+ xo = dd.clientLeft || b.clientLeft,
+ yo = dd.clientTop || b.clientTop;
+ return { x: r.left + xs - xo, y: r.top + ys - yo };
+}
+function Project(tc,p1,sx,sy) {
+ var m = tc.radius * tc.z1 / (tc.z1 + tc.z2 + p1.z);
+ return {
+ x: p1.x * m * sx,
+ y: p1.y * m * sy,
+ z: p1.z,
+ w: (tc.z1 - p1.z) / tc.z2
+ };
+}
+/**
+ * @constructor
+ * for recursively splitting tag contents on
tags
+ */
+function TextSplitter(e) {
+ this.e = e;
+ this.br = 0;
+ this.line = [];
+ this.text = [];
+ this.original = e.innerText || e.textContent;
+}
+TSproto = TextSplitter.prototype;
+TSproto.Empty = function() {
+ for(var i = 0; i < this.text.length; ++i)
+ if(this.text[i].length)
+ return false;
+ return true;
+};
+TSproto.Lines = function(e) {
+ var r = e ? 1 : 0, cn, cl, i;
+ e = e || this.e;
+ cn = e.childNodes;
+ cl = cn.length;
+
+ for(i = 0; i < cl; ++i) {
+ if(cn[i].nodeName == 'BR') {
+ this.text.push(this.line.join(' '));
+ this.br = 1;
+ } else if(cn[i].nodeType == 3) {
+ if(this.br) {
+ this.line = [cn[i].nodeValue];
+ this.br = 0;
+ } else {
+ this.line.push(cn[i].nodeValue);
+ }
+ } else {
+ this.Lines(cn[i]);
+ }
+ }
+ r || this.br || this.text.push(this.line.join(' '));
+ return this.text;
+};
+TSproto.SplitWidth = function(w, c, f, h) {
+ var i, j, words, text = [];
+ c.font = h + 'px ' + f;
+ for(i = 0; i < this.text.length; ++i) {
+ words = this.text[i].split(/\s+/);
+ this.line = [words[0]];
+ for(j = 1; j < words.length; ++j) {
+ if(c.measureText(this.line.join(' ') + ' ' + words[j]).width > w) {
+ text.push(this.line.join(' '));
+ this.line = [words[j]];
+ } else {
+ this.line.push(words[j]);
+ }
+ }
+ text.push(this.line.join(' '));
+ }
+ return this.text = text;
+};
+/**
+ * @constructor
+ */
+function Outline(tc,t) {
+ this.ts = null;
+ this.tc = tc;
+ this.tag = t;
+ this.x = this.y = this.w = this.h = this.sc = 1;
+ this.z = 0;
+ this.pulse = 1;
+ this.pulsate = tc.pulsateTo < 1;
+ this.colour = tc.outlineColour;
+ this.adash = ~~tc.outlineDash;
+ this.agap = ~~tc.outlineDashSpace || this.adash;
+ this.aspeed = tc.outlineDashSpeed * 1;
+ if(this.colour == 'tag')
+ this.colour = GetProperty(t.a, 'color');
+ else if(this.colour == 'tagbg')
+ this.colour = GetProperty(t.a, 'background-color');
+ this.Draw = this.pulsate ? this.DrawPulsate : this.DrawSimple;
+ this.radius = tc.outlineRadius | 0;
+ this.SetMethod(tc.outlineMethod);
+}
+Oproto = Outline.prototype;
+Oproto.SetMethod = function(om) {
+ var methods = {
+ block: ['PreDraw','DrawBlock'],
+ colour: ['PreDraw','DrawColour'],
+ outline: ['PostDraw','DrawOutline'],
+ classic: ['LastDraw','DrawOutline'],
+ size: ['PreDraw','DrawSize'],
+ none: ['LastDraw']
+ }, funcs = methods[om] || methods.outline;
+ if(om == 'none') {
+ this.Draw = function() { return 1; }
+ } else {
+ this.drawFunc = this[funcs[1]];
+ }
+ this[funcs[0]] = this.Draw;
+};
+Oproto.Update = function(x,y,w,h,sc,z,xo,yo) {
+ var o = this.tc.outlineOffset, o2 = 2 * o;
+ this.x = sc * x + xo - o;
+ this.y = sc * y + yo - o;
+ this.w = sc * w + o2;
+ this.h = sc * h + o2;
+ this.sc = sc; // used to determine frontmost
+ this.z = z;
+};
+Oproto.Ants = function(c) {
+ if(!this.adash)
+ return;
+ var l = this.adash, g = this.agap, s = this.aspeed, length = l + g,
+ l1 = 0, l2 = l, g1 = g, g2 = 0, seq = 0, ants;
+ if(s) {
+ seq = abs(s) * (TimeNow() - this.ts) / 50;
+ if(s < 0)
+ seq = 8.64e6 - seq;
+ s = ~~seq % length;
+ }
+ if(s) {
+ if(l >= s) {
+ l1 = l - s;
+ l2 = s;
+ } else {
+ g1 = length - s;
+ g2 = g - g1;
+ }
+ ants = [l1, g1, l2, g2];
+ } else {
+ ants = [l,g];
+ }
+ c.setLineDash(ants);
+}
+Oproto.DrawOutline = function(c,x,y,w,h,colour) {
+ var r = min(this.radius, h/2, w/2);
+ c.strokeStyle = colour;
+ this.Ants(c);
+ RRect(c, x, y, w, h, r, true);
+};
+Oproto.DrawSize = function(c,x,y,w,h,colour,tag,x1,y1) {
+ var tw = tag.w, th = tag.h, m, i, sc;
+ if(this.pulsate) {
+ if(tag.image)
+ sc = (tag.image.height + this.tc.outlineIncrease) / tag.image.height;
+ else
+ sc = tag.oscale;
+ i = tag.fimage || tag.image;
+ m = 1 + ((sc - 1) * (1-this.pulse));
+ tag.h *= m;
+ tag.w *= m;
+ } else {
+ i = tag.oimage;
+ }
+ tag.alpha = 1;
+ tag.Draw(c, x1, y1, i);
+ tag.h = th;
+ tag.w = tw;
+ return 1;
+};
+Oproto.DrawColour = function(c,x,y,w,h,colour,tag,x1,y1) {
+ if(tag.oimage) {
+ if(this.pulse < 1) {
+ tag.alpha = 1 - pow(this.pulse, 2);
+ tag.Draw(c, x1, y1, tag.fimage);
+ tag.alpha = this.pulse;
+ } else {
+ tag.alpha = 1;
+ }
+ tag.Draw(c, x1, y1, tag.oimage);
+ return 1;
+ }
+ return this[tag.image ? 'DrawColourImage' : 'DrawColourText'](c,x,y,w,h,colour,tag,x1,y1);
+};
+Oproto.DrawColourText = function(c,x,y,w,h,colour,tag,x1,y1) {
+ var normal = tag.colour;
+ tag.colour = colour;
+ tag.alpha = 1;
+ tag.Draw(c,x1,y1);
+ tag.colour = normal;
+ return 1;
+};
+Oproto.DrawColourImage = function(c,x,y,w,h,colour,tag,x1,y1) {
+ var ccanvas = c.canvas, fx = ~~max(x,0), fy = ~~max(y,0),
+ fw = min(ccanvas.width - fx, w) + .5|0, fh = min(ccanvas.height - fy,h) + .5|0, cc;
+ if(ocanvas)
+ ocanvas.width = fw, ocanvas.height = fh;
+ else
+ ocanvas = NewCanvas(fw, fh);
+ if(!ocanvas)
+ return this.SetMethod('outline'); // if using IE and images, give up!
+ cc = ocanvas.getContext('2d');
+
+ cc.drawImage(ccanvas,fx,fy,fw,fh,0,0,fw,fh);
+ c.clearRect(fx,fy,fw,fh);
+ if(this.pulsate) {
+ tag.alpha = 1 - pow(this.pulse, 2);
+ } else {
+ tag.alpha = 1;
+ }
+ tag.Draw(c,x1,y1);
+ c.setTransform(1,0,0,1,0,0);
+ c.save();
+ c.beginPath();
+ c.rect(fx,fy,fw,fh);
+ c.clip();
+ c.globalCompositeOperation = 'source-in';
+ c.fillStyle = colour;
+ c.fillRect(fx,fy,fw,fh);
+ c.restore();
+ c.globalAlpha = 1;
+ c.globalCompositeOperation = 'destination-over';
+ c.drawImage(ocanvas,0,0,fw,fh,fx,fy,fw,fh);
+ c.globalCompositeOperation = 'source-over';
+ return 1;
+};
+Oproto.DrawBlock = function(c,x,y,w,h,colour) {
+ var r = min(this.radius, h/2, w/2);
+ c.fillStyle = colour;
+ RRect(c, x, y, w, h, r);
+};
+Oproto.DrawSimple = function(c, tag, x1, y1, ga, useGa) {
+ var t = this.tc;
+ c.setTransform(1,0,0,1,0,0);
+ c.strokeStyle = this.colour;
+ c.lineWidth = t.outlineThickness;
+ c.shadowBlur = c.shadowOffsetX = c.shadowOffsetY = 0;
+ c.globalAlpha = useGa ? ga : 1;
+ return this.drawFunc(c,this.x,this.y,this.w,this.h,this.colour,tag,x1,y1);
+};
+Oproto.DrawPulsate = function(c, tag, x1, y1) {
+ var diff = TimeNow() - this.ts, t = this.tc,
+ ga = t.pulsateTo + ((1 - t.pulsateTo) *
+ (0.5 + (cos(2 * Math.PI * diff / (1000 * t.pulsateTime)) / 2)));
+ this.pulse = ga = TagCanvas.Smooth(1,ga);
+ return this.DrawSimple(c, tag, x1, y1, ga, 1);
+};
+Oproto.Active = function(c,x,y) {
+ var a = (x >= this.x && y >= this.y &&
+ x <= this.x + this.w && y <= this.y + this.h);
+ if(a) {
+ this.ts = this.ts || TimeNow();
+ } else {
+ this.ts = null;
+ }
+ return a;
+};
+Oproto.PreDraw = Oproto.PostDraw = Oproto.LastDraw = Nop;
+/**
+ * @constructor
+ */
+function Tag(tc, text, a, v, w, h, col, bcol, bradius, boutline, bothickness,
+ font, padding, original) {
+ this.tc = tc;
+ this.image = null;
+ this.text = text;
+ this.text_original = original;
+ this.line_widths = [];
+ this.title = a.title || null;
+ this.a = a;
+ this.position = new Vector(v[0], v[1], v[2]);
+ this.x = this.y = this.z = 0;
+ this.w = w;
+ this.h = h;
+ this.colour = col || tc.textColour;
+ this.bgColour = bcol || tc.bgColour;
+ this.bgRadius = bradius | 0;
+ this.bgOutline = boutline || this.colour;
+ this.bgOutlineThickness = bothickness | 0;
+ this.textFont = font || tc.textFont;
+ this.padding = padding | 0;
+ this.sc = this.alpha = 1;
+ this.weighted = !tc.weight;
+ this.outline = new Outline(tc,this);
+}
+Tproto = Tag.prototype;
+Tproto.Init = function(e) {
+ var tc = this.tc;
+ this.textHeight = tc.textHeight;
+ if(this.HasText()) {
+ this.Measure(tc.ctxt,tc);
+ } else {
+ this.w = this.iw;
+ this.h = this.ih;
+ }
+
+ this.SetShadowColour = tc.shadowAlpha ? this.SetShadowColourAlpha : this.SetShadowColourFixed;
+ this.SetDraw(tc);
+};
+Tproto.Draw = Nop;
+Tproto.HasText = function() {
+ return this.text && this.text[0].length > 0;
+};
+Tproto.EqualTo = function(e) {
+ var i = e.getElementsByTagName('img');
+ if(this.a.href != e.href)
+ return 0;
+ if(i.length)
+ return this.image.src == i[0].src;
+ return (e.innerText || e.textContent) == this.text_original;
+};
+Tproto.SetImage = function(i) {
+ this.image = this.fimage = i;
+};
+Tproto.SetDraw = function(t) {
+ this.Draw = this.fimage ? (t.ie > 7 ? this.DrawImageIE : this.DrawImage) : this.DrawText;
+ t.noSelect && (this.CheckActive = Nop);
+};
+Tproto.MeasureText = function(c) {
+ var i, l = this.text.length, w = 0, wl;
+ for(i = 0; i < l; ++i) {
+ this.line_widths[i] = wl = c.measureText(this.text[i]).width;
+ w = max(w, wl);
+ }
+ return w;
+};
+Tproto.Measure = function(c,t) {
+ var extents = FindTextBoundingBox(this.text, this.textFont, this.textHeight),
+ s, th, f, soff, cw, twidth, theight, img, tcv;
+ // add the gap at the top to the height to make equal gap at bottom
+ theight = extents ? extents.max.y + extents.min.y : this.textHeight;
+ c.font = this.font = this.textHeight + 'px ' + this.textFont;
+ twidth = this.MeasureText(c);
+ if(t.txtOpt) {
+ s = t.txtScale;
+ th = s * this.textHeight;
+ f = th + 'px ' + this.textFont;
+ soff = [s * t.shadowOffset[0], s * t.shadowOffset[1]];
+ c.font = f;
+ cw = this.MeasureText(c);
+ tcv = new TextCanvas(this.text, f, cw + s, (s * theight) + s, cw,
+ this.line_widths, t.textAlign, t.textVAlign, s);
+
+ if(this.image)
+ tcv.SetImage(this.image, this.iw, this.ih, t.imagePosition, t.imagePadding,
+ t.imageAlign, t.imageVAlign, t.imageScale);
+
+ img = tcv.Create(this.colour, this.bgColour, this.bgOutline,
+ s * this.bgOutlineThickness, t.shadow, s * t.shadowBlur, soff,
+ s * this.padding, s * this.bgRadius);
+
+ // add outline image using highlight colour
+ if(t.outlineMethod == 'colour') {
+ this.oimage = tcv.Create(this.outline.colour, this.bgColour, this.outline.colour,
+ s * this.bgOutlineThickness, t.shadow, s * t.shadowBlur, soff,
+ s * this.padding, s * this.bgRadius);
+
+ } else if(t.outlineMethod == 'size') {
+ extents = FindTextBoundingBox(this.text, this.textFont,
+ this.textHeight + t.outlineIncrease);
+ th = extents.max.y + extents.min.y;
+ f = (s * (this.textHeight + t.outlineIncrease)) + 'px ' + this.textFont;
+ c.font = f;
+ cw = this.MeasureText(c);
+
+ tcv = new TextCanvas(this.text, f, cw + s, (s * th) + s, cw,
+ this.line_widths, t.textAlign, t.textVAlign, s);
+ if(this.image)
+ tcv.SetImage(this.image, this.iw + t.outlineIncrease,
+ this.ih + t.outlineIncrease, t.imagePosition, t.imagePadding,
+ t.imageAlign, t.imageVAlign, t.imageScale);
+
+ this.oimage = tcv.Create(this.colour, this.bgColour, this.bgOutline,
+ s * this.bgOutlineThickness, t.shadow, s * t.shadowBlur, soff,
+ s * this.padding, s * this.bgRadius);
+
+ this.oscale = this.oimage.width / img.width;
+ if(t.outlineIncrease > 0)
+ img = ExpandImage(img, this.oimage.width, this.oimage.height);
+ else
+ this.oimage = ExpandImage(this.oimage, img.width, img.height);
+ }
+ if(img) {
+ this.fimage = img;
+ twidth = this.fimage.width / s;
+ theight = this.fimage.height / s;
+ }
+ this.SetDraw(t);
+ t.txtOpt = !!this.fimage;
+ }
+ this.h = theight;
+ this.w = twidth;
+};
+Tproto.SetFont = function(f, c, bc, boc) {
+ this.textFont = f;
+ this.colour = c;
+ this.bgColour = bc;
+ this.bgOutline = boc;
+ this.Measure(this.tc.ctxt, this.tc);
+};
+Tproto.SetWeight = function(w) {
+ var tc = this.tc, modes = tc.weightMode.split(/[, ]/), m, s, wl = w.length;
+ if(!this.HasText())
+ return;
+ this.weighted = true;
+ for(s = 0; s < wl; ++s) {
+ m = modes[s] || 'size';
+ if('both' == m) {
+ this.Weight(w[s], tc.ctxt, tc, 'size', tc.min_weight[s],
+ tc.max_weight[s], s);
+ this.Weight(w[s], tc.ctxt, tc, 'colour', tc.min_weight[s],
+ tc.max_weight[s], s);
+ } else {
+ this.Weight(w[s], tc.ctxt, tc, m, tc.min_weight[s], tc.max_weight[s], s);
+ }
+ }
+ this.Measure(tc.ctxt, tc);
+};
+Tproto.Weight = function(w, c, t, m, wmin, wmax, wnum) {
+ w = isNaN(w) ? 1 : w;
+ var nweight = (w - wmin) / (wmax - wmin);
+ if('colour' == m)
+ this.colour = FindGradientColour(t, nweight, wnum);
+ else if('bgcolour' == m)
+ this.bgColour = FindGradientColour(t, nweight, wnum);
+ else if('bgoutline' == m)
+ this.bgOutline = FindGradientColour(t, nweight, wnum);
+ else if('outline' == m)
+ this.outline.colour = FindGradientColour(t, nweight, wnum);
+ else if('size' == m) {
+ if(t.weightSizeMin > 0 && t.weightSizeMax > t.weightSizeMin) {
+ this.textHeight = t.weightSize *
+ (t.weightSizeMin + (t.weightSizeMax - t.weightSizeMin) * nweight);
+ } else {
+ // min textHeight of 1
+ this.textHeight = max(1, w * t.weightSize);
+ }
+ }
+};
+Tproto.SetShadowColourFixed = function(c,s,a) {
+ c.shadowColor = s;
+};
+Tproto.SetShadowColourAlpha = function(c,s,a) {
+ c.shadowColor = SetAlpha(s, a);
+};
+Tproto.DrawText = function(c,xoff,yoff) {
+ var t = this.tc, x = this.x, y = this.y, s = this.sc, i, xl;
+ c.globalAlpha = this.alpha;
+ c.fillStyle = this.colour;
+ t.shadow && this.SetShadowColour(c,t.shadow,this.alpha);
+ c.font = this.font;
+ x += xoff / s;
+ y += (yoff / s) - (this.h / 2);
+ for(i = 0; i < this.text.length; ++i) {
+ xl = x;
+ if('right' == t.textAlign) {
+ xl += this.w / 2 - this.line_widths[i];
+ } else if('centre' == t.textAlign) {
+ xl -= this.line_widths[i] / 2;
+ } else {
+ xl -= this.w / 2;
+ }
+ c.setTransform(s, 0, 0, s, s * xl, s * y);
+ c.fillText(this.text[i], 0, 0);
+ y += this.textHeight;
+ }
+};
+Tproto.DrawImage = function(c,xoff,yoff,im) {
+ var x = this.x, y = this.y, s = this.sc,
+ i = im || this.fimage, w = this.w, h = this.h, a = this.alpha,
+ shadow = this.shadow;
+ c.globalAlpha = a;
+ shadow && this.SetShadowColour(c,shadow,a);
+ x += (xoff / s) - (w / 2);
+ y += (yoff / s) - (h / 2);
+ c.setTransform(s, 0, 0, s, s * x, s * y);
+ c.drawImage(i, 0, 0, w, h);
+};
+Tproto.DrawImageIE = function(c,xoff,yoff) {
+ var i = this.fimage, s = this.sc,
+ w = i.width = this.w*s, h = i.height = this.h * s,
+ x = (this.x*s) + xoff - (w/2), y = (this.y*s) + yoff - (h/2);
+ c.setTransform(1,0,0,1,0,0);
+ c.globalAlpha = this.alpha;
+ c.drawImage(i, x, y);
+};
+Tproto.Calc = function(m,a) {
+ var pp, t = this.tc, mnb = t.minBrightness,
+ mxb = t.maxBrightness, r = t.max_radius;
+ pp = m.xform(this.position);
+ this.xformed = pp;
+ pp = Project(t, pp, t.stretchX, t.stretchY);
+ this.x = pp.x;
+ this.y = pp.y;
+ this.z = pp.z;
+ this.sc = pp.w;
+ this.alpha = a * Clamp(mnb + (mxb - mnb) * (r - this.z) / (2 * r), 0, 1);
+ return this.xformed;
+};
+Tproto.UpdateActive = function(c, xoff, yoff) {
+ var o = this.outline, w = this.w, h = this.h,
+ x = this.x - w/2, y = this.y - h/2;
+ o.Update(x, y, w, h, this.sc, this.z, xoff, yoff);
+ return o;
+};
+Tproto.CheckActive = function(c,xoff,yoff) {
+ var t = this.tc, o = this.UpdateActive(c, xoff, yoff);
+ return o.Active(c, t.mx, t.my) ? o : null;
+};
+Tproto.Clicked = function(e) {
+ var a = this.a, t = a.target, h = a.href, evt;
+ if(t != '' && t != '_self') {
+ if(self.frames[t]) {
+ self.frames[t].document.location = h;
+ } else{
+ try {
+ if(top.frames[t]) {
+ top.frames[t].document.location = h;
+ return;
+ }
+ } catch(err) {
+ // different domain/port/protocol?
+ }
+ window.open(h, t);
+ }
+ return;
+ }
+ if(doc.createEvent) {
+ evt = doc.createEvent('MouseEvents');
+ evt.initMouseEvent('click', 1, 1, window, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null);
+ if(!a.dispatchEvent(evt))
+ return;
+ } else if(a.fireEvent) {
+ if(!a.fireEvent('onclick'))
+ return;
+ }
+ doc.location = h;
+};
+/**
+ * @constructor
+ */
+function TagCanvas(cid,lctr,opt) {
+ var i, p, c = doc.getElementById(cid), cp = ['id','class','innerHTML'], raf;
+
+ if(!c) throw 0;
+ if(Defined(window.G_vmlCanvasManager)) {
+ c = window.G_vmlCanvasManager.initElement(c);
+ this.ie = parseFloat(navigator.appVersion.split('MSIE')[1]);
+ }
+ if(c && (!c.getContext || !c.getContext('2d').fillText)) {
+ p = doc.createElement('DIV');
+ for(i = 0; i < cp.length; ++i)
+ p[cp[i]] = c[cp[i]];
+ c.parentNode.insertBefore(p,c);
+ c.parentNode.removeChild(c);
+ throw 0;
+ }
+ for(i in TagCanvas.options)
+ this[i] = opt && Defined(opt[i]) ? opt[i] :
+ (Defined(TagCanvas[i]) ? TagCanvas[i] : TagCanvas.options[i]);
+
+ this.canvas = c;
+ this.ctxt = c.getContext('2d');
+ this.z1 = 250 / max(this.depth, 0.001);
+ this.z2 = this.z1 / this.zoom;
+ this.radius = min(c.height, c.width) * 0.0075; // fits radius of 100 in canvas
+ this.max_radius = 100;
+ this.max_weight = [];
+ this.min_weight = [];
+ this.textFont = this.textFont && FixFont(this.textFont);
+ this.textHeight *= 1;
+ this.imageRadius = this.imageRadius.toString();
+ this.pulsateTo = Clamp(this.pulsateTo, 0, 1);
+ this.minBrightness = Clamp(this.minBrightness, 0, 1);
+ this.maxBrightness = Clamp(this.maxBrightness, this.minBrightness, 1);
+ this.ctxt.textBaseline = 'top';
+ this.lx = (this.lock + '').indexOf('x') + 1;
+ this.ly = (this.lock + '').indexOf('y') + 1;
+ this.frozen = this.dx = this.dy = this.fixedAnim = this.touchState = 0;
+ this.fixedAlpha = 1;
+ this.source = lctr || cid;
+ this.repeatTags = min(64, ~~this.repeatTags);
+ this.minTags = min(200, ~~this.minTags);
+ if(~~this.scrollPause > 0)
+ TagCanvas.scrollPause = ~~this.scrollPause;
+ else
+ this.scrollPause = 0;
+ if(this.minTags > 0 && this.repeatTags < 1 && (i = this.GetTags().length))
+ this.repeatTags = ceil(this.minTags / i) - 1;
+ this.transform = Matrix.Identity();
+ this.startTime = this.time = TimeNow();
+ this.mx = this.my = -1;
+ this.centreImage && CentreImage(this);
+ this.Animate = this.dragControl ? this.AnimateDrag : this.AnimatePosition;
+ this.animTiming = (typeof TagCanvas[this.animTiming] == 'function' ?
+ TagCanvas[this.animTiming] : TagCanvas.Smooth);
+ if(this.shadowBlur || this.shadowOffset[0] || this.shadowOffset[1]) {
+ // let the browser translate "red" into "#ff0000"
+ this.ctxt.shadowColor = this.shadow;
+ this.shadow = this.ctxt.shadowColor;
+ this.shadowAlpha = ShadowAlphaBroken();
+ } else {
+ delete this.shadow;
+ }
+ this.Load();
+ if(lctr && this.hideTags) {
+ (function(t) {
+ if(TagCanvas.loaded)
+ t.HideTags();
+ else
+ AddHandler('load', function() { t.HideTags(); }, window);
+ })(this);
+ }
+
+ this.yaw = this.initial ? this.initial[0] * this.maxSpeed : 0;
+ this.pitch = this.initial ? this.initial[1] * this.maxSpeed : 0;
+ if(this.tooltip) {
+ this.ctitle = c.title;
+ c.title = '';
+ if(this.tooltip == 'native') {
+ this.Tooltip = this.TooltipNative;
+ } else {
+ this.Tooltip = this.TooltipDiv;
+ if(!this.ttdiv) {
+ this.ttdiv = doc.createElement('div');
+ this.ttdiv.className = this.tooltipClass;
+ this.ttdiv.style.position = 'absolute';
+ this.ttdiv.style.zIndex = c.style.zIndex + 1;
+ AddHandler('mouseover',function(e){e.target.style.display='none';},this.ttdiv);
+ doc.body.appendChild(this.ttdiv);
+ }
+ }
+ } else {
+ this.Tooltip = this.TooltipNone;
+ }
+ if(!this.noMouse && !handlers[cid]) {
+ handlers[cid] = [
+ ['mousemove', MouseMove],
+ ['mouseout', MouseOut],
+ ['mouseup', MouseUp],
+ ['touchstart', TouchDown],
+ ['touchend', TouchUp],
+ ['touchcancel', TouchUp],
+ ['touchmove', TouchMove]
+ ];
+ if(this.dragControl) {
+ handlers[cid].push(['mousedown', MouseDown]);
+ handlers[cid].push(['selectstart', Nop]);
+ }
+ if(this.wheelZoom) {
+ handlers[cid].push(['mousewheel', MouseWheel]);
+ handlers[cid].push(['DOMMouseScroll', MouseWheel]);
+ }
+ if(this.scrollPause) {
+ handlers[cid].push(['scroll', Scroll, window]);
+ }
+ for(i = 0; i < handlers[cid].length; ++i) {
+ p = handlers[cid][i];
+ AddHandler(p[0], p[1], p[2] ? p[2] : c);
+ }
+ }
+ if(!TagCanvas.started) {
+ raf = window.requestAnimationFrame = window.requestAnimationFrame ||
+ window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame ||
+ window.msRequestAnimationFrame;
+ TagCanvas.NextFrame = raf ? TagCanvas.NextFrameRAF :
+ TagCanvas.NextFrameTimeout;
+ TagCanvas.interval = this.interval;
+ TagCanvas.NextFrame(this.interval);
+ TagCanvas.started = 1;
+ }
+}
+TCproto = TagCanvas.prototype;
+TCproto.SourceElements = function() {
+ if(doc.querySelectorAll)
+ return doc.querySelectorAll('#' + this.source);
+ return [doc.getElementById(this.source)];
+};
+TCproto.HideTags = function() {
+ var el = this.SourceElements(), i;
+ for(i = 0; i < el.length; ++i)
+ el[i].style.display = 'none';
+};
+TCproto.GetTags = function() {
+ var el = this.SourceElements(), etl, tl = [], i, j, k;
+ for(k = 0; k <= this.repeatTags; ++k) {
+ for(i = 0; i < el.length; ++i) {
+ etl = el[i].getElementsByTagName('a');
+ for(j = 0; j < etl.length; ++j) {
+ tl.push(etl[j]);
+ }
+ }
+ }
+ return tl;
+};
+TCproto.Message = function(text) {
+ var tl = [], i, p, tc = text.split(''), a, t, x, z;
+ for(i = 0; i < tc.length; ++i) {
+ if(tc[i] != ' ') {
+ p = i - tc.length / 2;
+ a = doc.createElement('A');
+ a.href = '#';
+ a.innerText = tc[i];
+ x = 100 * sin(p / 9);
+ z = -100 * cos(p / 9);
+ t = new Tag(this, tc[i], a, [x,0,z], 2, 18, '#000', '#fff', 0, 0, 0,
+ 'monospace', 2, tc[i]);
+ t.Init();
+ tl.push(t);
+ }
+ }
+ return tl;
+};
+TCproto.CreateTag = function(e) {
+ var im, i, t, txt, ts, font, bc, boc, p = [0, 0, 0];
+ if('text' != this.imageMode) {
+ im = e.getElementsByTagName('img');
+ if(im.length) {
+ i = new Image;
+ i.src = im[0].src;
+
+ if(!this.imageMode) {
+ t = new Tag(this, "", e, p, 0, 0);
+ t.SetImage(i);
+ //t.Init();
+ AddImage(i, im[0], t, this);
+ return t;
+ }
+ }
+ }
+ if('image' != this.imageMode) {
+ ts = new TextSplitter(e);
+ txt = ts.Lines();
+ if(!ts.Empty()) {
+ font = this.textFont || FixFont(GetProperty(e,'font-family'));
+ if(this.splitWidth)
+ txt = ts.SplitWidth(this.splitWidth, this.ctxt, font, this.textHeight);
+
+ bc = this.bgColour == 'tag' ? GetProperty(e, 'background-color') :
+ this.bgColour;
+ boc = this.bgOutline == 'tag' ? GetProperty(e, 'color') : this.bgOutline;
+ } else {
+ ts = null;
+ }
+ }
+ if(ts || i) {
+ t = new Tag(this, txt, e, p, 2, this.textHeight + 2,
+ this.textColour || GetProperty(e,'color'), bc, this.bgRadius,
+ boc, this.bgOutlineThickness, font, this.padding, ts && ts.original);
+ if(i) {
+ t.SetImage(i);
+ AddImage(i, im[0], t, this);
+ } else {
+ t.Init();
+ }
+ return t;
+ }
+};
+TCproto.UpdateTag = function(t, a) {
+ var colour = this.textColour || GetProperty(a, 'color'),
+ font = this.textFont || FixFont(GetProperty(a, 'font-family')),
+ bc = this.bgColour == 'tag' ? GetProperty(a, 'background-color') :
+ this.bgColour, boc = this.bgOutline == 'tag' ? GetProperty(a, 'color') :
+ this.bgOutline;
+ t.a = a;
+ t.title = a.title;
+ if(t.colour != colour || t.textFont != font || t.bgColour != bc ||
+ t.bgOutline != boc)
+ t.SetFont(font, colour, bc, boc);
+};
+TCproto.Weight = function(tl) {
+ var ll = tl.length, w, i, s, weights = [], valid,
+ wfrom = this.weightFrom ? this.weightFrom.split(/[, ]/) : [null],
+ wl = wfrom.length;
+ for(i = 0; i < ll; ++i) {
+ weights[i] = [];
+ for(s = 0; s < wl; ++s) {
+ w = FindWeight(tl[i].a, wfrom[s], this.textHeight);
+ if(!this.max_weight[s] || w > this.max_weight[s])
+ this.max_weight[s] = w;
+ if(!this.min_weight[s] || w < this.min_weight[s])
+ this.min_weight[s] = w;
+ weights[i][s] = w;
+ }
+ }
+ for(s = 0; s < wl; ++s) {
+ if(this.max_weight[s] > this.min_weight[s])
+ valid = 1;
+ }
+ if(valid) {
+ for(i = 0; i < ll; ++i) {
+ tl[i].SetWeight(weights[i]);
+ }
+ }
+};
+TCproto.Load = function() {
+ var tl = this.GetTags(), taglist = [], shape, t,
+ shapeArgs, rx, ry, rz, vl, i, tagmap = [], pfuncs = {
+ sphere: PointsOnSphere,
+ vcylinder: PointsOnCylinderV,
+ hcylinder: PointsOnCylinderH,
+ vring: PointsOnRingV,
+ hring: PointsOnRingH
+ };
+
+ if(tl.length) {
+ tagmap.length = tl.length;
+ for(i = 0; i < tl.length; ++i)
+ tagmap[i] = i;
+ this.shuffleTags && Shuffle(tagmap);
+ rx = 100 * this.radiusX;
+ ry = 100 * this.radiusY;
+ rz = 100 * this.radiusZ;
+ this.max_radius = max(rx, max(ry, rz));
+
+ for(i = 0; i < tl.length; ++i) {
+ t = this.CreateTag(tl[tagmap[i]]);
+ if(t)
+ taglist.push(t);
+ }
+ this.weight && this.Weight(taglist, true);
+
+ if(this.shapeArgs) {
+ this.shapeArgs[0] = taglist.length;
+ } else {
+ shapeArgs = this.shape.toString().split(/[(),]/);
+ shape = shapeArgs.shift();
+ if(typeof window[shape] === 'function')
+ this.shape = window[shape];
+ else
+ this.shape = pfuncs[shape] || pfuncs.sphere;
+ this.shapeArgs = [taglist.length, rx, ry, rz].concat(shapeArgs);
+ }
+ vl = this.shape.apply(this, this.shapeArgs);
+ this.listLength = taglist.length;
+ for(i = 0; i < taglist.length; ++i)
+ taglist[i].position = new Vector(vl[i][0], vl[i][1], vl[i][2]);
+ }
+ if(this.noTagsMessage && !taglist.length) {
+ i = (this.imageMode && this.imageMode != 'both' ? this.imageMode + ' ': '');
+ taglist = this.Message('No ' + i + 'tags');
+ }
+ this.taglist = taglist;
+};
+TCproto.Update = function() {
+ var tl = this.GetTags(), newlist = [],
+ taglist = this.taglist, found,
+ added = [], removed = [], vl, ol, nl, i, j;
+
+ if(!this.shapeArgs)
+ return this.Load();
+
+ if(tl.length) {
+ nl = this.listLength = tl.length;
+ ol = taglist.length;
+
+ // copy existing list, populate "removed"
+ for(i = 0; i < ol; ++i) {
+ newlist.push(taglist[i]);
+ removed.push(i);
+ }
+
+ // find added and removed tags
+ for(i = 0; i < nl; ++i) {
+ for(j = 0, found = 0; j < ol; ++j) {
+ if(taglist[j].EqualTo(tl[i])) {
+ this.UpdateTag(newlist[j], tl[i]);
+ found = removed[j] = -1;
+ }
+ }
+ if(!found)
+ added.push(i);
+ }
+
+ // clean out found tags from removed list
+ for(i = 0, j = 0; i < ol; ++i) {
+ if(removed[j] == -1)
+ removed.splice(j,1);
+ else
+ ++j;
+ }
+
+ // insert new tags in gaps where old tags removed
+ if(removed.length) {
+ Shuffle(removed);
+ while(removed.length && added.length) {
+ i = removed.shift();
+ j = added.shift();
+ newlist[i] = this.CreateTag(tl[j]);
+ }
+
+ // remove any more (in reverse order)
+ removed.sort(function(a,b) {return a-b});
+ while(removed.length) {
+ newlist.splice(removed.pop(), 1);
+ }
+ }
+
+ // add any extra tags
+ j = newlist.length / (added.length + 1);
+ i = 0;
+ while(added.length) {
+ newlist.splice(ceil(++i * j), 0, this.CreateTag(tl[added.shift()]));
+ }
+
+ // assign correct positions to tags
+ this.shapeArgs[0] = nl = newlist.length;
+ vl = this.shape.apply(this, this.shapeArgs);
+ for(i = 0; i < nl; ++i)
+ newlist[i].position = new Vector(vl[i][0], vl[i][1], vl[i][2]);
+
+ // reweight tags
+ this.weight && this.Weight(newlist);
+ }
+ this.taglist = newlist;
+};
+TCproto.SetShadow = function(c) {
+ c.shadowBlur = this.shadowBlur;
+ c.shadowOffsetX = this.shadowOffset[0];
+ c.shadowOffsetY = this.shadowOffset[1];
+};
+TCproto.Draw = function(t) {
+ if(this.paused)
+ return;
+ var cv = this.canvas, cw = cv.width, ch = cv.height, max_sc = 0,
+ tdelta = (t - this.time) * TagCanvas.interval / 1000,
+ x = cw / 2 + this.offsetX, y = ch / 2 + this.offsetY, c = this.ctxt,
+ active, a, i, aindex = -1, tl = this.taglist, l = tl.length,
+ frontsel = this.frontSelect, centreDrawn = (this.centreFunc == Nop), fixed;
+ this.time = t;
+ if(this.frozen && this.drawn)
+ return this.Animate(cw,ch,tdelta);
+ fixed = this.AnimateFixed();
+ c.setTransform(1,0,0,1,0,0);
+ for(i = 0; i < l; ++i)
+ tl[i].Calc(this.transform, this.fixedAlpha);
+ tl = SortList(tl, function(a,b) {return b.z-a.z});
+
+ if(fixed && this.fixedAnim.active) {
+ active = this.fixedAnim.tag.UpdateActive(c, x, y);
+ } else {
+ this.active = null;
+ for(i = 0; i < l; ++i) {
+ a = this.mx >= 0 && this.my >= 0 && this.taglist[i].CheckActive(c, x, y);
+ if(a && a.sc > max_sc && (!frontsel || a.z <= 0)) {
+ active = a;
+ aindex = i;
+ active.tag = this.taglist[i];
+ max_sc = a.sc;
+ }
+ }
+ this.active = active;
+ }
+
+ this.txtOpt || (this.shadow && this.SetShadow(c));
+ c.clearRect(0,0,cw,ch);
+ for(i = 0; i < l; ++i) {
+ if(!centreDrawn && tl[i].z <= 0) {
+ // run the centreFunc if the next tag is at the front
+ try { this.centreFunc(c, cw, ch, x, y); }
+ catch(e) {
+ alert(e);
+ // don't run it again
+ this.centreFunc = Nop;
+ }
+ centreDrawn = true;
+ }
+
+ if(!(active && active.tag == tl[i] && active.PreDraw(c, tl[i], x, y)))
+ tl[i].Draw(c, x, y);
+ active && active.tag == tl[i] && active.PostDraw(c);
+ }
+ if(this.freezeActive && active) {
+ this.Freeze();
+ } else {
+ this.UnFreeze();
+ this.drawn = (l == this.listLength);
+ }
+ if(this.fixedCallback) {
+ this.fixedCallback(this,this.fixedCallbackTag);
+ this.fixedCallback = null;
+ }
+ fixed || this.Animate(cw, ch, tdelta);
+ active && active.LastDraw(c);
+ cv.style.cursor = active ? this.activeCursor : '';
+ this.Tooltip(active,this.taglist[aindex]);
+};
+TCproto.TooltipNone = function() { };
+TCproto.TooltipNative = function(active,tag) {
+ if(active)
+ this.canvas.title = tag && tag.title ? tag.title : '';
+ else
+ this.canvas.title = this.ctitle;
+};
+TCproto.SetTTDiv = function(title, tag) {
+ var tc = this, s = tc.ttdiv.style;
+ if(title != tc.ttdiv.innerHTML)
+ s.display = 'none';
+ tc.ttdiv.innerHTML = title;
+ tag && (tag.title = tc.ttdiv.innerHTML);
+ if(s.display == 'none' && ! tc.tttimer) {
+ tc.tttimer = setTimeout(function() {
+ var p = AbsPos(tc.canvas.id);
+ s.display = 'block';
+ s.left = p.x + tc.mx + 'px';
+ s.top = p.y + tc.my + 24 + 'px';
+ tc.tttimer = null;
+ }, tc.tooltipDelay);
+ }
+};
+TCproto.TooltipDiv = function(active,tag) {
+ if(active && tag && tag.title) {
+ this.SetTTDiv(tag.title, tag);
+ } else if(!active && this.mx != -1 && this.my != -1 && this.ctitle.length) {
+ this.SetTTDiv(this.ctitle);
+ } else {
+ this.ttdiv.style.display = 'none';
+ }
+};
+TCproto.Transform = function(tc, p, y) {
+ if(p || y) {
+ var sp = sin(p), cp = cos(p), sy = sin(y), cy = cos(y),
+ ym = new Matrix([cy,0,sy, 0,1,0, -sy,0,cy]),
+ pm = new Matrix([1,0,0, 0,cp,-sp, 0,sp,cp]);
+ tc.transform = tc.transform.mul(ym.mul(pm));
+ }
+};
+TCproto.AnimateFixed = function() {
+ var fa, t1, angle, m, d;
+ if(this.fadeIn) {
+ t1 = TimeNow() - this.startTime;
+ if(t1 >= this.fadeIn) {
+ this.fadeIn = 0;
+ this.fixedAlpha = 1;
+ } else {
+ this.fixedAlpha = t1 / this.fadeIn;
+ }
+ }
+ if(this.fixedAnim) {
+ if(!this.fixedAnim.transform)
+ this.fixedAnim.transform = this.transform;
+ fa = this.fixedAnim, t1 = TimeNow() - fa.t0, angle = fa.angle,
+ m, d = this.animTiming(fa.t, t1);
+ this.transform = fa.transform;
+ if(t1 >= fa.t) {
+ this.fixedCallbackTag = fa.tag;
+ this.fixedCallback = fa.cb;
+ this.fixedAnim = this.yaw = this.pitch = 0;
+ } else {
+ angle *= d;
+ }
+ m = Matrix.Rotation(angle, fa.axis);
+ this.transform = this.transform.mul(m);
+ return (this.fixedAnim != 0);
+ }
+ return false;
+};
+TCproto.AnimatePosition = function(w, h, t) {
+ var tc = this, x = tc.mx, y = tc.my, s, r;
+ if(!tc.frozen && x >= 0 && y >= 0 && x < w && y < h) {
+ s = tc.maxSpeed, r = tc.reverse ? -1 : 1;
+ tc.lx || (tc.yaw = ((x * 2 * s / w) - s) * r * t);
+ tc.ly || (tc.pitch = ((y * 2 * s / h) - s) * -r * t);
+ tc.initial = null;
+ } else if(!tc.initial) {
+ if(tc.frozen && !tc.freezeDecel)
+ tc.yaw = tc.pitch = 0;
+ else
+ tc.Decel(tc);
+ }
+ this.Transform(tc, tc.pitch, tc.yaw);
+};
+TCproto.AnimateDrag = function(w, h, t) {
+ var tc = this, rs = 100 * t * tc.maxSpeed / tc.max_radius / tc.zoom;
+ if(tc.dx || tc.dy) {
+ tc.lx || (tc.yaw = tc.dx * rs / tc.stretchX);
+ tc.ly || (tc.pitch = tc.dy * -rs / tc.stretchY);
+ tc.dx = tc.dy = 0;
+ tc.initial = null;
+ } else if(!tc.initial) {
+ tc.Decel(tc);
+ }
+ this.Transform(tc, tc.pitch, tc.yaw);
+};
+TCproto.Freeze = function() {
+ if(!this.frozen) {
+ this.preFreeze = [this.yaw, this.pitch];
+ this.frozen = 1;
+ this.drawn = 0;
+ }
+};
+TCproto.UnFreeze = function() {
+ if(this.frozen) {
+ this.yaw = this.preFreeze[0];
+ this.pitch = this.preFreeze[1];
+ this.frozen = 0;
+ }
+};
+TCproto.Decel = function(tc) {
+ var s = tc.minSpeed, ay = abs(tc.yaw), ap = abs(tc.pitch);
+ if(!tc.lx && ay > s)
+ tc.yaw = ay > tc.z0 ? tc.yaw * tc.decel : 0;
+ if(!tc.ly && ap > s)
+ tc.pitch = ap > tc.z0 ? tc.pitch * tc.decel : 0;
+};
+TCproto.Zoom = function(r) {
+ this.z2 = this.z1 * (1/r);
+ this.drawn = 0;
+};
+TCproto.Clicked = function(e) {
+ var a = this.active;
+ try {
+ if(a && a.tag)
+ if(this.clickToFront === false || this.clickToFront === null)
+ a.tag.Clicked(e);
+ else
+ this.TagToFront(a.tag, this.clickToFront, function() {
+ a.tag.Clicked(e);
+ }, true);
+ } catch(ex) {
+ }
+};
+TCproto.Wheel = function(i) {
+ var z = this.zoom + this.zoomStep * (i ? 1 : -1);
+ this.zoom = min(this.zoomMax,max(this.zoomMin,z));
+ this.Zoom(this.zoom);
+};
+TCproto.BeginDrag = function(e) {
+ this.down = EventXY(e, this.canvas);
+ e.cancelBubble = true;
+ e.returnValue = false;
+ e.preventDefault && e.preventDefault();
+};
+TCproto.Drag = function(e, p) {
+ if(this.dragControl && this.down) {
+ var t2 = this.dragThreshold * this.dragThreshold,
+ dx = p.x - this.down.x, dy = p.y - this.down.y;
+ if(this.dragging || dx * dx + dy * dy > t2) {
+ this.dx = dx;
+ this.dy = dy;
+ this.dragging = 1;
+ this.down = p;
+ }
+ }
+ return this.dragging;
+};
+TCproto.EndDrag = function() {
+ var res = this.dragging;
+ this.dragging = this.down = null;
+ return res;
+};
+function PinchDistance(e) {
+ var t1 = e.targetTouches[0], t2 = e.targetTouches[1];
+ return sqrt(pow(t2.pageX - t1.pageX, 2) + pow(t2.pageY - t1.pageY, 2));
+}
+TCproto.BeginPinch = function(e) {
+ this.pinched = [PinchDistance(e), this.zoom];
+ e.preventDefault && e.preventDefault();
+};
+TCproto.Pinch = function(e) {
+ var z, d, p = this.pinched;
+ if(!p)
+ return;
+ d = PinchDistance(e);
+ z = p[1] * d / p[0];
+ this.zoom = min(this.zoomMax,max(this.zoomMin,z));
+ this.Zoom(this.zoom);
+};
+TCproto.EndPinch = function(e) {
+ this.pinched = null;
+};
+TCproto.Pause = function() { this.paused = true; };
+TCproto.Resume = function() { this.paused = false; };
+TCproto.SetSpeed = function(i) {
+ this.initial = i;
+ this.yaw = i[0] * this.maxSpeed;
+ this.pitch = i[1] * this.maxSpeed;
+};
+TCproto.FindTag = function(t) {
+ if(!Defined(t))
+ return null;
+ Defined(t.index) && (t = t.index);
+ if(!IsObject(t))
+ return this.taglist[t];
+ var srch, tgt, i;
+ if(Defined(t.id))
+ srch = 'id', tgt = t.id;
+ else if(Defined(t.text))
+ srch = 'innerText', tgt = t.text;
+
+ for(i = 0; i < this.taglist.length; ++i)
+ if(this.taglist[i].a[srch] == tgt)
+ return this.taglist[i];
+};
+TCproto.RotateTag = function(tag, lt, lg, time, callback, active) {
+ var t = tag.Calc(this.transform, 1), v1 = new Vector(t.x, t.y, t.z),
+ v2 = MakeVector(lg, lt), angle = v1.angle(v2), u = v1.cross(v2).unit();
+ if(angle == 0) {
+ this.fixedCallbackTag = tag;
+ this.fixedCallback = callback;
+ } else {
+ this.fixedAnim = {
+ angle: -angle,
+ axis: u,
+ t: time,
+ t0: TimeNow(),
+ cb: callback,
+ tag: tag,
+ active: active
+ };
+ }
+};
+TCproto.TagToFront = function(tag, time, callback, active) {
+ this.RotateTag(tag, 0, 0, time, callback, active);
+};
+TagCanvas.Start = function(id,l,o) {
+ TagCanvas.Delete(id);
+ TagCanvas.tc[id] = new TagCanvas(id,l,o);
+};
+function tccall(f,id) {
+ TagCanvas.tc[id] && TagCanvas.tc[id][f]();
+}
+TagCanvas.Linear = function(t, t0) { return t0 / t; }
+TagCanvas.Smooth = function(t, t0) { return 0.5 - cos(t0 * Math.PI / t) / 2; }
+TagCanvas.Pause = function(id) { tccall('Pause',id); };
+TagCanvas.Resume = function(id) { tccall('Resume',id); };
+TagCanvas.Reload = function(id) { tccall('Load',id); };
+TagCanvas.Update = function(id) { tccall('Update',id); };
+TagCanvas.SetSpeed = function(id, speed) {
+ if(IsObject(speed) && TagCanvas.tc[id] &&
+ !isNaN(speed[0]) && !isNaN(speed[1])) {
+ TagCanvas.tc[id].SetSpeed(speed);
+ return true;
+ }
+ return false;
+};
+TagCanvas.TagToFront = function(id, options) {
+ if(!IsObject(options))
+ return false;
+ options.lat = options.lng = 0;
+ return TagCanvas.RotateTag(id, options);
+};
+TagCanvas.RotateTag = function(id, options) {
+ if(IsObject(options) && TagCanvas.tc[id]) {
+ if(isNaN(options.time))
+ options.time = 500;
+ var tt = TagCanvas.tc[id].FindTag(options);
+ if(tt) {
+ TagCanvas.tc[id].RotateTag(tt, options.lat, options.lng,
+ options.time, options.callback, options.active);
+ return true;
+ }
+ }
+ return false;
+};
+TagCanvas.Delete = function(id) {
+ var i, c;
+ if(handlers[id]) {
+ c = doc.getElementById(id);
+ if(c) {
+ for(i = 0; i < handlers[id].length; ++i)
+ RemoveHandler(handlers[id][i][0], handlers[id][i][1], c);
+ }
+ }
+ delete handlers[id];
+ delete TagCanvas.tc[id];
+};
+TagCanvas.NextFrameRAF = function() {
+ requestAnimationFrame(DrawCanvasRAF);
+};
+TagCanvas.NextFrameTimeout = function(iv) {
+ setTimeout(DrawCanvas, iv);
+};
+TagCanvas.tc = {};
+TagCanvas.options = {
+z1: 20000,
+z2: 20000,
+z0: 0.0002,
+freezeActive: true,
+freezeDecel: false,
+activeCursor: 'pointer',
+pulsateTo: 1,
+pulsateTime: 3,
+reverse: false,
+depth: 0.5,
+maxSpeed: 0.05,
+minSpeed: 0,
+decel: 0.95,
+interval: 20,
+minBrightness: 0.1,
+maxBrightness: 1,
+outlineColour: '',
+outlineThickness: 2,
+outlineOffset: 5,
+outlineMethod: 'outline',
+outlineRadius: 0,
+textColour: ['#222', '#000'],
+textHeight: 15,
+textFont: 'Helvetica, Arial, sans-serif',
+shadow: '#111',
+shadowBlur: 1,
+shadowOffset: [0.1,0.1],
+initial: null,
+hideTags: false,
+zoom: 0,
+weight: false,
+weightMode: 'size',
+weightFrom: null,
+weightSize: 1,
+weightSizeMin: null,
+weightSizeMax: null,
+weightGradient: {0:'#f00', 0.33:'#ff0', 0.66:'#0f0', 1:'#00f'},
+txtOpt: true,
+txtScale: 2,
+frontSelect: false,
+wheelZoom: true,
+zoomMin: 0.8,
+zoomMax: 0.8,
+zoomStep: 0.05,
+shape: 'sphere',
+lock: null,
+tooltip: null,
+tooltipDelay: 300,
+tooltipClass: 'tctooltip',
+radiusX: 1,
+radiusY: 1,
+radiusZ: 1,
+stretchX: 1,
+stretchY: 1,
+offsetX: 0,
+offsetY: 0,
+shuffleTags: false,
+noSelect: false,
+noMouse: false,
+imageScale: 1,
+paused: false,
+dragControl: false,
+dragThreshold: 4,
+centreFunc: Nop,
+splitWidth: 0,
+animTiming: 'Smooth',
+clickToFront: false,
+fadeIn: 0,
+padding: 0,
+bgColour: null,
+bgRadius: 0,
+bgOutline: null,
+bgOutlineThickness: 0,
+outlineIncrease: 4,
+textAlign: 'centre',
+textVAlign: 'middle',
+imageMode: null,
+imagePosition: null,
+imagePadding: 2,
+imageAlign: 'centre',
+imageVAlign: 'middle',
+noTagsMessage: true,
+centreImage: null,
+pinchZoom: false,
+repeatTags: 0,
+minTags: 0,
+imageRadius: 0,
+scrollPause: false,
+outlineDash: 0,
+outlineDashSpace: 0,
+outlineDashSpeed: 1
+};
+for(i in TagCanvas.options) TagCanvas[i] = TagCanvas.options[i];
+window.TagCanvas = TagCanvas;
+// set a flag for when the window has loaded
+AddHandler('load',function(){TagCanvas.loaded=1},window);
+})();
diff --git a/js/tagcloud.js b/js/tagcloud.js
new file mode 100644
index 0000000..8c32469
--- /dev/null
+++ b/js/tagcloud.js
@@ -0,0 +1,60 @@
+
+
+function addLoadEvent(func) {
+ var oldonload = window.onload;
+ if (typeof window.onload != 'function') {
+ window.onload = func;
+ } else {
+ window.onload = function() {
+ oldonload();
+ func();
+ }
+ }
+ }
+
+
+ addLoadEvent(function() {
+ console.log('tag cloud plugin rock and roll!');
+ try {
+ var wid = document.body.clientWidth
+ var textHeight = wid / 18
+ if(textHeight>40){
+ textHeight = 40
+ }
+ var wid2 = parseInt(document.body.clientWidth * 0.45)
+ if(wid2<320){
+ wid2 = 320
+ }
+ document.getElementById("resCanvas").width=wid2;
+ document.getElementById("resCanvas").height=wid2;
+
+ TagCanvas.textFont = 'PingHei, PingFang SC, Helvetica Neue, Microsoft YaHei';
+ TagCanvas.textColour = '#333';
+ TagCanvas.textHeight = textHeight;
+ TagCanvas.outlineColour = '#E2E1D1';
+ TagCanvas.maxSpeed = 0.07;
+ TagCanvas.freezeActive = true;
+ TagCanvas.outlineMethod = 'block';
+ TagCanvas.minBrightness = 0.2;
+ TagCanvas.depth = 0.92;
+ TagCanvas.pulsateTo = 0.6;
+ TagCanvas.initial = [0.1,-0.1];
+ TagCanvas.decel = 0.98;
+ TagCanvas.reverse = true;
+ TagCanvas.hideTags = false;
+ TagCanvas.shadow = '#ccf';
+ TagCanvas.shadowBlur = 3;
+ TagCanvas.weight = false;
+ TagCanvas.imageScale = null;
+ TagCanvas.fadeIn = 1000;
+ TagCanvas.clickToFront = 600;
+ TagCanvas.lock = false;
+ TagCanvas.Start('resCanvas');
+ TagCanvas.tc['resCanvas'].Wheel(true)
+ } catch(e) {
+ console.log(e);
+ document.getElementById('myCanvasContainer').style.display = 'none';
+ }
+ });
+
+
diff --git a/js/visitors.js b/js/visitors.js
new file mode 100644
index 0000000..98fb5c1
--- /dev/null
+++ b/js/visitors.js
@@ -0,0 +1,6 @@
+var visitors_path = window.location.pathname
+var visitors_title = $(".post-title h3 a").text()
+
+$(".leancloud_visitors").html('热度')
+$(".leancloud_visitors").attr('id',visitors_path)
+$(".leancloud_visitors").attr('data-flag-title',visitors_title)
\ No newline at end of file
diff --git a/less/animated.less b/less/animated.less
new file mode 100644
index 0000000..66ad52a
--- /dev/null
+++ b/less/animated.less
@@ -0,0 +1,34 @@
+// Animated Icons
+// --------------------------
+
+.@{fa-css-prefix}-spin {
+ -webkit-animation: fa-spin 2s infinite linear;
+ animation: fa-spin 2s infinite linear;
+}
+
+.@{fa-css-prefix}-pulse {
+ -webkit-animation: fa-spin 1s infinite steps(8);
+ animation: fa-spin 1s infinite steps(8);
+}
+
+@-webkit-keyframes fa-spin {
+ 0% {
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg);
+ }
+ 100% {
+ -webkit-transform: rotate(359deg);
+ transform: rotate(359deg);
+ }
+}
+
+@keyframes fa-spin {
+ 0% {
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg);
+ }
+ 100% {
+ -webkit-transform: rotate(359deg);
+ transform: rotate(359deg);
+ }
+}
diff --git a/less/bordered-pulled.less b/less/bordered-pulled.less
new file mode 100644
index 0000000..f1c8ad7
--- /dev/null
+++ b/less/bordered-pulled.less
@@ -0,0 +1,25 @@
+// Bordered & Pulled
+// -------------------------
+
+.@{fa-css-prefix}-border {
+ padding: .2em .25em .15em;
+ border: solid .08em @fa-border-color;
+ border-radius: .1em;
+}
+
+.@{fa-css-prefix}-pull-left { float: left; }
+.@{fa-css-prefix}-pull-right { float: right; }
+
+.@{fa-css-prefix} {
+ &.@{fa-css-prefix}-pull-left { margin-right: .3em; }
+ &.@{fa-css-prefix}-pull-right { margin-left: .3em; }
+}
+
+/* Deprecated as of 4.4.0 */
+.pull-right { float: right; }
+.pull-left { float: left; }
+
+.@{fa-css-prefix} {
+ &.pull-left { margin-right: .3em; }
+ &.pull-right { margin-left: .3em; }
+}
diff --git a/less/core.less b/less/core.less
new file mode 100644
index 0000000..c577ac8
--- /dev/null
+++ b/less/core.less
@@ -0,0 +1,12 @@
+// Base Class Definition
+// -------------------------
+
+.@{fa-css-prefix} {
+ display: inline-block;
+ font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration
+ font-size: inherit; // can't have font-size inherit on line above, so need to override
+ text-rendering: auto; // optimizelegibility throws things off #1094
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+
+}
diff --git a/less/fixed-width.less b/less/fixed-width.less
new file mode 100644
index 0000000..110289f
--- /dev/null
+++ b/less/fixed-width.less
@@ -0,0 +1,6 @@
+// Fixed Width Icons
+// -------------------------
+.@{fa-css-prefix}-fw {
+ width: (18em / 14);
+ text-align: center;
+}
diff --git a/less/font-awesome.less b/less/font-awesome.less
new file mode 100644
index 0000000..c3677de
--- /dev/null
+++ b/less/font-awesome.less
@@ -0,0 +1,18 @@
+/*!
+ * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome
+ * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
+ */
+
+@import "variables.less";
+@import "mixins.less";
+@import "path.less";
+@import "core.less";
+@import "larger.less";
+@import "fixed-width.less";
+@import "list.less";
+@import "bordered-pulled.less";
+@import "animated.less";
+@import "rotated-flipped.less";
+@import "stacked.less";
+@import "icons.less";
+@import "screen-reader.less";
diff --git a/less/icons.less b/less/icons.less
new file mode 100644
index 0000000..159d600
--- /dev/null
+++ b/less/icons.less
@@ -0,0 +1,789 @@
+/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen
+ readers do not read off random characters that represent icons */
+
+.@{fa-css-prefix}-glass:before { content: @fa-var-glass; }
+.@{fa-css-prefix}-music:before { content: @fa-var-music; }
+.@{fa-css-prefix}-search:before { content: @fa-var-search; }
+.@{fa-css-prefix}-envelope-o:before { content: @fa-var-envelope-o; }
+.@{fa-css-prefix}-heart:before { content: @fa-var-heart; }
+.@{fa-css-prefix}-star:before { content: @fa-var-star; }
+.@{fa-css-prefix}-star-o:before { content: @fa-var-star-o; }
+.@{fa-css-prefix}-user:before { content: @fa-var-user; }
+.@{fa-css-prefix}-film:before { content: @fa-var-film; }
+.@{fa-css-prefix}-th-large:before { content: @fa-var-th-large; }
+.@{fa-css-prefix}-th:before { content: @fa-var-th; }
+.@{fa-css-prefix}-th-list:before { content: @fa-var-th-list; }
+.@{fa-css-prefix}-check:before { content: @fa-var-check; }
+.@{fa-css-prefix}-remove:before,
+.@{fa-css-prefix}-close:before,
+.@{fa-css-prefix}-times:before { content: @fa-var-times; }
+.@{fa-css-prefix}-search-plus:before { content: @fa-var-search-plus; }
+.@{fa-css-prefix}-search-minus:before { content: @fa-var-search-minus; }
+.@{fa-css-prefix}-power-off:before { content: @fa-var-power-off; }
+.@{fa-css-prefix}-signal:before { content: @fa-var-signal; }
+.@{fa-css-prefix}-gear:before,
+.@{fa-css-prefix}-cog:before { content: @fa-var-cog; }
+.@{fa-css-prefix}-trash-o:before { content: @fa-var-trash-o; }
+.@{fa-css-prefix}-home:before { content: @fa-var-home; }
+.@{fa-css-prefix}-file-o:before { content: @fa-var-file-o; }
+.@{fa-css-prefix}-clock-o:before { content: @fa-var-clock-o; }
+.@{fa-css-prefix}-road:before { content: @fa-var-road; }
+.@{fa-css-prefix}-download:before { content: @fa-var-download; }
+.@{fa-css-prefix}-arrow-circle-o-down:before { content: @fa-var-arrow-circle-o-down; }
+.@{fa-css-prefix}-arrow-circle-o-up:before { content: @fa-var-arrow-circle-o-up; }
+.@{fa-css-prefix}-inbox:before { content: @fa-var-inbox; }
+.@{fa-css-prefix}-play-circle-o:before { content: @fa-var-play-circle-o; }
+.@{fa-css-prefix}-rotate-right:before,
+.@{fa-css-prefix}-repeat:before { content: @fa-var-repeat; }
+.@{fa-css-prefix}-refresh:before { content: @fa-var-refresh; }
+.@{fa-css-prefix}-list-alt:before { content: @fa-var-list-alt; }
+.@{fa-css-prefix}-lock:before { content: @fa-var-lock; }
+.@{fa-css-prefix}-flag:before { content: @fa-var-flag; }
+.@{fa-css-prefix}-headphones:before { content: @fa-var-headphones; }
+.@{fa-css-prefix}-volume-off:before { content: @fa-var-volume-off; }
+.@{fa-css-prefix}-volume-down:before { content: @fa-var-volume-down; }
+.@{fa-css-prefix}-volume-up:before { content: @fa-var-volume-up; }
+.@{fa-css-prefix}-qrcode:before { content: @fa-var-qrcode; }
+.@{fa-css-prefix}-barcode:before { content: @fa-var-barcode; }
+.@{fa-css-prefix}-tag:before { content: @fa-var-tag; }
+.@{fa-css-prefix}-tags:before { content: @fa-var-tags; }
+.@{fa-css-prefix}-book:before { content: @fa-var-book; }
+.@{fa-css-prefix}-bookmark:before { content: @fa-var-bookmark; }
+.@{fa-css-prefix}-print:before { content: @fa-var-print; }
+.@{fa-css-prefix}-camera:before { content: @fa-var-camera; }
+.@{fa-css-prefix}-font:before { content: @fa-var-font; }
+.@{fa-css-prefix}-bold:before { content: @fa-var-bold; }
+.@{fa-css-prefix}-italic:before { content: @fa-var-italic; }
+.@{fa-css-prefix}-text-height:before { content: @fa-var-text-height; }
+.@{fa-css-prefix}-text-width:before { content: @fa-var-text-width; }
+.@{fa-css-prefix}-align-left:before { content: @fa-var-align-left; }
+.@{fa-css-prefix}-align-center:before { content: @fa-var-align-center; }
+.@{fa-css-prefix}-align-right:before { content: @fa-var-align-right; }
+.@{fa-css-prefix}-align-justify:before { content: @fa-var-align-justify; }
+.@{fa-css-prefix}-list:before { content: @fa-var-list; }
+.@{fa-css-prefix}-dedent:before,
+.@{fa-css-prefix}-outdent:before { content: @fa-var-outdent; }
+.@{fa-css-prefix}-indent:before { content: @fa-var-indent; }
+.@{fa-css-prefix}-video-camera:before { content: @fa-var-video-camera; }
+.@{fa-css-prefix}-photo:before,
+.@{fa-css-prefix}-image:before,
+.@{fa-css-prefix}-picture-o:before { content: @fa-var-picture-o; }
+.@{fa-css-prefix}-pencil:before { content: @fa-var-pencil; }
+.@{fa-css-prefix}-map-marker:before { content: @fa-var-map-marker; }
+.@{fa-css-prefix}-adjust:before { content: @fa-var-adjust; }
+.@{fa-css-prefix}-tint:before { content: @fa-var-tint; }
+.@{fa-css-prefix}-edit:before,
+.@{fa-css-prefix}-pencil-square-o:before { content: @fa-var-pencil-square-o; }
+.@{fa-css-prefix}-share-square-o:before { content: @fa-var-share-square-o; }
+.@{fa-css-prefix}-check-square-o:before { content: @fa-var-check-square-o; }
+.@{fa-css-prefix}-arrows:before { content: @fa-var-arrows; }
+.@{fa-css-prefix}-step-backward:before { content: @fa-var-step-backward; }
+.@{fa-css-prefix}-fast-backward:before { content: @fa-var-fast-backward; }
+.@{fa-css-prefix}-backward:before { content: @fa-var-backward; }
+.@{fa-css-prefix}-play:before { content: @fa-var-play; }
+.@{fa-css-prefix}-pause:before { content: @fa-var-pause; }
+.@{fa-css-prefix}-stop:before { content: @fa-var-stop; }
+.@{fa-css-prefix}-forward:before { content: @fa-var-forward; }
+.@{fa-css-prefix}-fast-forward:before { content: @fa-var-fast-forward; }
+.@{fa-css-prefix}-step-forward:before { content: @fa-var-step-forward; }
+.@{fa-css-prefix}-eject:before { content: @fa-var-eject; }
+.@{fa-css-prefix}-chevron-left:before { content: @fa-var-chevron-left; }
+.@{fa-css-prefix}-chevron-right:before { content: @fa-var-chevron-right; }
+.@{fa-css-prefix}-plus-circle:before { content: @fa-var-plus-circle; }
+.@{fa-css-prefix}-minus-circle:before { content: @fa-var-minus-circle; }
+.@{fa-css-prefix}-times-circle:before { content: @fa-var-times-circle; }
+.@{fa-css-prefix}-check-circle:before { content: @fa-var-check-circle; }
+.@{fa-css-prefix}-question-circle:before { content: @fa-var-question-circle; }
+.@{fa-css-prefix}-info-circle:before { content: @fa-var-info-circle; }
+.@{fa-css-prefix}-crosshairs:before { content: @fa-var-crosshairs; }
+.@{fa-css-prefix}-times-circle-o:before { content: @fa-var-times-circle-o; }
+.@{fa-css-prefix}-check-circle-o:before { content: @fa-var-check-circle-o; }
+.@{fa-css-prefix}-ban:before { content: @fa-var-ban; }
+.@{fa-css-prefix}-arrow-left:before { content: @fa-var-arrow-left; }
+.@{fa-css-prefix}-arrow-right:before { content: @fa-var-arrow-right; }
+.@{fa-css-prefix}-arrow-up:before { content: @fa-var-arrow-up; }
+.@{fa-css-prefix}-arrow-down:before { content: @fa-var-arrow-down; }
+.@{fa-css-prefix}-mail-forward:before,
+.@{fa-css-prefix}-share:before { content: @fa-var-share; }
+.@{fa-css-prefix}-expand:before { content: @fa-var-expand; }
+.@{fa-css-prefix}-compress:before { content: @fa-var-compress; }
+.@{fa-css-prefix}-plus:before { content: @fa-var-plus; }
+.@{fa-css-prefix}-minus:before { content: @fa-var-minus; }
+.@{fa-css-prefix}-asterisk:before { content: @fa-var-asterisk; }
+.@{fa-css-prefix}-exclamation-circle:before { content: @fa-var-exclamation-circle; }
+.@{fa-css-prefix}-gift:before { content: @fa-var-gift; }
+.@{fa-css-prefix}-leaf:before { content: @fa-var-leaf; }
+.@{fa-css-prefix}-fire:before { content: @fa-var-fire; }
+.@{fa-css-prefix}-eye:before { content: @fa-var-eye; }
+.@{fa-css-prefix}-eye-slash:before { content: @fa-var-eye-slash; }
+.@{fa-css-prefix}-warning:before,
+.@{fa-css-prefix}-exclamation-triangle:before { content: @fa-var-exclamation-triangle; }
+.@{fa-css-prefix}-plane:before { content: @fa-var-plane; }
+.@{fa-css-prefix}-calendar:before { content: @fa-var-calendar; }
+.@{fa-css-prefix}-random:before { content: @fa-var-random; }
+.@{fa-css-prefix}-comment:before { content: @fa-var-comment; }
+.@{fa-css-prefix}-magnet:before { content: @fa-var-magnet; }
+.@{fa-css-prefix}-chevron-up:before { content: @fa-var-chevron-up; }
+.@{fa-css-prefix}-chevron-down:before { content: @fa-var-chevron-down; }
+.@{fa-css-prefix}-retweet:before { content: @fa-var-retweet; }
+.@{fa-css-prefix}-shopping-cart:before { content: @fa-var-shopping-cart; }
+.@{fa-css-prefix}-folder:before { content: @fa-var-folder; }
+.@{fa-css-prefix}-folder-open:before { content: @fa-var-folder-open; }
+.@{fa-css-prefix}-arrows-v:before { content: @fa-var-arrows-v; }
+.@{fa-css-prefix}-arrows-h:before { content: @fa-var-arrows-h; }
+.@{fa-css-prefix}-bar-chart-o:before,
+.@{fa-css-prefix}-bar-chart:before { content: @fa-var-bar-chart; }
+.@{fa-css-prefix}-twitter-square:before { content: @fa-var-twitter-square; }
+.@{fa-css-prefix}-facebook-square:before { content: @fa-var-facebook-square; }
+.@{fa-css-prefix}-camera-retro:before { content: @fa-var-camera-retro; }
+.@{fa-css-prefix}-key:before { content: @fa-var-key; }
+.@{fa-css-prefix}-gears:before,
+.@{fa-css-prefix}-cogs:before { content: @fa-var-cogs; }
+.@{fa-css-prefix}-comments:before { content: @fa-var-comments; }
+.@{fa-css-prefix}-thumbs-o-up:before { content: @fa-var-thumbs-o-up; }
+.@{fa-css-prefix}-thumbs-o-down:before { content: @fa-var-thumbs-o-down; }
+.@{fa-css-prefix}-star-half:before { content: @fa-var-star-half; }
+.@{fa-css-prefix}-heart-o:before { content: @fa-var-heart-o; }
+.@{fa-css-prefix}-sign-out:before { content: @fa-var-sign-out; }
+.@{fa-css-prefix}-linkedin-square:before { content: @fa-var-linkedin-square; }
+.@{fa-css-prefix}-thumb-tack:before { content: @fa-var-thumb-tack; }
+.@{fa-css-prefix}-external-link:before { content: @fa-var-external-link; }
+.@{fa-css-prefix}-sign-in:before { content: @fa-var-sign-in; }
+.@{fa-css-prefix}-trophy:before { content: @fa-var-trophy; }
+.@{fa-css-prefix}-github-square:before { content: @fa-var-github-square; }
+.@{fa-css-prefix}-upload:before { content: @fa-var-upload; }
+.@{fa-css-prefix}-lemon-o:before { content: @fa-var-lemon-o; }
+.@{fa-css-prefix}-phone:before { content: @fa-var-phone; }
+.@{fa-css-prefix}-square-o:before { content: @fa-var-square-o; }
+.@{fa-css-prefix}-bookmark-o:before { content: @fa-var-bookmark-o; }
+.@{fa-css-prefix}-phone-square:before { content: @fa-var-phone-square; }
+.@{fa-css-prefix}-twitter:before { content: @fa-var-twitter; }
+.@{fa-css-prefix}-facebook-f:before,
+.@{fa-css-prefix}-facebook:before { content: @fa-var-facebook; }
+.@{fa-css-prefix}-github:before { content: @fa-var-github; }
+.@{fa-css-prefix}-unlock:before { content: @fa-var-unlock; }
+.@{fa-css-prefix}-credit-card:before { content: @fa-var-credit-card; }
+.@{fa-css-prefix}-feed:before,
+.@{fa-css-prefix}-rss:before { content: @fa-var-rss; }
+.@{fa-css-prefix}-hdd-o:before { content: @fa-var-hdd-o; }
+.@{fa-css-prefix}-bullhorn:before { content: @fa-var-bullhorn; }
+.@{fa-css-prefix}-bell:before { content: @fa-var-bell; }
+.@{fa-css-prefix}-certificate:before { content: @fa-var-certificate; }
+.@{fa-css-prefix}-hand-o-right:before { content: @fa-var-hand-o-right; }
+.@{fa-css-prefix}-hand-o-left:before { content: @fa-var-hand-o-left; }
+.@{fa-css-prefix}-hand-o-up:before { content: @fa-var-hand-o-up; }
+.@{fa-css-prefix}-hand-o-down:before { content: @fa-var-hand-o-down; }
+.@{fa-css-prefix}-arrow-circle-left:before { content: @fa-var-arrow-circle-left; }
+.@{fa-css-prefix}-arrow-circle-right:before { content: @fa-var-arrow-circle-right; }
+.@{fa-css-prefix}-arrow-circle-up:before { content: @fa-var-arrow-circle-up; }
+.@{fa-css-prefix}-arrow-circle-down:before { content: @fa-var-arrow-circle-down; }
+.@{fa-css-prefix}-globe:before { content: @fa-var-globe; }
+.@{fa-css-prefix}-wrench:before { content: @fa-var-wrench; }
+.@{fa-css-prefix}-tasks:before { content: @fa-var-tasks; }
+.@{fa-css-prefix}-filter:before { content: @fa-var-filter; }
+.@{fa-css-prefix}-briefcase:before { content: @fa-var-briefcase; }
+.@{fa-css-prefix}-arrows-alt:before { content: @fa-var-arrows-alt; }
+.@{fa-css-prefix}-group:before,
+.@{fa-css-prefix}-users:before { content: @fa-var-users; }
+.@{fa-css-prefix}-chain:before,
+.@{fa-css-prefix}-link:before { content: @fa-var-link; }
+.@{fa-css-prefix}-cloud:before { content: @fa-var-cloud; }
+.@{fa-css-prefix}-flask:before { content: @fa-var-flask; }
+.@{fa-css-prefix}-cut:before,
+.@{fa-css-prefix}-scissors:before { content: @fa-var-scissors; }
+.@{fa-css-prefix}-copy:before,
+.@{fa-css-prefix}-files-o:before { content: @fa-var-files-o; }
+.@{fa-css-prefix}-paperclip:before { content: @fa-var-paperclip; }
+.@{fa-css-prefix}-save:before,
+.@{fa-css-prefix}-floppy-o:before { content: @fa-var-floppy-o; }
+.@{fa-css-prefix}-square:before { content: @fa-var-square; }
+.@{fa-css-prefix}-navicon:before,
+.@{fa-css-prefix}-reorder:before,
+.@{fa-css-prefix}-bars:before { content: @fa-var-bars; }
+.@{fa-css-prefix}-list-ul:before { content: @fa-var-list-ul; }
+.@{fa-css-prefix}-list-ol:before { content: @fa-var-list-ol; }
+.@{fa-css-prefix}-strikethrough:before { content: @fa-var-strikethrough; }
+.@{fa-css-prefix}-underline:before { content: @fa-var-underline; }
+.@{fa-css-prefix}-table:before { content: @fa-var-table; }
+.@{fa-css-prefix}-magic:before { content: @fa-var-magic; }
+.@{fa-css-prefix}-truck:before { content: @fa-var-truck; }
+.@{fa-css-prefix}-pinterest:before { content: @fa-var-pinterest; }
+.@{fa-css-prefix}-pinterest-square:before { content: @fa-var-pinterest-square; }
+.@{fa-css-prefix}-google-plus-square:before { content: @fa-var-google-plus-square; }
+.@{fa-css-prefix}-google-plus:before { content: @fa-var-google-plus; }
+.@{fa-css-prefix}-money:before { content: @fa-var-money; }
+.@{fa-css-prefix}-caret-down:before { content: @fa-var-caret-down; }
+.@{fa-css-prefix}-caret-up:before { content: @fa-var-caret-up; }
+.@{fa-css-prefix}-caret-left:before { content: @fa-var-caret-left; }
+.@{fa-css-prefix}-caret-right:before { content: @fa-var-caret-right; }
+.@{fa-css-prefix}-columns:before { content: @fa-var-columns; }
+.@{fa-css-prefix}-unsorted:before,
+.@{fa-css-prefix}-sort:before { content: @fa-var-sort; }
+.@{fa-css-prefix}-sort-down:before,
+.@{fa-css-prefix}-sort-desc:before { content: @fa-var-sort-desc; }
+.@{fa-css-prefix}-sort-up:before,
+.@{fa-css-prefix}-sort-asc:before { content: @fa-var-sort-asc; }
+.@{fa-css-prefix}-envelope:before { content: @fa-var-envelope; }
+.@{fa-css-prefix}-linkedin:before { content: @fa-var-linkedin; }
+.@{fa-css-prefix}-rotate-left:before,
+.@{fa-css-prefix}-undo:before { content: @fa-var-undo; }
+.@{fa-css-prefix}-legal:before,
+.@{fa-css-prefix}-gavel:before { content: @fa-var-gavel; }
+.@{fa-css-prefix}-dashboard:before,
+.@{fa-css-prefix}-tachometer:before { content: @fa-var-tachometer; }
+.@{fa-css-prefix}-comment-o:before { content: @fa-var-comment-o; }
+.@{fa-css-prefix}-comments-o:before { content: @fa-var-comments-o; }
+.@{fa-css-prefix}-flash:before,
+.@{fa-css-prefix}-bolt:before { content: @fa-var-bolt; }
+.@{fa-css-prefix}-sitemap:before { content: @fa-var-sitemap; }
+.@{fa-css-prefix}-umbrella:before { content: @fa-var-umbrella; }
+.@{fa-css-prefix}-paste:before,
+.@{fa-css-prefix}-clipboard:before { content: @fa-var-clipboard; }
+.@{fa-css-prefix}-lightbulb-o:before { content: @fa-var-lightbulb-o; }
+.@{fa-css-prefix}-exchange:before { content: @fa-var-exchange; }
+.@{fa-css-prefix}-cloud-download:before { content: @fa-var-cloud-download; }
+.@{fa-css-prefix}-cloud-upload:before { content: @fa-var-cloud-upload; }
+.@{fa-css-prefix}-user-md:before { content: @fa-var-user-md; }
+.@{fa-css-prefix}-stethoscope:before { content: @fa-var-stethoscope; }
+.@{fa-css-prefix}-suitcase:before { content: @fa-var-suitcase; }
+.@{fa-css-prefix}-bell-o:before { content: @fa-var-bell-o; }
+.@{fa-css-prefix}-coffee:before { content: @fa-var-coffee; }
+.@{fa-css-prefix}-cutlery:before { content: @fa-var-cutlery; }
+.@{fa-css-prefix}-file-text-o:before { content: @fa-var-file-text-o; }
+.@{fa-css-prefix}-building-o:before { content: @fa-var-building-o; }
+.@{fa-css-prefix}-hospital-o:before { content: @fa-var-hospital-o; }
+.@{fa-css-prefix}-ambulance:before { content: @fa-var-ambulance; }
+.@{fa-css-prefix}-medkit:before { content: @fa-var-medkit; }
+.@{fa-css-prefix}-fighter-jet:before { content: @fa-var-fighter-jet; }
+.@{fa-css-prefix}-beer:before { content: @fa-var-beer; }
+.@{fa-css-prefix}-h-square:before { content: @fa-var-h-square; }
+.@{fa-css-prefix}-plus-square:before { content: @fa-var-plus-square; }
+.@{fa-css-prefix}-angle-double-left:before { content: @fa-var-angle-double-left; }
+.@{fa-css-prefix}-angle-double-right:before { content: @fa-var-angle-double-right; }
+.@{fa-css-prefix}-angle-double-up:before { content: @fa-var-angle-double-up; }
+.@{fa-css-prefix}-angle-double-down:before { content: @fa-var-angle-double-down; }
+.@{fa-css-prefix}-angle-left:before { content: @fa-var-angle-left; }
+.@{fa-css-prefix}-angle-right:before { content: @fa-var-angle-right; }
+.@{fa-css-prefix}-angle-up:before { content: @fa-var-angle-up; }
+.@{fa-css-prefix}-angle-down:before { content: @fa-var-angle-down; }
+.@{fa-css-prefix}-desktop:before { content: @fa-var-desktop; }
+.@{fa-css-prefix}-laptop:before { content: @fa-var-laptop; }
+.@{fa-css-prefix}-tablet:before { content: @fa-var-tablet; }
+.@{fa-css-prefix}-mobile-phone:before,
+.@{fa-css-prefix}-mobile:before { content: @fa-var-mobile; }
+.@{fa-css-prefix}-circle-o:before { content: @fa-var-circle-o; }
+.@{fa-css-prefix}-quote-left:before { content: @fa-var-quote-left; }
+.@{fa-css-prefix}-quote-right:before { content: @fa-var-quote-right; }
+.@{fa-css-prefix}-spinner:before { content: @fa-var-spinner; }
+.@{fa-css-prefix}-circle:before { content: @fa-var-circle; }
+.@{fa-css-prefix}-mail-reply:before,
+.@{fa-css-prefix}-reply:before { content: @fa-var-reply; }
+.@{fa-css-prefix}-github-alt:before { content: @fa-var-github-alt; }
+.@{fa-css-prefix}-folder-o:before { content: @fa-var-folder-o; }
+.@{fa-css-prefix}-folder-open-o:before { content: @fa-var-folder-open-o; }
+.@{fa-css-prefix}-smile-o:before { content: @fa-var-smile-o; }
+.@{fa-css-prefix}-frown-o:before { content: @fa-var-frown-o; }
+.@{fa-css-prefix}-meh-o:before { content: @fa-var-meh-o; }
+.@{fa-css-prefix}-gamepad:before { content: @fa-var-gamepad; }
+.@{fa-css-prefix}-keyboard-o:before { content: @fa-var-keyboard-o; }
+.@{fa-css-prefix}-flag-o:before { content: @fa-var-flag-o; }
+.@{fa-css-prefix}-flag-checkered:before { content: @fa-var-flag-checkered; }
+.@{fa-css-prefix}-terminal:before { content: @fa-var-terminal; }
+.@{fa-css-prefix}-code:before { content: @fa-var-code; }
+.@{fa-css-prefix}-mail-reply-all:before,
+.@{fa-css-prefix}-reply-all:before { content: @fa-var-reply-all; }
+.@{fa-css-prefix}-star-half-empty:before,
+.@{fa-css-prefix}-star-half-full:before,
+.@{fa-css-prefix}-star-half-o:before { content: @fa-var-star-half-o; }
+.@{fa-css-prefix}-location-arrow:before { content: @fa-var-location-arrow; }
+.@{fa-css-prefix}-crop:before { content: @fa-var-crop; }
+.@{fa-css-prefix}-code-fork:before { content: @fa-var-code-fork; }
+.@{fa-css-prefix}-unlink:before,
+.@{fa-css-prefix}-chain-broken:before { content: @fa-var-chain-broken; }
+.@{fa-css-prefix}-question:before { content: @fa-var-question; }
+.@{fa-css-prefix}-info:before { content: @fa-var-info; }
+.@{fa-css-prefix}-exclamation:before { content: @fa-var-exclamation; }
+.@{fa-css-prefix}-superscript:before { content: @fa-var-superscript; }
+.@{fa-css-prefix}-subscript:before { content: @fa-var-subscript; }
+.@{fa-css-prefix}-eraser:before { content: @fa-var-eraser; }
+.@{fa-css-prefix}-puzzle-piece:before { content: @fa-var-puzzle-piece; }
+.@{fa-css-prefix}-microphone:before { content: @fa-var-microphone; }
+.@{fa-css-prefix}-microphone-slash:before { content: @fa-var-microphone-slash; }
+.@{fa-css-prefix}-shield:before { content: @fa-var-shield; }
+.@{fa-css-prefix}-calendar-o:before { content: @fa-var-calendar-o; }
+.@{fa-css-prefix}-fire-extinguisher:before { content: @fa-var-fire-extinguisher; }
+.@{fa-css-prefix}-rocket:before { content: @fa-var-rocket; }
+.@{fa-css-prefix}-maxcdn:before { content: @fa-var-maxcdn; }
+.@{fa-css-prefix}-chevron-circle-left:before { content: @fa-var-chevron-circle-left; }
+.@{fa-css-prefix}-chevron-circle-right:before { content: @fa-var-chevron-circle-right; }
+.@{fa-css-prefix}-chevron-circle-up:before { content: @fa-var-chevron-circle-up; }
+.@{fa-css-prefix}-chevron-circle-down:before { content: @fa-var-chevron-circle-down; }
+.@{fa-css-prefix}-html5:before { content: @fa-var-html5; }
+.@{fa-css-prefix}-css3:before { content: @fa-var-css3; }
+.@{fa-css-prefix}-anchor:before { content: @fa-var-anchor; }
+.@{fa-css-prefix}-unlock-alt:before { content: @fa-var-unlock-alt; }
+.@{fa-css-prefix}-bullseye:before { content: @fa-var-bullseye; }
+.@{fa-css-prefix}-ellipsis-h:before { content: @fa-var-ellipsis-h; }
+.@{fa-css-prefix}-ellipsis-v:before { content: @fa-var-ellipsis-v; }
+.@{fa-css-prefix}-rss-square:before { content: @fa-var-rss-square; }
+.@{fa-css-prefix}-play-circle:before { content: @fa-var-play-circle; }
+.@{fa-css-prefix}-ticket:before { content: @fa-var-ticket; }
+.@{fa-css-prefix}-minus-square:before { content: @fa-var-minus-square; }
+.@{fa-css-prefix}-minus-square-o:before { content: @fa-var-minus-square-o; }
+.@{fa-css-prefix}-level-up:before { content: @fa-var-level-up; }
+.@{fa-css-prefix}-level-down:before { content: @fa-var-level-down; }
+.@{fa-css-prefix}-check-square:before { content: @fa-var-check-square; }
+.@{fa-css-prefix}-pencil-square:before { content: @fa-var-pencil-square; }
+.@{fa-css-prefix}-external-link-square:before { content: @fa-var-external-link-square; }
+.@{fa-css-prefix}-share-square:before { content: @fa-var-share-square; }
+.@{fa-css-prefix}-compass:before { content: @fa-var-compass; }
+.@{fa-css-prefix}-toggle-down:before,
+.@{fa-css-prefix}-caret-square-o-down:before { content: @fa-var-caret-square-o-down; }
+.@{fa-css-prefix}-toggle-up:before,
+.@{fa-css-prefix}-caret-square-o-up:before { content: @fa-var-caret-square-o-up; }
+.@{fa-css-prefix}-toggle-right:before,
+.@{fa-css-prefix}-caret-square-o-right:before { content: @fa-var-caret-square-o-right; }
+.@{fa-css-prefix}-euro:before,
+.@{fa-css-prefix}-eur:before { content: @fa-var-eur; }
+.@{fa-css-prefix}-gbp:before { content: @fa-var-gbp; }
+.@{fa-css-prefix}-dollar:before,
+.@{fa-css-prefix}-usd:before { content: @fa-var-usd; }
+.@{fa-css-prefix}-rupee:before,
+.@{fa-css-prefix}-inr:before { content: @fa-var-inr; }
+.@{fa-css-prefix}-cny:before,
+.@{fa-css-prefix}-rmb:before,
+.@{fa-css-prefix}-yen:before,
+.@{fa-css-prefix}-jpy:before { content: @fa-var-jpy; }
+.@{fa-css-prefix}-ruble:before,
+.@{fa-css-prefix}-rouble:before,
+.@{fa-css-prefix}-rub:before { content: @fa-var-rub; }
+.@{fa-css-prefix}-won:before,
+.@{fa-css-prefix}-krw:before { content: @fa-var-krw; }
+.@{fa-css-prefix}-bitcoin:before,
+.@{fa-css-prefix}-btc:before { content: @fa-var-btc; }
+.@{fa-css-prefix}-file:before { content: @fa-var-file; }
+.@{fa-css-prefix}-file-text:before { content: @fa-var-file-text; }
+.@{fa-css-prefix}-sort-alpha-asc:before { content: @fa-var-sort-alpha-asc; }
+.@{fa-css-prefix}-sort-alpha-desc:before { content: @fa-var-sort-alpha-desc; }
+.@{fa-css-prefix}-sort-amount-asc:before { content: @fa-var-sort-amount-asc; }
+.@{fa-css-prefix}-sort-amount-desc:before { content: @fa-var-sort-amount-desc; }
+.@{fa-css-prefix}-sort-numeric-asc:before { content: @fa-var-sort-numeric-asc; }
+.@{fa-css-prefix}-sort-numeric-desc:before { content: @fa-var-sort-numeric-desc; }
+.@{fa-css-prefix}-thumbs-up:before { content: @fa-var-thumbs-up; }
+.@{fa-css-prefix}-thumbs-down:before { content: @fa-var-thumbs-down; }
+.@{fa-css-prefix}-youtube-square:before { content: @fa-var-youtube-square; }
+.@{fa-css-prefix}-youtube:before { content: @fa-var-youtube; }
+.@{fa-css-prefix}-xing:before { content: @fa-var-xing; }
+.@{fa-css-prefix}-xing-square:before { content: @fa-var-xing-square; }
+.@{fa-css-prefix}-youtube-play:before { content: @fa-var-youtube-play; }
+.@{fa-css-prefix}-dropbox:before { content: @fa-var-dropbox; }
+.@{fa-css-prefix}-stack-overflow:before { content: @fa-var-stack-overflow; }
+.@{fa-css-prefix}-instagram:before { content: @fa-var-instagram; }
+.@{fa-css-prefix}-flickr:before { content: @fa-var-flickr; }
+.@{fa-css-prefix}-adn:before { content: @fa-var-adn; }
+.@{fa-css-prefix}-bitbucket:before { content: @fa-var-bitbucket; }
+.@{fa-css-prefix}-bitbucket-square:before { content: @fa-var-bitbucket-square; }
+.@{fa-css-prefix}-tumblr:before { content: @fa-var-tumblr; }
+.@{fa-css-prefix}-tumblr-square:before { content: @fa-var-tumblr-square; }
+.@{fa-css-prefix}-long-arrow-down:before { content: @fa-var-long-arrow-down; }
+.@{fa-css-prefix}-long-arrow-up:before { content: @fa-var-long-arrow-up; }
+.@{fa-css-prefix}-long-arrow-left:before { content: @fa-var-long-arrow-left; }
+.@{fa-css-prefix}-long-arrow-right:before { content: @fa-var-long-arrow-right; }
+.@{fa-css-prefix}-apple:before { content: @fa-var-apple; }
+.@{fa-css-prefix}-windows:before { content: @fa-var-windows; }
+.@{fa-css-prefix}-android:before { content: @fa-var-android; }
+.@{fa-css-prefix}-linux:before { content: @fa-var-linux; }
+.@{fa-css-prefix}-dribbble:before { content: @fa-var-dribbble; }
+.@{fa-css-prefix}-skype:before { content: @fa-var-skype; }
+.@{fa-css-prefix}-foursquare:before { content: @fa-var-foursquare; }
+.@{fa-css-prefix}-trello:before { content: @fa-var-trello; }
+.@{fa-css-prefix}-female:before { content: @fa-var-female; }
+.@{fa-css-prefix}-male:before { content: @fa-var-male; }
+.@{fa-css-prefix}-gittip:before,
+.@{fa-css-prefix}-gratipay:before { content: @fa-var-gratipay; }
+.@{fa-css-prefix}-sun-o:before { content: @fa-var-sun-o; }
+.@{fa-css-prefix}-moon-o:before { content: @fa-var-moon-o; }
+.@{fa-css-prefix}-archive:before { content: @fa-var-archive; }
+.@{fa-css-prefix}-bug:before { content: @fa-var-bug; }
+.@{fa-css-prefix}-vk:before { content: @fa-var-vk; }
+.@{fa-css-prefix}-weibo:before { content: @fa-var-weibo; }
+.@{fa-css-prefix}-renren:before { content: @fa-var-renren; }
+.@{fa-css-prefix}-pagelines:before { content: @fa-var-pagelines; }
+.@{fa-css-prefix}-stack-exchange:before { content: @fa-var-stack-exchange; }
+.@{fa-css-prefix}-arrow-circle-o-right:before { content: @fa-var-arrow-circle-o-right; }
+.@{fa-css-prefix}-arrow-circle-o-left:before { content: @fa-var-arrow-circle-o-left; }
+.@{fa-css-prefix}-toggle-left:before,
+.@{fa-css-prefix}-caret-square-o-left:before { content: @fa-var-caret-square-o-left; }
+.@{fa-css-prefix}-dot-circle-o:before { content: @fa-var-dot-circle-o; }
+.@{fa-css-prefix}-wheelchair:before { content: @fa-var-wheelchair; }
+.@{fa-css-prefix}-vimeo-square:before { content: @fa-var-vimeo-square; }
+.@{fa-css-prefix}-turkish-lira:before,
+.@{fa-css-prefix}-try:before { content: @fa-var-try; }
+.@{fa-css-prefix}-plus-square-o:before { content: @fa-var-plus-square-o; }
+.@{fa-css-prefix}-space-shuttle:before { content: @fa-var-space-shuttle; }
+.@{fa-css-prefix}-slack:before { content: @fa-var-slack; }
+.@{fa-css-prefix}-envelope-square:before { content: @fa-var-envelope-square; }
+.@{fa-css-prefix}-wordpress:before { content: @fa-var-wordpress; }
+.@{fa-css-prefix}-openid:before { content: @fa-var-openid; }
+.@{fa-css-prefix}-institution:before,
+.@{fa-css-prefix}-bank:before,
+.@{fa-css-prefix}-university:before { content: @fa-var-university; }
+.@{fa-css-prefix}-mortar-board:before,
+.@{fa-css-prefix}-graduation-cap:before { content: @fa-var-graduation-cap; }
+.@{fa-css-prefix}-yahoo:before { content: @fa-var-yahoo; }
+.@{fa-css-prefix}-google:before { content: @fa-var-google; }
+.@{fa-css-prefix}-reddit:before { content: @fa-var-reddit; }
+.@{fa-css-prefix}-reddit-square:before { content: @fa-var-reddit-square; }
+.@{fa-css-prefix}-stumbleupon-circle:before { content: @fa-var-stumbleupon-circle; }
+.@{fa-css-prefix}-stumbleupon:before { content: @fa-var-stumbleupon; }
+.@{fa-css-prefix}-delicious:before { content: @fa-var-delicious; }
+.@{fa-css-prefix}-digg:before { content: @fa-var-digg; }
+.@{fa-css-prefix}-pied-piper-pp:before { content: @fa-var-pied-piper-pp; }
+.@{fa-css-prefix}-pied-piper-alt:before { content: @fa-var-pied-piper-alt; }
+.@{fa-css-prefix}-drupal:before { content: @fa-var-drupal; }
+.@{fa-css-prefix}-joomla:before { content: @fa-var-joomla; }
+.@{fa-css-prefix}-language:before { content: @fa-var-language; }
+.@{fa-css-prefix}-fax:before { content: @fa-var-fax; }
+.@{fa-css-prefix}-building:before { content: @fa-var-building; }
+.@{fa-css-prefix}-child:before { content: @fa-var-child; }
+.@{fa-css-prefix}-paw:before { content: @fa-var-paw; }
+.@{fa-css-prefix}-spoon:before { content: @fa-var-spoon; }
+.@{fa-css-prefix}-cube:before { content: @fa-var-cube; }
+.@{fa-css-prefix}-cubes:before { content: @fa-var-cubes; }
+.@{fa-css-prefix}-behance:before { content: @fa-var-behance; }
+.@{fa-css-prefix}-behance-square:before { content: @fa-var-behance-square; }
+.@{fa-css-prefix}-steam:before { content: @fa-var-steam; }
+.@{fa-css-prefix}-steam-square:before { content: @fa-var-steam-square; }
+.@{fa-css-prefix}-recycle:before { content: @fa-var-recycle; }
+.@{fa-css-prefix}-automobile:before,
+.@{fa-css-prefix}-car:before { content: @fa-var-car; }
+.@{fa-css-prefix}-cab:before,
+.@{fa-css-prefix}-taxi:before { content: @fa-var-taxi; }
+.@{fa-css-prefix}-tree:before { content: @fa-var-tree; }
+.@{fa-css-prefix}-spotify:before { content: @fa-var-spotify; }
+.@{fa-css-prefix}-deviantart:before { content: @fa-var-deviantart; }
+.@{fa-css-prefix}-soundcloud:before { content: @fa-var-soundcloud; }
+.@{fa-css-prefix}-database:before { content: @fa-var-database; }
+.@{fa-css-prefix}-file-pdf-o:before { content: @fa-var-file-pdf-o; }
+.@{fa-css-prefix}-file-word-o:before { content: @fa-var-file-word-o; }
+.@{fa-css-prefix}-file-excel-o:before { content: @fa-var-file-excel-o; }
+.@{fa-css-prefix}-file-powerpoint-o:before { content: @fa-var-file-powerpoint-o; }
+.@{fa-css-prefix}-file-photo-o:before,
+.@{fa-css-prefix}-file-picture-o:before,
+.@{fa-css-prefix}-file-image-o:before { content: @fa-var-file-image-o; }
+.@{fa-css-prefix}-file-zip-o:before,
+.@{fa-css-prefix}-file-archive-o:before { content: @fa-var-file-archive-o; }
+.@{fa-css-prefix}-file-sound-o:before,
+.@{fa-css-prefix}-file-audio-o:before { content: @fa-var-file-audio-o; }
+.@{fa-css-prefix}-file-movie-o:before,
+.@{fa-css-prefix}-file-video-o:before { content: @fa-var-file-video-o; }
+.@{fa-css-prefix}-file-code-o:before { content: @fa-var-file-code-o; }
+.@{fa-css-prefix}-vine:before { content: @fa-var-vine; }
+.@{fa-css-prefix}-codepen:before { content: @fa-var-codepen; }
+.@{fa-css-prefix}-jsfiddle:before { content: @fa-var-jsfiddle; }
+.@{fa-css-prefix}-life-bouy:before,
+.@{fa-css-prefix}-life-buoy:before,
+.@{fa-css-prefix}-life-saver:before,
+.@{fa-css-prefix}-support:before,
+.@{fa-css-prefix}-life-ring:before { content: @fa-var-life-ring; }
+.@{fa-css-prefix}-circle-o-notch:before { content: @fa-var-circle-o-notch; }
+.@{fa-css-prefix}-ra:before,
+.@{fa-css-prefix}-resistance:before,
+.@{fa-css-prefix}-rebel:before { content: @fa-var-rebel; }
+.@{fa-css-prefix}-ge:before,
+.@{fa-css-prefix}-empire:before { content: @fa-var-empire; }
+.@{fa-css-prefix}-git-square:before { content: @fa-var-git-square; }
+.@{fa-css-prefix}-git:before { content: @fa-var-git; }
+.@{fa-css-prefix}-y-combinator-square:before,
+.@{fa-css-prefix}-yc-square:before,
+.@{fa-css-prefix}-hacker-news:before { content: @fa-var-hacker-news; }
+.@{fa-css-prefix}-tencent-weibo:before { content: @fa-var-tencent-weibo; }
+.@{fa-css-prefix}-qq:before { content: @fa-var-qq; }
+.@{fa-css-prefix}-wechat:before,
+.@{fa-css-prefix}-weixin:before { content: @fa-var-weixin; }
+.@{fa-css-prefix}-send:before,
+.@{fa-css-prefix}-paper-plane:before { content: @fa-var-paper-plane; }
+.@{fa-css-prefix}-send-o:before,
+.@{fa-css-prefix}-paper-plane-o:before { content: @fa-var-paper-plane-o; }
+.@{fa-css-prefix}-history:before { content: @fa-var-history; }
+.@{fa-css-prefix}-circle-thin:before { content: @fa-var-circle-thin; }
+.@{fa-css-prefix}-header:before { content: @fa-var-header; }
+.@{fa-css-prefix}-paragraph:before { content: @fa-var-paragraph; }
+.@{fa-css-prefix}-sliders:before { content: @fa-var-sliders; }
+.@{fa-css-prefix}-share-alt:before { content: @fa-var-share-alt; }
+.@{fa-css-prefix}-share-alt-square:before { content: @fa-var-share-alt-square; }
+.@{fa-css-prefix}-bomb:before { content: @fa-var-bomb; }
+.@{fa-css-prefix}-soccer-ball-o:before,
+.@{fa-css-prefix}-futbol-o:before { content: @fa-var-futbol-o; }
+.@{fa-css-prefix}-tty:before { content: @fa-var-tty; }
+.@{fa-css-prefix}-binoculars:before { content: @fa-var-binoculars; }
+.@{fa-css-prefix}-plug:before { content: @fa-var-plug; }
+.@{fa-css-prefix}-slideshare:before { content: @fa-var-slideshare; }
+.@{fa-css-prefix}-twitch:before { content: @fa-var-twitch; }
+.@{fa-css-prefix}-yelp:before { content: @fa-var-yelp; }
+.@{fa-css-prefix}-newspaper-o:before { content: @fa-var-newspaper-o; }
+.@{fa-css-prefix}-wifi:before { content: @fa-var-wifi; }
+.@{fa-css-prefix}-calculator:before { content: @fa-var-calculator; }
+.@{fa-css-prefix}-paypal:before { content: @fa-var-paypal; }
+.@{fa-css-prefix}-google-wallet:before { content: @fa-var-google-wallet; }
+.@{fa-css-prefix}-cc-visa:before { content: @fa-var-cc-visa; }
+.@{fa-css-prefix}-cc-mastercard:before { content: @fa-var-cc-mastercard; }
+.@{fa-css-prefix}-cc-discover:before { content: @fa-var-cc-discover; }
+.@{fa-css-prefix}-cc-amex:before { content: @fa-var-cc-amex; }
+.@{fa-css-prefix}-cc-paypal:before { content: @fa-var-cc-paypal; }
+.@{fa-css-prefix}-cc-stripe:before { content: @fa-var-cc-stripe; }
+.@{fa-css-prefix}-bell-slash:before { content: @fa-var-bell-slash; }
+.@{fa-css-prefix}-bell-slash-o:before { content: @fa-var-bell-slash-o; }
+.@{fa-css-prefix}-trash:before { content: @fa-var-trash; }
+.@{fa-css-prefix}-copyright:before { content: @fa-var-copyright; }
+.@{fa-css-prefix}-at:before { content: @fa-var-at; }
+.@{fa-css-prefix}-eyedropper:before { content: @fa-var-eyedropper; }
+.@{fa-css-prefix}-paint-brush:before { content: @fa-var-paint-brush; }
+.@{fa-css-prefix}-birthday-cake:before { content: @fa-var-birthday-cake; }
+.@{fa-css-prefix}-area-chart:before { content: @fa-var-area-chart; }
+.@{fa-css-prefix}-pie-chart:before { content: @fa-var-pie-chart; }
+.@{fa-css-prefix}-line-chart:before { content: @fa-var-line-chart; }
+.@{fa-css-prefix}-lastfm:before { content: @fa-var-lastfm; }
+.@{fa-css-prefix}-lastfm-square:before { content: @fa-var-lastfm-square; }
+.@{fa-css-prefix}-toggle-off:before { content: @fa-var-toggle-off; }
+.@{fa-css-prefix}-toggle-on:before { content: @fa-var-toggle-on; }
+.@{fa-css-prefix}-bicycle:before { content: @fa-var-bicycle; }
+.@{fa-css-prefix}-bus:before { content: @fa-var-bus; }
+.@{fa-css-prefix}-ioxhost:before { content: @fa-var-ioxhost; }
+.@{fa-css-prefix}-angellist:before { content: @fa-var-angellist; }
+.@{fa-css-prefix}-cc:before { content: @fa-var-cc; }
+.@{fa-css-prefix}-shekel:before,
+.@{fa-css-prefix}-sheqel:before,
+.@{fa-css-prefix}-ils:before { content: @fa-var-ils; }
+.@{fa-css-prefix}-meanpath:before { content: @fa-var-meanpath; }
+.@{fa-css-prefix}-buysellads:before { content: @fa-var-buysellads; }
+.@{fa-css-prefix}-connectdevelop:before { content: @fa-var-connectdevelop; }
+.@{fa-css-prefix}-dashcube:before { content: @fa-var-dashcube; }
+.@{fa-css-prefix}-forumbee:before { content: @fa-var-forumbee; }
+.@{fa-css-prefix}-leanpub:before { content: @fa-var-leanpub; }
+.@{fa-css-prefix}-sellsy:before { content: @fa-var-sellsy; }
+.@{fa-css-prefix}-shirtsinbulk:before { content: @fa-var-shirtsinbulk; }
+.@{fa-css-prefix}-simplybuilt:before { content: @fa-var-simplybuilt; }
+.@{fa-css-prefix}-skyatlas:before { content: @fa-var-skyatlas; }
+.@{fa-css-prefix}-cart-plus:before { content: @fa-var-cart-plus; }
+.@{fa-css-prefix}-cart-arrow-down:before { content: @fa-var-cart-arrow-down; }
+.@{fa-css-prefix}-diamond:before { content: @fa-var-diamond; }
+.@{fa-css-prefix}-ship:before { content: @fa-var-ship; }
+.@{fa-css-prefix}-user-secret:before { content: @fa-var-user-secret; }
+.@{fa-css-prefix}-motorcycle:before { content: @fa-var-motorcycle; }
+.@{fa-css-prefix}-street-view:before { content: @fa-var-street-view; }
+.@{fa-css-prefix}-heartbeat:before { content: @fa-var-heartbeat; }
+.@{fa-css-prefix}-venus:before { content: @fa-var-venus; }
+.@{fa-css-prefix}-mars:before { content: @fa-var-mars; }
+.@{fa-css-prefix}-mercury:before { content: @fa-var-mercury; }
+.@{fa-css-prefix}-intersex:before,
+.@{fa-css-prefix}-transgender:before { content: @fa-var-transgender; }
+.@{fa-css-prefix}-transgender-alt:before { content: @fa-var-transgender-alt; }
+.@{fa-css-prefix}-venus-double:before { content: @fa-var-venus-double; }
+.@{fa-css-prefix}-mars-double:before { content: @fa-var-mars-double; }
+.@{fa-css-prefix}-venus-mars:before { content: @fa-var-venus-mars; }
+.@{fa-css-prefix}-mars-stroke:before { content: @fa-var-mars-stroke; }
+.@{fa-css-prefix}-mars-stroke-v:before { content: @fa-var-mars-stroke-v; }
+.@{fa-css-prefix}-mars-stroke-h:before { content: @fa-var-mars-stroke-h; }
+.@{fa-css-prefix}-neuter:before { content: @fa-var-neuter; }
+.@{fa-css-prefix}-genderless:before { content: @fa-var-genderless; }
+.@{fa-css-prefix}-facebook-official:before { content: @fa-var-facebook-official; }
+.@{fa-css-prefix}-pinterest-p:before { content: @fa-var-pinterest-p; }
+.@{fa-css-prefix}-whatsapp:before { content: @fa-var-whatsapp; }
+.@{fa-css-prefix}-server:before { content: @fa-var-server; }
+.@{fa-css-prefix}-user-plus:before { content: @fa-var-user-plus; }
+.@{fa-css-prefix}-user-times:before { content: @fa-var-user-times; }
+.@{fa-css-prefix}-hotel:before,
+.@{fa-css-prefix}-bed:before { content: @fa-var-bed; }
+.@{fa-css-prefix}-viacoin:before { content: @fa-var-viacoin; }
+.@{fa-css-prefix}-train:before { content: @fa-var-train; }
+.@{fa-css-prefix}-subway:before { content: @fa-var-subway; }
+.@{fa-css-prefix}-medium:before { content: @fa-var-medium; }
+.@{fa-css-prefix}-yc:before,
+.@{fa-css-prefix}-y-combinator:before { content: @fa-var-y-combinator; }
+.@{fa-css-prefix}-optin-monster:before { content: @fa-var-optin-monster; }
+.@{fa-css-prefix}-opencart:before { content: @fa-var-opencart; }
+.@{fa-css-prefix}-expeditedssl:before { content: @fa-var-expeditedssl; }
+.@{fa-css-prefix}-battery-4:before,
+.@{fa-css-prefix}-battery:before,
+.@{fa-css-prefix}-battery-full:before { content: @fa-var-battery-full; }
+.@{fa-css-prefix}-battery-3:before,
+.@{fa-css-prefix}-battery-three-quarters:before { content: @fa-var-battery-three-quarters; }
+.@{fa-css-prefix}-battery-2:before,
+.@{fa-css-prefix}-battery-half:before { content: @fa-var-battery-half; }
+.@{fa-css-prefix}-battery-1:before,
+.@{fa-css-prefix}-battery-quarter:before { content: @fa-var-battery-quarter; }
+.@{fa-css-prefix}-battery-0:before,
+.@{fa-css-prefix}-battery-empty:before { content: @fa-var-battery-empty; }
+.@{fa-css-prefix}-mouse-pointer:before { content: @fa-var-mouse-pointer; }
+.@{fa-css-prefix}-i-cursor:before { content: @fa-var-i-cursor; }
+.@{fa-css-prefix}-object-group:before { content: @fa-var-object-group; }
+.@{fa-css-prefix}-object-ungroup:before { content: @fa-var-object-ungroup; }
+.@{fa-css-prefix}-sticky-note:before { content: @fa-var-sticky-note; }
+.@{fa-css-prefix}-sticky-note-o:before { content: @fa-var-sticky-note-o; }
+.@{fa-css-prefix}-cc-jcb:before { content: @fa-var-cc-jcb; }
+.@{fa-css-prefix}-cc-diners-club:before { content: @fa-var-cc-diners-club; }
+.@{fa-css-prefix}-clone:before { content: @fa-var-clone; }
+.@{fa-css-prefix}-balance-scale:before { content: @fa-var-balance-scale; }
+.@{fa-css-prefix}-hourglass-o:before { content: @fa-var-hourglass-o; }
+.@{fa-css-prefix}-hourglass-1:before,
+.@{fa-css-prefix}-hourglass-start:before { content: @fa-var-hourglass-start; }
+.@{fa-css-prefix}-hourglass-2:before,
+.@{fa-css-prefix}-hourglass-half:before { content: @fa-var-hourglass-half; }
+.@{fa-css-prefix}-hourglass-3:before,
+.@{fa-css-prefix}-hourglass-end:before { content: @fa-var-hourglass-end; }
+.@{fa-css-prefix}-hourglass:before { content: @fa-var-hourglass; }
+.@{fa-css-prefix}-hand-grab-o:before,
+.@{fa-css-prefix}-hand-rock-o:before { content: @fa-var-hand-rock-o; }
+.@{fa-css-prefix}-hand-stop-o:before,
+.@{fa-css-prefix}-hand-paper-o:before { content: @fa-var-hand-paper-o; }
+.@{fa-css-prefix}-hand-scissors-o:before { content: @fa-var-hand-scissors-o; }
+.@{fa-css-prefix}-hand-lizard-o:before { content: @fa-var-hand-lizard-o; }
+.@{fa-css-prefix}-hand-spock-o:before { content: @fa-var-hand-spock-o; }
+.@{fa-css-prefix}-hand-pointer-o:before { content: @fa-var-hand-pointer-o; }
+.@{fa-css-prefix}-hand-peace-o:before { content: @fa-var-hand-peace-o; }
+.@{fa-css-prefix}-trademark:before { content: @fa-var-trademark; }
+.@{fa-css-prefix}-registered:before { content: @fa-var-registered; }
+.@{fa-css-prefix}-creative-commons:before { content: @fa-var-creative-commons; }
+.@{fa-css-prefix}-gg:before { content: @fa-var-gg; }
+.@{fa-css-prefix}-gg-circle:before { content: @fa-var-gg-circle; }
+.@{fa-css-prefix}-tripadvisor:before { content: @fa-var-tripadvisor; }
+.@{fa-css-prefix}-odnoklassniki:before { content: @fa-var-odnoklassniki; }
+.@{fa-css-prefix}-odnoklassniki-square:before { content: @fa-var-odnoklassniki-square; }
+.@{fa-css-prefix}-get-pocket:before { content: @fa-var-get-pocket; }
+.@{fa-css-prefix}-wikipedia-w:before { content: @fa-var-wikipedia-w; }
+.@{fa-css-prefix}-safari:before { content: @fa-var-safari; }
+.@{fa-css-prefix}-chrome:before { content: @fa-var-chrome; }
+.@{fa-css-prefix}-firefox:before { content: @fa-var-firefox; }
+.@{fa-css-prefix}-opera:before { content: @fa-var-opera; }
+.@{fa-css-prefix}-internet-explorer:before { content: @fa-var-internet-explorer; }
+.@{fa-css-prefix}-tv:before,
+.@{fa-css-prefix}-television:before { content: @fa-var-television; }
+.@{fa-css-prefix}-contao:before { content: @fa-var-contao; }
+.@{fa-css-prefix}-500px:before { content: @fa-var-500px; }
+.@{fa-css-prefix}-amazon:before { content: @fa-var-amazon; }
+.@{fa-css-prefix}-calendar-plus-o:before { content: @fa-var-calendar-plus-o; }
+.@{fa-css-prefix}-calendar-minus-o:before { content: @fa-var-calendar-minus-o; }
+.@{fa-css-prefix}-calendar-times-o:before { content: @fa-var-calendar-times-o; }
+.@{fa-css-prefix}-calendar-check-o:before { content: @fa-var-calendar-check-o; }
+.@{fa-css-prefix}-industry:before { content: @fa-var-industry; }
+.@{fa-css-prefix}-map-pin:before { content: @fa-var-map-pin; }
+.@{fa-css-prefix}-map-signs:before { content: @fa-var-map-signs; }
+.@{fa-css-prefix}-map-o:before { content: @fa-var-map-o; }
+.@{fa-css-prefix}-map:before { content: @fa-var-map; }
+.@{fa-css-prefix}-commenting:before { content: @fa-var-commenting; }
+.@{fa-css-prefix}-commenting-o:before { content: @fa-var-commenting-o; }
+.@{fa-css-prefix}-houzz:before { content: @fa-var-houzz; }
+.@{fa-css-prefix}-vimeo:before { content: @fa-var-vimeo; }
+.@{fa-css-prefix}-black-tie:before { content: @fa-var-black-tie; }
+.@{fa-css-prefix}-fonticons:before { content: @fa-var-fonticons; }
+.@{fa-css-prefix}-reddit-alien:before { content: @fa-var-reddit-alien; }
+.@{fa-css-prefix}-edge:before { content: @fa-var-edge; }
+.@{fa-css-prefix}-credit-card-alt:before { content: @fa-var-credit-card-alt; }
+.@{fa-css-prefix}-codiepie:before { content: @fa-var-codiepie; }
+.@{fa-css-prefix}-modx:before { content: @fa-var-modx; }
+.@{fa-css-prefix}-fort-awesome:before { content: @fa-var-fort-awesome; }
+.@{fa-css-prefix}-usb:before { content: @fa-var-usb; }
+.@{fa-css-prefix}-product-hunt:before { content: @fa-var-product-hunt; }
+.@{fa-css-prefix}-mixcloud:before { content: @fa-var-mixcloud; }
+.@{fa-css-prefix}-scribd:before { content: @fa-var-scribd; }
+.@{fa-css-prefix}-pause-circle:before { content: @fa-var-pause-circle; }
+.@{fa-css-prefix}-pause-circle-o:before { content: @fa-var-pause-circle-o; }
+.@{fa-css-prefix}-stop-circle:before { content: @fa-var-stop-circle; }
+.@{fa-css-prefix}-stop-circle-o:before { content: @fa-var-stop-circle-o; }
+.@{fa-css-prefix}-shopping-bag:before { content: @fa-var-shopping-bag; }
+.@{fa-css-prefix}-shopping-basket:before { content: @fa-var-shopping-basket; }
+.@{fa-css-prefix}-hashtag:before { content: @fa-var-hashtag; }
+.@{fa-css-prefix}-bluetooth:before { content: @fa-var-bluetooth; }
+.@{fa-css-prefix}-bluetooth-b:before { content: @fa-var-bluetooth-b; }
+.@{fa-css-prefix}-percent:before { content: @fa-var-percent; }
+.@{fa-css-prefix}-gitlab:before { content: @fa-var-gitlab; }
+.@{fa-css-prefix}-wpbeginner:before { content: @fa-var-wpbeginner; }
+.@{fa-css-prefix}-wpforms:before { content: @fa-var-wpforms; }
+.@{fa-css-prefix}-envira:before { content: @fa-var-envira; }
+.@{fa-css-prefix}-universal-access:before { content: @fa-var-universal-access; }
+.@{fa-css-prefix}-wheelchair-alt:before { content: @fa-var-wheelchair-alt; }
+.@{fa-css-prefix}-question-circle-o:before { content: @fa-var-question-circle-o; }
+.@{fa-css-prefix}-blind:before { content: @fa-var-blind; }
+.@{fa-css-prefix}-audio-description:before { content: @fa-var-audio-description; }
+.@{fa-css-prefix}-volume-control-phone:before { content: @fa-var-volume-control-phone; }
+.@{fa-css-prefix}-braille:before { content: @fa-var-braille; }
+.@{fa-css-prefix}-assistive-listening-systems:before { content: @fa-var-assistive-listening-systems; }
+.@{fa-css-prefix}-asl-interpreting:before,
+.@{fa-css-prefix}-american-sign-language-interpreting:before { content: @fa-var-american-sign-language-interpreting; }
+.@{fa-css-prefix}-deafness:before,
+.@{fa-css-prefix}-hard-of-hearing:before,
+.@{fa-css-prefix}-deaf:before { content: @fa-var-deaf; }
+.@{fa-css-prefix}-glide:before { content: @fa-var-glide; }
+.@{fa-css-prefix}-glide-g:before { content: @fa-var-glide-g; }
+.@{fa-css-prefix}-signing:before,
+.@{fa-css-prefix}-sign-language:before { content: @fa-var-sign-language; }
+.@{fa-css-prefix}-low-vision:before { content: @fa-var-low-vision; }
+.@{fa-css-prefix}-viadeo:before { content: @fa-var-viadeo; }
+.@{fa-css-prefix}-viadeo-square:before { content: @fa-var-viadeo-square; }
+.@{fa-css-prefix}-snapchat:before { content: @fa-var-snapchat; }
+.@{fa-css-prefix}-snapchat-ghost:before { content: @fa-var-snapchat-ghost; }
+.@{fa-css-prefix}-snapchat-square:before { content: @fa-var-snapchat-square; }
+.@{fa-css-prefix}-pied-piper:before { content: @fa-var-pied-piper; }
+.@{fa-css-prefix}-first-order:before { content: @fa-var-first-order; }
+.@{fa-css-prefix}-yoast:before { content: @fa-var-yoast; }
+.@{fa-css-prefix}-themeisle:before { content: @fa-var-themeisle; }
+.@{fa-css-prefix}-google-plus-circle:before,
+.@{fa-css-prefix}-google-plus-official:before { content: @fa-var-google-plus-official; }
+.@{fa-css-prefix}-fa:before,
+.@{fa-css-prefix}-font-awesome:before { content: @fa-var-font-awesome; }
+.@{fa-css-prefix}-handshake-o:before { content: @fa-var-handshake-o; }
+.@{fa-css-prefix}-envelope-open:before { content: @fa-var-envelope-open; }
+.@{fa-css-prefix}-envelope-open-o:before { content: @fa-var-envelope-open-o; }
+.@{fa-css-prefix}-linode:before { content: @fa-var-linode; }
+.@{fa-css-prefix}-address-book:before { content: @fa-var-address-book; }
+.@{fa-css-prefix}-address-book-o:before { content: @fa-var-address-book-o; }
+.@{fa-css-prefix}-vcard:before,
+.@{fa-css-prefix}-address-card:before { content: @fa-var-address-card; }
+.@{fa-css-prefix}-vcard-o:before,
+.@{fa-css-prefix}-address-card-o:before { content: @fa-var-address-card-o; }
+.@{fa-css-prefix}-user-circle:before { content: @fa-var-user-circle; }
+.@{fa-css-prefix}-user-circle-o:before { content: @fa-var-user-circle-o; }
+.@{fa-css-prefix}-user-o:before { content: @fa-var-user-o; }
+.@{fa-css-prefix}-id-badge:before { content: @fa-var-id-badge; }
+.@{fa-css-prefix}-drivers-license:before,
+.@{fa-css-prefix}-id-card:before { content: @fa-var-id-card; }
+.@{fa-css-prefix}-drivers-license-o:before,
+.@{fa-css-prefix}-id-card-o:before { content: @fa-var-id-card-o; }
+.@{fa-css-prefix}-quora:before { content: @fa-var-quora; }
+.@{fa-css-prefix}-free-code-camp:before { content: @fa-var-free-code-camp; }
+.@{fa-css-prefix}-telegram:before { content: @fa-var-telegram; }
+.@{fa-css-prefix}-thermometer-4:before,
+.@{fa-css-prefix}-thermometer:before,
+.@{fa-css-prefix}-thermometer-full:before { content: @fa-var-thermometer-full; }
+.@{fa-css-prefix}-thermometer-3:before,
+.@{fa-css-prefix}-thermometer-three-quarters:before { content: @fa-var-thermometer-three-quarters; }
+.@{fa-css-prefix}-thermometer-2:before,
+.@{fa-css-prefix}-thermometer-half:before { content: @fa-var-thermometer-half; }
+.@{fa-css-prefix}-thermometer-1:before,
+.@{fa-css-prefix}-thermometer-quarter:before { content: @fa-var-thermometer-quarter; }
+.@{fa-css-prefix}-thermometer-0:before,
+.@{fa-css-prefix}-thermometer-empty:before { content: @fa-var-thermometer-empty; }
+.@{fa-css-prefix}-shower:before { content: @fa-var-shower; }
+.@{fa-css-prefix}-bathtub:before,
+.@{fa-css-prefix}-s15:before,
+.@{fa-css-prefix}-bath:before { content: @fa-var-bath; }
+.@{fa-css-prefix}-podcast:before { content: @fa-var-podcast; }
+.@{fa-css-prefix}-window-maximize:before { content: @fa-var-window-maximize; }
+.@{fa-css-prefix}-window-minimize:before { content: @fa-var-window-minimize; }
+.@{fa-css-prefix}-window-restore:before { content: @fa-var-window-restore; }
+.@{fa-css-prefix}-times-rectangle:before,
+.@{fa-css-prefix}-window-close:before { content: @fa-var-window-close; }
+.@{fa-css-prefix}-times-rectangle-o:before,
+.@{fa-css-prefix}-window-close-o:before { content: @fa-var-window-close-o; }
+.@{fa-css-prefix}-bandcamp:before { content: @fa-var-bandcamp; }
+.@{fa-css-prefix}-grav:before { content: @fa-var-grav; }
+.@{fa-css-prefix}-etsy:before { content: @fa-var-etsy; }
+.@{fa-css-prefix}-imdb:before { content: @fa-var-imdb; }
+.@{fa-css-prefix}-ravelry:before { content: @fa-var-ravelry; }
+.@{fa-css-prefix}-eercast:before { content: @fa-var-eercast; }
+.@{fa-css-prefix}-microchip:before { content: @fa-var-microchip; }
+.@{fa-css-prefix}-snowflake-o:before { content: @fa-var-snowflake-o; }
+.@{fa-css-prefix}-superpowers:before { content: @fa-var-superpowers; }
+.@{fa-css-prefix}-wpexplorer:before { content: @fa-var-wpexplorer; }
+.@{fa-css-prefix}-meetup:before { content: @fa-var-meetup; }
diff --git a/less/larger.less b/less/larger.less
new file mode 100644
index 0000000..c9d6467
--- /dev/null
+++ b/less/larger.less
@@ -0,0 +1,13 @@
+// Icon Sizes
+// -------------------------
+
+/* makes the font 33% larger relative to the icon container */
+.@{fa-css-prefix}-lg {
+ font-size: (4em / 3);
+ line-height: (3em / 4);
+ vertical-align: -15%;
+}
+.@{fa-css-prefix}-2x { font-size: 2em; }
+.@{fa-css-prefix}-3x { font-size: 3em; }
+.@{fa-css-prefix}-4x { font-size: 4em; }
+.@{fa-css-prefix}-5x { font-size: 5em; }
diff --git a/less/list.less b/less/list.less
new file mode 100644
index 0000000..0b44038
--- /dev/null
+++ b/less/list.less
@@ -0,0 +1,19 @@
+// List Icons
+// -------------------------
+
+.@{fa-css-prefix}-ul {
+ padding-left: 0;
+ margin-left: @fa-li-width;
+ list-style-type: none;
+ > li { position: relative; }
+}
+.@{fa-css-prefix}-li {
+ position: absolute;
+ left: -@fa-li-width;
+ width: @fa-li-width;
+ top: (2em / 14);
+ text-align: center;
+ &.@{fa-css-prefix}-lg {
+ left: (-@fa-li-width + (4em / 14));
+ }
+}
diff --git a/less/mixins.less b/less/mixins.less
new file mode 100644
index 0000000..beef231
--- /dev/null
+++ b/less/mixins.less
@@ -0,0 +1,60 @@
+// Mixins
+// --------------------------
+
+.fa-icon() {
+ display: inline-block;
+ font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration
+ font-size: inherit; // can't have font-size inherit on line above, so need to override
+ text-rendering: auto; // optimizelegibility throws things off #1094
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+
+}
+
+.fa-icon-rotate(@degrees, @rotation) {
+ -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation})";
+ -webkit-transform: rotate(@degrees);
+ -ms-transform: rotate(@degrees);
+ transform: rotate(@degrees);
+}
+
+.fa-icon-flip(@horiz, @vert, @rotation) {
+ -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation}, mirror=1)";
+ -webkit-transform: scale(@horiz, @vert);
+ -ms-transform: scale(@horiz, @vert);
+ transform: scale(@horiz, @vert);
+}
+
+
+// Only display content to screen readers. A la Bootstrap 4.
+//
+// See: http://a11yproject.com/posts/how-to-hide-content/
+
+.sr-only() {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ clip: rect(0,0,0,0);
+ border: 0;
+}
+
+// Use in conjunction with .sr-only to only display content when it's focused.
+//
+// Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1
+//
+// Credit: HTML5 Boilerplate
+
+.sr-only-focusable() {
+ &:active,
+ &:focus {
+ position: static;
+ width: auto;
+ height: auto;
+ margin: 0;
+ overflow: visible;
+ clip: auto;
+ }
+}
diff --git a/less/path.less b/less/path.less
new file mode 100644
index 0000000..835be41
--- /dev/null
+++ b/less/path.less
@@ -0,0 +1,15 @@
+/* FONT PATH
+ * -------------------------- */
+
+@font-face {
+ font-family: 'FontAwesome';
+ src: url('@{fa-font-path}/fontawesome-webfont.eot?v=@{fa-version}');
+ src: url('@{fa-font-path}/fontawesome-webfont.eot?#iefix&v=@{fa-version}') format('embedded-opentype'),
+ url('@{fa-font-path}/fontawesome-webfont.woff2?v=@{fa-version}') format('woff2'),
+ url('@{fa-font-path}/fontawesome-webfont.woff?v=@{fa-version}') format('woff'),
+ url('@{fa-font-path}/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype'),
+ url('@{fa-font-path}/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg');
+ // src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts
+ font-weight: normal;
+ font-style: normal;
+}
diff --git a/less/rotated-flipped.less b/less/rotated-flipped.less
new file mode 100644
index 0000000..f6ba814
--- /dev/null
+++ b/less/rotated-flipped.less
@@ -0,0 +1,20 @@
+// Rotated & Flipped Icons
+// -------------------------
+
+.@{fa-css-prefix}-rotate-90 { .fa-icon-rotate(90deg, 1); }
+.@{fa-css-prefix}-rotate-180 { .fa-icon-rotate(180deg, 2); }
+.@{fa-css-prefix}-rotate-270 { .fa-icon-rotate(270deg, 3); }
+
+.@{fa-css-prefix}-flip-horizontal { .fa-icon-flip(-1, 1, 0); }
+.@{fa-css-prefix}-flip-vertical { .fa-icon-flip(1, -1, 2); }
+
+// Hook for IE8-9
+// -------------------------
+
+:root .@{fa-css-prefix}-rotate-90,
+:root .@{fa-css-prefix}-rotate-180,
+:root .@{fa-css-prefix}-rotate-270,
+:root .@{fa-css-prefix}-flip-horizontal,
+:root .@{fa-css-prefix}-flip-vertical {
+ filter: none;
+}
diff --git a/less/screen-reader.less b/less/screen-reader.less
new file mode 100644
index 0000000..11c1881
--- /dev/null
+++ b/less/screen-reader.less
@@ -0,0 +1,5 @@
+// Screen Readers
+// -------------------------
+
+.sr-only { .sr-only(); }
+.sr-only-focusable { .sr-only-focusable(); }
diff --git a/less/stacked.less b/less/stacked.less
new file mode 100644
index 0000000..fc53fb0
--- /dev/null
+++ b/less/stacked.less
@@ -0,0 +1,20 @@
+// Stacked Icons
+// -------------------------
+
+.@{fa-css-prefix}-stack {
+ position: relative;
+ display: inline-block;
+ width: 2em;
+ height: 2em;
+ line-height: 2em;
+ vertical-align: middle;
+}
+.@{fa-css-prefix}-stack-1x, .@{fa-css-prefix}-stack-2x {
+ position: absolute;
+ left: 0;
+ width: 100%;
+ text-align: center;
+}
+.@{fa-css-prefix}-stack-1x { line-height: inherit; }
+.@{fa-css-prefix}-stack-2x { font-size: 2em; }
+.@{fa-css-prefix}-inverse { color: @fa-inverse; }
diff --git a/less/variables.less b/less/variables.less
new file mode 100644
index 0000000..7ddbbc0
--- /dev/null
+++ b/less/variables.less
@@ -0,0 +1,800 @@
+// Variables
+// --------------------------
+
+@fa-font-path: "../fonts";
+@fa-font-size-base: 14px;
+@fa-line-height-base: 1;
+//@fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.7.0/fonts"; // for referencing Bootstrap CDN font files directly
+@fa-css-prefix: fa;
+@fa-version: "4.7.0";
+@fa-border-color: #eee;
+@fa-inverse: #fff;
+@fa-li-width: (30em / 14);
+
+@fa-var-500px: "\f26e";
+@fa-var-address-book: "\f2b9";
+@fa-var-address-book-o: "\f2ba";
+@fa-var-address-card: "\f2bb";
+@fa-var-address-card-o: "\f2bc";
+@fa-var-adjust: "\f042";
+@fa-var-adn: "\f170";
+@fa-var-align-center: "\f037";
+@fa-var-align-justify: "\f039";
+@fa-var-align-left: "\f036";
+@fa-var-align-right: "\f038";
+@fa-var-amazon: "\f270";
+@fa-var-ambulance: "\f0f9";
+@fa-var-american-sign-language-interpreting: "\f2a3";
+@fa-var-anchor: "\f13d";
+@fa-var-android: "\f17b";
+@fa-var-angellist: "\f209";
+@fa-var-angle-double-down: "\f103";
+@fa-var-angle-double-left: "\f100";
+@fa-var-angle-double-right: "\f101";
+@fa-var-angle-double-up: "\f102";
+@fa-var-angle-down: "\f107";
+@fa-var-angle-left: "\f104";
+@fa-var-angle-right: "\f105";
+@fa-var-angle-up: "\f106";
+@fa-var-apple: "\f179";
+@fa-var-archive: "\f187";
+@fa-var-area-chart: "\f1fe";
+@fa-var-arrow-circle-down: "\f0ab";
+@fa-var-arrow-circle-left: "\f0a8";
+@fa-var-arrow-circle-o-down: "\f01a";
+@fa-var-arrow-circle-o-left: "\f190";
+@fa-var-arrow-circle-o-right: "\f18e";
+@fa-var-arrow-circle-o-up: "\f01b";
+@fa-var-arrow-circle-right: "\f0a9";
+@fa-var-arrow-circle-up: "\f0aa";
+@fa-var-arrow-down: "\f063";
+@fa-var-arrow-left: "\f060";
+@fa-var-arrow-right: "\f061";
+@fa-var-arrow-up: "\f062";
+@fa-var-arrows: "\f047";
+@fa-var-arrows-alt: "\f0b2";
+@fa-var-arrows-h: "\f07e";
+@fa-var-arrows-v: "\f07d";
+@fa-var-asl-interpreting: "\f2a3";
+@fa-var-assistive-listening-systems: "\f2a2";
+@fa-var-asterisk: "\f069";
+@fa-var-at: "\f1fa";
+@fa-var-audio-description: "\f29e";
+@fa-var-automobile: "\f1b9";
+@fa-var-backward: "\f04a";
+@fa-var-balance-scale: "\f24e";
+@fa-var-ban: "\f05e";
+@fa-var-bandcamp: "\f2d5";
+@fa-var-bank: "\f19c";
+@fa-var-bar-chart: "\f080";
+@fa-var-bar-chart-o: "\f080";
+@fa-var-barcode: "\f02a";
+@fa-var-bars: "\f0c9";
+@fa-var-bath: "\f2cd";
+@fa-var-bathtub: "\f2cd";
+@fa-var-battery: "\f240";
+@fa-var-battery-0: "\f244";
+@fa-var-battery-1: "\f243";
+@fa-var-battery-2: "\f242";
+@fa-var-battery-3: "\f241";
+@fa-var-battery-4: "\f240";
+@fa-var-battery-empty: "\f244";
+@fa-var-battery-full: "\f240";
+@fa-var-battery-half: "\f242";
+@fa-var-battery-quarter: "\f243";
+@fa-var-battery-three-quarters: "\f241";
+@fa-var-bed: "\f236";
+@fa-var-beer: "\f0fc";
+@fa-var-behance: "\f1b4";
+@fa-var-behance-square: "\f1b5";
+@fa-var-bell: "\f0f3";
+@fa-var-bell-o: "\f0a2";
+@fa-var-bell-slash: "\f1f6";
+@fa-var-bell-slash-o: "\f1f7";
+@fa-var-bicycle: "\f206";
+@fa-var-binoculars: "\f1e5";
+@fa-var-birthday-cake: "\f1fd";
+@fa-var-bitbucket: "\f171";
+@fa-var-bitbucket-square: "\f172";
+@fa-var-bitcoin: "\f15a";
+@fa-var-black-tie: "\f27e";
+@fa-var-blind: "\f29d";
+@fa-var-bluetooth: "\f293";
+@fa-var-bluetooth-b: "\f294";
+@fa-var-bold: "\f032";
+@fa-var-bolt: "\f0e7";
+@fa-var-bomb: "\f1e2";
+@fa-var-book: "\f02d";
+@fa-var-bookmark: "\f02e";
+@fa-var-bookmark-o: "\f097";
+@fa-var-braille: "\f2a1";
+@fa-var-briefcase: "\f0b1";
+@fa-var-btc: "\f15a";
+@fa-var-bug: "\f188";
+@fa-var-building: "\f1ad";
+@fa-var-building-o: "\f0f7";
+@fa-var-bullhorn: "\f0a1";
+@fa-var-bullseye: "\f140";
+@fa-var-bus: "\f207";
+@fa-var-buysellads: "\f20d";
+@fa-var-cab: "\f1ba";
+@fa-var-calculator: "\f1ec";
+@fa-var-calendar: "\f073";
+@fa-var-calendar-check-o: "\f274";
+@fa-var-calendar-minus-o: "\f272";
+@fa-var-calendar-o: "\f133";
+@fa-var-calendar-plus-o: "\f271";
+@fa-var-calendar-times-o: "\f273";
+@fa-var-camera: "\f030";
+@fa-var-camera-retro: "\f083";
+@fa-var-car: "\f1b9";
+@fa-var-caret-down: "\f0d7";
+@fa-var-caret-left: "\f0d9";
+@fa-var-caret-right: "\f0da";
+@fa-var-caret-square-o-down: "\f150";
+@fa-var-caret-square-o-left: "\f191";
+@fa-var-caret-square-o-right: "\f152";
+@fa-var-caret-square-o-up: "\f151";
+@fa-var-caret-up: "\f0d8";
+@fa-var-cart-arrow-down: "\f218";
+@fa-var-cart-plus: "\f217";
+@fa-var-cc: "\f20a";
+@fa-var-cc-amex: "\f1f3";
+@fa-var-cc-diners-club: "\f24c";
+@fa-var-cc-discover: "\f1f2";
+@fa-var-cc-jcb: "\f24b";
+@fa-var-cc-mastercard: "\f1f1";
+@fa-var-cc-paypal: "\f1f4";
+@fa-var-cc-stripe: "\f1f5";
+@fa-var-cc-visa: "\f1f0";
+@fa-var-certificate: "\f0a3";
+@fa-var-chain: "\f0c1";
+@fa-var-chain-broken: "\f127";
+@fa-var-check: "\f00c";
+@fa-var-check-circle: "\f058";
+@fa-var-check-circle-o: "\f05d";
+@fa-var-check-square: "\f14a";
+@fa-var-check-square-o: "\f046";
+@fa-var-chevron-circle-down: "\f13a";
+@fa-var-chevron-circle-left: "\f137";
+@fa-var-chevron-circle-right: "\f138";
+@fa-var-chevron-circle-up: "\f139";
+@fa-var-chevron-down: "\f078";
+@fa-var-chevron-left: "\f053";
+@fa-var-chevron-right: "\f054";
+@fa-var-chevron-up: "\f077";
+@fa-var-child: "\f1ae";
+@fa-var-chrome: "\f268";
+@fa-var-circle: "\f111";
+@fa-var-circle-o: "\f10c";
+@fa-var-circle-o-notch: "\f1ce";
+@fa-var-circle-thin: "\f1db";
+@fa-var-clipboard: "\f0ea";
+@fa-var-clock-o: "\f017";
+@fa-var-clone: "\f24d";
+@fa-var-close: "\f00d";
+@fa-var-cloud: "\f0c2";
+@fa-var-cloud-download: "\f0ed";
+@fa-var-cloud-upload: "\f0ee";
+@fa-var-cny: "\f157";
+@fa-var-code: "\f121";
+@fa-var-code-fork: "\f126";
+@fa-var-codepen: "\f1cb";
+@fa-var-codiepie: "\f284";
+@fa-var-coffee: "\f0f4";
+@fa-var-cog: "\f013";
+@fa-var-cogs: "\f085";
+@fa-var-columns: "\f0db";
+@fa-var-comment: "\f075";
+@fa-var-comment-o: "\f0e5";
+@fa-var-commenting: "\f27a";
+@fa-var-commenting-o: "\f27b";
+@fa-var-comments: "\f086";
+@fa-var-comments-o: "\f0e6";
+@fa-var-compass: "\f14e";
+@fa-var-compress: "\f066";
+@fa-var-connectdevelop: "\f20e";
+@fa-var-contao: "\f26d";
+@fa-var-copy: "\f0c5";
+@fa-var-copyright: "\f1f9";
+@fa-var-creative-commons: "\f25e";
+@fa-var-credit-card: "\f09d";
+@fa-var-credit-card-alt: "\f283";
+@fa-var-crop: "\f125";
+@fa-var-crosshairs: "\f05b";
+@fa-var-css3: "\f13c";
+@fa-var-cube: "\f1b2";
+@fa-var-cubes: "\f1b3";
+@fa-var-cut: "\f0c4";
+@fa-var-cutlery: "\f0f5";
+@fa-var-dashboard: "\f0e4";
+@fa-var-dashcube: "\f210";
+@fa-var-database: "\f1c0";
+@fa-var-deaf: "\f2a4";
+@fa-var-deafness: "\f2a4";
+@fa-var-dedent: "\f03b";
+@fa-var-delicious: "\f1a5";
+@fa-var-desktop: "\f108";
+@fa-var-deviantart: "\f1bd";
+@fa-var-diamond: "\f219";
+@fa-var-digg: "\f1a6";
+@fa-var-dollar: "\f155";
+@fa-var-dot-circle-o: "\f192";
+@fa-var-download: "\f019";
+@fa-var-dribbble: "\f17d";
+@fa-var-drivers-license: "\f2c2";
+@fa-var-drivers-license-o: "\f2c3";
+@fa-var-dropbox: "\f16b";
+@fa-var-drupal: "\f1a9";
+@fa-var-edge: "\f282";
+@fa-var-edit: "\f044";
+@fa-var-eercast: "\f2da";
+@fa-var-eject: "\f052";
+@fa-var-ellipsis-h: "\f141";
+@fa-var-ellipsis-v: "\f142";
+@fa-var-empire: "\f1d1";
+@fa-var-envelope: "\f0e0";
+@fa-var-envelope-o: "\f003";
+@fa-var-envelope-open: "\f2b6";
+@fa-var-envelope-open-o: "\f2b7";
+@fa-var-envelope-square: "\f199";
+@fa-var-envira: "\f299";
+@fa-var-eraser: "\f12d";
+@fa-var-etsy: "\f2d7";
+@fa-var-eur: "\f153";
+@fa-var-euro: "\f153";
+@fa-var-exchange: "\f0ec";
+@fa-var-exclamation: "\f12a";
+@fa-var-exclamation-circle: "\f06a";
+@fa-var-exclamation-triangle: "\f071";
+@fa-var-expand: "\f065";
+@fa-var-expeditedssl: "\f23e";
+@fa-var-external-link: "\f08e";
+@fa-var-external-link-square: "\f14c";
+@fa-var-eye: "\f06e";
+@fa-var-eye-slash: "\f070";
+@fa-var-eyedropper: "\f1fb";
+@fa-var-fa: "\f2b4";
+@fa-var-facebook: "\f09a";
+@fa-var-facebook-f: "\f09a";
+@fa-var-facebook-official: "\f230";
+@fa-var-facebook-square: "\f082";
+@fa-var-fast-backward: "\f049";
+@fa-var-fast-forward: "\f050";
+@fa-var-fax: "\f1ac";
+@fa-var-feed: "\f09e";
+@fa-var-female: "\f182";
+@fa-var-fighter-jet: "\f0fb";
+@fa-var-file: "\f15b";
+@fa-var-file-archive-o: "\f1c6";
+@fa-var-file-audio-o: "\f1c7";
+@fa-var-file-code-o: "\f1c9";
+@fa-var-file-excel-o: "\f1c3";
+@fa-var-file-image-o: "\f1c5";
+@fa-var-file-movie-o: "\f1c8";
+@fa-var-file-o: "\f016";
+@fa-var-file-pdf-o: "\f1c1";
+@fa-var-file-photo-o: "\f1c5";
+@fa-var-file-picture-o: "\f1c5";
+@fa-var-file-powerpoint-o: "\f1c4";
+@fa-var-file-sound-o: "\f1c7";
+@fa-var-file-text: "\f15c";
+@fa-var-file-text-o: "\f0f6";
+@fa-var-file-video-o: "\f1c8";
+@fa-var-file-word-o: "\f1c2";
+@fa-var-file-zip-o: "\f1c6";
+@fa-var-files-o: "\f0c5";
+@fa-var-film: "\f008";
+@fa-var-filter: "\f0b0";
+@fa-var-fire: "\f06d";
+@fa-var-fire-extinguisher: "\f134";
+@fa-var-firefox: "\f269";
+@fa-var-first-order: "\f2b0";
+@fa-var-flag: "\f024";
+@fa-var-flag-checkered: "\f11e";
+@fa-var-flag-o: "\f11d";
+@fa-var-flash: "\f0e7";
+@fa-var-flask: "\f0c3";
+@fa-var-flickr: "\f16e";
+@fa-var-floppy-o: "\f0c7";
+@fa-var-folder: "\f07b";
+@fa-var-folder-o: "\f114";
+@fa-var-folder-open: "\f07c";
+@fa-var-folder-open-o: "\f115";
+@fa-var-font: "\f031";
+@fa-var-font-awesome: "\f2b4";
+@fa-var-fonticons: "\f280";
+@fa-var-fort-awesome: "\f286";
+@fa-var-forumbee: "\f211";
+@fa-var-forward: "\f04e";
+@fa-var-foursquare: "\f180";
+@fa-var-free-code-camp: "\f2c5";
+@fa-var-frown-o: "\f119";
+@fa-var-futbol-o: "\f1e3";
+@fa-var-gamepad: "\f11b";
+@fa-var-gavel: "\f0e3";
+@fa-var-gbp: "\f154";
+@fa-var-ge: "\f1d1";
+@fa-var-gear: "\f013";
+@fa-var-gears: "\f085";
+@fa-var-genderless: "\f22d";
+@fa-var-get-pocket: "\f265";
+@fa-var-gg: "\f260";
+@fa-var-gg-circle: "\f261";
+@fa-var-gift: "\f06b";
+@fa-var-git: "\f1d3";
+@fa-var-git-square: "\f1d2";
+@fa-var-github: "\f09b";
+@fa-var-github-alt: "\f113";
+@fa-var-github-square: "\f092";
+@fa-var-gitlab: "\f296";
+@fa-var-gittip: "\f184";
+@fa-var-glass: "\f000";
+@fa-var-glide: "\f2a5";
+@fa-var-glide-g: "\f2a6";
+@fa-var-globe: "\f0ac";
+@fa-var-google: "\f1a0";
+@fa-var-google-plus: "\f0d5";
+@fa-var-google-plus-circle: "\f2b3";
+@fa-var-google-plus-official: "\f2b3";
+@fa-var-google-plus-square: "\f0d4";
+@fa-var-google-wallet: "\f1ee";
+@fa-var-graduation-cap: "\f19d";
+@fa-var-gratipay: "\f184";
+@fa-var-grav: "\f2d6";
+@fa-var-group: "\f0c0";
+@fa-var-h-square: "\f0fd";
+@fa-var-hacker-news: "\f1d4";
+@fa-var-hand-grab-o: "\f255";
+@fa-var-hand-lizard-o: "\f258";
+@fa-var-hand-o-down: "\f0a7";
+@fa-var-hand-o-left: "\f0a5";
+@fa-var-hand-o-right: "\f0a4";
+@fa-var-hand-o-up: "\f0a6";
+@fa-var-hand-paper-o: "\f256";
+@fa-var-hand-peace-o: "\f25b";
+@fa-var-hand-pointer-o: "\f25a";
+@fa-var-hand-rock-o: "\f255";
+@fa-var-hand-scissors-o: "\f257";
+@fa-var-hand-spock-o: "\f259";
+@fa-var-hand-stop-o: "\f256";
+@fa-var-handshake-o: "\f2b5";
+@fa-var-hard-of-hearing: "\f2a4";
+@fa-var-hashtag: "\f292";
+@fa-var-hdd-o: "\f0a0";
+@fa-var-header: "\f1dc";
+@fa-var-headphones: "\f025";
+@fa-var-heart: "\f004";
+@fa-var-heart-o: "\f08a";
+@fa-var-heartbeat: "\f21e";
+@fa-var-history: "\f1da";
+@fa-var-home: "\f015";
+@fa-var-hospital-o: "\f0f8";
+@fa-var-hotel: "\f236";
+@fa-var-hourglass: "\f254";
+@fa-var-hourglass-1: "\f251";
+@fa-var-hourglass-2: "\f252";
+@fa-var-hourglass-3: "\f253";
+@fa-var-hourglass-end: "\f253";
+@fa-var-hourglass-half: "\f252";
+@fa-var-hourglass-o: "\f250";
+@fa-var-hourglass-start: "\f251";
+@fa-var-houzz: "\f27c";
+@fa-var-html5: "\f13b";
+@fa-var-i-cursor: "\f246";
+@fa-var-id-badge: "\f2c1";
+@fa-var-id-card: "\f2c2";
+@fa-var-id-card-o: "\f2c3";
+@fa-var-ils: "\f20b";
+@fa-var-image: "\f03e";
+@fa-var-imdb: "\f2d8";
+@fa-var-inbox: "\f01c";
+@fa-var-indent: "\f03c";
+@fa-var-industry: "\f275";
+@fa-var-info: "\f129";
+@fa-var-info-circle: "\f05a";
+@fa-var-inr: "\f156";
+@fa-var-instagram: "\f16d";
+@fa-var-institution: "\f19c";
+@fa-var-internet-explorer: "\f26b";
+@fa-var-intersex: "\f224";
+@fa-var-ioxhost: "\f208";
+@fa-var-italic: "\f033";
+@fa-var-joomla: "\f1aa";
+@fa-var-jpy: "\f157";
+@fa-var-jsfiddle: "\f1cc";
+@fa-var-key: "\f084";
+@fa-var-keyboard-o: "\f11c";
+@fa-var-krw: "\f159";
+@fa-var-language: "\f1ab";
+@fa-var-laptop: "\f109";
+@fa-var-lastfm: "\f202";
+@fa-var-lastfm-square: "\f203";
+@fa-var-leaf: "\f06c";
+@fa-var-leanpub: "\f212";
+@fa-var-legal: "\f0e3";
+@fa-var-lemon-o: "\f094";
+@fa-var-level-down: "\f149";
+@fa-var-level-up: "\f148";
+@fa-var-life-bouy: "\f1cd";
+@fa-var-life-buoy: "\f1cd";
+@fa-var-life-ring: "\f1cd";
+@fa-var-life-saver: "\f1cd";
+@fa-var-lightbulb-o: "\f0eb";
+@fa-var-line-chart: "\f201";
+@fa-var-link: "\f0c1";
+@fa-var-linkedin: "\f0e1";
+@fa-var-linkedin-square: "\f08c";
+@fa-var-linode: "\f2b8";
+@fa-var-linux: "\f17c";
+@fa-var-list: "\f03a";
+@fa-var-list-alt: "\f022";
+@fa-var-list-ol: "\f0cb";
+@fa-var-list-ul: "\f0ca";
+@fa-var-location-arrow: "\f124";
+@fa-var-lock: "\f023";
+@fa-var-long-arrow-down: "\f175";
+@fa-var-long-arrow-left: "\f177";
+@fa-var-long-arrow-right: "\f178";
+@fa-var-long-arrow-up: "\f176";
+@fa-var-low-vision: "\f2a8";
+@fa-var-magic: "\f0d0";
+@fa-var-magnet: "\f076";
+@fa-var-mail-forward: "\f064";
+@fa-var-mail-reply: "\f112";
+@fa-var-mail-reply-all: "\f122";
+@fa-var-male: "\f183";
+@fa-var-map: "\f279";
+@fa-var-map-marker: "\f041";
+@fa-var-map-o: "\f278";
+@fa-var-map-pin: "\f276";
+@fa-var-map-signs: "\f277";
+@fa-var-mars: "\f222";
+@fa-var-mars-double: "\f227";
+@fa-var-mars-stroke: "\f229";
+@fa-var-mars-stroke-h: "\f22b";
+@fa-var-mars-stroke-v: "\f22a";
+@fa-var-maxcdn: "\f136";
+@fa-var-meanpath: "\f20c";
+@fa-var-medium: "\f23a";
+@fa-var-medkit: "\f0fa";
+@fa-var-meetup: "\f2e0";
+@fa-var-meh-o: "\f11a";
+@fa-var-mercury: "\f223";
+@fa-var-microchip: "\f2db";
+@fa-var-microphone: "\f130";
+@fa-var-microphone-slash: "\f131";
+@fa-var-minus: "\f068";
+@fa-var-minus-circle: "\f056";
+@fa-var-minus-square: "\f146";
+@fa-var-minus-square-o: "\f147";
+@fa-var-mixcloud: "\f289";
+@fa-var-mobile: "\f10b";
+@fa-var-mobile-phone: "\f10b";
+@fa-var-modx: "\f285";
+@fa-var-money: "\f0d6";
+@fa-var-moon-o: "\f186";
+@fa-var-mortar-board: "\f19d";
+@fa-var-motorcycle: "\f21c";
+@fa-var-mouse-pointer: "\f245";
+@fa-var-music: "\f001";
+@fa-var-navicon: "\f0c9";
+@fa-var-neuter: "\f22c";
+@fa-var-newspaper-o: "\f1ea";
+@fa-var-object-group: "\f247";
+@fa-var-object-ungroup: "\f248";
+@fa-var-odnoklassniki: "\f263";
+@fa-var-odnoklassniki-square: "\f264";
+@fa-var-opencart: "\f23d";
+@fa-var-openid: "\f19b";
+@fa-var-opera: "\f26a";
+@fa-var-optin-monster: "\f23c";
+@fa-var-outdent: "\f03b";
+@fa-var-pagelines: "\f18c";
+@fa-var-paint-brush: "\f1fc";
+@fa-var-paper-plane: "\f1d8";
+@fa-var-paper-plane-o: "\f1d9";
+@fa-var-paperclip: "\f0c6";
+@fa-var-paragraph: "\f1dd";
+@fa-var-paste: "\f0ea";
+@fa-var-pause: "\f04c";
+@fa-var-pause-circle: "\f28b";
+@fa-var-pause-circle-o: "\f28c";
+@fa-var-paw: "\f1b0";
+@fa-var-paypal: "\f1ed";
+@fa-var-pencil: "\f040";
+@fa-var-pencil-square: "\f14b";
+@fa-var-pencil-square-o: "\f044";
+@fa-var-percent: "\f295";
+@fa-var-phone: "\f095";
+@fa-var-phone-square: "\f098";
+@fa-var-photo: "\f03e";
+@fa-var-picture-o: "\f03e";
+@fa-var-pie-chart: "\f200";
+@fa-var-pied-piper: "\f2ae";
+@fa-var-pied-piper-alt: "\f1a8";
+@fa-var-pied-piper-pp: "\f1a7";
+@fa-var-pinterest: "\f0d2";
+@fa-var-pinterest-p: "\f231";
+@fa-var-pinterest-square: "\f0d3";
+@fa-var-plane: "\f072";
+@fa-var-play: "\f04b";
+@fa-var-play-circle: "\f144";
+@fa-var-play-circle-o: "\f01d";
+@fa-var-plug: "\f1e6";
+@fa-var-plus: "\f067";
+@fa-var-plus-circle: "\f055";
+@fa-var-plus-square: "\f0fe";
+@fa-var-plus-square-o: "\f196";
+@fa-var-podcast: "\f2ce";
+@fa-var-power-off: "\f011";
+@fa-var-print: "\f02f";
+@fa-var-product-hunt: "\f288";
+@fa-var-puzzle-piece: "\f12e";
+@fa-var-qq: "\f1d6";
+@fa-var-qrcode: "\f029";
+@fa-var-question: "\f128";
+@fa-var-question-circle: "\f059";
+@fa-var-question-circle-o: "\f29c";
+@fa-var-quora: "\f2c4";
+@fa-var-quote-left: "\f10d";
+@fa-var-quote-right: "\f10e";
+@fa-var-ra: "\f1d0";
+@fa-var-random: "\f074";
+@fa-var-ravelry: "\f2d9";
+@fa-var-rebel: "\f1d0";
+@fa-var-recycle: "\f1b8";
+@fa-var-reddit: "\f1a1";
+@fa-var-reddit-alien: "\f281";
+@fa-var-reddit-square: "\f1a2";
+@fa-var-refresh: "\f021";
+@fa-var-registered: "\f25d";
+@fa-var-remove: "\f00d";
+@fa-var-renren: "\f18b";
+@fa-var-reorder: "\f0c9";
+@fa-var-repeat: "\f01e";
+@fa-var-reply: "\f112";
+@fa-var-reply-all: "\f122";
+@fa-var-resistance: "\f1d0";
+@fa-var-retweet: "\f079";
+@fa-var-rmb: "\f157";
+@fa-var-road: "\f018";
+@fa-var-rocket: "\f135";
+@fa-var-rotate-left: "\f0e2";
+@fa-var-rotate-right: "\f01e";
+@fa-var-rouble: "\f158";
+@fa-var-rss: "\f09e";
+@fa-var-rss-square: "\f143";
+@fa-var-rub: "\f158";
+@fa-var-ruble: "\f158";
+@fa-var-rupee: "\f156";
+@fa-var-s15: "\f2cd";
+@fa-var-safari: "\f267";
+@fa-var-save: "\f0c7";
+@fa-var-scissors: "\f0c4";
+@fa-var-scribd: "\f28a";
+@fa-var-search: "\f002";
+@fa-var-search-minus: "\f010";
+@fa-var-search-plus: "\f00e";
+@fa-var-sellsy: "\f213";
+@fa-var-send: "\f1d8";
+@fa-var-send-o: "\f1d9";
+@fa-var-server: "\f233";
+@fa-var-share: "\f064";
+@fa-var-share-alt: "\f1e0";
+@fa-var-share-alt-square: "\f1e1";
+@fa-var-share-square: "\f14d";
+@fa-var-share-square-o: "\f045";
+@fa-var-shekel: "\f20b";
+@fa-var-sheqel: "\f20b";
+@fa-var-shield: "\f132";
+@fa-var-ship: "\f21a";
+@fa-var-shirtsinbulk: "\f214";
+@fa-var-shopping-bag: "\f290";
+@fa-var-shopping-basket: "\f291";
+@fa-var-shopping-cart: "\f07a";
+@fa-var-shower: "\f2cc";
+@fa-var-sign-in: "\f090";
+@fa-var-sign-language: "\f2a7";
+@fa-var-sign-out: "\f08b";
+@fa-var-signal: "\f012";
+@fa-var-signing: "\f2a7";
+@fa-var-simplybuilt: "\f215";
+@fa-var-sitemap: "\f0e8";
+@fa-var-skyatlas: "\f216";
+@fa-var-skype: "\f17e";
+@fa-var-slack: "\f198";
+@fa-var-sliders: "\f1de";
+@fa-var-slideshare: "\f1e7";
+@fa-var-smile-o: "\f118";
+@fa-var-snapchat: "\f2ab";
+@fa-var-snapchat-ghost: "\f2ac";
+@fa-var-snapchat-square: "\f2ad";
+@fa-var-snowflake-o: "\f2dc";
+@fa-var-soccer-ball-o: "\f1e3";
+@fa-var-sort: "\f0dc";
+@fa-var-sort-alpha-asc: "\f15d";
+@fa-var-sort-alpha-desc: "\f15e";
+@fa-var-sort-amount-asc: "\f160";
+@fa-var-sort-amount-desc: "\f161";
+@fa-var-sort-asc: "\f0de";
+@fa-var-sort-desc: "\f0dd";
+@fa-var-sort-down: "\f0dd";
+@fa-var-sort-numeric-asc: "\f162";
+@fa-var-sort-numeric-desc: "\f163";
+@fa-var-sort-up: "\f0de";
+@fa-var-soundcloud: "\f1be";
+@fa-var-space-shuttle: "\f197";
+@fa-var-spinner: "\f110";
+@fa-var-spoon: "\f1b1";
+@fa-var-spotify: "\f1bc";
+@fa-var-square: "\f0c8";
+@fa-var-square-o: "\f096";
+@fa-var-stack-exchange: "\f18d";
+@fa-var-stack-overflow: "\f16c";
+@fa-var-star: "\f005";
+@fa-var-star-half: "\f089";
+@fa-var-star-half-empty: "\f123";
+@fa-var-star-half-full: "\f123";
+@fa-var-star-half-o: "\f123";
+@fa-var-star-o: "\f006";
+@fa-var-steam: "\f1b6";
+@fa-var-steam-square: "\f1b7";
+@fa-var-step-backward: "\f048";
+@fa-var-step-forward: "\f051";
+@fa-var-stethoscope: "\f0f1";
+@fa-var-sticky-note: "\f249";
+@fa-var-sticky-note-o: "\f24a";
+@fa-var-stop: "\f04d";
+@fa-var-stop-circle: "\f28d";
+@fa-var-stop-circle-o: "\f28e";
+@fa-var-street-view: "\f21d";
+@fa-var-strikethrough: "\f0cc";
+@fa-var-stumbleupon: "\f1a4";
+@fa-var-stumbleupon-circle: "\f1a3";
+@fa-var-subscript: "\f12c";
+@fa-var-subway: "\f239";
+@fa-var-suitcase: "\f0f2";
+@fa-var-sun-o: "\f185";
+@fa-var-superpowers: "\f2dd";
+@fa-var-superscript: "\f12b";
+@fa-var-support: "\f1cd";
+@fa-var-table: "\f0ce";
+@fa-var-tablet: "\f10a";
+@fa-var-tachometer: "\f0e4";
+@fa-var-tag: "\f02b";
+@fa-var-tags: "\f02c";
+@fa-var-tasks: "\f0ae";
+@fa-var-taxi: "\f1ba";
+@fa-var-telegram: "\f2c6";
+@fa-var-television: "\f26c";
+@fa-var-tencent-weibo: "\f1d5";
+@fa-var-terminal: "\f120";
+@fa-var-text-height: "\f034";
+@fa-var-text-width: "\f035";
+@fa-var-th: "\f00a";
+@fa-var-th-large: "\f009";
+@fa-var-th-list: "\f00b";
+@fa-var-themeisle: "\f2b2";
+@fa-var-thermometer: "\f2c7";
+@fa-var-thermometer-0: "\f2cb";
+@fa-var-thermometer-1: "\f2ca";
+@fa-var-thermometer-2: "\f2c9";
+@fa-var-thermometer-3: "\f2c8";
+@fa-var-thermometer-4: "\f2c7";
+@fa-var-thermometer-empty: "\f2cb";
+@fa-var-thermometer-full: "\f2c7";
+@fa-var-thermometer-half: "\f2c9";
+@fa-var-thermometer-quarter: "\f2ca";
+@fa-var-thermometer-three-quarters: "\f2c8";
+@fa-var-thumb-tack: "\f08d";
+@fa-var-thumbs-down: "\f165";
+@fa-var-thumbs-o-down: "\f088";
+@fa-var-thumbs-o-up: "\f087";
+@fa-var-thumbs-up: "\f164";
+@fa-var-ticket: "\f145";
+@fa-var-times: "\f00d";
+@fa-var-times-circle: "\f057";
+@fa-var-times-circle-o: "\f05c";
+@fa-var-times-rectangle: "\f2d3";
+@fa-var-times-rectangle-o: "\f2d4";
+@fa-var-tint: "\f043";
+@fa-var-toggle-down: "\f150";
+@fa-var-toggle-left: "\f191";
+@fa-var-toggle-off: "\f204";
+@fa-var-toggle-on: "\f205";
+@fa-var-toggle-right: "\f152";
+@fa-var-toggle-up: "\f151";
+@fa-var-trademark: "\f25c";
+@fa-var-train: "\f238";
+@fa-var-transgender: "\f224";
+@fa-var-transgender-alt: "\f225";
+@fa-var-trash: "\f1f8";
+@fa-var-trash-o: "\f014";
+@fa-var-tree: "\f1bb";
+@fa-var-trello: "\f181";
+@fa-var-tripadvisor: "\f262";
+@fa-var-trophy: "\f091";
+@fa-var-truck: "\f0d1";
+@fa-var-try: "\f195";
+@fa-var-tty: "\f1e4";
+@fa-var-tumblr: "\f173";
+@fa-var-tumblr-square: "\f174";
+@fa-var-turkish-lira: "\f195";
+@fa-var-tv: "\f26c";
+@fa-var-twitch: "\f1e8";
+@fa-var-twitter: "\f099";
+@fa-var-twitter-square: "\f081";
+@fa-var-umbrella: "\f0e9";
+@fa-var-underline: "\f0cd";
+@fa-var-undo: "\f0e2";
+@fa-var-universal-access: "\f29a";
+@fa-var-university: "\f19c";
+@fa-var-unlink: "\f127";
+@fa-var-unlock: "\f09c";
+@fa-var-unlock-alt: "\f13e";
+@fa-var-unsorted: "\f0dc";
+@fa-var-upload: "\f093";
+@fa-var-usb: "\f287";
+@fa-var-usd: "\f155";
+@fa-var-user: "\f007";
+@fa-var-user-circle: "\f2bd";
+@fa-var-user-circle-o: "\f2be";
+@fa-var-user-md: "\f0f0";
+@fa-var-user-o: "\f2c0";
+@fa-var-user-plus: "\f234";
+@fa-var-user-secret: "\f21b";
+@fa-var-user-times: "\f235";
+@fa-var-users: "\f0c0";
+@fa-var-vcard: "\f2bb";
+@fa-var-vcard-o: "\f2bc";
+@fa-var-venus: "\f221";
+@fa-var-venus-double: "\f226";
+@fa-var-venus-mars: "\f228";
+@fa-var-viacoin: "\f237";
+@fa-var-viadeo: "\f2a9";
+@fa-var-viadeo-square: "\f2aa";
+@fa-var-video-camera: "\f03d";
+@fa-var-vimeo: "\f27d";
+@fa-var-vimeo-square: "\f194";
+@fa-var-vine: "\f1ca";
+@fa-var-vk: "\f189";
+@fa-var-volume-control-phone: "\f2a0";
+@fa-var-volume-down: "\f027";
+@fa-var-volume-off: "\f026";
+@fa-var-volume-up: "\f028";
+@fa-var-warning: "\f071";
+@fa-var-wechat: "\f1d7";
+@fa-var-weibo: "\f18a";
+@fa-var-weixin: "\f1d7";
+@fa-var-whatsapp: "\f232";
+@fa-var-wheelchair: "\f193";
+@fa-var-wheelchair-alt: "\f29b";
+@fa-var-wifi: "\f1eb";
+@fa-var-wikipedia-w: "\f266";
+@fa-var-window-close: "\f2d3";
+@fa-var-window-close-o: "\f2d4";
+@fa-var-window-maximize: "\f2d0";
+@fa-var-window-minimize: "\f2d1";
+@fa-var-window-restore: "\f2d2";
+@fa-var-windows: "\f17a";
+@fa-var-won: "\f159";
+@fa-var-wordpress: "\f19a";
+@fa-var-wpbeginner: "\f297";
+@fa-var-wpexplorer: "\f2de";
+@fa-var-wpforms: "\f298";
+@fa-var-wrench: "\f0ad";
+@fa-var-xing: "\f168";
+@fa-var-xing-square: "\f169";
+@fa-var-y-combinator: "\f23b";
+@fa-var-y-combinator-square: "\f1d4";
+@fa-var-yahoo: "\f19e";
+@fa-var-yc: "\f23b";
+@fa-var-yc-square: "\f1d4";
+@fa-var-yelp: "\f1e9";
+@fa-var-yen: "\f157";
+@fa-var-yoast: "\f2b1";
+@fa-var-youtube: "\f167";
+@fa-var-youtube-play: "\f16a";
+@fa-var-youtube-square: "\f166";
+
diff --git a/scss/font-awesome.scss b/scss/font-awesome.scss
new file mode 100644
index 0000000..f1c83aa
--- /dev/null
+++ b/scss/font-awesome.scss
@@ -0,0 +1,18 @@
+/*!
+ * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome
+ * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
+ */
+
+@import "variables";
+@import "mixins";
+@import "path";
+@import "core";
+@import "larger";
+@import "fixed-width";
+@import "list";
+@import "bordered-pulled";
+@import "animated";
+@import "rotated-flipped";
+@import "stacked";
+@import "icons";
+@import "screen-reader";
diff --git a/webfonts/fa-brands-400.ttf b/webfonts/fa-brands-400.ttf
new file mode 100644
index 0000000..1fbb1f7
Binary files /dev/null and b/webfonts/fa-brands-400.ttf differ
diff --git a/webfonts/fa-brands-400.woff2 b/webfonts/fa-brands-400.woff2
new file mode 100644
index 0000000..5d28021
Binary files /dev/null and b/webfonts/fa-brands-400.woff2 differ
diff --git a/webfonts/fa-regular-400.ttf b/webfonts/fa-regular-400.ttf
new file mode 100644
index 0000000..549d68d
Binary files /dev/null and b/webfonts/fa-regular-400.ttf differ
diff --git a/webfonts/fa-regular-400.woff2 b/webfonts/fa-regular-400.woff2
new file mode 100644
index 0000000..18400d7
Binary files /dev/null and b/webfonts/fa-regular-400.woff2 differ
diff --git a/webfonts/fa-solid-900.ttf b/webfonts/fa-solid-900.ttf
new file mode 100644
index 0000000..bb2a869
Binary files /dev/null and b/webfonts/fa-solid-900.ttf differ
diff --git a/webfonts/fa-solid-900.woff2 b/webfonts/fa-solid-900.woff2
new file mode 100644
index 0000000..758dd4f
Binary files /dev/null and b/webfonts/fa-solid-900.woff2 differ
diff --git a/webfonts/fa-v4compatibility.ttf b/webfonts/fa-v4compatibility.ttf
new file mode 100644
index 0000000..8c5864c
Binary files /dev/null and b/webfonts/fa-v4compatibility.ttf differ
diff --git a/webfonts/fa-v4compatibility.woff2 b/webfonts/fa-v4compatibility.woff2
new file mode 100644
index 0000000..f94bec2
Binary files /dev/null and b/webfonts/fa-v4compatibility.woff2 differ