").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.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",
+ json: "responseJSON"
+ },
+
+ // Data converters
+ // Keys separate source (or catchall "*") and destination types with a single space
+ converters: {
+
+ // Convert anything to text
+ "* text": 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 // Cross-domain detection vars
+ parts,
+ // Loop variable
+ i,
+ // URL without anti-cache param
+ cacheURL,
+ // Response headers as string
+ responseHeadersString,
+ // timeout handle
+ timeoutTimer,
+
+ // To know if global events are to be dispatched
+ fireGlobals,
+
+ transport,
+ // Response headers
+ responseHeaders,
+ // 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;
+
+ // Determine if successful
+ isSuccess = status >= 200 && status < 300 || status === 304;
+
+ // Get response data
+ if ( responses ) {
+ response = ajaxHandleResponses( s, jqXHR, responses );
+ }
+
+ // Convert no matter what (that way responseXXX fields are always set)
+ response = ajaxConvert( s, response, jqXHR, isSuccess );
+
+ // If successful, handle type chaining
+ if ( isSuccess ) {
+
+ // 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 no content
+ if ( status === 204 || s.type === "HEAD" ) {
+ statusText = "nocontent";
+
+ // if not modified
+ } else if ( status === 304 ) {
+ statusText = "notmodified";
+
+ // If we have data, let's convert it
+ } else {
+ statusText = response.state;
+ success = response.data;
+ error = response.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;
+ },
+
+ getJSON: function( url, data, callback ) {
+ return jQuery.get( url, data, callback, "json" );
+ },
+
+ getScript: function( url, callback ) {
+ return jQuery.get( url, undefined, callback, "script" );
+ }
+});
+
+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
+ });
+ };
+});
+
+/* Handles responses to an ajax request:
+ * - finds the right dataType (mediates between content-type and expected dataType)
+ * - returns the corresponding response
+ */
+function ajaxHandleResponses( s, jqXHR, responses ) {
+ var firstDataType, ct, finalDataType, type,
+ contents = s.contents,
+ dataTypes = s.dataTypes;
+
+ // 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
+ * Also sets the responseXXX fields on the jqXHR instance
+ */
+function ajaxConvert( s, response, jqXHR, isSuccess ) {
+ var conv2, current, conv, tmp, prev,
+ converters = {},
+ // Work with a copy of dataTypes in case we need to modify it for conversion
+ dataTypes = s.dataTypes.slice();
+
+ // Create converters map with lowercased keys
+ if ( dataTypes[ 1 ] ) {
+ for ( conv in s.converters ) {
+ converters[ conv.toLowerCase() ] = s.converters[ conv ];
+ }
+ }
+
+ current = dataTypes.shift();
+
+ // Convert to each sequential dataType
+ while ( current ) {
+
+ if ( s.responseFields[ current ] ) {
+ jqXHR[ s.responseFields[ current ] ] = response;
+ }
+
+ // Apply the dataFilter if provided
+ if ( !prev && isSuccess && s.dataFilter ) {
+ response = s.dataFilter( response, s.dataType );
+ }
+
+ prev = current;
+ current = dataTypes.shift();
+
+ if ( current ) {
+
+ // There's only work to do if current dataType is non-auto
+ if ( current === "*" ) {
+
+ current = prev;
+
+ // Convert response if prev dataType is non-auto and differs from current
+ } else 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.unshift( tmp[ 1 ] );
+ }
+ 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 };
+ }
+ }
+ }
+ }
+ }
+ }
+
+ 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, responseHeaders, statusText, responses;
+
+ // Firefox throws exceptions when accessing properties
+ // of an xhr when a network error occurred
+ // https://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;
+ responseHeaders = xhr.getAllResponseHeaders();
+
+ // 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 tween = this.createTween( prop, value ),
+ target = tween.cur(),
+ parts = rfxnum.exec( value ),
+ unit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
+
+ // Starting value computation is required for potential unit mismatches
+ start = ( jQuery.cssNumber[ prop ] || unit !== "px" && +target ) &&
+ rfxnum.exec( jQuery.css( tween.elem, prop ) ),
+ scale = 1,
+ maxIterations = 20;
+
+ if ( start && start[ 3 ] !== unit ) {
+ // Trust units reported by jQuery.css
+ unit = unit || start[ 3 ];
+
+ // Make sure we update the tween properties later on
+ parts = parts || [];
+
+ // Iteratively approximate from a nonzero starting point
+ start = +target || 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 );
+ }
+
+ // Update tween properties
+ if ( parts ) {
+ start = tween.start = +start || +target || 0;
+ tween.unit = unit;
+ // If a +=/-= token was provided, we're doing a relative animation
+ tween.end = parts[ 1 ] ?
+ start + ( parts[ 1 ] + 1 ) * parts[ 2 ] :
+ +parts[ 2 ];
+ }
+
+ return tween;
+ }]
+ };
+
+// Animations created synchronously will run synchronously
+function createFxNow() {
+ setTimeout(function() {
+ fxNow = undefined;
+ });
+ return ( fxNow = jQuery.now() );
+}
+
+function createTween( value, prop, animation ) {
+ var tween,
+ collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
+ index = 0,
+ length = collection.length;
+ for ( ; index < length; index++ ) {
+ if ( (tween = collection[ index ].call( animation, prop, value )) ) {
+
+ // we're done with this property
+ return tween;
+ }
+ }
+}
+
+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;
+ }
+ }
+
+ jQuery.map( props, createTween, animation );
+
+ 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 prop, value, toggle, tween, hooks, oldfire,
+ anim = this,
+ orig = {},
+ style = elem.style,
+ hidden = elem.nodeType && isHidden( elem ),
+ dataShow = jQuery._data( elem, "fxshow" );
+
+ // 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.always(function() {
+ style.overflow = opts.overflow[ 0 ];
+ style.overflowX = opts.overflow[ 1 ];
+ style.overflowY = opts.overflow[ 2 ];
+ });
+ }
+ }
+
+
+ // show/hide pass
+ for ( prop in props ) {
+ value = props[ prop ];
+ if ( rfxtypes.exec( value ) ) {
+ delete props[ prop ];
+ toggle = toggle || value === "toggle";
+ if ( value === ( hidden ? "hide" : "show" ) ) {
+ continue;
+ }
+ orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
+ }
+ }
+
+ if ( !jQuery.isEmptyObject( orig ) ) {
+ if ( dataShow ) {
+ if ( "hidden" in dataShow ) {
+ hidden = dataShow.hidden;
+ }
+ } else {
+ dataShow = jQuery._data( elem, "fxshow", {} );
+ }
+
+ // 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 ( prop in orig ) {
+ tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
+
+ 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 an 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, "" );
+ // 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;
+ }
+ }
+ }
+};
+
+// Support: IE <=9
+// 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 );
+
+ // 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.stop ) {
+ hooks.stop.call( this, true );
+ }
+
+ // 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 !== core_strundefined ) {
+ 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 || docElem;
+ while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position") === "static" ) ) {
+ offsetParent = offsetParent.offsetParent;
+ }
+ return offsetParent || docElem;
+ });
+ }
+});
+
+
+// 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() {
+
+// The number of elements contained in the matched element set
+jQuery.fn.size = function() {
+ return this.length;
+};
+
+jQuery.fn.andSelf = jQuery.fn.addBack;
+
+// })();
+if ( typeof module === "object" && module && typeof module.exports === "object" ) {
+ // Expose jQuery as module.exports in loaders that implement the Node
+ // module pattern (including browserify). Do not create the global, since
+ // the user will be storing it themselves locally, and globals are frowned
+ // upon in the Node module world.
+ module.exports = jQuery;
+} else {
+ // Otherwise expose jQuery to the global object as usual
+ window.jQuery = window.$ = jQuery;
+
+ // Register as a named AMD module, since jQuery can be concatenated with other
+ // files that may use define, but not via 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( "jquery", [], function () { return jQuery; } );
+ }
+}
+
+})( window );
diff --git a/js/projectDocumentationWidget.js b/js/projectDocumentationWidget.js
new file mode 100644
index 00000000..2e30a358
--- /dev/null
+++ b/js/projectDocumentationWidget.js
@@ -0,0 +1,192 @@
+window.Spring = window.Spring || {};
+
+/* ERB style templates conflict with Jekyll HTML escaping */
+_.templateSettings = {
+ evaluate : /\{@([\s\S]+?)@\}/g,
+ interpolate : /\{@=([\s\S]+?)@\}/g,
+ escape : /\{@-([\s\S]+?)@\}/g
+};
+
+Spring.ProjectDocumentationWidget = function () {
+ var quickStartEl = $('[data-download-widget-controls]');
+ var mavenWidgetEl = $('.js-download-maven-widget');
+ var documentationEl = $('.js-documentation-widget');
+
+ var projectUrl = apiBaseUrl + "/project_metadata/" + projectId;
+ var promise = Spring.loadProject(projectUrl);
+
+ promise.then(function (project) {
+ Spring.buildDocumentationWidget(documentationEl, project);
+ Spring.buildQuickStartWidget(quickStartEl, mavenWidgetEl, project);
+ });
+};
+
+Spring.buildDocumentationWidget = function (documentationEl, project) {
+ new Spring.DocumentationWidgetView({
+ el: documentationEl,
+ model: project,
+ template: $("#project-documentation-widget-template").text()
+ }).render();
+
+}
+Spring.buildQuickStartWidget = function (quickStartEl, mavenWidgetEl, project) {
+ new Spring.QuickStartSelectorView({
+ el: quickStartEl,
+ model: project,
+ template: $("#project-download-widget-controls-template").text(),
+ snippetWidgetEl: mavenWidgetEl
+ }).render();
+}
+
+Spring.loadProject = function (url) {
+ return $.ajax(url, {
+ dataType: 'jsonp',
+ processData: false
+ }).then(function (value) {
+ return new Spring.Project(value);
+ });
+}
+
+Spring.Release = function (data) {
+ _.extend(this, data);
+}
+
+Spring.Release.prototype = {
+ statusIconClass: function () {
+ if (this.preRelease) {
+ return "spring-icon-pre-release";
+ } else if (this.generalAvailability) {
+ return "spring-icon-ga-release";
+ } else {
+ return "spring-icon-snapshot-release";
+ }
+ }
+}
+
+Spring.Project = function (data) {
+ _.extend(this, data);
+ var self = this;
+ this.releases = _.map(this.projectReleases, function (r) {
+ return new Spring.Release(r);
+ });
+
+ return this;
+};
+
+Spring.DocumentationWidgetView = Backbone.View.extend({
+ initialize: function () {
+ this.template = _.template(this.options.template);
+ _.bindAll(this, "render");
+ },
+
+ render: function () {
+ this.$el.html(
+ this.template(this.model)
+ );
+ return this;
+ }
+});
+
+Spring.SnippetView = Backbone.View.extend({
+ initialize: function () {
+ var snippetType = this.options.snippetType;
+ var downloadTemplate = $(document.createElement('div')).html($("#project-download-" + snippetType + "-widget-template").text());
+ var repositoryTemplate = $(document.createElement('div')).html($("#project-repository-" + snippetType + "-widget-template").text());
+ this.combinedTemplate = _.template(
+ "
" +
+ downloadTemplate.find("code:first").html() +
+ "{@ if (repository) { @}" +
+ repositoryTemplate.find("code:first").html() +
+ "{@ } @}" +
+ ""
+ );
+ _.bindAll(this, "render");
+ },
+
+ render: function () {
+
+ var html = $(this.combinedTemplate(this.model));
+ this.$el.html(html);
+ Spring.buildCopyButton(html.find(":first"), "snippet");
+ return this;
+ },
+
+ remove: function() {
+ this.undelegateEvents();
+ this.$el.empty();
+ this.unbind();
+ }
+});
+
+Spring.QuickStartSelectorView = Backbone.View.extend({
+ events: {
+ "change .selector": "renderActiveWidget",
+ "click .js-item": "changeDownloadSource"
+ },
+
+ initialize: function () {
+ this.template = _.template(this.options.template);
+ this.snippetWidgetEl = this.options.snippetWidgetEl;
+ _.bindAll(this, "render", "renderActiveWidget", "changeDownloadSource", "_moveItemSlider", "selectCurrent");
+ },
+
+ render: function () {
+ this.$el.html(
+ this.template(this.model)
+ );
+ this.renderActiveWidget();
+ this.selectCurrent();
+ this.$('.selectpicker').selectpicker();
+ return this;
+ },
+
+ selectCurrent: function() {
+ var selectedIndex = $('.selectpicker [data-current="true"]').val();
+ if(selectedIndex == undefined) {
+ selectedIndex = 0;
+ }
+ this.$('.selectpicker').val(selectedIndex).change();
+ },
+
+ renderActiveWidget: function() {
+ if(this.activeWidget != null) this.activeWidget.remove();
+
+ this.activeWidget = new Spring.SnippetView({
+ el: this.snippetWidgetEl,
+ model: this.model.releases[this.$('.selector :selected').val()],
+ snippetType: this.$('.js-active').data('snippet-type')
+ });
+ this.activeWidget.render();
+
+ },
+
+ changeDownloadSource: function (event) {
+ var target = $(event.target);
+
+ target.addClass("js-active");
+ target.siblings().removeClass("js-active");
+
+ this._moveItemSlider();
+ this.renderActiveWidget();
+ },
+
+ _moveItemSlider: function () {
+ var activeItem = $(".js-item-slider--wrapper .js-item.js-active");
+ if (activeItem.length == 0) {
+ return;
+ } else {
+ var activeItemPosition = activeItem.position();
+ var activeItemOffset = activeItemPosition.left;
+ var activeItemWidth = activeItem.outerWidth();
+
+ var slider = $(".js-item--slider");
+ var sliderPosition = slider.position();
+ var sliderOffset = sliderPosition.left;
+ var sliderTarget = activeItemOffset - sliderOffset;
+
+ slider.width(activeItemWidth);
+ slider.css("margin-left", sliderTarget);
+ }
+ }
+
+});
diff --git a/js/test/SpecRunner.html b/js/test/SpecRunner.html
new file mode 100644
index 00000000..66bdd3b6
--- /dev/null
+++ b/js/test/SpecRunner.html
@@ -0,0 +1,66 @@
+---
+layout: spec_layout
+title: Your Project Name Here
+---
+
+
+
+
+
Jasmine Spec Runner
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {% include widget_templates.html %}
+
+
+
+
+
+
+
+
diff --git a/js/test/lib/jasmine-1.3.1/MIT.LICENSE b/js/test/lib/jasmine-1.3.1/MIT.LICENSE
new file mode 100644
index 00000000..7c435baa
--- /dev/null
+++ b/js/test/lib/jasmine-1.3.1/MIT.LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2008-2011 Pivotal Labs
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/js/test/lib/jasmine-1.3.1/jasmine-html.js b/js/test/lib/jasmine-1.3.1/jasmine-html.js
new file mode 100644
index 00000000..fa1863d1
--- /dev/null
+++ b/js/test/lib/jasmine-1.3.1/jasmine-html.js
@@ -0,0 +1,681 @@
+jasmine.HtmlReporterHelpers = {};
+
+jasmine.HtmlReporterHelpers.createDom = function(type, attrs, childrenVarArgs) {
+ var el = document.createElement(type);
+
+ for (var i = 2; i < arguments.length; i++) {
+ var child = arguments[i];
+
+ if (typeof child === 'string') {
+ el.appendChild(document.createTextNode(child));
+ } else {
+ if (child) {
+ el.appendChild(child);
+ }
+ }
+ }
+
+ for (var attr in attrs) {
+ if (attr == "className") {
+ el[attr] = attrs[attr];
+ } else {
+ el.setAttribute(attr, attrs[attr]);
+ }
+ }
+
+ return el;
+};
+
+jasmine.HtmlReporterHelpers.getSpecStatus = function(child) {
+ var results = child.results();
+ var status = results.passed() ? 'passed' : 'failed';
+ if (results.skipped) {
+ status = 'skipped';
+ }
+
+ return status;
+};
+
+jasmine.HtmlReporterHelpers.appendToSummary = function(child, childElement) {
+ var parentDiv = this.dom.summary;
+ var parentSuite = (typeof child.parentSuite == 'undefined') ? 'suite' : 'parentSuite';
+ var parent = child[parentSuite];
+
+ if (parent) {
+ if (typeof this.views.suites[parent.id] == 'undefined') {
+ this.views.suites[parent.id] = new jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views);
+ }
+ parentDiv = this.views.suites[parent.id].element;
+ }
+
+ parentDiv.appendChild(childElement);
+};
+
+
+jasmine.HtmlReporterHelpers.addHelpers = function(ctor) {
+ for(var fn in jasmine.HtmlReporterHelpers) {
+ ctor.prototype[fn] = jasmine.HtmlReporterHelpers[fn];
+ }
+};
+
+jasmine.HtmlReporter = function(_doc) {
+ var self = this;
+ var doc = _doc || window.document;
+
+ var reporterView;
+
+ var dom = {};
+
+ // Jasmine Reporter Public Interface
+ self.logRunningSpecs = false;
+
+ self.reportRunnerStarting = function(runner) {
+ var specs = runner.specs() || [];
+
+ if (specs.length == 0) {
+ return;
+ }
+
+ createReporterDom(runner.env.versionString());
+ doc.body.appendChild(dom.reporter);
+ setExceptionHandling();
+
+ reporterView = new jasmine.HtmlReporter.ReporterView(dom);
+ reporterView.addSpecs(specs, self.specFilter);
+ };
+
+ self.reportRunnerResults = function(runner) {
+ reporterView && reporterView.complete();
+ };
+
+ self.reportSuiteResults = function(suite) {
+ reporterView.suiteComplete(suite);
+ };
+
+ self.reportSpecStarting = function(spec) {
+ if (self.logRunningSpecs) {
+ self.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
+ }
+ };
+
+ self.reportSpecResults = function(spec) {
+ reporterView.specComplete(spec);
+ };
+
+ self.log = function() {
+ var console = jasmine.getGlobal().console;
+ if (console && console.log) {
+ if (console.log.apply) {
+ console.log.apply(console, arguments);
+ } else {
+ console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
+ }
+ }
+ };
+
+ self.specFilter = function(spec) {
+ if (!focusedSpecName()) {
+ return true;
+ }
+
+ return spec.getVersion().indexOf(focusedSpecName()) === 0;
+ };
+
+ return self;
+
+ function focusedSpecName() {
+ var specName;
+
+ (function memoizeFocusedSpec() {
+ if (specName) {
+ return;
+ }
+
+ var paramMap = [];
+ var params = jasmine.HtmlReporter.parameters(doc);
+
+ for (var i = 0; i < params.length; i++) {
+ var p = params[i].split('=');
+ paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
+ }
+
+ specName = paramMap.spec;
+ })();
+
+ return specName;
+ }
+
+ function createReporterDom(version) {
+ dom.reporter = self.createDom('div', { id: 'HTMLReporter', className: 'jasmine_reporter' },
+ dom.banner = self.createDom('div', { className: 'banner' },
+ self.createDom('span', { className: 'title' }, "Jasmine "),
+ self.createDom('span', { className: 'version' }, version)),
+
+ dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}),
+ dom.alert = self.createDom('div', {className: 'alert'},
+ self.createDom('span', { className: 'exceptions' },
+ self.createDom('label', { className: 'label', 'for': 'no_try_catch' }, 'No try/catch'),
+ self.createDom('input', { id: 'no_try_catch', type: 'checkbox' }))),
+ dom.results = self.createDom('div', {className: 'results'},
+ dom.summary = self.createDom('div', { className: 'summary' }),
+ dom.details = self.createDom('div', { id: 'details' }))
+ );
+ }
+
+ function noTryCatch() {
+ return window.location.search.match(/catch=false/);
+ }
+
+ function searchWithCatch() {
+ var params = jasmine.HtmlReporter.parameters(window.document);
+ var removed = false;
+ var i = 0;
+
+ while (!removed && i < params.length) {
+ if (params[i].match(/catch=/)) {
+ params.splice(i, 1);
+ removed = true;
+ }
+ i++;
+ }
+ if (jasmine.CATCH_EXCEPTIONS) {
+ params.push("catch=false");
+ }
+
+ return params.join("&");
+ }
+
+ function setExceptionHandling() {
+ var chxCatch = document.getElementById('no_try_catch');
+
+ if (noTryCatch()) {
+ chxCatch.setAttribute('checked', true);
+ jasmine.CATCH_EXCEPTIONS = false;
+ }
+ chxCatch.onclick = function() {
+ window.location.search = searchWithCatch();
+ };
+ }
+};
+jasmine.HtmlReporter.parameters = function(doc) {
+ var paramStr = doc.location.search.substring(1);
+ var params = [];
+
+ if (paramStr.length > 0) {
+ params = paramStr.split('&');
+ }
+ return params;
+}
+jasmine.HtmlReporter.sectionLink = function(sectionName) {
+ var link = '?';
+ var params = [];
+
+ if (sectionName) {
+ params.push('spec=' + encodeURIComponent(sectionName));
+ }
+ if (!jasmine.CATCH_EXCEPTIONS) {
+ params.push("catch=false");
+ }
+ if (params.length > 0) {
+ link += params.join("&");
+ }
+
+ return link;
+};
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter);
+jasmine.HtmlReporter.ReporterView = function(dom) {
+ this.startedAt = new Date();
+ this.runningSpecCount = 0;
+ this.completeSpecCount = 0;
+ this.passedCount = 0;
+ this.failedCount = 0;
+ this.skippedCount = 0;
+
+ this.createResultsMenu = function() {
+ this.resultsMenu = this.createDom('span', {className: 'resultsMenu bar'},
+ this.summaryMenuItem = this.createDom('a', {className: 'summaryMenuItem', href: "#"}, '0 specs'),
+ ' | ',
+ this.detailsMenuItem = this.createDom('a', {className: 'detailsMenuItem', href: "#"}, '0 failing'));
+
+ this.summaryMenuItem.onclick = function() {
+ dom.reporter.className = dom.reporter.className.replace(/ showDetails/g, '');
+ };
+
+ this.detailsMenuItem.onclick = function() {
+ showDetails();
+ };
+ };
+
+ this.addSpecs = function(specs, specFilter) {
+ this.totalSpecCount = specs.length;
+
+ this.views = {
+ specs: {},
+ suites: {}
+ };
+
+ for (var i = 0; i < specs.length; i++) {
+ var spec = specs[i];
+ this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom, this.views);
+ if (specFilter(spec)) {
+ this.runningSpecCount++;
+ }
+ }
+ };
+
+ this.specComplete = function(spec) {
+ this.completeSpecCount++;
+
+ if (isUndefined(this.views.specs[spec.id])) {
+ this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom);
+ }
+
+ var specView = this.views.specs[spec.id];
+
+ switch (specView.status()) {
+ case 'passed':
+ this.passedCount++;
+ break;
+
+ case 'failed':
+ this.failedCount++;
+ break;
+
+ case 'skipped':
+ this.skippedCount++;
+ break;
+ }
+
+ specView.refresh();
+ this.refresh();
+ };
+
+ this.suiteComplete = function(suite) {
+ var suiteView = this.views.suites[suite.id];
+ if (isUndefined(suiteView)) {
+ return;
+ }
+ suiteView.refresh();
+ };
+
+ this.refresh = function() {
+
+ if (isUndefined(this.resultsMenu)) {
+ this.createResultsMenu();
+ }
+
+ // currently running UI
+ if (isUndefined(this.runningAlert)) {
+ this.runningAlert = this.createDom('a', { href: jasmine.HtmlReporter.sectionLink(), className: "runningAlert bar" });
+ dom.alert.appendChild(this.runningAlert);
+ }
+ this.runningAlert.innerHTML = "Running " + this.completeSpecCount + " of " + specPluralizedFor(this.totalSpecCount);
+
+ // skipped specs UI
+ if (isUndefined(this.skippedAlert)) {
+ this.skippedAlert = this.createDom('a', { href: jasmine.HtmlReporter.sectionLink(), className: "skippedAlert bar" });
+ }
+
+ this.skippedAlert.innerHTML = "Skipping " + this.skippedCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
+
+ if (this.skippedCount === 1 && isDefined(dom.alert)) {
+ dom.alert.appendChild(this.skippedAlert);
+ }
+
+ // passing specs UI
+ if (isUndefined(this.passedAlert)) {
+ this.passedAlert = this.createDom('span', { href: jasmine.HtmlReporter.sectionLink(), className: "passingAlert bar" });
+ }
+ this.passedAlert.innerHTML = "Passing " + specPluralizedFor(this.passedCount);
+
+ // failing specs UI
+ if (isUndefined(this.failedAlert)) {
+ this.failedAlert = this.createDom('span', {href: "?", className: "failingAlert bar"});
+ }
+ this.failedAlert.innerHTML = "Failing " + specPluralizedFor(this.failedCount);
+
+ if (this.failedCount === 1 && isDefined(dom.alert)) {
+ dom.alert.appendChild(this.failedAlert);
+ dom.alert.appendChild(this.resultsMenu);
+ }
+
+ // summary info
+ this.summaryMenuItem.innerHTML = "" + specPluralizedFor(this.runningSpecCount);
+ this.detailsMenuItem.innerHTML = "" + this.failedCount + " failing";
+ };
+
+ this.complete = function() {
+ dom.alert.removeChild(this.runningAlert);
+
+ this.skippedAlert.innerHTML = "Ran " + this.runningSpecCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
+
+ if (this.failedCount === 0) {
+ dom.alert.appendChild(this.createDom('span', {className: 'passingAlert bar'}, "Passing " + specPluralizedFor(this.passedCount)));
+ } else {
+ showDetails();
+ }
+
+ dom.banner.appendChild(this.createDom('span', {className: 'duration'}, "finished in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"));
+ };
+
+ return this;
+
+ function showDetails() {
+ if (dom.reporter.className.search(/showDetails/) === -1) {
+ dom.reporter.className += " showDetails";
+ }
+ }
+
+ function isUndefined(obj) {
+ return typeof obj === 'undefined';
+ }
+
+ function isDefined(obj) {
+ return !isUndefined(obj);
+ }
+
+ function specPluralizedFor(count) {
+ var str = count + " spec";
+ if (count > 1) {
+ str += "s"
+ }
+ return str;
+ }
+
+};
+
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.ReporterView);
+
+
+jasmine.HtmlReporter.SpecView = function(spec, dom, views) {
+ this.spec = spec;
+ this.dom = dom;
+ this.views = views;
+
+ this.symbol = this.createDom('li', { className: 'pending' });
+ this.dom.symbolSummary.appendChild(this.symbol);
+
+ this.summary = this.createDom('div', { className: 'specSummary' },
+ this.createDom('a', {
+ className: 'description',
+ href: jasmine.HtmlReporter.sectionLink(this.spec.getVersion()),
+ title: this.spec.getVersion()
+ }, this.spec.description)
+ );
+
+ this.detail = this.createDom('div', { className: 'specDetail' },
+ this.createDom('a', {
+ className: 'description',
+ href: '?spec=' + encodeURIComponent(this.spec.getVersion()),
+ title: this.spec.getVersion()
+ }, this.spec.getVersion())
+ );
+};
+
+jasmine.HtmlReporter.SpecView.prototype.status = function() {
+ return this.getSpecStatus(this.spec);
+};
+
+jasmine.HtmlReporter.SpecView.prototype.refresh = function() {
+ this.symbol.className = this.status();
+
+ switch (this.status()) {
+ case 'skipped':
+ break;
+
+ case 'passed':
+ this.appendSummaryToSuiteDiv();
+ break;
+
+ case 'failed':
+ this.appendSummaryToSuiteDiv();
+ this.appendFailureDetail();
+ break;
+ }
+};
+
+jasmine.HtmlReporter.SpecView.prototype.appendSummaryToSuiteDiv = function() {
+ this.summary.className += ' ' + this.status();
+ this.appendToSummary(this.spec, this.summary);
+};
+
+jasmine.HtmlReporter.SpecView.prototype.appendFailureDetail = function() {
+ this.detail.className += ' ' + this.status();
+
+ var resultItems = this.spec.results().getItems();
+ var messagesDiv = this.createDom('div', { className: 'messages' });
+
+ for (var i = 0; i < resultItems.length; i++) {
+ var result = resultItems[i];
+
+ if (result.type == 'log') {
+ messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
+ } else if (result.type == 'expect' && result.passed && !result.passed()) {
+ messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
+
+ if (result.trace.stack) {
+ messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
+ }
+ }
+ }
+
+ if (messagesDiv.childNodes.length > 0) {
+ this.detail.appendChild(messagesDiv);
+ this.dom.details.appendChild(this.detail);
+ }
+};
+
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView);jasmine.HtmlReporter.SuiteView = function(suite, dom, views) {
+ this.suite = suite;
+ this.dom = dom;
+ this.views = views;
+
+ this.element = this.createDom('div', { className: 'suite' },
+ this.createDom('a', { className: 'description', href: jasmine.HtmlReporter.sectionLink(this.suite.getVersion()) }, this.suite.description)
+ );
+
+ this.appendToSummary(this.suite, this.element);
+};
+
+jasmine.HtmlReporter.SuiteView.prototype.status = function() {
+ return this.getSpecStatus(this.suite);
+};
+
+jasmine.HtmlReporter.SuiteView.prototype.refresh = function() {
+ this.element.className += " " + this.status();
+};
+
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SuiteView);
+
+/* @deprecated Use jasmine.HtmlReporter instead
+ */
+jasmine.TrivialReporter = function(doc) {
+ this.document = doc || document;
+ this.suiteDivs = {};
+ this.logRunningSpecs = false;
+};
+
+jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {
+ var el = document.createElement(type);
+
+ for (var i = 2; i < arguments.length; i++) {
+ var child = arguments[i];
+
+ if (typeof child === 'string') {
+ el.appendChild(document.createTextNode(child));
+ } else {
+ if (child) { el.appendChild(child); }
+ }
+ }
+
+ for (var attr in attrs) {
+ if (attr == "className") {
+ el[attr] = attrs[attr];
+ } else {
+ el.setAttribute(attr, attrs[attr]);
+ }
+ }
+
+ return el;
+};
+
+jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
+ var showPassed, showSkipped;
+
+ this.outerDiv = this.createDom('div', { id: 'TrivialReporter', className: 'jasmine_reporter' },
+ this.createDom('div', { className: 'banner' },
+ this.createDom('div', { className: 'logo' },
+ this.createDom('span', { className: 'title' }, "Jasmine"),
+ this.createDom('span', { className: 'version' }, runner.env.versionString())),
+ this.createDom('div', { className: 'options' },
+ "Show ",
+ showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }),
+ this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "),
+ showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }),
+ this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped")
+ )
+ ),
+
+ this.runnerDiv = this.createDom('div', { className: 'runner running' },
+ this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
+ this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
+ this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
+ );
+
+ this.document.body.appendChild(this.outerDiv);
+
+ var suites = runner.suites();
+ for (var i = 0; i < suites.length; i++) {
+ var suite = suites[i];
+ var suiteDiv = this.createDom('div', { className: 'suite' },
+ this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getVersion()) }, "run"),
+ this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getVersion()) }, suite.description));
+ this.suiteDivs[suite.id] = suiteDiv;
+ var parentDiv = this.outerDiv;
+ if (suite.parentSuite) {
+ parentDiv = this.suiteDivs[suite.parentSuite.id];
+ }
+ parentDiv.appendChild(suiteDiv);
+ }
+
+ this.startedAt = new Date();
+
+ var self = this;
+ showPassed.onclick = function(evt) {
+ if (showPassed.checked) {
+ self.outerDiv.className += ' show-passed';
+ } else {
+ self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
+ }
+ };
+
+ showSkipped.onclick = function(evt) {
+ if (showSkipped.checked) {
+ self.outerDiv.className += ' show-skipped';
+ } else {
+ self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
+ }
+ };
+};
+
+jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
+ var results = runner.results();
+ var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
+ this.runnerDiv.setAttribute("class", className);
+ //do it twice for IE
+ this.runnerDiv.setAttribute("className", className);
+ var specs = runner.specs();
+ var specCount = 0;
+ for (var i = 0; i < specs.length; i++) {
+ if (this.specFilter(specs[i])) {
+ specCount++;
+ }
+ }
+ var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
+ message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
+ this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
+
+ this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
+};
+
+jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {
+ var results = suite.results();
+ var status = results.passed() ? 'passed' : 'failed';
+ if (results.totalCount === 0) { // todo: change this to check results.skipped
+ status = 'skipped';
+ }
+ this.suiteDivs[suite.id].className += " " + status;
+};
+
+jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) {
+ if (this.logRunningSpecs) {
+ this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
+ }
+};
+
+jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
+ var results = spec.results();
+ var status = results.passed() ? 'passed' : 'failed';
+ if (results.skipped) {
+ status = 'skipped';
+ }
+ var specDiv = this.createDom('div', { className: 'spec ' + status },
+ this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getVersion()) }, "run"),
+ this.createDom('a', {
+ className: 'description',
+ href: '?spec=' + encodeURIComponent(spec.getVersion()),
+ title: spec.getVersion()
+ }, spec.description));
+
+
+ var resultItems = results.getItems();
+ var messagesDiv = this.createDom('div', { className: 'messages' });
+ for (var i = 0; i < resultItems.length; i++) {
+ var result = resultItems[i];
+
+ if (result.type == 'log') {
+ messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
+ } else if (result.type == 'expect' && result.passed && !result.passed()) {
+ messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
+
+ if (result.trace.stack) {
+ messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
+ }
+ }
+ }
+
+ if (messagesDiv.childNodes.length > 0) {
+ specDiv.appendChild(messagesDiv);
+ }
+
+ this.suiteDivs[spec.suite.id].appendChild(specDiv);
+};
+
+jasmine.TrivialReporter.prototype.log = function() {
+ var console = jasmine.getGlobal().console;
+ if (console && console.log) {
+ if (console.log.apply) {
+ console.log.apply(console, arguments);
+ } else {
+ console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
+ }
+ }
+};
+
+jasmine.TrivialReporter.prototype.getLocation = function() {
+ return this.document.location;
+};
+
+jasmine.TrivialReporter.prototype.specFilter = function(spec) {
+ var paramMap = {};
+ var params = this.getLocation().search.substring(1).split('&');
+ for (var i = 0; i < params.length; i++) {
+ var p = params[i].split('=');
+ paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
+ }
+
+ if (!paramMap.spec) {
+ return true;
+ }
+ return spec.getVersion().indexOf(paramMap.spec) === 0;
+};
diff --git a/js/test/lib/jasmine-1.3.1/jasmine.css b/js/test/lib/jasmine-1.3.1/jasmine.css
new file mode 100644
index 00000000..8c008dc7
--- /dev/null
+++ b/js/test/lib/jasmine-1.3.1/jasmine.css
@@ -0,0 +1,82 @@
+body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; }
+
+#HTMLReporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; }
+#HTMLReporter a { text-decoration: none; }
+#HTMLReporter a:hover { text-decoration: underline; }
+#HTMLReporter p, #HTMLReporter h1, #HTMLReporter h2, #HTMLReporter h3, #HTMLReporter h4, #HTMLReporter h5, #HTMLReporter h6 { margin: 0; line-height: 14px; }
+#HTMLReporter .banner, #HTMLReporter .symbolSummary, #HTMLReporter .summary, #HTMLReporter .resultMessage, #HTMLReporter .specDetail .description, #HTMLReporter .alert .bar, #HTMLReporter .stackTrace { padding-left: 9px; padding-right: 9px; }
+#HTMLReporter #jasmine_content { position: fixed; right: 100%; }
+#HTMLReporter .version { color: #aaaaaa; }
+#HTMLReporter .banner { margin-top: 14px; }
+#HTMLReporter .duration { color: #aaaaaa; float: right; }
+#HTMLReporter .symbolSummary { overflow: hidden; *zoom: 1; margin: 14px 0; }
+#HTMLReporter .symbolSummary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; }
+#HTMLReporter .symbolSummary li.passed { font-size: 14px; }
+#HTMLReporter .symbolSummary li.passed:before { color: #5e7d00; content: "\02022"; }
+#HTMLReporter .symbolSummary li.failed { line-height: 9px; }
+#HTMLReporter .symbolSummary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; }
+#HTMLReporter .symbolSummary li.skipped { font-size: 14px; }
+#HTMLReporter .symbolSummary li.skipped:before { color: #bababa; content: "\02022"; }
+#HTMLReporter .symbolSummary li.pending { line-height: 11px; }
+#HTMLReporter .symbolSummary li.pending:before { color: #aaaaaa; content: "-"; }
+#HTMLReporter .exceptions { color: #fff; float: right; margin-top: 5px; margin-right: 5px; }
+#HTMLReporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; }
+#HTMLReporter .runningAlert { background-color: #666666; }
+#HTMLReporter .skippedAlert { background-color: #aaaaaa; }
+#HTMLReporter .skippedAlert:first-child { background-color: #333333; }
+#HTMLReporter .skippedAlert:hover { text-decoration: none; color: white; text-decoration: underline; }
+#HTMLReporter .passingAlert { background-color: #a6b779; }
+#HTMLReporter .passingAlert:first-child { background-color: #5e7d00; }
+#HTMLReporter .failingAlert { background-color: #cf867e; }
+#HTMLReporter .failingAlert:first-child { background-color: #b03911; }
+#HTMLReporter .results { margin-top: 14px; }
+#HTMLReporter #details { display: none; }
+#HTMLReporter .resultsMenu, #HTMLReporter .resultsMenu a { background-color: #fff; color: #333333; }
+#HTMLReporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; }
+#HTMLReporter.showDetails .summaryMenuItem:hover { text-decoration: underline; }
+#HTMLReporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; }
+#HTMLReporter.showDetails .summary { display: none; }
+#HTMLReporter.showDetails #details { display: block; }
+#HTMLReporter .summaryMenuItem { font-weight: bold; text-decoration: underline; }
+#HTMLReporter .summary { margin-top: 14px; }
+#HTMLReporter .summary .suite .suite, #HTMLReporter .summary .specSummary { margin-left: 14px; }
+#HTMLReporter .summary .specSummary.passed a { color: #5e7d00; }
+#HTMLReporter .summary .specSummary.failed a { color: #b03911; }
+#HTMLReporter .description + .suite { margin-top: 0; }
+#HTMLReporter .suite { margin-top: 14px; }
+#HTMLReporter .suite a { color: #333333; }
+#HTMLReporter #details .specDetail { margin-bottom: 28px; }
+#HTMLReporter #details .specDetail .description { display: block; color: white; background-color: #b03911; }
+#HTMLReporter .resultMessage { padding-top: 14px; color: #333333; }
+#HTMLReporter .resultMessage span.result { display: block; }
+#HTMLReporter .stackTrace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; }
+
+#TrivialReporter { padding: 8px 13px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; overflow-y: scroll; background-color: white; font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; /*.resultMessage {*/ /*white-space: pre;*/ /*}*/ }
+#TrivialReporter a:visited, #TrivialReporter a { color: #303; }
+#TrivialReporter a:hover, #TrivialReporter a:active { color: blue; }
+#TrivialReporter .run_spec { float: right; padding-right: 5px; font-size: .8em; text-decoration: none; }
+#TrivialReporter .banner { color: #303; background-color: #fef; padding: 5px; }
+#TrivialReporter .logo { float: left; font-size: 1.1em; padding-left: 5px; }
+#TrivialReporter .logo .version { font-size: .6em; padding-left: 1em; }
+#TrivialReporter .runner.running { background-color: yellow; }
+#TrivialReporter .options { text-align: right; font-size: .8em; }
+#TrivialReporter .suite { border: 1px outset gray; margin: 5px 0; padding-left: 1em; }
+#TrivialReporter .suite .suite { margin: 5px; }
+#TrivialReporter .suite.passed { background-color: #dfd; }
+#TrivialReporter .suite.failed { background-color: #fdd; }
+#TrivialReporter .spec { margin: 5px; padding-left: 1em; clear: both; }
+#TrivialReporter .spec.failed, #TrivialReporter .spec.passed, #TrivialReporter .spec.skipped { padding-bottom: 5px; border: 1px solid gray; }
+#TrivialReporter .spec.failed { background-color: #fbb; border-color: red; }
+#TrivialReporter .spec.passed { background-color: #bfb; border-color: green; }
+#TrivialReporter .spec.skipped { background-color: #bbb; }
+#TrivialReporter .messages { border-left: 1px dashed gray; padding-left: 1em; padding-right: 1em; }
+#TrivialReporter .passed { background-color: #cfc; display: none; }
+#TrivialReporter .failed { background-color: #fbb; }
+#TrivialReporter .skipped { color: #777; background-color: #eee; display: none; }
+#TrivialReporter .resultMessage span.result { display: block; line-height: 2em; color: black; }
+#TrivialReporter .resultMessage .mismatch { color: black; }
+#TrivialReporter .stackTrace { white-space: pre; font-size: .8em; margin-left: 10px; max-height: 5em; overflow: auto; border: 1px inset red; padding: 1em; background: #eef; }
+#TrivialReporter .finished-at { padding-left: 1em; font-size: .6em; }
+#TrivialReporter.show-passed .passed, #TrivialReporter.show-skipped .skipped { display: block; }
+#TrivialReporter #jasmine_content { position: fixed; right: 100%; }
+#TrivialReporter .runner { border: 1px solid gray; display: block; margin: 5px 0; padding: 2px 0 2px 10px; }
diff --git a/js/test/lib/jasmine-1.3.1/jasmine.js b/js/test/lib/jasmine-1.3.1/jasmine.js
new file mode 100644
index 00000000..eaf7d426
--- /dev/null
+++ b/js/test/lib/jasmine-1.3.1/jasmine.js
@@ -0,0 +1,2600 @@
+var isCommonJS = typeof window == "undefined" && typeof exports == "object";
+
+/**
+ * Top level namespace for Jasmine, a lightweight JavaScript BDD/spec/testing framework.
+ *
+ * @namespace
+ */
+var jasmine = {};
+if (isCommonJS) exports.jasmine = jasmine;
+/**
+ * @private
+ */
+jasmine.unimplementedMethod_ = function() {
+ throw new Error("unimplemented method");
+};
+
+/**
+ * Use
jasmine.undefined instead of
undefined, since
undefined is just
+ * a plain old variable and may be redefined by somebody else.
+ *
+ * @private
+ */
+jasmine.undefined = jasmine.___undefined___;
+
+/**
+ * Show diagnostic messages in the console if set to true
+ *
+ */
+jasmine.VERBOSE = false;
+
+/**
+ * Default interval in milliseconds for event loop yields (e.g. to allow network activity or to refresh the screen with the HTML-based runner). Small values here may result in slow test running. Zero means no updates until all tests have completed.
+ *
+ */
+jasmine.DEFAULT_UPDATE_INTERVAL = 250;
+
+/**
+ * Maximum levels of nesting that will be included when an object is pretty-printed
+ */
+jasmine.MAX_PRETTY_PRINT_DEPTH = 40;
+
+/**
+ * Default timeout interval in milliseconds for waitsFor() blocks.
+ */
+jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000;
+
+/**
+ * By default exceptions thrown in the context of a test are caught by jasmine so that it can run the remaining tests in the suite.
+ * Set to false to let the exception bubble up in the browser.
+ *
+ */
+jasmine.CATCH_EXCEPTIONS = true;
+
+jasmine.getGlobal = function() {
+ function getGlobal() {
+ return this;
+ }
+
+ return getGlobal();
+};
+
+/**
+ * Allows for bound functions to be compared. Internal use only.
+ *
+ * @ignore
+ * @private
+ * @param base {Object} bound 'this' for the function
+ * @param name {Function} function to find
+ */
+jasmine.bindOriginal_ = function(base, name) {
+ var original = base[name];
+ if (original.apply) {
+ return function() {
+ return original.apply(base, arguments);
+ };
+ } else {
+ // IE support
+ return jasmine.getGlobal()[name];
+ }
+};
+
+jasmine.setTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'setTimeout');
+jasmine.clearTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearTimeout');
+jasmine.setInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'setInterval');
+jasmine.clearInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearInterval');
+
+jasmine.MessageResult = function(values) {
+ this.type = 'log';
+ this.values = values;
+ this.trace = new Error(); // todo: test better
+};
+
+jasmine.MessageResult.prototype.toString = function() {
+ var text = "";
+ for (var i = 0; i < this.values.length; i++) {
+ if (i > 0) text += " ";
+ if (jasmine.isString_(this.values[i])) {
+ text += this.values[i];
+ } else {
+ text += jasmine.pp(this.values[i]);
+ }
+ }
+ return text;
+};
+
+jasmine.ExpectationResult = function(params) {
+ this.type = 'expect';
+ this.matcherName = params.matcherName;
+ this.passed_ = params.passed;
+ this.expected = params.expected;
+ this.actual = params.actual;
+ this.message = this.passed_ ? 'Passed.' : params.message;
+
+ var trace = (params.trace || new Error(this.message));
+ this.trace = this.passed_ ? '' : trace;
+};
+
+jasmine.ExpectationResult.prototype.toString = function () {
+ return this.message;
+};
+
+jasmine.ExpectationResult.prototype.passed = function () {
+ return this.passed_;
+};
+
+/**
+ * Getter for the Jasmine environment. Ensures one gets created
+ */
+jasmine.getEnv = function() {
+ var env = jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env();
+ return env;
+};
+
+/**
+ * @ignore
+ * @private
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isArray_ = function(value) {
+ return jasmine.isA_("Array", value);
+};
+
+/**
+ * @ignore
+ * @private
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isString_ = function(value) {
+ return jasmine.isA_("String", value);
+};
+
+/**
+ * @ignore
+ * @private
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isNumber_ = function(value) {
+ return jasmine.isA_("Number", value);
+};
+
+/**
+ * @ignore
+ * @private
+ * @param {String} typeName
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isA_ = function(typeName, value) {
+ return Object.prototype.toString.apply(value) === '[object ' + typeName + ']';
+};
+
+/**
+ * Pretty printer for expecations. Takes any object and turns it into a human-readable string.
+ *
+ * @param value {Object} an object to be outputted
+ * @returns {String}
+ */
+jasmine.pp = function(value) {
+ var stringPrettyPrinter = new jasmine.StringPrettyPrinter();
+ stringPrettyPrinter.format(value);
+ return stringPrettyPrinter.string;
+};
+
+/**
+ * Returns true if the object is a DOM Node.
+ *
+ * @param {Object} obj object to check
+ * @returns {Boolean}
+ */
+jasmine.isDomNode = function(obj) {
+ return obj.nodeType > 0;
+};
+
+/**
+ * Returns a matchable 'generic' object of the class type. For use in expecations of type when values don't matter.
+ *
+ * @example
+ * // don't care about which function is passed in, as long as it's a function
+ * expect(mySpy).toHaveBeenCalledWith(jasmine.any(Function));
+ *
+ * @param {Class} clazz
+ * @returns matchable object of the type clazz
+ */
+jasmine.any = function(clazz) {
+ return new jasmine.Matchers.Any(clazz);
+};
+
+/**
+ * Returns a matchable subset of a JSON object. For use in expectations when you don't care about all of the
+ * attributes on the object.
+ *
+ * @example
+ * // don't care about any other attributes than foo.
+ * expect(mySpy).toHaveBeenCalledWith(jasmine.objectContaining({foo: "bar"});
+ *
+ * @param sample {Object} sample
+ * @returns matchable object for the sample
+ */
+jasmine.objectContaining = function (sample) {
+ return new jasmine.Matchers.ObjectContaining(sample);
+};
+
+/**
+ * Jasmine Spies are test doubles that can act as stubs, spies, fakes or when used in an expecation, mocks.
+ *
+ * Spies should be created in test setup, before expectations. They can then be checked, using the standard Jasmine
+ * expectation syntax. Spies can be checked if they were called or not and what the calling params were.
+ *
+ * A Spy has the following fields: wasCalled, callCount, mostRecentCall, and argsForCall (see docs).
+ *
+ * Spies are torn down at the end of every spec.
+ *
+ * Note: Do
not call new jasmine.Spy() directly - a spy must be created using spyOn, jasmine.createSpy or jasmine.createSpyObj.
+ *
+ * @example
+ * // a stub
+ * var myStub = jasmine.createSpy('myStub'); // can be used anywhere
+ *
+ * // spy example
+ * var foo = {
+ * not: function(bool) { return !bool; }
+ * }
+ *
+ * // actual foo.not will not be called, execution stops
+ * spyOn(foo, 'not');
+
+ // foo.not spied upon, execution will continue to implementation
+ * spyOn(foo, 'not').andCallThrough();
+ *
+ * // fake example
+ * var foo = {
+ * not: function(bool) { return !bool; }
+ * }
+ *
+ * // foo.not(val) will return val
+ * spyOn(foo, 'not').andCallFake(function(value) {return value;});
+ *
+ * // mock example
+ * foo.not(7 == 7);
+ * expect(foo.not).toHaveBeenCalled();
+ * expect(foo.not).toHaveBeenCalledWith(true);
+ *
+ * @constructor
+ * @see spyOn, jasmine.createSpy, jasmine.createSpyObj
+ * @param {String} name
+ */
+jasmine.Spy = function(name) {
+ /**
+ * The name of the spy, if provided.
+ */
+ this.identity = name || 'unknown';
+ /**
+ * Is this Object a spy?
+ */
+ this.isSpy = true;
+ /**
+ * The actual function this spy stubs.
+ */
+ this.plan = function() {
+ };
+ /**
+ * Tracking of the most recent call to the spy.
+ * @example
+ * var mySpy = jasmine.createSpy('foo');
+ * mySpy(1, 2);
+ * mySpy.mostRecentCall.args = [1, 2];
+ */
+ this.mostRecentCall = {};
+
+ /**
+ * Holds arguments for each call to the spy, indexed by call count
+ * @example
+ * var mySpy = jasmine.createSpy('foo');
+ * mySpy(1, 2);
+ * mySpy(7, 8);
+ * mySpy.mostRecentCall.args = [7, 8];
+ * mySpy.argsForCall[0] = [1, 2];
+ * mySpy.argsForCall[1] = [7, 8];
+ */
+ this.argsForCall = [];
+ this.calls = [];
+};
+
+/**
+ * Tells a spy to call through to the actual implemenatation.
+ *
+ * @example
+ * var foo = {
+ * bar: function() { // do some stuff }
+ * }
+ *
+ * // defining a spy on an existing property: foo.bar
+ * spyOn(foo, 'bar').andCallThrough();
+ */
+jasmine.Spy.prototype.andCallThrough = function() {
+ this.plan = this.originalValue;
+ return this;
+};
+
+/**
+ * For setting the return value of a spy.
+ *
+ * @example
+ * // defining a spy from scratch: foo() returns 'baz'
+ * var foo = jasmine.createSpy('spy on foo').andReturn('baz');
+ *
+ * // defining a spy on an existing property: foo.bar() returns 'baz'
+ * spyOn(foo, 'bar').andReturn('baz');
+ *
+ * @param {Object} value
+ */
+jasmine.Spy.prototype.andReturn = function(value) {
+ this.plan = function() {
+ return value;
+ };
+ return this;
+};
+
+/**
+ * For throwing an exception when a spy is called.
+ *
+ * @example
+ * // defining a spy from scratch: foo() throws an exception w/ message 'ouch'
+ * var foo = jasmine.createSpy('spy on foo').andThrow('baz');
+ *
+ * // defining a spy on an existing property: foo.bar() throws an exception w/ message 'ouch'
+ * spyOn(foo, 'bar').andThrow('baz');
+ *
+ * @param {String} exceptionMsg
+ */
+jasmine.Spy.prototype.andThrow = function(exceptionMsg) {
+ this.plan = function() {
+ throw exceptionMsg;
+ };
+ return this;
+};
+
+/**
+ * Calls an alternate implementation when a spy is called.
+ *
+ * @example
+ * var baz = function() {
+ * // do some stuff, return something
+ * }
+ * // defining a spy from scratch: foo() calls the function baz
+ * var foo = jasmine.createSpy('spy on foo').andCall(baz);
+ *
+ * // defining a spy on an existing property: foo.bar() calls an anonymnous function
+ * spyOn(foo, 'bar').andCall(function() { return 'baz';} );
+ *
+ * @param {Function} fakeFunc
+ */
+jasmine.Spy.prototype.andCallFake = function(fakeFunc) {
+ this.plan = fakeFunc;
+ return this;
+};
+
+/**
+ * Resets all of a spy's the tracking variables so that it can be used again.
+ *
+ * @example
+ * spyOn(foo, 'bar');
+ *
+ * foo.bar();
+ *
+ * expect(foo.bar.callCount).toEqual(1);
+ *
+ * foo.bar.reset();
+ *
+ * expect(foo.bar.callCount).toEqual(0);
+ */
+jasmine.Spy.prototype.reset = function() {
+ this.wasCalled = false;
+ this.callCount = 0;
+ this.argsForCall = [];
+ this.calls = [];
+ this.mostRecentCall = {};
+};
+
+jasmine.createSpy = function(name) {
+
+ var spyObj = function() {
+ spyObj.wasCalled = true;
+ spyObj.callCount++;
+ var args = jasmine.util.argsToArray(arguments);
+ spyObj.mostRecentCall.object = this;
+ spyObj.mostRecentCall.args = args;
+ spyObj.argsForCall.push(args);
+ spyObj.calls.push({object: this, args: args});
+ return spyObj.plan.apply(this, arguments);
+ };
+
+ var spy = new jasmine.Spy(name);
+
+ for (var prop in spy) {
+ spyObj[prop] = spy[prop];
+ }
+
+ spyObj.reset();
+
+ return spyObj;
+};
+
+/**
+ * Determines whether an object is a spy.
+ *
+ * @param {jasmine.Spy|Object} putativeSpy
+ * @returns {Boolean}
+ */
+jasmine.isSpy = function(putativeSpy) {
+ return putativeSpy && putativeSpy.isSpy;
+};
+
+/**
+ * Creates a more complicated spy: an Object that has every property a function that is a spy. Used for stubbing something
+ * large in one call.
+ *
+ * @param {String} baseName name of spy class
+ * @param {Array} methodNames array of names of methods to make spies
+ */
+jasmine.createSpyObj = function(baseName, methodNames) {
+ if (!jasmine.isArray_(methodNames) || methodNames.length === 0) {
+ throw new Error('createSpyObj requires a non-empty array of method names to create spies for');
+ }
+ var obj = {};
+ for (var i = 0; i < methodNames.length; i++) {
+ obj[methodNames[i]] = jasmine.createSpy(baseName + '.' + methodNames[i]);
+ }
+ return obj;
+};
+
+/**
+ * All parameters are pretty-printed and concatenated together, then written to the current spec's output.
+ *
+ * Be careful not to leave calls to
jasmine.log in production code.
+ */
+jasmine.log = function() {
+ var spec = jasmine.getEnv().currentSpec;
+ spec.log.apply(spec, arguments);
+};
+
+/**
+ * Function that installs a spy on an existing object's method name. Used within a Spec to create a spy.
+ *
+ * @example
+ * // spy example
+ * var foo = {
+ * not: function(bool) { return !bool; }
+ * }
+ * spyOn(foo, 'not'); // actual foo.not will not be called, execution stops
+ *
+ * @see jasmine.createSpy
+ * @param obj
+ * @param methodName
+ * @return {jasmine.Spy} a Jasmine spy that can be chained with all spy methods
+ */
+var spyOn = function(obj, methodName) {
+ return jasmine.getEnv().currentSpec.spyOn(obj, methodName);
+};
+if (isCommonJS) exports.spyOn = spyOn;
+
+/**
+ * Creates a Jasmine spec that will be added to the current suite.
+ *
+ * // TODO: pending tests
+ *
+ * @example
+ * it('should be true', function() {
+ * expect(true).toEqual(true);
+ * });
+ *
+ * @param {String} desc description of this specification
+ * @param {Function} func defines the preconditions and expectations of the spec
+ */
+var it = function(desc, func) {
+ return jasmine.getEnv().it(desc, func);
+};
+if (isCommonJS) exports.it = it;
+
+/**
+ * Creates a
disabled Jasmine spec.
+ *
+ * A convenience method that allows existing specs to be disabled temporarily during development.
+ *
+ * @param {String} desc description of this specification
+ * @param {Function} func defines the preconditions and expectations of the spec
+ */
+var xit = function(desc, func) {
+ return jasmine.getEnv().xit(desc, func);
+};
+if (isCommonJS) exports.xit = xit;
+
+/**
+ * Starts a chain for a Jasmine expectation.
+ *
+ * It is passed an Object that is the actual value and should chain to one of the many
+ * jasmine.Matchers functions.
+ *
+ * @param {Object} actual Actual value to test against and expected value
+ * @return {jasmine.Matchers}
+ */
+var expect = function(actual) {
+ return jasmine.getEnv().currentSpec.expect(actual);
+};
+if (isCommonJS) exports.expect = expect;
+
+/**
+ * Defines part of a jasmine spec. Used in cominbination with waits or waitsFor in asynchrnous specs.
+ *
+ * @param {Function} func Function that defines part of a jasmine spec.
+ */
+var runs = function(func) {
+ jasmine.getEnv().currentSpec.runs(func);
+};
+if (isCommonJS) exports.runs = runs;
+
+/**
+ * Waits a fixed time period before moving to the next block.
+ *
+ * @deprecated Use waitsFor() instead
+ * @param {Number} timeout milliseconds to wait
+ */
+var waits = function(timeout) {
+ jasmine.getEnv().currentSpec.waits(timeout);
+};
+if (isCommonJS) exports.waits = waits;
+
+/**
+ * Waits for the latchFunction to return true before proceeding to the next block.
+ *
+ * @param {Function} latchFunction
+ * @param {String} optional_timeoutMessage
+ * @param {Number} optional_timeout
+ */
+var waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
+ jasmine.getEnv().currentSpec.waitsFor.apply(jasmine.getEnv().currentSpec, arguments);
+};
+if (isCommonJS) exports.waitsFor = waitsFor;
+
+/**
+ * A function that is called before each spec in a suite.
+ *
+ * Used for spec setup, including validating assumptions.
+ *
+ * @param {Function} beforeEachFunction
+ */
+var beforeEach = function(beforeEachFunction) {
+ jasmine.getEnv().beforeEach(beforeEachFunction);
+};
+if (isCommonJS) exports.beforeEach = beforeEach;
+
+/**
+ * A function that is called after each spec in a suite.
+ *
+ * Used for restoring any state that is hijacked during spec execution.
+ *
+ * @param {Function} afterEachFunction
+ */
+var afterEach = function(afterEachFunction) {
+ jasmine.getEnv().afterEach(afterEachFunction);
+};
+if (isCommonJS) exports.afterEach = afterEach;
+
+/**
+ * Defines a suite of specifications.
+ *
+ * Stores the description and all defined specs in the Jasmine environment as one suite of specs. Variables declared
+ * are accessible by calls to beforeEach, it, and afterEach. Describe blocks can be nested, allowing for specialization
+ * of setup in some tests.
+ *
+ * @example
+ * // TODO: a simple suite
+ *
+ * // TODO: a simple suite with a nested describe block
+ *
+ * @param {String} description A string, usually the class under test.
+ * @param {Function} specDefinitions function that defines several specs.
+ */
+var describe = function(description, specDefinitions) {
+ return jasmine.getEnv().describe(description, specDefinitions);
+};
+if (isCommonJS) exports.describe = describe;
+
+/**
+ * Disables a suite of specifications. Used to disable some suites in a file, or files, temporarily during development.
+ *
+ * @param {String} description A string, usually the class under test.
+ * @param {Function} specDefinitions function that defines several specs.
+ */
+var xdescribe = function(description, specDefinitions) {
+ return jasmine.getEnv().xdescribe(description, specDefinitions);
+};
+if (isCommonJS) exports.xdescribe = xdescribe;
+
+
+// Provide the XMLHttpRequest class for IE 5.x-6.x:
+jasmine.XmlHttpRequest = (typeof XMLHttpRequest == "undefined") ? function() {
+ function tryIt(f) {
+ try {
+ return f();
+ } catch(e) {
+ }
+ return null;
+ }
+
+ var xhr = tryIt(function() {
+ return new ActiveXObject("Msxml2.XMLHTTP.6.0");
+ }) ||
+ tryIt(function() {
+ return new ActiveXObject("Msxml2.XMLHTTP.3.0");
+ }) ||
+ tryIt(function() {
+ return new ActiveXObject("Msxml2.XMLHTTP");
+ }) ||
+ tryIt(function() {
+ return new ActiveXObject("Microsoft.XMLHTTP");
+ });
+
+ if (!xhr) throw new Error("This browser does not support XMLHttpRequest.");
+
+ return xhr;
+} : XMLHttpRequest;
+/**
+ * @namespace
+ */
+jasmine.util = {};
+
+/**
+ * Declare that a child class inherit it's prototype from the parent class.
+ *
+ * @private
+ * @param {Function} childClass
+ * @param {Function} parentClass
+ */
+jasmine.util.inherit = function(childClass, parentClass) {
+ /**
+ * @private
+ */
+ var subclass = function() {
+ };
+ subclass.prototype = parentClass.prototype;
+ childClass.prototype = new subclass();
+};
+
+jasmine.util.formatException = function(e) {
+ var lineNumber;
+ if (e.line) {
+ lineNumber = e.line;
+ }
+ else if (e.lineNumber) {
+ lineNumber = e.lineNumber;
+ }
+
+ var file;
+
+ if (e.sourceURL) {
+ file = e.sourceURL;
+ }
+ else if (e.fileName) {
+ file = e.fileName;
+ }
+
+ var message = (e.name && e.message) ? (e.name + ': ' + e.message) : e.toString();
+
+ if (file && lineNumber) {
+ message += ' in ' + file + ' (line ' + lineNumber + ')';
+ }
+
+ return message;
+};
+
+jasmine.util.htmlEscape = function(str) {
+ if (!str) return str;
+ return str.replace(/&/g, '&')
+ .replace(//g, '>');
+};
+
+jasmine.util.argsToArray = function(args) {
+ var arrayOfArgs = [];
+ for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]);
+ return arrayOfArgs;
+};
+
+jasmine.util.extend = function(destination, source) {
+ for (var property in source) destination[property] = source[property];
+ return destination;
+};
+
+/**
+ * Environment for Jasmine
+ *
+ * @constructor
+ */
+jasmine.Env = function() {
+ this.currentSpec = null;
+ this.currentSuite = null;
+ this.currentRunner_ = new jasmine.Runner(this);
+
+ this.reporter = new jasmine.MultiReporter();
+
+ this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL;
+ this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL;
+ this.lastUpdate = 0;
+ this.specFilter = function() {
+ return true;
+ };
+
+ this.nextSpecId_ = 0;
+ this.nextSuiteId_ = 0;
+ this.equalityTesters_ = [];
+
+ // wrap matchers
+ this.matchersClass = function() {
+ jasmine.Matchers.apply(this, arguments);
+ };
+ jasmine.util.inherit(this.matchersClass, jasmine.Matchers);
+
+ jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass);
+};
+
+
+jasmine.Env.prototype.setTimeout = jasmine.setTimeout;
+jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout;
+jasmine.Env.prototype.setInterval = jasmine.setInterval;
+jasmine.Env.prototype.clearInterval = jasmine.clearInterval;
+
+/**
+ * @returns an object containing jasmine version build info, if set.
+ */
+jasmine.Env.prototype.version = function () {
+ if (jasmine.version_) {
+ return jasmine.version_;
+ } else {
+ throw new Error('Version not set');
+ }
+};
+
+/**
+ * @returns string containing jasmine version build info, if set.
+ */
+jasmine.Env.prototype.versionString = function() {
+ if (!jasmine.version_) {
+ return "version unknown";
+ }
+
+ var version = this.version();
+ var versionString = version.major + "." + version.minor + "." + version.build;
+ if (version.release_candidate) {
+ versionString += ".rc" + version.release_candidate;
+ }
+ versionString += " revision " + version.revision;
+ return versionString;
+};
+
+/**
+ * @returns a sequential integer starting at 0
+ */
+jasmine.Env.prototype.nextSpecId = function () {
+ return this.nextSpecId_++;
+};
+
+/**
+ * @returns a sequential integer starting at 0
+ */
+jasmine.Env.prototype.nextSuiteId = function () {
+ return this.nextSuiteId_++;
+};
+
+/**
+ * Register a reporter to receive status updates from Jasmine.
+ * @param {jasmine.Reporter} reporter An object which will receive status updates.
+ */
+jasmine.Env.prototype.addReporter = function(reporter) {
+ this.reporter.addReporter(reporter);
+};
+
+jasmine.Env.prototype.execute = function() {
+ this.currentRunner_.execute();
+};
+
+jasmine.Env.prototype.describe = function(description, specDefinitions) {
+ var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite);
+
+ var parentSuite = this.currentSuite;
+ if (parentSuite) {
+ parentSuite.add(suite);
+ } else {
+ this.currentRunner_.add(suite);
+ }
+
+ this.currentSuite = suite;
+
+ var declarationError = null;
+ try {
+ specDefinitions.call(suite);
+ } catch(e) {
+ declarationError = e;
+ }
+
+ if (declarationError) {
+ this.it("encountered a declaration exception", function() {
+ throw declarationError;
+ });
+ }
+
+ this.currentSuite = parentSuite;
+
+ return suite;
+};
+
+jasmine.Env.prototype.beforeEach = function(beforeEachFunction) {
+ if (this.currentSuite) {
+ this.currentSuite.beforeEach(beforeEachFunction);
+ } else {
+ this.currentRunner_.beforeEach(beforeEachFunction);
+ }
+};
+
+jasmine.Env.prototype.currentRunner = function () {
+ return this.currentRunner_;
+};
+
+jasmine.Env.prototype.afterEach = function(afterEachFunction) {
+ if (this.currentSuite) {
+ this.currentSuite.afterEach(afterEachFunction);
+ } else {
+ this.currentRunner_.afterEach(afterEachFunction);
+ }
+
+};
+
+jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) {
+ return {
+ execute: function() {
+ }
+ };
+};
+
+jasmine.Env.prototype.it = function(description, func) {
+ var spec = new jasmine.Spec(this, this.currentSuite, description);
+ this.currentSuite.add(spec);
+ this.currentSpec = spec;
+
+ if (func) {
+ spec.runs(func);
+ }
+
+ return spec;
+};
+
+jasmine.Env.prototype.xit = function(desc, func) {
+ return {
+ id: this.nextSpecId(),
+ runs: function() {
+ }
+ };
+};
+
+jasmine.Env.prototype.compareRegExps_ = function(a, b, mismatchKeys, mismatchValues) {
+ if (a.source != b.source)
+ mismatchValues.push("expected pattern /" + b.source + "/ is not equal to the pattern /" + a.source + "/");
+
+ if (a.ignoreCase != b.ignoreCase)
+ mismatchValues.push("expected modifier i was" + (b.ignoreCase ? " " : " not ") + "set and does not equal the origin modifier");
+
+ if (a.global != b.global)
+ mismatchValues.push("expected modifier g was" + (b.global ? " " : " not ") + "set and does not equal the origin modifier");
+
+ if (a.multiline != b.multiline)
+ mismatchValues.push("expected modifier m was" + (b.multiline ? " " : " not ") + "set and does not equal the origin modifier");
+
+ if (a.sticky != b.sticky)
+ mismatchValues.push("expected modifier y was" + (b.sticky ? " " : " not ") + "set and does not equal the origin modifier");
+
+ return (mismatchValues.length === 0);
+};
+
+jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) {
+ if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) {
+ return true;
+ }
+
+ a.__Jasmine_been_here_before__ = b;
+ b.__Jasmine_been_here_before__ = a;
+
+ var hasKey = function(obj, keyName) {
+ return obj !== null && obj[keyName] !== jasmine.undefined;
+ };
+
+ for (var property in b) {
+ if (!hasKey(a, property) && hasKey(b, property)) {
+ mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
+ }
+ }
+ for (property in a) {
+ if (!hasKey(b, property) && hasKey(a, property)) {
+ mismatchKeys.push("expected missing key '" + property + "', but present in actual.");
+ }
+ }
+ for (property in b) {
+ if (property == '__Jasmine_been_here_before__') continue;
+ if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) {
+ mismatchValues.push("'" + property + "' was '" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual.");
+ }
+ }
+
+ if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) {
+ mismatchValues.push("arrays were not the same length");
+ }
+
+ delete a.__Jasmine_been_here_before__;
+ delete b.__Jasmine_been_here_before__;
+ return (mismatchKeys.length === 0 && mismatchValues.length === 0);
+};
+
+jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) {
+ mismatchKeys = mismatchKeys || [];
+ mismatchValues = mismatchValues || [];
+
+ for (var i = 0; i < this.equalityTesters_.length; i++) {
+ var equalityTester = this.equalityTesters_[i];
+ var result = equalityTester(a, b, this, mismatchKeys, mismatchValues);
+ if (result !== jasmine.undefined) return result;
+ }
+
+ if (a === b) return true;
+
+ if (a === jasmine.undefined || a === null || b === jasmine.undefined || b === null) {
+ return (a == jasmine.undefined && b == jasmine.undefined);
+ }
+
+ if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) {
+ return a === b;
+ }
+
+ if (a instanceof Date && b instanceof Date) {
+ return a.getTime() == b.getTime();
+ }
+
+ if (a.jasmineMatches) {
+ return a.jasmineMatches(b);
+ }
+
+ if (b.jasmineMatches) {
+ return b.jasmineMatches(a);
+ }
+
+ if (a instanceof jasmine.Matchers.ObjectContaining) {
+ return a.matches(b);
+ }
+
+ if (b instanceof jasmine.Matchers.ObjectContaining) {
+ return b.matches(a);
+ }
+
+ if (jasmine.isString_(a) && jasmine.isString_(b)) {
+ return (a == b);
+ }
+
+ if (jasmine.isNumber_(a) && jasmine.isNumber_(b)) {
+ return (a == b);
+ }
+
+ if (a instanceof RegExp && b instanceof RegExp) {
+ return this.compareRegExps_(a, b, mismatchKeys, mismatchValues);
+ }
+
+ if (typeof a === "object" && typeof b === "object") {
+ return this.compareObjects_(a, b, mismatchKeys, mismatchValues);
+ }
+
+ //Straight check
+ return (a === b);
+};
+
+jasmine.Env.prototype.contains_ = function(haystack, needle) {
+ if (jasmine.isArray_(haystack)) {
+ for (var i = 0; i < haystack.length; i++) {
+ if (this.equals_(haystack[i], needle)) return true;
+ }
+ return false;
+ }
+ return haystack.indexOf(needle) >= 0;
+};
+
+jasmine.Env.prototype.addEqualityTester = function(equalityTester) {
+ this.equalityTesters_.push(equalityTester);
+};
+/** No-op base class for Jasmine reporters.
+ *
+ * @constructor
+ */
+jasmine.Reporter = function() {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportRunnerStarting = function(runner) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportRunnerResults = function(runner) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportSuiteResults = function(suite) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportSpecStarting = function(spec) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportSpecResults = function(spec) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.log = function(str) {
+};
+
+/**
+ * Blocks are functions with executable code that make up a spec.
+ *
+ * @constructor
+ * @param {jasmine.Env} env
+ * @param {Function} func
+ * @param {jasmine.Spec} spec
+ */
+jasmine.Block = function(env, func, spec) {
+ this.env = env;
+ this.func = func;
+ this.spec = spec;
+};
+
+jasmine.Block.prototype.execute = function(onComplete) {
+ if (!jasmine.CATCH_EXCEPTIONS) {
+ this.func.apply(this.spec);
+ }
+ else {
+ try {
+ this.func.apply(this.spec);
+ } catch (e) {
+ this.spec.fail(e);
+ }
+ }
+ onComplete();
+};
+/** JavaScript API reporter.
+ *
+ * @constructor
+ */
+jasmine.JsApiReporter = function() {
+ this.started = false;
+ this.finished = false;
+ this.suites_ = [];
+ this.results_ = {};
+};
+
+jasmine.JsApiReporter.prototype.reportRunnerStarting = function(runner) {
+ this.started = true;
+ var suites = runner.topLevelSuites();
+ for (var i = 0; i < suites.length; i++) {
+ var suite = suites[i];
+ this.suites_.push(this.summarize_(suite));
+ }
+};
+
+jasmine.JsApiReporter.prototype.suites = function() {
+ return this.suites_;
+};
+
+jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) {
+ var isSuite = suiteOrSpec instanceof jasmine.Suite;
+ var summary = {
+ id: suiteOrSpec.id,
+ name: suiteOrSpec.description,
+ type: isSuite ? 'suite' : 'spec',
+ children: []
+ };
+
+ if (isSuite) {
+ var children = suiteOrSpec.children();
+ for (var i = 0; i < children.length; i++) {
+ summary.children.push(this.summarize_(children[i]));
+ }
+ }
+ return summary;
+};
+
+jasmine.JsApiReporter.prototype.results = function() {
+ return this.results_;
+};
+
+jasmine.JsApiReporter.prototype.resultsForSpec = function(specId) {
+ return this.results_[specId];
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.reportRunnerResults = function(runner) {
+ this.finished = true;
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.reportSuiteResults = function(suite) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.reportSpecResults = function(spec) {
+ this.results_[spec.id] = {
+ messages: spec.results().getItems(),
+ result: spec.results().failedCount > 0 ? "failed" : "passed"
+ };
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.log = function(str) {
+};
+
+jasmine.JsApiReporter.prototype.resultsForSpecs = function(specIds){
+ var results = {};
+ for (var i = 0; i < specIds.length; i++) {
+ var specId = specIds[i];
+ results[specId] = this.summarizeResult_(this.results_[specId]);
+ }
+ return results;
+};
+
+jasmine.JsApiReporter.prototype.summarizeResult_ = function(result){
+ var summaryMessages = [];
+ var messagesLength = result.messages.length;
+ for (var messageIndex = 0; messageIndex < messagesLength; messageIndex++) {
+ var resultMessage = result.messages[messageIndex];
+ summaryMessages.push({
+ text: resultMessage.type == 'log' ? resultMessage.toString() : jasmine.undefined,
+ passed: resultMessage.passed ? resultMessage.passed() : true,
+ type: resultMessage.type,
+ message: resultMessage.message,
+ trace: {
+ stack: resultMessage.passed && !resultMessage.passed() ? resultMessage.trace.stack : jasmine.undefined
+ }
+ });
+ }
+
+ return {
+ result : result.result,
+ messages : summaryMessages
+ };
+};
+
+/**
+ * @constructor
+ * @param {jasmine.Env} env
+ * @param actual
+ * @param {jasmine.Spec} spec
+ */
+jasmine.Matchers = function(env, actual, spec, opt_isNot) {
+ this.env = env;
+ this.actual = actual;
+ this.spec = spec;
+ this.isNot = opt_isNot || false;
+ this.reportWasCalled_ = false;
+};
+
+// todo: @deprecated as of Jasmine 0.11, remove soon [xw]
+jasmine.Matchers.pp = function(str) {
+ throw new Error("jasmine.Matchers.pp() is no longer supported, please use jasmine.pp() instead!");
+};
+
+// todo: @deprecated Deprecated as of Jasmine 0.10. Rewrite your custom matchers to return true or false. [xw]
+jasmine.Matchers.prototype.report = function(result, failing_message, details) {
+ throw new Error("As of jasmine 0.11, custom matchers must be implemented differently -- please see jasmine docs");
+};
+
+jasmine.Matchers.wrapInto_ = function(prototype, matchersClass) {
+ for (var methodName in prototype) {
+ if (methodName == 'report') continue;
+ var orig = prototype[methodName];
+ matchersClass.prototype[methodName] = jasmine.Matchers.matcherFn_(methodName, orig);
+ }
+};
+
+jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) {
+ return function() {
+ var matcherArgs = jasmine.util.argsToArray(arguments);
+ var result = matcherFunction.apply(this, arguments);
+
+ if (this.isNot) {
+ result = !result;
+ }
+
+ if (this.reportWasCalled_) return result;
+
+ var message;
+ if (!result) {
+ if (this.message) {
+ message = this.message.apply(this, arguments);
+ if (jasmine.isArray_(message)) {
+ message = message[this.isNot ? 1 : 0];
+ }
+ } else {
+ var englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
+ message = "Expected " + jasmine.pp(this.actual) + (this.isNot ? " not " : " ") + englishyPredicate;
+ if (matcherArgs.length > 0) {
+ for (var i = 0; i < matcherArgs.length; i++) {
+ if (i > 0) message += ",";
+ message += " " + jasmine.pp(matcherArgs[i]);
+ }
+ }
+ message += ".";
+ }
+ }
+ var expectationResult = new jasmine.ExpectationResult({
+ matcherName: matcherName,
+ passed: result,
+ expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0],
+ actual: this.actual,
+ message: message
+ });
+ this.spec.addMatcherResult(expectationResult);
+ return jasmine.undefined;
+ };
+};
+
+
+
+
+/**
+ * toBe: compares the actual to the expected using ===
+ * @param expected
+ */
+jasmine.Matchers.prototype.toBe = function(expected) {
+ return this.actual === expected;
+};
+
+/**
+ * toNotBe: compares the actual to the expected using !==
+ * @param expected
+ * @deprecated as of 1.0. Use not.toBe() instead.
+ */
+jasmine.Matchers.prototype.toNotBe = function(expected) {
+ return this.actual !== expected;
+};
+
+/**
+ * toEqual: compares the actual to the expected using common sense equality. Handles Objects, Arrays, etc.
+ *
+ * @param expected
+ */
+jasmine.Matchers.prototype.toEqual = function(expected) {
+ return this.env.equals_(this.actual, expected);
+};
+
+/**
+ * toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual
+ * @param expected
+ * @deprecated as of 1.0. Use not.toEqual() instead.
+ */
+jasmine.Matchers.prototype.toNotEqual = function(expected) {
+ return !this.env.equals_(this.actual, expected);
+};
+
+/**
+ * Matcher that compares the actual to the expected using a regular expression. Constructs a RegExp, so takes
+ * a pattern or a String.
+ *
+ * @param expected
+ */
+jasmine.Matchers.prototype.toMatch = function(expected) {
+ return new RegExp(expected).test(this.actual);
+};
+
+/**
+ * Matcher that compares the actual to the expected using the boolean inverse of jasmine.Matchers.toMatch
+ * @param expected
+ * @deprecated as of 1.0. Use not.toMatch() instead.
+ */
+jasmine.Matchers.prototype.toNotMatch = function(expected) {
+ return !(new RegExp(expected).test(this.actual));
+};
+
+/**
+ * Matcher that compares the actual to jasmine.undefined.
+ */
+jasmine.Matchers.prototype.toBeDefined = function() {
+ return (this.actual !== jasmine.undefined);
+};
+
+/**
+ * Matcher that compares the actual to jasmine.undefined.
+ */
+jasmine.Matchers.prototype.toBeUndefined = function() {
+ return (this.actual === jasmine.undefined);
+};
+
+/**
+ * Matcher that compares the actual to null.
+ */
+jasmine.Matchers.prototype.toBeNull = function() {
+ return (this.actual === null);
+};
+
+/**
+ * Matcher that compares the actual to NaN.
+ */
+jasmine.Matchers.prototype.toBeNaN = function() {
+ this.message = function() {
+ return [ "Expected " + jasmine.pp(this.actual) + " to be NaN." ];
+ };
+
+ return (this.actual !== this.actual);
+};
+
+/**
+ * Matcher that boolean not-nots the actual.
+ */
+jasmine.Matchers.prototype.toBeTruthy = function() {
+ return !!this.actual;
+};
+
+
+/**
+ * Matcher that boolean nots the actual.
+ */
+jasmine.Matchers.prototype.toBeFalsy = function() {
+ return !this.actual;
+};
+
+
+/**
+ * Matcher that checks to see if the actual, a Jasmine spy, was called.
+ */
+jasmine.Matchers.prototype.toHaveBeenCalled = function() {
+ if (arguments.length > 0) {
+ throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith');
+ }
+
+ if (!jasmine.isSpy(this.actual)) {
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+ }
+
+ this.message = function() {
+ return [
+ "Expected spy " + this.actual.identity + " to have been called.",
+ "Expected spy " + this.actual.identity + " not to have been called."
+ ];
+ };
+
+ return this.actual.wasCalled;
+};
+
+/** @deprecated Use expect(xxx).toHaveBeenCalled() instead */
+jasmine.Matchers.prototype.wasCalled = jasmine.Matchers.prototype.toHaveBeenCalled;
+
+/**
+ * Matcher that checks to see if the actual, a Jasmine spy, was not called.
+ *
+ * @deprecated Use expect(xxx).not.toHaveBeenCalled() instead
+ */
+jasmine.Matchers.prototype.wasNotCalled = function() {
+ if (arguments.length > 0) {
+ throw new Error('wasNotCalled does not take arguments');
+ }
+
+ if (!jasmine.isSpy(this.actual)) {
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+ }
+
+ this.message = function() {
+ return [
+ "Expected spy " + this.actual.identity + " to not have been called.",
+ "Expected spy " + this.actual.identity + " to have been called."
+ ];
+ };
+
+ return !this.actual.wasCalled;
+};
+
+/**
+ * Matcher that checks to see if the actual, a Jasmine spy, was called with a set of parameters.
+ *
+ * @example
+ *
+ */
+jasmine.Matchers.prototype.toHaveBeenCalledWith = function() {
+ var expectedArgs = jasmine.util.argsToArray(arguments);
+ if (!jasmine.isSpy(this.actual)) {
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+ }
+ this.message = function() {
+ var invertedMessage = "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but it was.";
+ var positiveMessage = "";
+ if (this.actual.callCount === 0) {
+ positiveMessage = "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but it was never called.";
+ } else {
+ positiveMessage = "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but actual calls were " + jasmine.pp(this.actual.argsForCall).replace(/^\[ | \]$/g, '')
+ }
+ return [positiveMessage, invertedMessage];
+ };
+
+ return this.env.contains_(this.actual.argsForCall, expectedArgs);
+};
+
+/** @deprecated Use expect(xxx).toHaveBeenCalledWith() instead */
+jasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.prototype.toHaveBeenCalledWith;
+
+/** @deprecated Use expect(xxx).not.toHaveBeenCalledWith() instead */
+jasmine.Matchers.prototype.wasNotCalledWith = function() {
+ var expectedArgs = jasmine.util.argsToArray(arguments);
+ if (!jasmine.isSpy(this.actual)) {
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+ }
+
+ this.message = function() {
+ return [
+ "Expected spy not to have been called with " + jasmine.pp(expectedArgs) + " but it was",
+ "Expected spy to have been called with " + jasmine.pp(expectedArgs) + " but it was"
+ ];
+ };
+
+ return !this.env.contains_(this.actual.argsForCall, expectedArgs);
+};
+
+/**
+ * Matcher that checks that the expected item is an element in the actual Array.
+ *
+ * @param {Object} expected
+ */
+jasmine.Matchers.prototype.toContain = function(expected) {
+ return this.env.contains_(this.actual, expected);
+};
+
+/**
+ * Matcher that checks that the expected item is NOT an element in the actual Array.
+ *
+ * @param {Object} expected
+ * @deprecated as of 1.0. Use not.toContain() instead.
+ */
+jasmine.Matchers.prototype.toNotContain = function(expected) {
+ return !this.env.contains_(this.actual, expected);
+};
+
+jasmine.Matchers.prototype.toBeLessThan = function(expected) {
+ return this.actual < expected;
+};
+
+jasmine.Matchers.prototype.toBeGreaterThan = function(expected) {
+ return this.actual > expected;
+};
+
+/**
+ * Matcher that checks that the expected item is equal to the actual item
+ * up to a given level of decimal precision (default 2).
+ *
+ * @param {Number} expected
+ * @param {Number} precision, as number of decimal places
+ */
+jasmine.Matchers.prototype.toBeCloseTo = function(expected, precision) {
+ if (!(precision === 0)) {
+ precision = precision || 2;
+ }
+ return Math.abs(expected - this.actual) < (Math.pow(10, -precision) / 2);
+};
+
+/**
+ * Matcher that checks that the expected exception was thrown by the actual.
+ *
+ * @param {String} [expected]
+ */
+jasmine.Matchers.prototype.toThrow = function(expected) {
+ var result = false;
+ var exception;
+ if (typeof this.actual != 'function') {
+ throw new Error('Actual is not a function');
+ }
+ try {
+ this.actual();
+ } catch (e) {
+ exception = e;
+ }
+ if (exception) {
+ result = (expected === jasmine.undefined || this.env.equals_(exception.message || exception, expected.message || expected));
+ }
+
+ var not = this.isNot ? "not " : "";
+
+ this.message = function() {
+ if (exception && (expected === jasmine.undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) {
+ return ["Expected function " + not + "to throw", expected ? expected.message || expected : "an exception", ", but it threw", exception.message || exception].join(' ');
+ } else {
+ return "Expected function to throw an exception.";
+ }
+ };
+
+ return result;
+};
+
+jasmine.Matchers.Any = function(expectedClass) {
+ this.expectedClass = expectedClass;
+};
+
+jasmine.Matchers.Any.prototype.jasmineMatches = function(other) {
+ if (this.expectedClass == String) {
+ return typeof other == 'string' || other instanceof String;
+ }
+
+ if (this.expectedClass == Number) {
+ return typeof other == 'number' || other instanceof Number;
+ }
+
+ if (this.expectedClass == Function) {
+ return typeof other == 'function' || other instanceof Function;
+ }
+
+ if (this.expectedClass == Object) {
+ return typeof other == 'object';
+ }
+
+ return other instanceof this.expectedClass;
+};
+
+jasmine.Matchers.Any.prototype.jasmineToString = function() {
+ return '
';
+};
+
+jasmine.Matchers.ObjectContaining = function (sample) {
+ this.sample = sample;
+};
+
+jasmine.Matchers.ObjectContaining.prototype.jasmineMatches = function(other, mismatchKeys, mismatchValues) {
+ mismatchKeys = mismatchKeys || [];
+ mismatchValues = mismatchValues || [];
+
+ var env = jasmine.getEnv();
+
+ var hasKey = function(obj, keyName) {
+ return obj != null && obj[keyName] !== jasmine.undefined;
+ };
+
+ for (var property in this.sample) {
+ if (!hasKey(other, property) && hasKey(this.sample, property)) {
+ mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
+ }
+ else if (!env.equals_(this.sample[property], other[property], mismatchKeys, mismatchValues)) {
+ mismatchValues.push("'" + property + "' was '" + (other[property] ? jasmine.util.htmlEscape(other[property].toString()) : other[property]) + "' in expected, but was '" + (this.sample[property] ? jasmine.util.htmlEscape(this.sample[property].toString()) : this.sample[property]) + "' in actual.");
+ }
+ }
+
+ return (mismatchKeys.length === 0 && mismatchValues.length === 0);
+};
+
+jasmine.Matchers.ObjectContaining.prototype.jasmineToString = function () {
+ return "";
+};
+// Mock setTimeout, clearTimeout
+// Contributed by Pivotal Computer Systems, www.pivotalsf.com
+
+jasmine.FakeTimer = function() {
+ this.reset();
+
+ var self = this;
+ self.setTimeout = function(funcToCall, millis) {
+ self.timeoutsMade++;
+ self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false);
+ return self.timeoutsMade;
+ };
+
+ self.setInterval = function(funcToCall, millis) {
+ self.timeoutsMade++;
+ self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true);
+ return self.timeoutsMade;
+ };
+
+ self.clearTimeout = function(timeoutKey) {
+ self.scheduledFunctions[timeoutKey] = jasmine.undefined;
+ };
+
+ self.clearInterval = function(timeoutKey) {
+ self.scheduledFunctions[timeoutKey] = jasmine.undefined;
+ };
+
+};
+
+jasmine.FakeTimer.prototype.reset = function() {
+ this.timeoutsMade = 0;
+ this.scheduledFunctions = {};
+ this.nowMillis = 0;
+};
+
+jasmine.FakeTimer.prototype.tick = function(millis) {
+ var oldMillis = this.nowMillis;
+ var newMillis = oldMillis + millis;
+ this.runFunctionsWithinRange(oldMillis, newMillis);
+ this.nowMillis = newMillis;
+};
+
+jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) {
+ var scheduledFunc;
+ var funcsToRun = [];
+ for (var timeoutKey in this.scheduledFunctions) {
+ scheduledFunc = this.scheduledFunctions[timeoutKey];
+ if (scheduledFunc != jasmine.undefined &&
+ scheduledFunc.runAtMillis >= oldMillis &&
+ scheduledFunc.runAtMillis <= nowMillis) {
+ funcsToRun.push(scheduledFunc);
+ this.scheduledFunctions[timeoutKey] = jasmine.undefined;
+ }
+ }
+
+ if (funcsToRun.length > 0) {
+ funcsToRun.sort(function(a, b) {
+ return a.runAtMillis - b.runAtMillis;
+ });
+ for (var i = 0; i < funcsToRun.length; ++i) {
+ try {
+ var funcToRun = funcsToRun[i];
+ this.nowMillis = funcToRun.runAtMillis;
+ funcToRun.funcToCall();
+ if (funcToRun.recurring) {
+ this.scheduleFunction(funcToRun.timeoutKey,
+ funcToRun.funcToCall,
+ funcToRun.millis,
+ true);
+ }
+ } catch(e) {
+ }
+ }
+ this.runFunctionsWithinRange(oldMillis, nowMillis);
+ }
+};
+
+jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) {
+ this.scheduledFunctions[timeoutKey] = {
+ runAtMillis: this.nowMillis + millis,
+ funcToCall: funcToCall,
+ recurring: recurring,
+ timeoutKey: timeoutKey,
+ millis: millis
+ };
+};
+
+/**
+ * @namespace
+ */
+jasmine.Clock = {
+ defaultFakeTimer: new jasmine.FakeTimer(),
+
+ reset: function() {
+ jasmine.Clock.assertInstalled();
+ jasmine.Clock.defaultFakeTimer.reset();
+ },
+
+ tick: function(millis) {
+ jasmine.Clock.assertInstalled();
+ jasmine.Clock.defaultFakeTimer.tick(millis);
+ },
+
+ runFunctionsWithinRange: function(oldMillis, nowMillis) {
+ jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis);
+ },
+
+ scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) {
+ jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring);
+ },
+
+ useMock: function() {
+ if (!jasmine.Clock.isInstalled()) {
+ var spec = jasmine.getEnv().currentSpec;
+ spec.after(jasmine.Clock.uninstallMock);
+
+ jasmine.Clock.installMock();
+ }
+ },
+
+ installMock: function() {
+ jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer;
+ },
+
+ uninstallMock: function() {
+ jasmine.Clock.assertInstalled();
+ jasmine.Clock.installed = jasmine.Clock.real;
+ },
+
+ real: {
+ setTimeout: jasmine.getGlobal().setTimeout,
+ clearTimeout: jasmine.getGlobal().clearTimeout,
+ setInterval: jasmine.getGlobal().setInterval,
+ clearInterval: jasmine.getGlobal().clearInterval
+ },
+
+ assertInstalled: function() {
+ if (!jasmine.Clock.isInstalled()) {
+ throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()");
+ }
+ },
+
+ isInstalled: function() {
+ return jasmine.Clock.installed == jasmine.Clock.defaultFakeTimer;
+ },
+
+ installed: null
+};
+jasmine.Clock.installed = jasmine.Clock.real;
+
+//else for IE support
+jasmine.getGlobal().setTimeout = function(funcToCall, millis) {
+ if (jasmine.Clock.installed.setTimeout.apply) {
+ return jasmine.Clock.installed.setTimeout.apply(this, arguments);
+ } else {
+ return jasmine.Clock.installed.setTimeout(funcToCall, millis);
+ }
+};
+
+jasmine.getGlobal().setInterval = function(funcToCall, millis) {
+ if (jasmine.Clock.installed.setInterval.apply) {
+ return jasmine.Clock.installed.setInterval.apply(this, arguments);
+ } else {
+ return jasmine.Clock.installed.setInterval(funcToCall, millis);
+ }
+};
+
+jasmine.getGlobal().clearTimeout = function(timeoutKey) {
+ if (jasmine.Clock.installed.clearTimeout.apply) {
+ return jasmine.Clock.installed.clearTimeout.apply(this, arguments);
+ } else {
+ return jasmine.Clock.installed.clearTimeout(timeoutKey);
+ }
+};
+
+jasmine.getGlobal().clearInterval = function(timeoutKey) {
+ if (jasmine.Clock.installed.clearTimeout.apply) {
+ return jasmine.Clock.installed.clearInterval.apply(this, arguments);
+ } else {
+ return jasmine.Clock.installed.clearInterval(timeoutKey);
+ }
+};
+
+/**
+ * @constructor
+ */
+jasmine.MultiReporter = function() {
+ this.subReporters_ = [];
+};
+jasmine.util.inherit(jasmine.MultiReporter, jasmine.Reporter);
+
+jasmine.MultiReporter.prototype.addReporter = function(reporter) {
+ this.subReporters_.push(reporter);
+};
+
+(function() {
+ var functionNames = [
+ "reportRunnerStarting",
+ "reportRunnerResults",
+ "reportSuiteResults",
+ "reportSpecStarting",
+ "reportSpecResults",
+ "log"
+ ];
+ for (var i = 0; i < functionNames.length; i++) {
+ var functionName = functionNames[i];
+ jasmine.MultiReporter.prototype[functionName] = (function(functionName) {
+ return function() {
+ for (var j = 0; j < this.subReporters_.length; j++) {
+ var subReporter = this.subReporters_[j];
+ if (subReporter[functionName]) {
+ subReporter[functionName].apply(subReporter, arguments);
+ }
+ }
+ };
+ })(functionName);
+ }
+})();
+/**
+ * Holds results for a set of Jasmine spec. Allows for the results array to hold another jasmine.NestedResults
+ *
+ * @constructor
+ */
+jasmine.NestedResults = function() {
+ /**
+ * The total count of results
+ */
+ this.totalCount = 0;
+ /**
+ * Number of passed results
+ */
+ this.passedCount = 0;
+ /**
+ * Number of failed results
+ */
+ this.failedCount = 0;
+ /**
+ * Was this suite/spec skipped?
+ */
+ this.skipped = false;
+ /**
+ * @ignore
+ */
+ this.items_ = [];
+};
+
+/**
+ * Roll up the result counts.
+ *
+ * @param result
+ */
+jasmine.NestedResults.prototype.rollupCounts = function(result) {
+ this.totalCount += result.totalCount;
+ this.passedCount += result.passedCount;
+ this.failedCount += result.failedCount;
+};
+
+/**
+ * Adds a log message.
+ * @param values Array of message parts which will be concatenated later.
+ */
+jasmine.NestedResults.prototype.log = function(values) {
+ this.items_.push(new jasmine.MessageResult(values));
+};
+
+/**
+ * Getter for the results: message & results.
+ */
+jasmine.NestedResults.prototype.getItems = function() {
+ return this.items_;
+};
+
+/**
+ * Adds a result, tracking counts (total, passed, & failed)
+ * @param {jasmine.ExpectationResult|jasmine.NestedResults} result
+ */
+jasmine.NestedResults.prototype.addResult = function(result) {
+ if (result.type != 'log') {
+ if (result.items_) {
+ this.rollupCounts(result);
+ } else {
+ this.totalCount++;
+ if (result.passed()) {
+ this.passedCount++;
+ } else {
+ this.failedCount++;
+ }
+ }
+ }
+ this.items_.push(result);
+};
+
+/**
+ * @returns {Boolean} True if everything below passed
+ */
+jasmine.NestedResults.prototype.passed = function() {
+ return this.passedCount === this.totalCount;
+};
+/**
+ * Base class for pretty printing for expectation results.
+ */
+jasmine.PrettyPrinter = function() {
+ this.ppNestLevel_ = 0;
+};
+
+/**
+ * Formats a value in a nice, human-readable string.
+ *
+ * @param value
+ */
+jasmine.PrettyPrinter.prototype.format = function(value) {
+ this.ppNestLevel_++;
+ try {
+ if (value === jasmine.undefined) {
+ this.emitScalar('undefined');
+ } else if (value === null) {
+ this.emitScalar('null');
+ } else if (value === jasmine.getGlobal()) {
+ this.emitScalar('');
+ } else if (value.jasmineToString) {
+ this.emitScalar(value.jasmineToString());
+ } else if (typeof value === 'string') {
+ this.emitString(value);
+ } else if (jasmine.isSpy(value)) {
+ this.emitScalar("spy on " + value.identity);
+ } else if (value instanceof RegExp) {
+ this.emitScalar(value.toString());
+ } else if (typeof value === 'function') {
+ this.emitScalar('Function');
+ } else if (typeof value.nodeType === 'number') {
+ this.emitScalar('HTMLNode');
+ } else if (value instanceof Date) {
+ this.emitScalar('Date(' + value + ')');
+ } else if (value.__Jasmine_been_here_before__) {
+ this.emitScalar('');
+ } else if (jasmine.isArray_(value) || typeof value == 'object') {
+ value.__Jasmine_been_here_before__ = true;
+ if (jasmine.isArray_(value)) {
+ this.emitArray(value);
+ } else {
+ this.emitObject(value);
+ }
+ delete value.__Jasmine_been_here_before__;
+ } else {
+ this.emitScalar(value.toString());
+ }
+ } finally {
+ this.ppNestLevel_--;
+ }
+};
+
+jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) {
+ for (var property in obj) {
+ if (!obj.hasOwnProperty(property)) continue;
+ if (property == '__Jasmine_been_here_before__') continue;
+ fn(property, obj.__lookupGetter__ ? (obj.__lookupGetter__(property) !== jasmine.undefined &&
+ obj.__lookupGetter__(property) !== null) : false);
+ }
+};
+
+jasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_;
+jasmine.PrettyPrinter.prototype.emitObject = jasmine.unimplementedMethod_;
+jasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_;
+jasmine.PrettyPrinter.prototype.emitString = jasmine.unimplementedMethod_;
+
+jasmine.StringPrettyPrinter = function() {
+ jasmine.PrettyPrinter.call(this);
+
+ this.string = '';
+};
+jasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter);
+
+jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) {
+ this.append(value);
+};
+
+jasmine.StringPrettyPrinter.prototype.emitString = function(value) {
+ this.append("'" + value + "'");
+};
+
+jasmine.StringPrettyPrinter.prototype.emitArray = function(array) {
+ if (this.ppNestLevel_ > jasmine.MAX_PRETTY_PRINT_DEPTH) {
+ this.append("Array");
+ return;
+ }
+
+ this.append('[ ');
+ for (var i = 0; i < array.length; i++) {
+ if (i > 0) {
+ this.append(', ');
+ }
+ this.format(array[i]);
+ }
+ this.append(' ]');
+};
+
+jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) {
+ if (this.ppNestLevel_ > jasmine.MAX_PRETTY_PRINT_DEPTH) {
+ this.append("Object");
+ return;
+ }
+
+ var self = this;
+ this.append('{ ');
+ var first = true;
+
+ this.iterateObject(obj, function(property, isGetter) {
+ if (first) {
+ first = false;
+ } else {
+ self.append(', ');
+ }
+
+ self.append(property);
+ self.append(' : ');
+ if (isGetter) {
+ self.append('');
+ } else {
+ self.format(obj[property]);
+ }
+ });
+
+ this.append(' }');
+};
+
+jasmine.StringPrettyPrinter.prototype.append = function(value) {
+ this.string += value;
+};
+jasmine.Queue = function(env) {
+ this.env = env;
+
+ // parallel to blocks. each true value in this array means the block will
+ // get executed even if we abort
+ this.ensured = [];
+ this.blocks = [];
+ this.running = false;
+ this.index = 0;
+ this.offset = 0;
+ this.abort = false;
+};
+
+jasmine.Queue.prototype.addBefore = function(block, ensure) {
+ if (ensure === jasmine.undefined) {
+ ensure = false;
+ }
+
+ this.blocks.unshift(block);
+ this.ensured.unshift(ensure);
+};
+
+jasmine.Queue.prototype.add = function(block, ensure) {
+ if (ensure === jasmine.undefined) {
+ ensure = false;
+ }
+
+ this.blocks.push(block);
+ this.ensured.push(ensure);
+};
+
+jasmine.Queue.prototype.insertNext = function(block, ensure) {
+ if (ensure === jasmine.undefined) {
+ ensure = false;
+ }
+
+ this.ensured.splice((this.index + this.offset + 1), 0, ensure);
+ this.blocks.splice((this.index + this.offset + 1), 0, block);
+ this.offset++;
+};
+
+jasmine.Queue.prototype.start = function(onComplete) {
+ this.running = true;
+ this.onComplete = onComplete;
+ this.next_();
+};
+
+jasmine.Queue.prototype.isRunning = function() {
+ return this.running;
+};
+
+jasmine.Queue.LOOP_DONT_RECURSE = true;
+
+jasmine.Queue.prototype.next_ = function() {
+ var self = this;
+ var goAgain = true;
+
+ while (goAgain) {
+ goAgain = false;
+
+ if (self.index < self.blocks.length && !(this.abort && !this.ensured[self.index])) {
+ var calledSynchronously = true;
+ var completedSynchronously = false;
+
+ var onComplete = function () {
+ if (jasmine.Queue.LOOP_DONT_RECURSE && calledSynchronously) {
+ completedSynchronously = true;
+ return;
+ }
+
+ if (self.blocks[self.index].abort) {
+ self.abort = true;
+ }
+
+ self.offset = 0;
+ self.index++;
+
+ var now = new Date().getTime();
+ if (self.env.updateInterval && now - self.env.lastUpdate > self.env.updateInterval) {
+ self.env.lastUpdate = now;
+ self.env.setTimeout(function() {
+ self.next_();
+ }, 0);
+ } else {
+ if (jasmine.Queue.LOOP_DONT_RECURSE && completedSynchronously) {
+ goAgain = true;
+ } else {
+ self.next_();
+ }
+ }
+ };
+ self.blocks[self.index].execute(onComplete);
+
+ calledSynchronously = false;
+ if (completedSynchronously) {
+ onComplete();
+ }
+
+ } else {
+ self.running = false;
+ if (self.onComplete) {
+ self.onComplete();
+ }
+ }
+ }
+};
+
+jasmine.Queue.prototype.results = function() {
+ var results = new jasmine.NestedResults();
+ for (var i = 0; i < this.blocks.length; i++) {
+ if (this.blocks[i].results) {
+ results.addResult(this.blocks[i].results());
+ }
+ }
+ return results;
+};
+
+
+/**
+ * Runner
+ *
+ * @constructor
+ * @param {jasmine.Env} env
+ */
+jasmine.Runner = function(env) {
+ var self = this;
+ self.env = env;
+ self.queue = new jasmine.Queue(env);
+ self.before_ = [];
+ self.after_ = [];
+ self.suites_ = [];
+};
+
+jasmine.Runner.prototype.execute = function() {
+ var self = this;
+ if (self.env.reporter.reportRunnerStarting) {
+ self.env.reporter.reportRunnerStarting(this);
+ }
+ self.queue.start(function () {
+ self.finishCallback();
+ });
+};
+
+jasmine.Runner.prototype.beforeEach = function(beforeEachFunction) {
+ beforeEachFunction.typeName = 'beforeEach';
+ this.before_.splice(0,0,beforeEachFunction);
+};
+
+jasmine.Runner.prototype.afterEach = function(afterEachFunction) {
+ afterEachFunction.typeName = 'afterEach';
+ this.after_.splice(0,0,afterEachFunction);
+};
+
+
+jasmine.Runner.prototype.finishCallback = function() {
+ this.env.reporter.reportRunnerResults(this);
+};
+
+jasmine.Runner.prototype.addSuite = function(suite) {
+ this.suites_.push(suite);
+};
+
+jasmine.Runner.prototype.add = function(block) {
+ if (block instanceof jasmine.Suite) {
+ this.addSuite(block);
+ }
+ this.queue.add(block);
+};
+
+jasmine.Runner.prototype.specs = function () {
+ var suites = this.suites();
+ var specs = [];
+ for (var i = 0; i < suites.length; i++) {
+ specs = specs.concat(suites[i].specs());
+ }
+ return specs;
+};
+
+jasmine.Runner.prototype.suites = function() {
+ return this.suites_;
+};
+
+jasmine.Runner.prototype.topLevelSuites = function() {
+ var topLevelSuites = [];
+ for (var i = 0; i < this.suites_.length; i++) {
+ if (!this.suites_[i].parentSuite) {
+ topLevelSuites.push(this.suites_[i]);
+ }
+ }
+ return topLevelSuites;
+};
+
+jasmine.Runner.prototype.results = function() {
+ return this.queue.results();
+};
+/**
+ * Internal representation of a Jasmine specification, or test.
+ *
+ * @constructor
+ * @param {jasmine.Env} env
+ * @param {jasmine.Suite} suite
+ * @param {String} description
+ */
+jasmine.Spec = function(env, suite, description) {
+ if (!env) {
+ throw new Error('jasmine.Env() required');
+ }
+ if (!suite) {
+ throw new Error('jasmine.Suite() required');
+ }
+ var spec = this;
+ spec.id = env.nextSpecId ? env.nextSpecId() : null;
+ spec.env = env;
+ spec.suite = suite;
+ spec.description = description;
+ spec.queue = new jasmine.Queue(env);
+
+ spec.afterCallbacks = [];
+ spec.spies_ = [];
+
+ spec.results_ = new jasmine.NestedResults();
+ spec.results_.description = description;
+ spec.matchersClass = null;
+};
+
+jasmine.Spec.prototype.getVersion = function() {
+ return this.suite.getVersion() + ' ' + this.description + '.';
+};
+
+
+jasmine.Spec.prototype.results = function() {
+ return this.results_;
+};
+
+/**
+ * All parameters are pretty-printed and concatenated together, then written to the spec's output.
+ *
+ * Be careful not to leave calls to jasmine.log in production code.
+ */
+jasmine.Spec.prototype.log = function() {
+ return this.results_.log(arguments);
+};
+
+jasmine.Spec.prototype.runs = function (func) {
+ var block = new jasmine.Block(this.env, func, this);
+ this.addToQueue(block);
+ return this;
+};
+
+jasmine.Spec.prototype.addToQueue = function (block) {
+ if (this.queue.isRunning()) {
+ this.queue.insertNext(block);
+ } else {
+ this.queue.add(block);
+ }
+};
+
+/**
+ * @param {jasmine.ExpectationResult} result
+ */
+jasmine.Spec.prototype.addMatcherResult = function(result) {
+ this.results_.addResult(result);
+};
+
+jasmine.Spec.prototype.expect = function(actual) {
+ var positive = new (this.getMatchersClass_())(this.env, actual, this);
+ positive.not = new (this.getMatchersClass_())(this.env, actual, this, true);
+ return positive;
+};
+
+/**
+ * Waits a fixed time period before moving to the next block.
+ *
+ * @deprecated Use waitsFor() instead
+ * @param {Number} timeout milliseconds to wait
+ */
+jasmine.Spec.prototype.waits = function(timeout) {
+ var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this);
+ this.addToQueue(waitsFunc);
+ return this;
+};
+
+/**
+ * Waits for the latchFunction to return true before proceeding to the next block.
+ *
+ * @param {Function} latchFunction
+ * @param {String} optional_timeoutMessage
+ * @param {Number} optional_timeout
+ */
+jasmine.Spec.prototype.waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
+ var latchFunction_ = null;
+ var optional_timeoutMessage_ = null;
+ var optional_timeout_ = null;
+
+ for (var i = 0; i < arguments.length; i++) {
+ var arg = arguments[i];
+ switch (typeof arg) {
+ case 'function':
+ latchFunction_ = arg;
+ break;
+ case 'string':
+ optional_timeoutMessage_ = arg;
+ break;
+ case 'number':
+ optional_timeout_ = arg;
+ break;
+ }
+ }
+
+ var waitsForFunc = new jasmine.WaitsForBlock(this.env, optional_timeout_, latchFunction_, optional_timeoutMessage_, this);
+ this.addToQueue(waitsForFunc);
+ return this;
+};
+
+jasmine.Spec.prototype.fail = function (e) {
+ var expectationResult = new jasmine.ExpectationResult({
+ passed: false,
+ message: e ? jasmine.util.formatException(e) : 'Exception',
+ trace: { stack: e.stack }
+ });
+ this.results_.addResult(expectationResult);
+};
+
+jasmine.Spec.prototype.getMatchersClass_ = function() {
+ return this.matchersClass || this.env.matchersClass;
+};
+
+jasmine.Spec.prototype.addMatchers = function(matchersPrototype) {
+ var parent = this.getMatchersClass_();
+ var newMatchersClass = function() {
+ parent.apply(this, arguments);
+ };
+ jasmine.util.inherit(newMatchersClass, parent);
+ jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass);
+ this.matchersClass = newMatchersClass;
+};
+
+jasmine.Spec.prototype.finishCallback = function() {
+ this.env.reporter.reportSpecResults(this);
+};
+
+jasmine.Spec.prototype.finish = function(onComplete) {
+ this.removeAllSpies();
+ this.finishCallback();
+ if (onComplete) {
+ onComplete();
+ }
+};
+
+jasmine.Spec.prototype.after = function(doAfter) {
+ if (this.queue.isRunning()) {
+ this.queue.add(new jasmine.Block(this.env, doAfter, this), true);
+ } else {
+ this.afterCallbacks.unshift(doAfter);
+ }
+};
+
+jasmine.Spec.prototype.execute = function(onComplete) {
+ var spec = this;
+ if (!spec.env.specFilter(spec)) {
+ spec.results_.skipped = true;
+ spec.finish(onComplete);
+ return;
+ }
+
+ this.env.reporter.reportSpecStarting(this);
+
+ spec.env.currentSpec = spec;
+
+ spec.addBeforesAndAftersToQueue();
+
+ spec.queue.start(function () {
+ spec.finish(onComplete);
+ });
+};
+
+jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() {
+ var runner = this.env.currentRunner();
+ var i;
+
+ for (var suite = this.suite; suite; suite = suite.parentSuite) {
+ for (i = 0; i < suite.before_.length; i++) {
+ this.queue.addBefore(new jasmine.Block(this.env, suite.before_[i], this));
+ }
+ }
+ for (i = 0; i < runner.before_.length; i++) {
+ this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this));
+ }
+ for (i = 0; i < this.afterCallbacks.length; i++) {
+ this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this), true);
+ }
+ for (suite = this.suite; suite; suite = suite.parentSuite) {
+ for (i = 0; i < suite.after_.length; i++) {
+ this.queue.add(new jasmine.Block(this.env, suite.after_[i], this), true);
+ }
+ }
+ for (i = 0; i < runner.after_.length; i++) {
+ this.queue.add(new jasmine.Block(this.env, runner.after_[i], this), true);
+ }
+};
+
+jasmine.Spec.prototype.explodes = function() {
+ throw 'explodes function should not have been called';
+};
+
+jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) {
+ if (obj == jasmine.undefined) {
+ throw "spyOn could not find an object to spy upon for " + methodName + "()";
+ }
+
+ if (!ignoreMethodDoesntExist && obj[methodName] === jasmine.undefined) {
+ throw methodName + '() method does not exist';
+ }
+
+ if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) {
+ throw new Error(methodName + ' has already been spied upon');
+ }
+
+ var spyObj = jasmine.createSpy(methodName);
+
+ this.spies_.push(spyObj);
+ spyObj.baseObj = obj;
+ spyObj.methodName = methodName;
+ spyObj.originalValue = obj[methodName];
+
+ obj[methodName] = spyObj;
+
+ return spyObj;
+};
+
+jasmine.Spec.prototype.removeAllSpies = function() {
+ for (var i = 0; i < this.spies_.length; i++) {
+ var spy = this.spies_[i];
+ spy.baseObj[spy.methodName] = spy.originalValue;
+ }
+ this.spies_ = [];
+};
+
+/**
+ * Internal representation of a Jasmine suite.
+ *
+ * @constructor
+ * @param {jasmine.Env} env
+ * @param {String} description
+ * @param {Function} specDefinitions
+ * @param {jasmine.Suite} parentSuite
+ */
+jasmine.Suite = function(env, description, specDefinitions, parentSuite) {
+ var self = this;
+ self.id = env.nextSuiteId ? env.nextSuiteId() : null;
+ self.description = description;
+ self.queue = new jasmine.Queue(env);
+ self.parentSuite = parentSuite;
+ self.env = env;
+ self.before_ = [];
+ self.after_ = [];
+ self.children_ = [];
+ self.suites_ = [];
+ self.specs_ = [];
+};
+
+jasmine.Suite.prototype.getVersion = function() {
+ var version = this.description;
+ for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
+ version = parentSuite.description + ' ' + version;
+ }
+ return version;
+};
+
+jasmine.Suite.prototype.finish = function(onComplete) {
+ this.env.reporter.reportSuiteResults(this);
+ this.finished = true;
+ if (typeof(onComplete) == 'function') {
+ onComplete();
+ }
+};
+
+jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) {
+ beforeEachFunction.typeName = 'beforeEach';
+ this.before_.unshift(beforeEachFunction);
+};
+
+jasmine.Suite.prototype.afterEach = function(afterEachFunction) {
+ afterEachFunction.typeName = 'afterEach';
+ this.after_.unshift(afterEachFunction);
+};
+
+jasmine.Suite.prototype.results = function() {
+ return this.queue.results();
+};
+
+jasmine.Suite.prototype.add = function(suiteOrSpec) {
+ this.children_.push(suiteOrSpec);
+ if (suiteOrSpec instanceof jasmine.Suite) {
+ this.suites_.push(suiteOrSpec);
+ this.env.currentRunner().addSuite(suiteOrSpec);
+ } else {
+ this.specs_.push(suiteOrSpec);
+ }
+ this.queue.add(suiteOrSpec);
+};
+
+jasmine.Suite.prototype.specs = function() {
+ return this.specs_;
+};
+
+jasmine.Suite.prototype.suites = function() {
+ return this.suites_;
+};
+
+jasmine.Suite.prototype.children = function() {
+ return this.children_;
+};
+
+jasmine.Suite.prototype.execute = function(onComplete) {
+ var self = this;
+ this.queue.start(function () {
+ self.finish(onComplete);
+ });
+};
+jasmine.WaitsBlock = function(env, timeout, spec) {
+ this.timeout = timeout;
+ jasmine.Block.call(this, env, null, spec);
+};
+
+jasmine.util.inherit(jasmine.WaitsBlock, jasmine.Block);
+
+jasmine.WaitsBlock.prototype.execute = function (onComplete) {
+ if (jasmine.VERBOSE) {
+ this.env.reporter.log('>> Jasmine waiting for ' + this.timeout + ' ms...');
+ }
+ this.env.setTimeout(function () {
+ onComplete();
+ }, this.timeout);
+};
+/**
+ * A block which waits for some condition to become true, with timeout.
+ *
+ * @constructor
+ * @extends jasmine.Block
+ * @param {jasmine.Env} env The Jasmine environment.
+ * @param {Number} timeout The maximum time in milliseconds to wait for the condition to become true.
+ * @param {Function} latchFunction A function which returns true when the desired condition has been met.
+ * @param {String} message The message to display if the desired condition hasn't been met within the given time period.
+ * @param {jasmine.Spec} spec The Jasmine spec.
+ */
+jasmine.WaitsForBlock = function(env, timeout, latchFunction, message, spec) {
+ this.timeout = timeout || env.defaultTimeoutInterval;
+ this.latchFunction = latchFunction;
+ this.message = message;
+ this.totalTimeSpentWaitingForLatch = 0;
+ jasmine.Block.call(this, env, null, spec);
+};
+jasmine.util.inherit(jasmine.WaitsForBlock, jasmine.Block);
+
+jasmine.WaitsForBlock.TIMEOUT_INCREMENT = 10;
+
+jasmine.WaitsForBlock.prototype.execute = function(onComplete) {
+ if (jasmine.VERBOSE) {
+ this.env.reporter.log('>> Jasmine waiting for ' + (this.message || 'something to happen'));
+ }
+ var latchFunctionResult;
+ try {
+ latchFunctionResult = this.latchFunction.apply(this.spec);
+ } catch (e) {
+ this.spec.fail(e);
+ onComplete();
+ return;
+ }
+
+ if (latchFunctionResult) {
+ onComplete();
+ } else if (this.totalTimeSpentWaitingForLatch >= this.timeout) {
+ var message = 'timed out after ' + this.timeout + ' msec waiting for ' + (this.message || 'something to happen');
+ this.spec.fail({
+ name: 'timeout',
+ message: message
+ });
+
+ this.abort = true;
+ onComplete();
+ } else {
+ this.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT;
+ var self = this;
+ this.env.setTimeout(function() {
+ self.execute(onComplete);
+ }, jasmine.WaitsForBlock.TIMEOUT_INCREMENT);
+ }
+};
+
+jasmine.version_= {
+ "major": 1,
+ "minor": 3,
+ "build": 1,
+ "revision": 1354556913
+};
diff --git a/js/test/lib/support/jasmine-content.js b/js/test/lib/support/jasmine-content.js
new file mode 100644
index 00000000..969b7c1e
--- /dev/null
+++ b/js/test/lib/support/jasmine-content.js
@@ -0,0 +1,7 @@
+beforeEach(function() {
+ $('body').append('
');
+});
+
+afterEach(function() {
+ $('body #jasmine_content').remove();
+});
\ No newline at end of file
diff --git a/js/test/lib/support/jasmine-jquery.js b/js/test/lib/support/jasmine-jquery.js
new file mode 100644
index 00000000..c04edfb7
--- /dev/null
+++ b/js/test/lib/support/jasmine-jquery.js
@@ -0,0 +1,673 @@
+/*!
+ Jasmine-jQuery: a set of jQuery helpers for Jasmine tests.
+
+ Version 1.5.8
+
+ https://github.com/velesin/jasmine-jquery
+
+ Copyright (c) 2010-2013 Wojciech Zawistowski, Travis Jeffery
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+var readFixtures = function() {
+ return jasmine.getFixtures().proxyCallTo_('read', arguments)
+}
+
+var preloadFixtures = function() {
+ jasmine.getFixtures().proxyCallTo_('preload', arguments)
+}
+
+var loadFixtures = function() {
+ jasmine.getFixtures().proxyCallTo_('load', arguments)
+}
+
+var appendLoadFixtures = function() {
+ jasmine.getFixtures().proxyCallTo_('appendLoad', arguments)
+}
+
+var setFixtures = function(html) {
+ return jasmine.getFixtures().proxyCallTo_('set', arguments)
+}
+
+var appendSetFixtures = function() {
+ jasmine.getFixtures().proxyCallTo_('appendSet', arguments)
+}
+
+var sandbox = function(attributes) {
+ return jasmine.getFixtures().sandbox(attributes)
+}
+
+var spyOnEvent = function(selector, eventName) {
+ return jasmine.JQuery.events.spyOn(selector, eventName)
+}
+
+var preloadStyleFixtures = function() {
+ jasmine.getStyleFixtures().proxyCallTo_('preload', arguments)
+}
+
+var loadStyleFixtures = function() {
+ jasmine.getStyleFixtures().proxyCallTo_('load', arguments)
+}
+
+var appendLoadStyleFixtures = function() {
+ jasmine.getStyleFixtures().proxyCallTo_('appendLoad', arguments)
+}
+
+var setStyleFixtures = function(html) {
+ jasmine.getStyleFixtures().proxyCallTo_('set', arguments)
+}
+
+var appendSetStyleFixtures = function(html) {
+ jasmine.getStyleFixtures().proxyCallTo_('appendSet', arguments)
+}
+
+var loadJSONFixtures = function() {
+ return jasmine.getJSONFixtures().proxyCallTo_('load', arguments)
+}
+
+var getJSONFixture = function(url) {
+ return jasmine.getJSONFixtures().proxyCallTo_('read', arguments)[url]
+}
+
+jasmine.spiedEventsKey = function (selector, eventName) {
+ return [$(selector).selector, eventName].toString()
+}
+
+jasmine.getFixtures = function() {
+ return jasmine.currentFixtures_ = jasmine.currentFixtures_ || new jasmine.Fixtures()
+}
+
+jasmine.getStyleFixtures = function() {
+ return jasmine.currentStyleFixtures_ = jasmine.currentStyleFixtures_ || new jasmine.StyleFixtures()
+}
+
+jasmine.Fixtures = function() {
+ this.containerId = 'jasmine-fixtures'
+ this.fixturesCache_ = {}
+ this.fixturesPath = 'spec/javascripts/fixtures'
+}
+
+jasmine.Fixtures.prototype.set = function(html) {
+ this.cleanUp()
+ return this.createContainer_(html)
+}
+
+jasmine.Fixtures.prototype.appendSet= function(html) {
+ this.addToContainer_(html)
+}
+
+jasmine.Fixtures.prototype.preload = function() {
+ this.read.apply(this, arguments)
+}
+
+jasmine.Fixtures.prototype.load = function() {
+ this.cleanUp()
+ this.createContainer_(this.read.apply(this, arguments))
+}
+
+jasmine.Fixtures.prototype.appendLoad = function() {
+ this.addToContainer_(this.read.apply(this, arguments))
+}
+
+jasmine.Fixtures.prototype.read = function() {
+ var htmlChunks = []
+
+ var fixtureUrls = arguments
+ for(var urlCount = fixtureUrls.length, urlIndex = 0; urlIndex < urlCount; urlIndex++) {
+ htmlChunks.push(this.getFixtureHtml_(fixtureUrls[urlIndex]))
+ }
+
+ return htmlChunks.join('')
+}
+
+jasmine.Fixtures.prototype.clearCache = function() {
+ this.fixturesCache_ = {}
+}
+
+jasmine.Fixtures.prototype.cleanUp = function() {
+ $('#' + this.containerId).remove()
+}
+
+jasmine.Fixtures.prototype.sandbox = function(attributes) {
+ var attributesToSet = attributes || {}
+ return $('
').attr(attributesToSet)
+}
+
+jasmine.Fixtures.prototype.createContainer_ = function(html) {
+ var container = $('')
+ .attr('id', this.containerId)
+ .html(html);
+ $(document.body).append(container)
+ return container
+}
+
+jasmine.Fixtures.prototype.addToContainer_ = function(html){
+ var container = $(document.body).find('#'+this.containerId).append(html)
+ if(!container.length){
+ this.createContainer_(html)
+ }
+}
+
+jasmine.Fixtures.prototype.getFixtureHtml_ = function(url) {
+ if (typeof this.fixturesCache_[url] === 'undefined') {
+ this.loadFixtureIntoCache_(url)
+ }
+ return this.fixturesCache_[url]
+}
+
+jasmine.Fixtures.prototype.loadFixtureIntoCache_ = function(relativeUrl) {
+ var url = this.makeFixtureUrl_(relativeUrl)
+ var request = $.ajax({
+ type: "GET",
+ url: url + "?" + new Date().getTime(),
+ async: false
+ })
+ this.fixturesCache_[relativeUrl] = request.responseText
+}
+
+jasmine.Fixtures.prototype.makeFixtureUrl_ = function(relativeUrl){
+ return this.fixturesPath.match('/$') ? this.fixturesPath + relativeUrl : this.fixturesPath + '/' + relativeUrl
+}
+
+jasmine.Fixtures.prototype.proxyCallTo_ = function(methodName, passedArguments) {
+ return this[methodName].apply(this, passedArguments)
+}
+
+
+jasmine.StyleFixtures = function() {
+ this.fixturesCache_ = {}
+ this.fixturesNodes_ = []
+ this.fixturesPath = 'spec/javascripts/fixtures'
+}
+
+jasmine.StyleFixtures.prototype.set = function(css) {
+ this.cleanUp()
+ this.createStyle_(css)
+}
+
+jasmine.StyleFixtures.prototype.appendSet = function(css) {
+ this.createStyle_(css)
+}
+
+jasmine.StyleFixtures.prototype.preload = function() {
+ this.read_.apply(this, arguments)
+}
+
+jasmine.StyleFixtures.prototype.load = function() {
+ this.cleanUp()
+ this.createStyle_(this.read_.apply(this, arguments))
+}
+
+jasmine.StyleFixtures.prototype.appendLoad = function() {
+ this.createStyle_(this.read_.apply(this, arguments))
+}
+
+jasmine.StyleFixtures.prototype.cleanUp = function() {
+ while(this.fixturesNodes_.length) {
+ this.fixturesNodes_.pop().remove()
+ }
+}
+
+jasmine.StyleFixtures.prototype.createStyle_ = function(html) {
+ var styleText = $('
').html(html).text(),
+ style = $('')
+
+ this.fixturesNodes_.push(style)
+
+ $('head').append(style)
+}
+
+jasmine.StyleFixtures.prototype.clearCache = jasmine.Fixtures.prototype.clearCache
+
+jasmine.StyleFixtures.prototype.read_ = jasmine.Fixtures.prototype.read
+
+jasmine.StyleFixtures.prototype.getFixtureHtml_ = jasmine.Fixtures.prototype.getFixtureHtml_
+
+jasmine.StyleFixtures.prototype.loadFixtureIntoCache_ = jasmine.Fixtures.prototype.loadFixtureIntoCache_
+
+jasmine.StyleFixtures.prototype.makeFixtureUrl_ = jasmine.Fixtures.prototype.makeFixtureUrl_
+
+jasmine.StyleFixtures.prototype.proxyCallTo_ = jasmine.Fixtures.prototype.proxyCallTo_
+
+jasmine.getJSONFixtures = function() {
+ return jasmine.currentJSONFixtures_ = jasmine.currentJSONFixtures_ || new jasmine.JSONFixtures()
+}
+
+jasmine.JSONFixtures = function() {
+ this.fixturesCache_ = {}
+ this.fixturesPath = 'spec/javascripts/fixtures/json'
+}
+
+jasmine.JSONFixtures.prototype.load = function() {
+ this.read.apply(this, arguments)
+ return this.fixturesCache_
+}
+
+jasmine.JSONFixtures.prototype.read = function() {
+ var fixtureUrls = arguments
+ for(var urlCount = fixtureUrls.length, urlIndex = 0; urlIndex < urlCount; urlIndex++) {
+ this.getFixtureData_(fixtureUrls[urlIndex])
+ }
+ return this.fixturesCache_
+}
+
+jasmine.JSONFixtures.prototype.clearCache = function() {
+ this.fixturesCache_ = {}
+}
+
+jasmine.JSONFixtures.prototype.getFixtureData_ = function(url) {
+ this.loadFixtureIntoCache_(url)
+ return this.fixturesCache_[url]
+}
+
+jasmine.JSONFixtures.prototype.loadFixtureIntoCache_ = function(relativeUrl) {
+ var self = this
+ var url = this.fixturesPath.match('/$') ? this.fixturesPath + relativeUrl : this.fixturesPath + '/' + relativeUrl
+ $.ajax({
+ async: false, // must be synchronous to guarantee that no tests are run before fixture is loaded
+ cache: false,
+ dataType: 'json',
+ url: url,
+ success: function(data) {
+ self.fixturesCache_[relativeUrl] = data
+ },
+ error: function(jqXHR, status, errorThrown) {
+ throw Error('JSONFixture could not be loaded: ' + url + ' (status: ' + status + ', message: ' + errorThrown.message + ')')
+ }
+ })
+}
+
+jasmine.JSONFixtures.prototype.proxyCallTo_ = function(methodName, passedArguments) {
+ return this[methodName].apply(this, passedArguments)
+}
+
+jasmine.JQuery = function() {}
+
+jasmine.JQuery.browserTagCaseIndependentHtml = function(html) {
+ return $('
').append(html).html()
+}
+
+jasmine.JQuery.elementToString = function(element) {
+ var domEl = $(element).get(0)
+ if (domEl == undefined || domEl.cloneNode)
+ return $('
').append($(element).clone()).html()
+ else
+ return element.toString()
+}
+
+jasmine.JQuery.matchersClass = {}
+
+!function(namespace) {
+ var data = {
+ spiedEvents: {},
+ handlers: []
+ }
+
+ namespace.events = {
+ spyOn: function(selector, eventName) {
+ var handler = function(e) {
+ data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)] = jasmine.util.argsToArray(arguments)
+ }
+ $(selector).on(eventName, handler)
+ data.handlers.push(handler)
+ return {
+ selector: selector,
+ eventName: eventName,
+ handler: handler,
+ reset: function(){
+ delete data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)]
+ }
+ }
+ },
+
+ args: function(selector, eventName) {
+ var actualArgs = data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)];
+
+ if (!actualArgs) {
+ throw "There is no spy for " + eventName + " on " + selector.toString() + ". Make sure to create a spy using spyOnEvent.";
+ }
+
+ return actualArgs;
+ },
+
+ wasTriggered: function(selector, eventName) {
+ return !!(data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)])
+ },
+
+ wasTriggeredWith: function(selector, eventName, expectedArgs, env) {
+ var actualArgs = jasmine.JQuery.events.args(selector, eventName).slice(1);
+ if (Object.prototype.toString.call(expectedArgs) !== '[object Array]') {
+ actualArgs = actualArgs[0];
+ }
+ return env.equals_(expectedArgs, actualArgs);
+ },
+
+ wasPrevented: function(selector, eventName) {
+ var args = data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)],
+ e = args ? args[0] : undefined;
+ return e && e.isDefaultPrevented()
+ },
+
+ wasStopped: function(selector, eventName) {
+ var args = data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)],
+ e = args ? args[0] : undefined;
+ return e && e.isPropagationStopped()
+ },
+
+ cleanUp: function() {
+ data.spiedEvents = {}
+ data.handlers = []
+ }
+ }
+}(jasmine.JQuery)
+
+!function(){
+ var jQueryMatchers = {
+ toHaveClass: function(className) {
+ return this.actual.hasClass(className)
+ },
+
+ toHaveCss: function(css){
+ for (var prop in css){
+ if (this.actual.css(prop) !== css[prop]) return false
+ }
+ return true
+ },
+
+ toBeVisible: function() {
+ return this.actual.is(':visible')
+ },
+
+ toBeHidden: function() {
+ return this.actual.is(':hidden')
+ },
+
+ toBeSelected: function() {
+ return this.actual.is(':selected')
+ },
+
+ toBeChecked: function() {
+ return this.actual.is(':checked')
+ },
+
+ toBeEmpty: function() {
+ return this.actual.is(':empty')
+ },
+
+ toExist: function() {
+ return $(document).find(this.actual).length
+ },
+
+ toHaveLength: function(length) {
+ return this.actual.length === length
+ },
+
+ toHaveAttr: function(attributeName, expectedAttributeValue) {
+ return hasProperty(this.actual.attr(attributeName), expectedAttributeValue)
+ },
+
+ toHaveProp: function(propertyName, expectedPropertyValue) {
+ return hasProperty(this.actual.prop(propertyName), expectedPropertyValue)
+ },
+
+ toHaveId: function(id) {
+ return this.actual.attr('id') == id
+ },
+
+ toHaveHtml: function(html) {
+ return this.actual.html() == jasmine.JQuery.browserTagCaseIndependentHtml(html)
+ },
+
+ toContainHtml: function(html){
+ var actualHtml = this.actual.html()
+ var expectedHtml = jasmine.JQuery.browserTagCaseIndependentHtml(html)
+ return (actualHtml.indexOf(expectedHtml) >= 0)
+ },
+
+ toHaveText: function(text) {
+ var trimmedText = $.trim(this.actual.text())
+ if (text && $.isFunction(text.test)) {
+ return text.test(trimmedText)
+ } else {
+ return trimmedText == text
+ }
+ },
+
+ toContainText: function(text) {
+ var trimmedText = $.trim(this.actual.text())
+ if (text && $.isFunction(text.test)) {
+ return text.test(trimmedText)
+ } else {
+ return trimmedText.indexOf(text) != -1;
+ }
+ },
+
+ toHaveValue: function(value) {
+ return this.actual.val() === value
+ },
+
+ toHaveData: function(key, expectedValue) {
+ return hasProperty(this.actual.data(key), expectedValue)
+ },
+
+ toBe: function(selector) {
+ return this.actual.is(selector)
+ },
+
+ toContain: function(selector) {
+ return this.actual.find(selector).length
+ },
+
+ toBeMatchedBy: function(selector) {
+ return this.actual.filter(selector).length
+ },
+
+ toBeDisabled: function(selector){
+ return this.actual.is(':disabled')
+ },
+
+ toBeFocused: function(selector) {
+ return this.actual[0] === this.actual[0].ownerDocument.activeElement
+ },
+
+ toHandle: function(event) {
+
+ var events = $._data(this.actual.get(0), "events")
+
+ if(!events || !event || typeof event !== "string") {
+ return false
+ }
+
+ var namespaces = event.split(".")
+ var eventType = namespaces.shift()
+ var sortedNamespaces = namespaces.slice(0).sort()
+ var namespaceRegExp = new RegExp("(^|\\.)" + sortedNamespaces.join("\\.(?:.*\\.)?") + "(\\.|$)")
+
+ if(events[eventType] && namespaces.length) {
+ for(var i = 0; i < events[eventType].length; i++) {
+ var namespace = events[eventType][i].namespace
+ if(namespaceRegExp.test(namespace)) {
+ return true
+ }
+ }
+ } else {
+ return events[eventType] && events[eventType].length > 0
+ }
+ },
+
+ // tests the existence of a specific event binding + handler
+ toHandleWith: function(eventName, eventHandler) {
+ var normalizedEventName = eventName.split('.')[0];
+ var stack = $._data(this.actual.get(0), "events")[normalizedEventName]
+ for (var i = 0; i < stack.length; i++) {
+ if (stack[i].handler == eventHandler) return true
+ }
+ return false
+ }
+ }
+
+ var hasProperty = function(actualValue, expectedValue) {
+ if (expectedValue === undefined) return actualValue !== undefined
+ return actualValue == expectedValue
+ }
+
+ var bindMatcher = function(methodName) {
+ var builtInMatcher = jasmine.Matchers.prototype[methodName]
+
+ jasmine.JQuery.matchersClass[methodName] = function() {
+ if (this.actual
+ && (this.actual instanceof $
+ || jasmine.isDomNode(this.actual))) {
+ this.actual = $(this.actual)
+ var result = jQueryMatchers[methodName].apply(this, arguments)
+ var element
+ if (this.actual.get && (element = this.actual.get()[0]) && !$.isWindow(element) && element.tagName !== "HTML")
+ this.actual = jasmine.JQuery.elementToString(this.actual)
+ return result
+ }
+
+ if (builtInMatcher) {
+ return builtInMatcher.apply(this, arguments)
+ }
+
+ return false
+ }
+ }
+
+ for(var methodName in jQueryMatchers) {
+ bindMatcher(methodName)
+ }
+}()
+
+beforeEach(function() {
+ this.addMatchers(jasmine.JQuery.matchersClass)
+ this.addMatchers({
+ toHaveBeenTriggeredOn: function(selector) {
+ this.message = function() {
+ return [
+ "Expected event " + this.actual + " to have been triggered on " + selector,
+ "Expected event " + this.actual + " not to have been triggered on " + selector
+ ]
+ }
+ return jasmine.JQuery.events.wasTriggered(selector, this.actual)
+ }
+ })
+ this.addMatchers({
+ toHaveBeenTriggered: function(){
+ var eventName = this.actual.eventName,
+ selector = this.actual.selector
+ this.message = function() {
+ return [
+ "Expected event " + eventName + " to have been triggered on " + selector,
+ "Expected event " + eventName + " not to have been triggered on " + selector
+ ]
+ }
+ return jasmine.JQuery.events.wasTriggered(selector, eventName)
+ }
+ })
+ this.addMatchers({
+ toHaveBeenTriggeredOnAndWith: function() {
+ var selector = arguments[0],
+ expectedArgs = arguments[1],
+ wasTriggered = jasmine.JQuery.events.wasTriggered(selector, this.actual);
+ this.message = function() {
+ if (wasTriggered) {
+ var actualArgs = jasmine.JQuery.events.args(selector, this.actual, expectedArgs)[1];
+ return [
+ "Expected event " + this.actual + " to have been triggered with " + jasmine.pp(expectedArgs) + " but it was triggered with " + jasmine.pp(actualArgs),
+ "Expected event " + this.actual + " not to have been triggered with " + jasmine.pp(expectedArgs) + " but it was triggered with " + jasmine.pp(actualArgs)
+ ]
+ } else {
+ return [
+ "Expected event " + this.actual + " to have been triggered on " + selector,
+ "Expected event " + this.actual + " not to have been triggered on " + selector
+ ]
+ }
+ }
+ return wasTriggered && jasmine.JQuery.events.wasTriggeredWith(selector, this.actual, expectedArgs, this.env);
+ }
+ })
+ this.addMatchers({
+ toHaveBeenPreventedOn: function(selector) {
+ this.message = function() {
+ return [
+ "Expected event " + this.actual + " to have been prevented on " + selector,
+ "Expected event " + this.actual + " not to have been prevented on " + selector
+ ]
+ }
+ return jasmine.JQuery.events.wasPrevented(selector, this.actual)
+ }
+ })
+ this.addMatchers({
+ toHaveBeenPrevented: function() {
+ var eventName = this.actual.eventName,
+ selector = this.actual.selector
+ this.message = function() {
+ return [
+ "Expected event " + eventName + " to have been prevented on " + selector,
+ "Expected event " + eventName + " not to have been prevented on " + selector
+ ]
+ }
+ return jasmine.JQuery.events.wasPrevented(selector, eventName)
+ }
+ })
+ this.addMatchers({
+ toHaveBeenStoppedOn: function(selector) {
+ this.message = function() {
+ return [
+ "Expected event " + this.actual + " to have been stopped on " + selector,
+ "Expected event " + this.actual + " not to have been stopped on " + selector
+ ]
+ }
+ return jasmine.JQuery.events.wasStopped(selector, this.actual)
+ }
+ })
+ this.addMatchers({
+ toHaveBeenStopped: function() {
+ var eventName = this.actual.eventName,
+ selector = this.actual.selector
+ this.message = function() {
+ return [
+ "Expected event " + eventName + " to have been stopped on " + selector,
+ "Expected event " + eventName + " not to have been stopped on " + selector
+ ]
+ }
+ return jasmine.JQuery.events.wasStopped(selector, eventName)
+ }
+ })
+ jasmine.getEnv().addEqualityTester(function(a, b) {
+ if(a instanceof jQuery && b instanceof jQuery) {
+ if(a.size() != b.size()) {
+ return jasmine.undefined;
+ }
+ else if(a.is(b)) {
+ return true;
+ }
+ }
+ return jasmine.undefined;
+
+ })
+})
+
+afterEach(function() {
+ jasmine.getFixtures().cleanUp()
+ jasmine.getStyleFixtures().cleanUp()
+ jasmine.JQuery.events.cleanUp()
+})
diff --git a/js/test/lib/support/mock-ajax.js b/js/test/lib/support/mock-ajax.js
new file mode 100644
index 00000000..bf17886f
--- /dev/null
+++ b/js/test/lib/support/mock-ajax.js
@@ -0,0 +1,207 @@
+/*
+ Jasmine-Ajax : a set of helpers for testing AJAX requests under the Jasmine
+ BDD framework for JavaScript.
+
+ Supports both Prototype.js and jQuery.
+
+ https://github.com/pivotal/jasmine-ajax
+
+ Jasmine Home page: https://pivotal.github.com/jasmine
+
+ Copyright (c) 2008-2010 Pivotal Labs
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ */
+
+// Jasmine-Ajax interface
+var ajaxRequests = [];
+
+function mostRecentAjaxRequest() {
+ if (ajaxRequests.length > 0) {
+ return ajaxRequests[ajaxRequests.length - 1];
+ } else {
+ return null;
+ }
+}
+
+function clearAjaxRequests() {
+ ajaxRequests = [];
+}
+
+// Fake XHR for mocking Ajax Requests & Responses
+function FakeXMLHttpRequest() {
+ var extend = Object.extend || $.extend;
+ extend(this, {
+ requestHeaders: {},
+
+ open: function() {
+ this.method = arguments[0];
+ this.url = arguments[1];
+ this.readyState = 1;
+ },
+
+ setRequestHeader: function(header, value) {
+ this.requestHeaders[header] = value;
+ },
+
+ abort: function() {
+ this.readyState = 0;
+ },
+
+ readyState: 0,
+
+ onreadystatechange: function(isTimeout) {
+ },
+
+ status: null,
+
+ send: function(data) {
+ this.params = data;
+ this.readyState = 2;
+ },
+
+ getResponseHeader: function(name) {
+ return this.responseHeaders[name];
+ },
+
+ getAllResponseHeaders: function() {
+ var responseHeaders = [];
+ for (var i in this.responseHeaders) {
+ if (this.responseHeaders.hasOwnProperty(i)) {
+ responseHeaders.push(i + ': ' + this.responseHeaders[i]);
+ }
+ }
+ return responseHeaders.join('\r\n');
+ },
+
+ responseText: null,
+
+ response: function(response) {
+ this.status = response.status;
+ this.responseText = response.responseText || "";
+ this.readyState = 4;
+ this.responseHeaders = response.responseHeaders ||
+ {"Content-type": response.contentType || "application/json" };
+ // uncomment for jquery 1.3.x support
+ // jasmine.Clock.tick(20);
+
+ this.onreadystatechange();
+ },
+ responseTimeout: function() {
+ this.readyState = 4;
+ jasmine.Clock.tick(jQuery.ajaxSettings.timeout || 30000);
+ this.onreadystatechange('timeout');
+ }
+ });
+
+ return this;
+}
+
+
+jasmine.Ajax = {
+
+ isInstalled: function() {
+ return jasmine.Ajax.installed == true;
+ },
+
+ assertInstalled: function() {
+ if (!jasmine.Ajax.isInstalled()) {
+ throw new Error("Mock ajax is not installed, use jasmine.Ajax.useMock()")
+ }
+ },
+
+ useMock: function() {
+ if (!jasmine.Ajax.isInstalled()) {
+ var spec = jasmine.getEnv().currentSpec;
+ spec.after(jasmine.Ajax.uninstallMock);
+
+ jasmine.Ajax.installMock();
+ }
+ },
+
+ installMock: function() {
+ if (typeof jQuery != 'undefined') {
+ jasmine.Ajax.installJquery();
+ } else if (typeof Prototype != 'undefined') {
+ jasmine.Ajax.installPrototype();
+ } else {
+ throw new Error("jasmine.Ajax currently only supports jQuery and Prototype");
+ }
+ jasmine.Ajax.installed = true;
+ },
+
+ installJquery: function() {
+ jasmine.Ajax.mode = 'jQuery';
+ jasmine.Ajax.real = jQuery.ajaxSettings.xhr;
+ jQuery.ajaxSettings.xhr = jasmine.Ajax.jQueryMock;
+
+ },
+
+ installPrototype: function() {
+ jasmine.Ajax.mode = 'Prototype';
+ jasmine.Ajax.real = Ajax.getTransport;
+
+ Ajax.getTransport = jasmine.Ajax.prototypeMock;
+ },
+
+ uninstallMock: function() {
+ jasmine.Ajax.assertInstalled();
+ if (jasmine.Ajax.mode == 'jQuery') {
+ jQuery.ajaxSettings.xhr = jasmine.Ajax.real;
+ } else if (jasmine.Ajax.mode == 'Prototype') {
+ Ajax.getTransport = jasmine.Ajax.real;
+ }
+ jasmine.Ajax.reset();
+ },
+
+ reset: function() {
+ jasmine.Ajax.installed = false;
+ jasmine.Ajax.mode = null;
+ jasmine.Ajax.real = null;
+ },
+
+ jQueryMock: function() {
+ var newXhr = new FakeXMLHttpRequest();
+ ajaxRequests.push(newXhr);
+ return newXhr;
+ },
+
+ prototypeMock: function() {
+ return new FakeXMLHttpRequest();
+ },
+
+ installed: false,
+ mode: null
+}
+
+
+// Jasmine-Ajax Glue code for Prototype.js
+if (typeof Prototype != 'undefined' && Ajax && Ajax.Request) {
+ Ajax.Request.prototype.originalRequest = Ajax.Request.prototype.request;
+ Ajax.Request.prototype.request = function(url) {
+ this.originalRequest(url);
+ ajaxRequests.push(this);
+ };
+
+ Ajax.Request.prototype.response = function(responseOptions) {
+ return this.transport.response(responseOptions);
+ };
+}
diff --git a/js/test/spec/QuickStartWidgetSpec.js b/js/test/spec/QuickStartWidgetSpec.js
new file mode 100644
index 00000000..3bafa1d0
--- /dev/null
+++ b/js/test/spec/QuickStartWidgetSpec.js
@@ -0,0 +1,109 @@
+describe("QuickStartWidget", function () {
+
+ describe("rendering", function () {
+
+ beforeEach(function () {
+ var project = new Spring.Project({
+ "id": "spring-data-jpa",
+ "name": "Spring Data JPA",
+ "repoUrl": "https://github.com/SpringSource/spring-data-jpa",
+ "siteUrl": "https://projects.spring.io/spring-data-jpa",
+ "projectReleases": [
+ {
+ "refDocUrl": "https://docs.spring.io/spring-data/jpa/docs/1.4.0.RC1/reference/html/",
+ "apiDocUrl": "https://docs.spring.io/spring-data/jpa/docs/1.4.0.RC1/api/",
+ "groupId": "org.springframework.data",
+ "artifactId": "spring-data-jpa",
+ "repository": {
+ "id": "spring-milestones",
+ "name": "Spring Milestones",
+ "url": "https://repo.spring.io/milestone",
+ "snapshotsEnabled": false
+ },
+ "version": "1.4.0.RC1",
+ "current": false,
+ "preRelease": true,
+ "snapshot": false,
+ "generalAvailability": false,
+ "versionDisplayName": "1.4.0.RC1"
+ },
+ {
+ "refDocUrl": "https://docs.spring.io/spring-data/jpa/docs/1.3.4.RELEASE/reference/html/",
+ "apiDocUrl": "https://docs.spring.io/spring-data/jpa/docs/1.3.4.RELEASE/api/",
+ "groupId": "org.springframework.data",
+ "artifactId": "spring-data-jpa",
+ "repository": null,
+ "version": "1.3.4.RELEASE",
+ "current": true,
+ "preRelease": false,
+ "snapshot": false,
+ "generalAvailability": true,
+ "versionDisplayName": "1.3.4"
+ }
+ ]
+ });
+
+ $('#jasmine_content').append("
");
+ $('#jasmine_content').append("
");
+ Spring.buildQuickStartWidget("#quick_select_widget", "#maven_widget", project);
+ });
+
+ it("lists out each release's version", function () {
+ expect($('#quick_select_widget')).toContainText("1.4.0.RC1");
+ expect($('#quick_select_widget')).toContainText("1.3.4");
+ });
+
+ describe("maven view", function() {
+ it("shows the current release dependency by default", function() {
+ expect($('#maven_widget')).toContainText("org.springframework.data");
+ expect($('#maven_widget')).toContainText("spring-data-jpa");
+ expect($('#maven_widget')).toContainText("1.3.4.RELEASE");
+ });
+
+ it("shows the correct dependency when users select a different release", function() {
+ $('#jasmine_content select').val(0).change();
+
+ expect($('#maven_widget')).toContainText("org.springframework.data");
+ expect($('#maven_widget')).toContainText("spring-data-jpa");
+ expect($('#maven_widget')).toContainText("1.4.0.RC1");
+ });
+
+ it("shows the repository information if user selects a release with a repository", function() {
+ $('#jasmine_content select').val(0).change();
+
+ expect($('#maven_widget')).toContainText("spring-milestones");
+ expect($('#maven_widget')).toContainText("Spring Milestones");
+ expect($('#maven_widget')).toContainText("https://repo.spring.io/milestone");
+ expect($('#maven_widget')).toContainText("false");
+ });
+
+ it("doesn't show the repository if the user selects a release without a repository", function (){
+ $('#jasmine_content select').val(1).change();
+
+ expect($('#maven_widget')).not.toContainText("repository");
+ expect($('#maven_widget')).not.toContainText("spring-milestones");
+ expect($('#maven_widget')).not.toContainText("Spring Milestones");
+ expect($('#maven_widget')).not.toContainText("https://repo.spring.io/milestone");
+ expect($('#maven_widget')).not.toContainText("false");
+ });
+ });
+
+ describe("gradle view", function() {
+ beforeEach(function() {
+ $("#quick_select_widget [data-snippet-type=gradle]").click();
+ });
+
+ it("shows the current release dependency by default", function() {
+ expect($('#maven_widget')).toContainText("dependencies");
+ expect($('#maven_widget')).toContainText("org.springframework.data:spring-data-jpa:1.3.4.RELEASE");
+ });
+
+ it("shows the repository if the data has one", function() {
+ $('#jasmine_content select').val(0).change();
+
+ expect($('#maven_widget')).toContainText("repositories");
+ expect($('#maven_widget')).toContainText("https://repo.spring.io/milestone");
+ });
+ });
+ });
+});
diff --git a/js/toc.js b/js/toc.js
new file mode 100644
index 00000000..a6e933bf
--- /dev/null
+++ b/js/toc.js
@@ -0,0 +1,107 @@
+var toctitle = document.getElementById('toctitle');
+var path = window.location.pathname;
+if (toctitle != null) {
+ var oldtoc = toctitle.nextElementSibling;
+ var newtoc = document.createElement('div');
+ newtoc.setAttribute('id', 'tocbot');
+ newtoc.setAttribute('class', 'js-toc desktop-toc');
+ oldtoc.setAttribute('class', 'mobile-toc');
+ oldtoc.parentNode.appendChild(newtoc);
+ tocbot.init({
+ contentSelector: '#content',
+ headingSelector: 'h1, h2, h3, h4, h5',
+ positionFixedSelector: 'body',
+ fixedSidebarOffset: 90,
+ smoothScroll: false
+ });
+ if (!path.endsWith("index.html") && !path.endsWith("/")) {
+ var link = document.createElement("a");
+ link.setAttribute("href", "index.html");
+ link.innerHTML = "
Back to index";
+ var block = document.createElement("div");
+ block.setAttribute('class', 'back-action');
+ block.appendChild(link);
+ var toc = document.getElementById('toc');
+ var next = document.getElementById('toctitle').nextElementSibling;
+ toc.insertBefore(block, next);
+ }
+}
+
+var headerHtml = '';
+
+var header = document.createElement("div");
+header.innerHTML = headerHtml;
+document.body.insertBefore(header, document.body.firstChild);
\ No newline at end of file
diff --git a/js/tocbot/tocbot.css b/js/tocbot/tocbot.css
new file mode 100644
index 00000000..0632de23
--- /dev/null
+++ b/js/tocbot/tocbot.css
@@ -0,0 +1 @@
+.toc{overflow-y:auto}.toc>.toc-list{overflow:hidden;position:relative}.toc>.toc-list li{list-style:none}.toc-list{margin:0;padding-left:10px}a.toc-link{color:currentColor;height:100%}.is-collapsible{max-height:1000px;overflow:hidden;transition:all 300ms ease-in-out}.is-collapsed{max-height:0}.is-position-fixed{position:fixed !important;top:0}.is-active-link{font-weight:700}.toc-link::before{background-color:#EEE;content:' ';display:inline-block;height:inherit;left:0;margin-top:-1px;position:absolute;width:2px}.is-active-link::before{background-color:#54BC4B}
diff --git a/js/tocbot/tocbot.min.js b/js/tocbot/tocbot.min.js
new file mode 100644
index 00000000..943d8fdb
--- /dev/null
+++ b/js/tocbot/tocbot.min.js
@@ -0,0 +1 @@
+!function(e){function t(o){if(n[o])return n[o].exports;var l=n[o]={i:o,l:!1,exports:{}};return e[o].call(l.exports,l,l.exports,t),l.l=!0,l.exports}var n={};t.m=e,t.c=n,t.d=function(e,n,o){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:o})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=0)}([function(e,t,n){(function(o){var l,i,s;!function(n,o){i=[],l=o(n),void 0!==(s="function"==typeof l?l.apply(t,i):l)&&(e.exports=s)}(void 0!==o?o:this.window||this.global,function(e){"use strict";function t(){for(var e={},t=0;t
e.fixedSidebarOffset?-1===n.className.indexOf(e.positionFixedClass)&&(n.className+=h+e.positionFixedClass):n.className=n.className.split(h+e.positionFixedClass).join("")}function s(t){var n=document.documentElement.scrollTop||f.scrollTop;e.positionFixedSelector&&i();var o,l=t;if(m&&null!==document.querySelector(e.tocSelector)&&l.length>0){d.call(l,function(t,i){if(t.offsetTop>n+e.headingsOffset+10){return o=l[0===i?i:i-1],!0}if(i===l.length-1)return o=l[l.length-1],!0});var s=document.querySelector(e.tocSelector).querySelectorAll("."+e.linkClass);u.call(s,function(t){t.className=t.className.split(h+e.activeLinkClass).join("")});var c=document.querySelector(e.tocSelector).querySelectorAll("."+e.listItemClass);u.call(c,function(t){t.className=t.className.split(h+e.activeListItemClass).join("")});var a=document.querySelector(e.tocSelector).querySelector("."+e.linkClass+".node-name--"+o.nodeName+'[href="#'+o.id+'"]');-1===a.className.indexOf(e.activeLinkClass)&&(a.className+=h+e.activeLinkClass);var p=a.parentNode;p&&-1===p.className.indexOf(e.activeListItemClass)&&(p.className+=h+e.activeListItemClass);var C=document.querySelector(e.tocSelector).querySelectorAll("."+e.listClass+"."+e.collapsibleClass);u.call(C,function(t){-1===t.className.indexOf(e.isCollapsedClass)&&(t.className+=h+e.isCollapsedClass)}),a.nextSibling&&-1!==a.nextSibling.className.indexOf(e.isCollapsedClass)&&(a.nextSibling.className=a.nextSibling.className.split(h+e.isCollapsedClass).join("")),r(a.parentNode.parentNode)}}function r(t){return-1!==t.className.indexOf(e.collapsibleClass)&&-1!==t.className.indexOf(e.isCollapsedClass)?(t.className=t.className.split(h+e.isCollapsedClass).join(""),r(t.parentNode.parentNode)):t}function c(t){var n=t.target||t.srcElement;"string"==typeof n.className&&-1!==n.className.indexOf(e.linkClass)&&(m=!1)}function a(){m=!0}var u=[].forEach,d=[].some,f=document.body,m=!0,h=" ";return{enableTocAnimation:a,disableTocAnimation:c,render:n,updateToc:s}}},function(e,t){e.exports=function(e){function t(e){return e[e.length-1]}function n(e){return+e.nodeName.split("H").join("")}function o(t){var o={id:t.id,children:[],nodeName:t.nodeName,headingLevel:n(t),textContent:t.textContent.trim()};return e.includeHtml&&(o.childNodes=t.childNodes),o}function l(l,i){for(var s=o(l),r=n(l),c=i,a=t(c),u=a?a.headingLevel:0,d=r-u;d>0;)a=t(c),a&&void 0!==a.children&&(c=a.children),d--;return r>=e.collapseDepth&&(s.isCollapsed=!0),c.push(s),c}function i(t,n){var o=n;e.ignoreSelector&&(o=n.split(",").map(function(t){return t.trim()+":not("+e.ignoreSelector+")"}));try{return document.querySelector(t).querySelectorAll(o)}catch(e){return console.warn("Element not found: "+t),null}}function s(e){return r.call(e,function(e,t){return l(o(t),e.nest),e},{nest:[]})}var r=[].reduce;return{nestHeadingsArray:s,selectHeadings:i}}},function(e,t){function n(e){function t(e){return"a"===e.tagName.toLowerCase()&&(e.hash.length>0||"#"===e.href.charAt(e.href.length-1))&&(n(e.href)===s||n(e.href)+"#"===s)}function n(e){return e.slice(0,e.lastIndexOf("#"))}function l(e){var t=document.getElementById(e.substring(1));t&&(/^(?:a|select|input|button|textarea)$/i.test(t.tagName)||(t.tabIndex=-1),t.focus())}!function(){document.documentElement.style}();var i=e.duration,s=location.hash?n(location.href):location.href;!function(){function n(n){!t(n.target)||n.target.className.indexOf("no-smooth-scroll")>-1||"#"===n.target.href.charAt(n.target.href.length-2)&&"!"===n.target.href.charAt(n.target.href.length-1)||-1===n.target.className.indexOf(e.linkClass)||o(n.target.hash,{duration:i,callback:function(){l(n.target.hash)}})}document.body.addEventListener("click",n,!1)}()}function o(e,t){function n(e){s=e-i,window.scrollTo(0,c.easing(s,r,u,d)),s 2;
+ if (obj == null) obj = [];
+ if (nativeReduce && obj.reduce === nativeReduce) {
+ if (context) iterator = _.bind(iterator, context);
+ return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
+ }
+ each(obj, function(value, index, list) {
+ if (!initial) {
+ memo = value;
+ initial = true;
+ } else {
+ memo = iterator.call(context, memo, value, index, list);
+ }
+ });
+ if (!initial) throw new TypeError(reduceError);
+ return memo;
+ };
+
+ // The right-associative version of reduce, also known as `foldr`.
+ // Delegates to **ECMAScript 5**'s native `reduceRight` if available.
+ _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
+ var initial = arguments.length > 2;
+ if (obj == null) obj = [];
+ if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
+ if (context) iterator = _.bind(iterator, context);
+ return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
+ }
+ var length = obj.length;
+ if (length !== +length) {
+ var keys = _.keys(obj);
+ length = keys.length;
+ }
+ each(obj, function(value, index, list) {
+ index = keys ? keys[--length] : --length;
+ if (!initial) {
+ memo = obj[index];
+ initial = true;
+ } else {
+ memo = iterator.call(context, memo, obj[index], index, list);
+ }
+ });
+ if (!initial) throw new TypeError(reduceError);
+ return memo;
+ };
+
+ // Return the first value which passes a truth test. Aliased as `detect`.
+ _.find = _.detect = function(obj, iterator, context) {
+ var result;
+ any(obj, function(value, index, list) {
+ if (iterator.call(context, value, index, list)) {
+ result = value;
+ return true;
+ }
+ });
+ return result;
+ };
+
+ // Return all the elements that pass a truth test.
+ // Delegates to **ECMAScript 5**'s native `filter` if available.
+ // Aliased as `select`.
+ _.filter = _.select = function(obj, iterator, context) {
+ var results = [];
+ if (obj == null) return results;
+ if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
+ each(obj, function(value, index, list) {
+ if (iterator.call(context, value, index, list)) results.push(value);
+ });
+ return results;
+ };
+
+ // Return all the elements for which a truth test fails.
+ _.reject = function(obj, iterator, context) {
+ return _.filter(obj, function(value, index, list) {
+ return !iterator.call(context, value, index, list);
+ }, context);
+ };
+
+ // Determine whether all of the elements match a truth test.
+ // Delegates to **ECMAScript 5**'s native `every` if available.
+ // Aliased as `all`.
+ _.every = _.all = function(obj, iterator, context) {
+ iterator || (iterator = _.identity);
+ var result = true;
+ if (obj == null) return result;
+ if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
+ each(obj, function(value, index, list) {
+ if (!(result = result && iterator.call(context, value, index, list))) return breaker;
+ });
+ return !!result;
+ };
+
+ // Determine if at least one element in the object matches a truth test.
+ // Delegates to **ECMAScript 5**'s native `some` if available.
+ // Aliased as `any`.
+ var any = _.some = _.any = function(obj, iterator, context) {
+ iterator || (iterator = _.identity);
+ var result = false;
+ if (obj == null) return result;
+ if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
+ each(obj, function(value, index, list) {
+ if (result || (result = iterator.call(context, value, index, list))) return breaker;
+ });
+ return !!result;
+ };
+
+ // Determine if the array or object contains a given value (using `===`).
+ // Aliased as `include`.
+ _.contains = _.include = function(obj, target) {
+ if (obj == null) return false;
+ if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
+ return any(obj, function(value) {
+ return value === target;
+ });
+ };
+
+ // Invoke a method (with arguments) on every item in a collection.
+ _.invoke = function(obj, method) {
+ var args = slice.call(arguments, 2);
+ var isFunc = _.isFunction(method);
+ return _.map(obj, function(value) {
+ return (isFunc ? method : value[method]).apply(value, args);
+ });
+ };
+
+ // Convenience version of a common use case of `map`: fetching a property.
+ _.pluck = function(obj, key) {
+ return _.map(obj, function(value){ return value[key]; });
+ };
+
+ // Convenience version of a common use case of `filter`: selecting only objects
+ // containing specific `key:value` pairs.
+ _.where = function(obj, attrs, first) {
+ if (_.isEmpty(attrs)) return first ? void 0 : [];
+ return _[first ? 'find' : 'filter'](obj, function(value) {
+ for (var key in attrs) {
+ if (attrs[key] !== value[key]) return false;
+ }
+ return true;
+ });
+ };
+
+ // Convenience version of a common use case of `find`: getting the first object
+ // containing specific `key:value` pairs.
+ _.findWhere = function(obj, attrs) {
+ return _.where(obj, attrs, true);
+ };
+
+ // Return the maximum element or (element-based computation).
+ // Can't optimize arrays of integers longer than 65,535 elements.
+ // See [WebKit Bug 80797](https://bugs.webkit.org/show_bug.cgi?id=80797)
+ _.max = function(obj, iterator, context) {
+ if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
+ return Math.max.apply(Math, obj);
+ }
+ if (!iterator && _.isEmpty(obj)) return -Infinity;
+ var result = {computed : -Infinity, value: -Infinity};
+ each(obj, function(value, index, list) {
+ var computed = iterator ? iterator.call(context, value, index, list) : value;
+ computed > result.computed && (result = {value : value, computed : computed});
+ });
+ return result.value;
+ };
+
+ // Return the minimum element (or element-based computation).
+ _.min = function(obj, iterator, context) {
+ if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
+ return Math.min.apply(Math, obj);
+ }
+ if (!iterator && _.isEmpty(obj)) return Infinity;
+ var result = {computed : Infinity, value: Infinity};
+ each(obj, function(value, index, list) {
+ var computed = iterator ? iterator.call(context, value, index, list) : value;
+ computed < result.computed && (result = {value : value, computed : computed});
+ });
+ return result.value;
+ };
+
+ // Shuffle an array.
+ _.shuffle = function(obj) {
+ var rand;
+ var index = 0;
+ var shuffled = [];
+ each(obj, function(value) {
+ rand = _.random(index++);
+ shuffled[index - 1] = shuffled[rand];
+ shuffled[rand] = value;
+ });
+ return shuffled;
+ };
+
+ // An internal function to generate lookup iterators.
+ var lookupIterator = function(value) {
+ return _.isFunction(value) ? value : function(obj){ return obj[value]; };
+ };
+
+ // Sort the object's values by a criterion produced by an iterator.
+ _.sortBy = function(obj, value, context) {
+ var iterator = lookupIterator(value);
+ return _.pluck(_.map(obj, function(value, index, list) {
+ return {
+ value : value,
+ index : index,
+ criteria : iterator.call(context, value, index, list)
+ };
+ }).sort(function(left, right) {
+ var a = left.criteria;
+ var b = right.criteria;
+ if (a !== b) {
+ if (a > b || a === void 0) return 1;
+ if (a < b || b === void 0) return -1;
+ }
+ return left.index < right.index ? -1 : 1;
+ }), 'value');
+ };
+
+ // An internal function used for aggregate "group by" operations.
+ var group = function(obj, value, context, behavior) {
+ var result = {};
+ var iterator = lookupIterator(value == null ? _.identity : value);
+ each(obj, function(value, index) {
+ var key = iterator.call(context, value, index, obj);
+ behavior(result, key, value);
+ });
+ return result;
+ };
+
+ // Groups the object's values by a criterion. Pass either a string attribute
+ // to group by, or a function that returns the criterion.
+ _.groupBy = function(obj, value, context) {
+ return group(obj, value, context, function(result, key, value) {
+ (_.has(result, key) ? result[key] : (result[key] = [])).push(value);
+ });
+ };
+
+ // Counts instances of an object that group by a certain criterion. Pass
+ // either a string attribute to count by, or a function that returns the
+ // criterion.
+ _.countBy = function(obj, value, context) {
+ return group(obj, value, context, function(result, key) {
+ if (!_.has(result, key)) result[key] = 0;
+ result[key]++;
+ });
+ };
+
+ // Use a comparator function to figure out the smallest index at which
+ // an object should be inserted so as to maintain order. Uses binary search.
+ _.sortedIndex = function(array, obj, iterator, context) {
+ iterator = iterator == null ? _.identity : lookupIterator(iterator);
+ var value = iterator.call(context, obj);
+ var low = 0, high = array.length;
+ while (low < high) {
+ var mid = (low + high) >>> 1;
+ iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;
+ }
+ return low;
+ };
+
+ // Safely create a real, live array from anything iterable.
+ _.toArray = function(obj) {
+ if (!obj) return [];
+ if (_.isArray(obj)) return slice.call(obj);
+ if (obj.length === +obj.length) return _.map(obj, _.identity);
+ return _.values(obj);
+ };
+
+ // Return the number of elements in an object.
+ _.size = function(obj) {
+ if (obj == null) return 0;
+ return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;
+ };
+
+ // Array Functions
+ // ---------------
+
+ // Get the first element of an array. Passing **n** will return the first N
+ // values in the array. Aliased as `head` and `take`. The **guard** check
+ // allows it to work with `_.map`.
+ _.first = _.head = _.take = function(array, n, guard) {
+ if (array == null) return void 0;
+ return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
+ };
+
+ // Returns everything but the last entry of the array. Especially useful on
+ // the arguments object. Passing **n** will return all the values in
+ // the array, excluding the last N. The **guard** check allows it to work with
+ // `_.map`.
+ _.initial = function(array, n, guard) {
+ return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
+ };
+
+ // Get the last element of an array. Passing **n** will return the last N
+ // values in the array. The **guard** check allows it to work with `_.map`.
+ _.last = function(array, n, guard) {
+ if (array == null) return void 0;
+ if ((n != null) && !guard) {
+ return slice.call(array, Math.max(array.length - n, 0));
+ } else {
+ return array[array.length - 1];
+ }
+ };
+
+ // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
+ // Especially useful on the arguments object. Passing an **n** will return
+ // the rest N values in the array. The **guard**
+ // check allows it to work with `_.map`.
+ _.rest = _.tail = _.drop = function(array, n, guard) {
+ return slice.call(array, (n == null) || guard ? 1 : n);
+ };
+
+ // Trim out all falsy values from an array.
+ _.compact = function(array) {
+ return _.filter(array, _.identity);
+ };
+
+ // Internal implementation of a recursive `flatten` function.
+ var flatten = function(input, shallow, output) {
+ if (shallow && _.every(input, _.isArray)) {
+ return concat.apply(output, input);
+ }
+ each(input, function(value) {
+ if (_.isArray(value) || _.isArguments(value)) {
+ shallow ? push.apply(output, value) : flatten(value, shallow, output);
+ } else {
+ output.push(value);
+ }
+ });
+ return output;
+ };
+
+ // Return a completely flattened version of an array.
+ _.flatten = function(array, shallow) {
+ return flatten(array, shallow, []);
+ };
+
+ // Return a version of the array that does not contain the specified value(s).
+ _.without = function(array) {
+ return _.difference(array, slice.call(arguments, 1));
+ };
+
+ // Produce a duplicate-free version of the array. If the array has already
+ // been sorted, you have the option of using a faster algorithm.
+ // Aliased as `unique`.
+ _.uniq = _.unique = function(array, isSorted, iterator, context) {
+ if (_.isFunction(isSorted)) {
+ context = iterator;
+ iterator = isSorted;
+ isSorted = false;
+ }
+ var initial = iterator ? _.map(array, iterator, context) : array;
+ var results = [];
+ var seen = [];
+ each(initial, function(value, index) {
+ if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {
+ seen.push(value);
+ results.push(array[index]);
+ }
+ });
+ return results;
+ };
+
+ // Produce an array that contains the union: each distinct element from all of
+ // the passed-in arrays.
+ _.union = function() {
+ return _.uniq(_.flatten(arguments, true));
+ };
+
+ // Produce an array that contains every item shared between all the
+ // passed-in arrays.
+ _.intersection = function(array) {
+ var rest = slice.call(arguments, 1);
+ return _.filter(_.uniq(array), function(item) {
+ return _.every(rest, function(other) {
+ return _.indexOf(other, item) >= 0;
+ });
+ });
+ };
+
+ // Take the difference between one array and a number of other arrays.
+ // Only the elements present in just the first array will remain.
+ _.difference = function(array) {
+ var rest = concat.apply(ArrayProto, slice.call(arguments, 1));
+ return _.filter(array, function(value){ return !_.contains(rest, value); });
+ };
+
+ // Zip together multiple lists into a single array -- elements that share
+ // an index go together.
+ _.zip = function() {
+ var length = _.max(_.pluck(arguments, "length").concat(0));
+ var results = new Array(length);
+ for (var i = 0; i < length; i++) {
+ results[i] = _.pluck(arguments, '' + i);
+ }
+ return results;
+ };
+
+ // Converts lists into objects. Pass either a single array of `[key, value]`
+ // pairs, or two parallel arrays of the same length -- one of keys, and one of
+ // the corresponding values.
+ _.object = function(list, values) {
+ if (list == null) return {};
+ var result = {};
+ for (var i = 0, l = list.length; i < l; i++) {
+ if (values) {
+ result[list[i]] = values[i];
+ } else {
+ result[list[i][0]] = list[i][1];
+ }
+ }
+ return result;
+ };
+
+ // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
+ // we need this function. Return the position of the first occurrence of an
+ // item in an array, or -1 if the item is not included in the array.
+ // Delegates to **ECMAScript 5**'s native `indexOf` if available.
+ // If the array is large and already in sort order, pass `true`
+ // for **isSorted** to use binary search.
+ _.indexOf = function(array, item, isSorted) {
+ if (array == null) return -1;
+ var i = 0, l = array.length;
+ if (isSorted) {
+ if (typeof isSorted == 'number') {
+ i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted);
+ } else {
+ i = _.sortedIndex(array, item);
+ return array[i] === item ? i : -1;
+ }
+ }
+ if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
+ for (; i < l; i++) if (array[i] === item) return i;
+ return -1;
+ };
+
+ // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
+ _.lastIndexOf = function(array, item, from) {
+ if (array == null) return -1;
+ var hasIndex = from != null;
+ if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {
+ return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);
+ }
+ var i = (hasIndex ? from : array.length);
+ while (i--) if (array[i] === item) return i;
+ return -1;
+ };
+
+ // Generate an integer Array containing an arithmetic progression. A port of
+ // the native Python `range()` function. See
+ // [the Python documentation](https://docs.python.org/library/functions.html#range).
+ _.range = function(start, stop, step) {
+ if (arguments.length <= 1) {
+ stop = start || 0;
+ start = 0;
+ }
+ step = arguments[2] || 1;
+
+ var len = Math.max(Math.ceil((stop - start) / step), 0);
+ var idx = 0;
+ var range = new Array(len);
+
+ while(idx < len) {
+ range[idx++] = start;
+ start += step;
+ }
+
+ return range;
+ };
+
+ // Function (ahem) Functions
+ // ------------------
+
+ // Reusable constructor function for prototype setting.
+ var ctor = function(){};
+
+ // Create a function bound to a given object (assigning `this`, and arguments,
+ // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
+ // available.
+ _.bind = function(func, context) {
+ var args, bound;
+ if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
+ if (!_.isFunction(func)) throw new TypeError;
+ args = slice.call(arguments, 2);
+ return bound = function() {
+ if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
+ ctor.prototype = func.prototype;
+ var self = new ctor;
+ ctor.prototype = null;
+ var result = func.apply(self, args.concat(slice.call(arguments)));
+ if (Object(result) === result) return result;
+ return self;
+ };
+ };
+
+ // Partially apply a function by creating a version that has had some of its
+ // arguments pre-filled, without changing its dynamic `this` context.
+ _.partial = function(func) {
+ var args = slice.call(arguments, 1);
+ return function() {
+ return func.apply(this, args.concat(slice.call(arguments)));
+ };
+ };
+
+ // Bind all of an object's methods to that object. Useful for ensuring that
+ // all callbacks defined on an object belong to it.
+ _.bindAll = function(obj) {
+ var funcs = slice.call(arguments, 1);
+ if (funcs.length === 0) throw new Error("bindAll must be passed function names");
+ each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
+ return obj;
+ };
+
+ // Memoize an expensive function by storing its results.
+ _.memoize = function(func, hasher) {
+ var memo = {};
+ hasher || (hasher = _.identity);
+ return function() {
+ var key = hasher.apply(this, arguments);
+ return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
+ };
+ };
+
+ // Delays a function for the given number of milliseconds, and then calls
+ // it with the arguments supplied.
+ _.delay = function(func, wait) {
+ var args = slice.call(arguments, 2);
+ return setTimeout(function(){ return func.apply(null, args); }, wait);
+ };
+
+ // Defers a function, scheduling it to run after the current call stack has
+ // cleared.
+ _.defer = function(func) {
+ return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
+ };
+
+ // Returns a function, that, when invoked, will only be triggered at most once
+ // during a given window of time. Normally, the throttled function will run
+ // as much as it can, without ever going more than once per `wait` duration;
+ // but if you'd like to disable the execution on the leading edge, pass
+ // `{leading: false}`. To disable execution on the trailing edge, ditto.
+ _.throttle = function(func, wait, options) {
+ var context, args, result;
+ var timeout = null;
+ var previous = 0;
+ options || (options = {});
+ var later = function() {
+ previous = options.leading === false ? 0 : new Date;
+ timeout = null;
+ result = func.apply(context, args);
+ };
+ return function() {
+ var now = new Date;
+ if (!previous && options.leading === false) previous = now;
+ var remaining = wait - (now - previous);
+ context = this;
+ args = arguments;
+ if (remaining <= 0) {
+ clearTimeout(timeout);
+ timeout = null;
+ previous = now;
+ result = func.apply(context, args);
+ } else if (!timeout && options.trailing !== false) {
+ timeout = setTimeout(later, remaining);
+ }
+ return result;
+ };
+ };
+
+ // Returns a function, that, as long as it continues to be invoked, will not
+ // be triggered. The function will be called after it stops being called for
+ // N milliseconds. If `immediate` is passed, trigger the function on the
+ // leading edge, instead of the trailing.
+ _.debounce = function(func, wait, immediate) {
+ var result;
+ var timeout = null;
+ return function() {
+ var context = this, args = arguments;
+ var later = function() {
+ timeout = null;
+ if (!immediate) result = func.apply(context, args);
+ };
+ var callNow = immediate && !timeout;
+ clearTimeout(timeout);
+ timeout = setTimeout(later, wait);
+ if (callNow) result = func.apply(context, args);
+ return result;
+ };
+ };
+
+ // Returns a function that will be executed at most one time, no matter how
+ // often you call it. Useful for lazy initialization.
+ _.once = function(func) {
+ var ran = false, memo;
+ return function() {
+ if (ran) return memo;
+ ran = true;
+ memo = func.apply(this, arguments);
+ func = null;
+ return memo;
+ };
+ };
+
+ // Returns the first function passed as an argument to the second,
+ // allowing you to adjust arguments, run code before and after, and
+ // conditionally execute the original function.
+ _.wrap = function(func, wrapper) {
+ return function() {
+ var args = [func];
+ push.apply(args, arguments);
+ return wrapper.apply(this, args);
+ };
+ };
+
+ // Returns a function that is the composition of a list of functions, each
+ // consuming the return value of the function that follows.
+ _.compose = function() {
+ var funcs = arguments;
+ return function() {
+ var args = arguments;
+ for (var i = funcs.length - 1; i >= 0; i--) {
+ args = [funcs[i].apply(this, args)];
+ }
+ return args[0];
+ };
+ };
+
+ // Returns a function that will only be executed after being called N times.
+ _.after = function(times, func) {
+ return function() {
+ if (--times < 1) {
+ return func.apply(this, arguments);
+ }
+ };
+ };
+
+ // Object Functions
+ // ----------------
+
+ // Retrieve the names of an object's properties.
+ // Delegates to **ECMAScript 5**'s native `Object.keys`
+ _.keys = nativeKeys || function(obj) {
+ if (obj !== Object(obj)) throw new TypeError('Invalid object');
+ var keys = [];
+ for (var key in obj) if (_.has(obj, key)) keys.push(key);
+ return keys;
+ };
+
+ // Retrieve the values of an object's properties.
+ _.values = function(obj) {
+ var values = [];
+ for (var key in obj) if (_.has(obj, key)) values.push(obj[key]);
+ return values;
+ };
+
+ // Convert an object into a list of `[key, value]` pairs.
+ _.pairs = function(obj) {
+ var pairs = [];
+ for (var key in obj) if (_.has(obj, key)) pairs.push([key, obj[key]]);
+ return pairs;
+ };
+
+ // Invert the keys and values of an object. The values must be serializable.
+ _.invert = function(obj) {
+ var result = {};
+ for (var key in obj) if (_.has(obj, key)) result[obj[key]] = key;
+ return result;
+ };
+
+ // Return a sorted list of the function names available on the object.
+ // Aliased as `methods`
+ _.functions = _.methods = function(obj) {
+ var names = [];
+ for (var key in obj) {
+ if (_.isFunction(obj[key])) names.push(key);
+ }
+ return names.sort();
+ };
+
+ // Extend a given object with all the properties in passed-in object(s).
+ _.extend = function(obj) {
+ each(slice.call(arguments, 1), function(source) {
+ if (source) {
+ for (var prop in source) {
+ obj[prop] = source[prop];
+ }
+ }
+ });
+ return obj;
+ };
+
+ // Return a copy of the object only containing the whitelisted properties.
+ _.pick = function(obj) {
+ var copy = {};
+ var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
+ each(keys, function(key) {
+ if (key in obj) copy[key] = obj[key];
+ });
+ return copy;
+ };
+
+ // Return a copy of the object without the blacklisted properties.
+ _.omit = function(obj) {
+ var copy = {};
+ var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
+ for (var key in obj) {
+ if (!_.contains(keys, key)) copy[key] = obj[key];
+ }
+ return copy;
+ };
+
+ // Fill in a given object with default properties.
+ _.defaults = function(obj) {
+ each(slice.call(arguments, 1), function(source) {
+ if (source) {
+ for (var prop in source) {
+ if (obj[prop] === void 0) obj[prop] = source[prop];
+ }
+ }
+ });
+ return obj;
+ };
+
+ // Create a (shallow-cloned) duplicate of an object.
+ _.clone = function(obj) {
+ if (!_.isObject(obj)) return obj;
+ return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
+ };
+
+ // Invokes interceptor with the obj, and then returns obj.
+ // The primary purpose of this method is to "tap into" a method chain, in
+ // order to perform operations on intermediate results within the chain.
+ _.tap = function(obj, interceptor) {
+ interceptor(obj);
+ return obj;
+ };
+
+ // Internal recursive comparison function for `isEqual`.
+ var eq = function(a, b, aStack, bStack) {
+ // Identical objects are equal. `0 === -0`, but they aren't identical.
+ // See the [Harmony `egal` proposal](https://wiki.ecmascript.org/doku.php?id=harmony:egal).
+ if (a === b) return a !== 0 || 1 / a == 1 / b;
+ // A strict comparison is necessary because `null == undefined`.
+ if (a == null || b == null) return a === b;
+ // Unwrap any wrapped objects.
+ if (a instanceof _) a = a._wrapped;
+ if (b instanceof _) b = b._wrapped;
+ // Compare `[[Class]]` names.
+ var className = toString.call(a);
+ if (className != toString.call(b)) return false;
+ switch (className) {
+ // Strings, numbers, dates, and booleans are compared by value.
+ case '[object String]':
+ // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
+ // equivalent to `new String("5")`.
+ return a == String(b);
+ case '[object Number]':
+ // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
+ // other numeric values.
+ return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
+ case '[object Date]':
+ case '[object Boolean]':
+ // Coerce dates and booleans to numeric primitive values. Dates are compared by their
+ // millisecond representations. Note that invalid dates with millisecond representations
+ // of `NaN` are not equivalent.
+ return +a == +b;
+ // RegExps are compared by their source patterns and flags.
+ case '[object RegExp]':
+ return a.source == b.source &&
+ a.global == b.global &&
+ a.multiline == b.multiline &&
+ a.ignoreCase == b.ignoreCase;
+ }
+ if (typeof a != 'object' || typeof b != 'object') return false;
+ // Assume equality for cyclic structures. The algorithm for detecting cyclic
+ // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
+ var length = aStack.length;
+ while (length--) {
+ // Linear search. Performance is inversely proportional to the number of
+ // unique nested structures.
+ if (aStack[length] == a) return bStack[length] == b;
+ }
+ // Objects with different constructors are not equivalent, but `Object`s
+ // from different frames are.
+ var aCtor = a.constructor, bCtor = b.constructor;
+ if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&
+ _.isFunction(bCtor) && (bCtor instanceof bCtor))) {
+ return false;
+ }
+ // Add the first object to the stack of traversed objects.
+ aStack.push(a);
+ bStack.push(b);
+ var size = 0, result = true;
+ // Recursively compare objects and arrays.
+ if (className == '[object Array]') {
+ // Compare array lengths to determine if a deep comparison is necessary.
+ size = a.length;
+ result = size == b.length;
+ if (result) {
+ // Deep compare the contents, ignoring non-numeric properties.
+ while (size--) {
+ if (!(result = eq(a[size], b[size], aStack, bStack))) break;
+ }
+ }
+ } else {
+ // Deep compare objects.
+ for (var key in a) {
+ if (_.has(a, key)) {
+ // Count the expected number of properties.
+ size++;
+ // Deep compare each member.
+ if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
+ }
+ }
+ // Ensure that both objects contain the same number of properties.
+ if (result) {
+ for (key in b) {
+ if (_.has(b, key) && !(size--)) break;
+ }
+ result = !size;
+ }
+ }
+ // Remove the first object from the stack of traversed objects.
+ aStack.pop();
+ bStack.pop();
+ return result;
+ };
+
+ // Perform a deep comparison to check if two objects are equal.
+ _.isEqual = function(a, b) {
+ return eq(a, b, [], []);
+ };
+
+ // Is a given array, string, or object empty?
+ // An "empty" object has no enumerable own-properties.
+ _.isEmpty = function(obj) {
+ if (obj == null) return true;
+ if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
+ for (var key in obj) if (_.has(obj, key)) return false;
+ return true;
+ };
+
+ // Is a given value a DOM element?
+ _.isElement = function(obj) {
+ return !!(obj && obj.nodeType === 1);
+ };
+
+ // Is a given value an array?
+ // Delegates to ECMA5's native Array.isArray
+ _.isArray = nativeIsArray || function(obj) {
+ return toString.call(obj) == '[object Array]';
+ };
+
+ // Is a given variable an object?
+ _.isObject = function(obj) {
+ return obj === Object(obj);
+ };
+
+ // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
+ each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
+ _['is' + name] = function(obj) {
+ return toString.call(obj) == '[object ' + name + ']';
+ };
+ });
+
+ // Define a fallback version of the method in browsers (ahem, IE), where
+ // there isn't any inspectable "Arguments" type.
+ if (!_.isArguments(arguments)) {
+ _.isArguments = function(obj) {
+ return !!(obj && _.has(obj, 'callee'));
+ };
+ }
+
+ // Optimize `isFunction` if appropriate.
+ if (typeof (/./) !== 'function') {
+ _.isFunction = function(obj) {
+ return typeof obj === 'function';
+ };
+ }
+
+ // Is a given object a finite number?
+ _.isFinite = function(obj) {
+ return isFinite(obj) && !isNaN(parseFloat(obj));
+ };
+
+ // Is the given value `NaN`? (NaN is the only number which does not equal itself).
+ _.isNaN = function(obj) {
+ return _.isNumber(obj) && obj != +obj;
+ };
+
+ // Is a given value a boolean?
+ _.isBoolean = function(obj) {
+ return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
+ };
+
+ // Is a given value equal to null?
+ _.isNull = function(obj) {
+ return obj === null;
+ };
+
+ // Is a given variable undefined?
+ _.isUndefined = function(obj) {
+ return obj === void 0;
+ };
+
+ // Shortcut function for checking if an object has a given property directly
+ // on itself (in other words, not on a prototype).
+ _.has = function(obj, key) {
+ return hasOwnProperty.call(obj, key);
+ };
+
+ // Utility Functions
+ // -----------------
+
+ // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
+ // previous owner. Returns a reference to the Underscore object.
+ _.noConflict = function() {
+ root._ = previousUnderscore;
+ return this;
+ };
+
+ // Keep the identity function around for default iterators.
+ _.identity = function(value) {
+ return value;
+ };
+
+ // Run a function **n** times.
+ _.times = function(n, iterator, context) {
+ var accum = Array(Math.max(0, n));
+ for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);
+ return accum;
+ };
+
+ // Return a random integer between min and max (inclusive).
+ _.random = function(min, max) {
+ if (max == null) {
+ max = min;
+ min = 0;
+ }
+ return min + Math.floor(Math.random() * (max - min + 1));
+ };
+
+ // List of HTML entities for escaping.
+ var entityMap = {
+ escape: {
+ '&': '&',
+ '<': '<',
+ '>': '>',
+ '"': '"',
+ "'": ''',
+ '/': '/'
+ }
+ };
+ entityMap.unescape = _.invert(entityMap.escape);
+
+ // Regexes containing the keys and values listed immediately above.
+ var entityRegexes = {
+ escape: new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'),
+ unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')
+ };
+
+ // Functions for escaping and unescaping strings to/from HTML interpolation.
+ _.each(['escape', 'unescape'], function(method) {
+ _[method] = function(string) {
+ if (string == null) return '';
+ return ('' + string).replace(entityRegexes[method], function(match) {
+ return entityMap[method][match];
+ });
+ };
+ });
+
+ // If the value of the named `property` is a function then invoke it with the
+ // `object` as context; otherwise, return it.
+ _.result = function(object, property) {
+ if (object == null) return void 0;
+ var value = object[property];
+ return _.isFunction(value) ? value.call(object) : value;
+ };
+
+ // Add your own custom functions to the Underscore object.
+ _.mixin = function(obj) {
+ each(_.functions(obj), function(name){
+ var func = _[name] = obj[name];
+ _.prototype[name] = function() {
+ var args = [this._wrapped];
+ push.apply(args, arguments);
+ return result.call(this, func.apply(_, args));
+ };
+ });
+ };
+
+ // Generate a unique integer id (unique within the entire client session).
+ // Useful for temporary DOM ids.
+ var idCounter = 0;
+ _.uniqueId = function(prefix) {
+ var id = ++idCounter + '';
+ return prefix ? prefix + id : id;
+ };
+
+ // By default, Underscore uses ERB-style template delimiters, change the
+ // following template settings to use alternative delimiters.
+ _.templateSettings = {
+ evaluate : /<%([\s\S]+?)%>/g,
+ interpolate : /<%=([\s\S]+?)%>/g,
+ escape : /<%-([\s\S]+?)%>/g
+ };
+
+ // When customizing `templateSettings`, if you don't want to define an
+ // interpolation, evaluation or escaping regex, we need one that is
+ // guaranteed not to match.
+ var noMatch = /(.)^/;
+
+ // Certain characters need to be escaped so that they can be put into a
+ // string literal.
+ var escapes = {
+ "'": "'",
+ '\\': '\\',
+ '\r': 'r',
+ '\n': 'n',
+ '\t': 't',
+ '\u2028': 'u2028',
+ '\u2029': 'u2029'
+ };
+
+ var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
+
+ // JavaScript micro-templating, similar to John Resig's implementation.
+ // Underscore templating handles arbitrary delimiters, preserves whitespace,
+ // and correctly escapes quotes within interpolated code.
+ _.template = function(text, data, settings) {
+ var render;
+ settings = _.defaults({}, settings, _.templateSettings);
+
+ // Combine delimiters into one regular expression via alternation.
+ var matcher = new RegExp([
+ (settings.escape || noMatch).source,
+ (settings.interpolate || noMatch).source,
+ (settings.evaluate || noMatch).source
+ ].join('|') + '|$', 'g');
+
+ // Compile the template source, escaping string literals appropriately.
+ var index = 0;
+ var source = "__p+='";
+ text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
+ source += text.slice(index, offset)
+ .replace(escaper, function(match) { return '\\' + escapes[match]; });
+
+ if (escape) {
+ source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
+ }
+ if (interpolate) {
+ source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
+ }
+ if (evaluate) {
+ source += "';\n" + evaluate + "\n__p+='";
+ }
+ index = offset + match.length;
+ return match;
+ });
+ source += "';\n";
+
+ // If a variable is not specified, place data values in local scope.
+ if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
+
+ source = "var __t,__p='',__j=Array.prototype.join," +
+ "print=function(){__p+=__j.call(arguments,'');};\n" +
+ source + "return __p;\n";
+
+ try {
+ render = new Function(settings.variable || 'obj', '_', source);
+ } catch (e) {
+ e.source = source;
+ throw e;
+ }
+
+ if (data) return render(data, _);
+ var template = function(data) {
+ return render.call(this, data, _);
+ };
+
+ // Provide the compiled function source as a convenience for precompilation.
+ template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
+
+ return template;
+ };
+
+ // Add a "chain" function, which will delegate to the wrapper.
+ _.chain = function(obj) {
+ return _(obj).chain();
+ };
+
+ // OOP
+ // ---------------
+ // If Underscore is called as a function, it returns a wrapped object that
+ // can be used OO-style. This wrapper holds altered versions of all the
+ // underscore functions. Wrapped objects may be chained.
+
+ // Helper function to continue chaining intermediate results.
+ var result = function(obj) {
+ return this._chain ? _(obj).chain() : obj;
+ };
+
+ // Add all of the Underscore functions to the wrapper object.
+ _.mixin(_);
+
+ // Add all mutator Array functions to the wrapper.
+ each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
+ var method = ArrayProto[name];
+ _.prototype[name] = function() {
+ var obj = this._wrapped;
+ method.apply(obj, arguments);
+ if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];
+ return result.call(this, obj);
+ };
+ });
+
+ // Add all accessor Array functions to the wrapper.
+ each(['concat', 'join', 'slice'], function(name) {
+ var method = ArrayProto[name];
+ _.prototype[name] = function() {
+ return result.call(this, method.apply(this._wrapped, arguments));
+ };
+ });
+
+ _.extend(_.prototype, {
+
+ // Start chaining a wrapped Underscore object.
+ chain: function() {
+ this._chain = true;
+ return this;
+ },
+
+ // Extracts the result from a wrapped and chained object.
+ value: function() {
+ return this._wrapped;
+ }
+
+ });
+
+}).call(this);
diff --git a/multi/css/highlight.css b/multi/css/highlight.css
new file mode 100644
index 00000000..ffefef72
--- /dev/null
+++ b/multi/css/highlight.css
@@ -0,0 +1,35 @@
+/*
+ code highlight CSS resemblign the Eclipse IDE default color schema
+ @author Costin Leau
+*/
+
+.hl-keyword {
+ color: #7F0055;
+ font-weight: bold;
+}
+
+.hl-comment {
+ color: #3F5F5F;
+ font-style: italic;
+}
+
+.hl-multiline-comment {
+ color: #3F5FBF;
+ font-style: italic;
+}
+
+.hl-tag {
+ color: #3F7F7F;
+}
+
+.hl-attribute {
+ color: #7F007F;
+}
+
+.hl-value {
+ color: #2A00FF;
+}
+
+.hl-string {
+ color: #2A00FF;
+}
\ No newline at end of file
diff --git a/multi/css/manual-multipage.css b/multi/css/manual-multipage.css
new file mode 100644
index 00000000..0c484531
--- /dev/null
+++ b/multi/css/manual-multipage.css
@@ -0,0 +1,9 @@
+@IMPORT url("manual.css");
+
+body.firstpage {
+ background: url("../images/background.png") no-repeat center top;
+}
+
+div.part h1 {
+ border-top: none;
+}
diff --git a/multi/css/manual-singlepage.css b/multi/css/manual-singlepage.css
new file mode 100644
index 00000000..4a7fd140
--- /dev/null
+++ b/multi/css/manual-singlepage.css
@@ -0,0 +1,6 @@
+@IMPORT url("manual.css");
+
+body {
+ background: url("../images/background.png") no-repeat center top;
+}
+
diff --git a/multi/css/manual.css b/multi/css/manual.css
new file mode 100644
index 00000000..0ecbe2e8
--- /dev/null
+++ b/multi/css/manual.css
@@ -0,0 +1,344 @@
+@IMPORT url("highlight.css");
+
+html {
+ padding: 0pt;
+ margin: 0pt;
+}
+
+body {
+ color: #333333;
+ margin: 15px 30px;
+ font-family: Helvetica, Arial, Freesans, Clean, Sans-serif;
+ line-height: 1.6;
+ -webkit-font-smoothing: antialiased;
+}
+
+code {
+ font-size: 16px;
+ font-family: Consolas, "Liberation Mono", Courier, monospace;
+}
+
+:not(a)>code {
+ color: #6D180B;
+}
+
+:not(pre)>code {
+ background-color: #F2F2F2;
+ border: 1px solid #CCCCCC;
+ border-radius: 4px;
+ padding: 1px 3px 0;
+ text-shadow: none;
+ white-space: nowrap;
+}
+
+body>*:first-child {
+ margin-top: 0 !important;
+}
+
+div {
+ margin: 0pt;
+}
+
+hr {
+ border: 1px solid #CCCCCC;
+ background: #CCCCCC;
+}
+
+h1,h2,h3,h4,h5,h6 {
+ color: #000000;
+ cursor: text;
+ font-weight: bold;
+ margin: 30px 0 10px;
+ padding: 0;
+}
+
+h1,h2,h3 {
+ margin: 40px 0 10px;
+}
+
+h1 {
+ margin: 70px 0 30px;
+ padding-top: 20px;
+}
+
+div.part h1 {
+ border-top: 1px dotted #CCCCCC;
+}
+
+h1,h1 code {
+ font-size: 32px;
+}
+
+h2,h2 code {
+ font-size: 24px;
+}
+
+h3,h3 code {
+ font-size: 20px;
+}
+
+h4,h1 code,h5,h5 code,h6,h6 code {
+ font-size: 18px;
+}
+
+div.book,div.chapter,div.appendix,div.part,div.preface {
+ min-width: 300px;
+ max-width: 1200px;
+ margin: 0 auto;
+}
+
+p.releaseinfo {
+ font-weight: bold;
+ margin-bottom: 40px;
+ margin-top: 40px;
+}
+
+div.authorgroup {
+ line-height: 1;
+}
+
+p.copyright {
+ line-height: 1;
+ margin-bottom: -5px;
+}
+
+.legalnotice p {
+ font-style: italic;
+ font-size: 14px;
+ line-height: 1;
+}
+
+div.titlepage+p,div.titlepage+p {
+ margin-top: 0;
+}
+
+pre {
+ line-height: 1.0;
+ color: black;
+}
+
+a {
+ color: #4183C4;
+ text-decoration: none;
+}
+
+p {
+ margin: 15px 0;
+ text-align: left;
+}
+
+ul,ol {
+ padding-left: 30px;
+}
+
+li p {
+ margin: 0;
+}
+
+div.table {
+ margin: 1em;
+ padding: 0.5em;
+ text-align: center;
+}
+
+div.table table,div.informaltable table {
+ display: table;
+ width: 100%;
+}
+
+div.table td {
+ padding-left: 7px;
+ padding-right: 7px;
+}
+
+.sidebar {
+ line-height: 1.4;
+ padding: 0 20px;
+ background-color: #F8F8F8;
+ border: 1px solid #CCCCCC;
+ border-radius: 3px 3px 3px 3px;
+}
+
+.sidebar p.title {
+ color: #6D180B;
+}
+
+pre.programlisting,pre.screen {
+ font-size: 15px;
+ padding: 6px 10px;
+ background-color: #F8F8F8;
+ border: 1px solid #CCCCCC;
+ border-radius: 3px 3px 3px 3px;
+ clear: both;
+ overflow: auto;
+ line-height: 1.4;
+ font-family: Consolas, "Liberation Mono", Courier, monospace;
+}
+
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+ border: 1px solid #DDDDDD !important;
+ border-radius: 4px !important;
+ border-collapse: separate !important;
+ line-height: 1.6;
+}
+
+table thead {
+ background: #F5F5F5;
+}
+
+table tr {
+ border: none;
+ border-bottom: none;
+}
+
+table th {
+ font-weight: bold;
+}
+
+table th,table td {
+ border: none !important;
+ padding: 6px 13px;
+}
+
+table tr:nth-child(2n) {
+ background-color: #F8F8F8;
+}
+
+td p {
+ margin: 0 0 15px 0;
+}
+
+div.table-contents td p {
+ margin: 0;
+}
+
+div.important *,div.note *,div.tip *,div.warning *,div.navheader *,div.navfooter *,div.calloutlist *
+ {
+ border: none !important;
+ background: none !important;
+ margin: 0;
+}
+
+div.important p,div.note p,div.tip p,div.warning p {
+ color: #6F6F6F;
+ line-height: 1.6;
+}
+
+div.important code,div.note code,div.tip code,div.warning code {
+ background-color: #F2F2F2 !important;
+ border: 1px solid #CCCCCC !important;
+ border-radius: 4px !important;
+ padding: 1px 3px 0 !important;
+ text-shadow: none !important;
+ white-space: nowrap !important;
+}
+
+.note th,.tip th,.warning th {
+ display: none;
+}
+
+.note tr:first-child td,.tip tr:first-child td,.warning tr:first-child td
+ {
+ border-right: 1px solid #CCCCCC !important;
+ padding-top: 10px;
+}
+
+div.calloutlist p,div.calloutlist td {
+ padding: 0;
+ margin: 0;
+}
+
+div.calloutlist>table>tbody>tr>td:first-child {
+ padding-left: 10px;
+ width: 30px !important;
+}
+
+div.important,div.note,div.tip,div.warning {
+ margin-left: 0px !important;
+ margin-right: 20px !important;
+ margin-top: 20px;
+ margin-bottom: 20px;
+ padding-top: 10px;
+ padding-bottom: 10px;
+}
+
+div.toc {
+ line-height: 1.2;
+}
+
+dl,dt {
+ margin-top: 1px;
+ margin-bottom: 0;
+}
+
+div.toc>dl>dt {
+ font-size: 32px;
+ font-weight: bold;
+ margin: 30px 0 10px 0;
+ display: block;
+}
+
+div.toc>dl>dd>dl>dt {
+ font-size: 24px;
+ font-weight: bold;
+ margin: 20px 0 10px 0;
+ display: block;
+}
+
+div.toc>dl>dd>dl>dd>dl>dt {
+ font-weight: bold;
+ font-size: 20px;
+ margin: 10px 0 0 0;
+}
+
+tbody.footnotes * {
+ border: none !important;
+}
+
+div.footnote p {
+ margin: 0;
+ line-height: 1;
+}
+
+div.footnote p sup {
+ margin-right: 6px;
+ vertical-align: middle;
+}
+
+div.navheader {
+ border-bottom: 1px solid #CCCCCC;
+}
+
+div.navfooter {
+ border-top: 1px solid #CCCCCC;
+}
+
+.title {
+ margin-left: -1em;
+ padding-left: 1em;
+}
+
+.title>a {
+ position: absolute;
+ visibility: hidden;
+ display: block;
+ font-size: 0.85em;
+ margin-top: 0.05em;
+ margin-left: -1em;
+ vertical-align: text-top;
+ color: black;
+}
+
+.title>a:before {
+ content: "\00A7";
+}
+
+.title:hover>a,.title>a:hover,.title:hover>a:hover {
+ visibility: visible;
+}
+
+.title:focus>a,.title>a:focus,.title:focus>a:focus {
+ outline: 0;
+}
diff --git a/multi/images/background.png b/multi/images/background.png
new file mode 100644
index 00000000..15dca6fb
Binary files /dev/null and b/multi/images/background.png differ
diff --git a/multi/images/callouts/1.png b/multi/images/callouts/1.png
new file mode 100644
index 00000000..7d473430
Binary files /dev/null and b/multi/images/callouts/1.png differ
diff --git a/multi/images/callouts/2.png b/multi/images/callouts/2.png
new file mode 100644
index 00000000..5d09341b
Binary files /dev/null and b/multi/images/callouts/2.png differ
diff --git a/multi/images/callouts/3.png b/multi/images/callouts/3.png
new file mode 100644
index 00000000..ef7b7004
Binary files /dev/null and b/multi/images/callouts/3.png differ
diff --git a/multi/images/caution.png b/multi/images/caution.png
new file mode 100644
index 00000000..8a5e4fca
Binary files /dev/null and b/multi/images/caution.png differ
diff --git a/multi/images/important.png b/multi/images/important.png
new file mode 100644
index 00000000..ec54df65
Binary files /dev/null and b/multi/images/important.png differ
diff --git a/multi/images/logo.png b/multi/images/logo.png
new file mode 100644
index 00000000..ade2ce6e
Binary files /dev/null and b/multi/images/logo.png differ
diff --git a/multi/images/note.png b/multi/images/note.png
new file mode 100644
index 00000000..88d997b1
Binary files /dev/null and b/multi/images/note.png differ
diff --git a/multi/images/sts_exception.png b/multi/images/sts_exception.png
new file mode 100644
index 00000000..8607c38a
Binary files /dev/null and b/multi/images/sts_exception.png differ
diff --git a/multi/images/tip.png b/multi/images/tip.png
new file mode 100644
index 00000000..6530abb4
Binary files /dev/null and b/multi/images/tip.png differ
diff --git a/multi/images/warning.png b/multi/images/warning.png
new file mode 100644
index 00000000..0d5b5244
Binary files /dev/null and b/multi/images/warning.png differ
diff --git a/multi/images/web-selected.png b/multi/images/web-selected.png
new file mode 100644
index 00000000..aa6b2da6
Binary files /dev/null and b/multi/images/web-selected.png differ
diff --git a/multi/multi__encryption_and_decryption.html b/multi/multi__encryption_and_decryption.html
new file mode 100644
index 00000000..a57f75aa
--- /dev/null
+++ b/multi/multi__encryption_and_decryption.html
@@ -0,0 +1,10 @@
+
+
+ 4. Encryption and Decryption 4. Encryption and DecryptionThe Spring Cloud CLI comes with an "encrypt" and a "decrypt"
+command. Both accept arguments in the same form with a key specified
+as a mandatory "--key", e.g.
$ spring encrypt mysecret --key foo
+682bc583f4641835fa2db009355293665d2647dade3375c0ee201de2a49f7bda
+$ spring decrypt --key foo 682bc583f4641835fa2db009355293665d2647dade3375c0ee201de2a49f7bda
+mysecret To use a key in a file (e.g. an RSA public key for encyption) prepend
+the key value with "@" and provide the file path, e.g.
$ spring encrypt mysecret --key @${HOME}/.ssh/id_rsa.pub
+AQAjPgt3eFZQXwt8tsHAVv/QHiY5sI2dRcR+...
\ No newline at end of file
diff --git a/multi/multi__installation.html b/multi/multi__installation.html
new file mode 100644
index 00000000..7e5c2c88
--- /dev/null
+++ b/multi/multi__installation.html
@@ -0,0 +1,13 @@
+
+
+ 1. Installation To install, make
+sure you have
+Spring Boot CLI
+(2.0.0 or better):
$ spring version
+Spring CLI v2.1.0.M4 E.g. for SDKMan users
$ sdk install springboot 2.1.0.M4
+$ sdk use springboot 2.1.0.M4 and install the Spring Cloud plugin
$ mvn install
+$ spring install org.springframework.cloud:spring-cloud-cli:2.1.0.BUILD-SNAPSHOT Important Prerequisites: to use the encryption and decryption features
+you need the full-strength JCE installed in your JVM (it’s not there by default).
+You can download the "Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files"
+from Oracle, and follow instructions for installation (essentially replace the 2 policy files
+in the JRE lib/security directory with the ones that you downloaded).
\ No newline at end of file
diff --git a/multi/multi__running_spring_cloud_services_in_development.html b/multi/multi__running_spring_cloud_services_in_development.html
new file mode 100644
index 00000000..bef72098
--- /dev/null
+++ b/multi/multi__running_spring_cloud_services_in_development.html
@@ -0,0 +1,36 @@
+
+
+ 2. Running Spring Cloud Services in Development 2. Running Spring Cloud Services in DevelopmentThe Launcher CLI can be used to run common services like Eureka,
+Config Server etc. from the command line. To list the available
+services you can do spring cloud --list, and to launch a default set
+of services just spring cloud. To choose the services to deploy,
+just list them on the command line, e.g.
$ spring cloud eureka configserver h2 kafka stubrunner zipkin Summary of supported deployables:
Each of these apps can be configured using a local YAML file with the same name (in the current
+working directory or a subdirectory called "config" or in ~/.spring-cloud). E.g. in configserver.yml you might want to
+do something like this to locate a local git repository for the backend:
configserver.yml.
+
spring :
+ profiles :
+ active : git
+ cloud :
+ config :
+ server :
+ git :
+ uri : file://${user.home}/dev/demo/config-repo
+
E.g. in Stub Runner app you could fetch stubs from your local .m2 in the following way.
stubrunner.yml.
+
stubrunner :
+ workOffline : true
+ ids :
+ - com.example :beer-api-producer:+:9876
+
2.1 Adding Additional ApplicationsAdditional applications can be added to ./config/cloud.yml (not
+./config.yml because that would replace the defaults), e.g. with
config/cloud.yml.
+
spring :
+ cloud :
+ launcher :
+ deployables :
+ source :
+ coordinates : maven://com.example:source:0.0 .1 -SNAPSHOT
+ port : 7000
+ sink :
+ coordinates : maven://com.example:sink:0.0 .1 -SNAPSHOT
+ port : 7001
+
when you list the apps:
$ spring cloud --list
+source sink configserver dataflow eureka h2 hystrixdashboard kafka stubrunner zipkin (notice the additional apps at the start of the list).
\ No newline at end of file
diff --git a/multi/multi__writing_groovy_scripts_and_running_applications.html b/multi/multi__writing_groovy_scripts_and_running_applications.html
new file mode 100644
index 00000000..10525196
--- /dev/null
+++ b/multi/multi__writing_groovy_scripts_and_running_applications.html
@@ -0,0 +1,21 @@
+
+
+ 3. Writing Groovy Scripts and Running Applications 3. Writing Groovy Scripts and Running ApplicationsSpring Cloud CLI has support for most of the Spring Cloud declarative
+features, such as the @Enable* class of annotations. For example,
+here is a fully functional Eureka server
app.groovy.
+
@EnableEurekaServer
+class Eureka {}
+
which you can run from the command line like this
$ spring run app.groovy To include additional dependencies, often it suffices just to add the
+appropriate feature-enabling annotation, e.g. @EnableConfigServer,
+@EnableOAuth2Sso or @EnableEurekaClient. To manually include a
+dependency you can use a @Grab with the special "Spring Boot" short
+style artifact co-ordinates, i.e. with just the artifact ID (no need
+for group or version information), e.g. to set up a client app to
+listen on AMQP for management events from the Spring CLoud Bus:
app.groovy.
+
@Grab('spring-cloud-starter-bus-amqp')
+@RestController
+class Service {
+ @RequestMapping('/')
+ def home() { [message: 'Hello' ] }
+}
+
\ No newline at end of file
diff --git a/multi/multi_pr01.html b/multi/multi_pr01.html
new file mode 100644
index 00000000..7f1a5e3c
--- /dev/null
+++ b/multi/multi_pr01.html
@@ -0,0 +1,11 @@
+
+
+ Spring Boot CLI provides Spring
+Boot command line features for Spring
+Cloud . You can write Groovy scripts to run Spring Cloud component
+applications (e.g. @EnableEurekaServer). You can also easily do
+things like encryption and decryption to support Spring Cloud Config
+clients with secret configuration values. With the Launcher CLI you
+can launch services like Eureka, Zipkin, Config Server
+conveniently all at once from the command line (very useful at
+development time).
Note Spring Cloud is released under the non-restrictive Apache 2.0 license. If you would like to contribute to this section of the documentation or if you find an error, please find the source code and issue trackers in the project at github .
\ No newline at end of file
diff --git a/multi/multi_spring-cloud-cli.html b/multi/multi_spring-cloud-cli.html
new file mode 100644
index 00000000..48e6a8f9
--- /dev/null
+++ b/multi/multi_spring-cloud-cli.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+Page Redirection
+
+If you are not redirected automatically, follow the link to latest snapshot documentation
diff --git a/mvnw b/mvnw
deleted file mode 100755
index a08b219e..00000000
--- a/mvnw
+++ /dev/null
@@ -1,253 +0,0 @@
-#!/bin/sh
-# ----------------------------------------------------------------------------
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-# ----------------------------------------------------------------------------
-
-# ----------------------------------------------------------------------------
-# Maven2 Start Up Batch script
-#
-# Required ENV vars:
-# ------------------
-# JAVA_HOME - location of a JDK home dir
-#
-# Optional ENV vars
-# -----------------
-# M2_HOME - location of maven2's installed home dir
-# MAVEN_OPTS - parameters passed to the Java VM when running Maven
-# e.g. to debug Maven itself, use
-# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
-# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
-# ----------------------------------------------------------------------------
-
-if [ -z "$MAVEN_SKIP_RC" ] ; then
-
- if [ -f /etc/mavenrc ] ; then
- . /etc/mavenrc
- fi
-
- if [ -f "$HOME/.mavenrc" ] ; then
- . "$HOME/.mavenrc"
- fi
-
-fi
-
-# OS specific support. $var _must_ be set to either true or false.
-cygwin=false;
-darwin=false;
-mingw=false
-case "`uname`" in
- CYGWIN*) cygwin=true ;;
- MINGW*) mingw=true;;
- Darwin*) darwin=true
- #
- # Look for the Apple JDKs first to preserve the existing behaviour, and then look
- # for the new JDKs provided by Oracle.
- #
- if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then
- #
- # Apple JDKs
- #
- export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home
- fi
-
- if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then
- #
- # Apple JDKs
- #
- export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home
- fi
-
- if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then
- #
- # Oracle JDKs
- #
- export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home
- fi
-
- if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then
- #
- # Apple JDKs
- #
- export JAVA_HOME=`/usr/libexec/java_home`
- fi
- ;;
-esac
-
-if [ -z "$JAVA_HOME" ] ; then
- if [ -r /etc/gentoo-release ] ; then
- JAVA_HOME=`java-config --jre-home`
- fi
-fi
-
-if [ -z "$M2_HOME" ] ; then
- ## resolve links - $0 may be a link to maven's home
- PRG="$0"
-
- # need this for relative symlinks
- while [ -h "$PRG" ] ; do
- ls=`ls -ld "$PRG"`
- link=`expr "$ls" : '.*-> \(.*\)$'`
- if expr "$link" : '/.*' > /dev/null; then
- PRG="$link"
- else
- PRG="`dirname "$PRG"`/$link"
- fi
- done
-
- saveddir=`pwd`
-
- M2_HOME=`dirname "$PRG"`/..
-
- # make it fully qualified
- M2_HOME=`cd "$M2_HOME" && pwd`
-
- cd "$saveddir"
- # echo Using m2 at $M2_HOME
-fi
-
-# For Cygwin, ensure paths are in UNIX format before anything is touched
-if $cygwin ; then
- [ -n "$M2_HOME" ] &&
- M2_HOME=`cygpath --unix "$M2_HOME"`
- [ -n "$JAVA_HOME" ] &&
- JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
- [ -n "$CLASSPATH" ] &&
- CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
-fi
-
-# For Migwn, ensure paths are in UNIX format before anything is touched
-if $mingw ; then
- [ -n "$M2_HOME" ] &&
- M2_HOME="`(cd "$M2_HOME"; pwd)`"
- [ -n "$JAVA_HOME" ] &&
- JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
- # TODO classpath?
-fi
-
-if [ -z "$JAVA_HOME" ]; then
- javaExecutable="`which javac`"
- if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
- # readlink(1) is not available as standard on Solaris 10.
- readLink=`which readlink`
- if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
- if $darwin ; then
- javaHome="`dirname \"$javaExecutable\"`"
- javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
- else
- javaExecutable="`readlink -f \"$javaExecutable\"`"
- fi
- javaHome="`dirname \"$javaExecutable\"`"
- javaHome=`expr "$javaHome" : '\(.*\)/bin'`
- JAVA_HOME="$javaHome"
- export JAVA_HOME
- fi
- fi
-fi
-
-if [ -z "$JAVACMD" ] ; then
- if [ -n "$JAVA_HOME" ] ; then
- if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
- # IBM's JDK on AIX uses strange locations for the executables
- JAVACMD="$JAVA_HOME/jre/sh/java"
- else
- JAVACMD="$JAVA_HOME/bin/java"
- fi
- else
- JAVACMD="`which java`"
- fi
-fi
-
-if [ ! -x "$JAVACMD" ] ; then
- echo "Error: JAVA_HOME is not defined correctly." >&2
- echo " We cannot execute $JAVACMD" >&2
- exit 1
-fi
-
-if [ -z "$JAVA_HOME" ] ; then
- echo "Warning: JAVA_HOME environment variable is not set."
-fi
-
-CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
-
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin; then
- [ -n "$M2_HOME" ] &&
- M2_HOME=`cygpath --path --windows "$M2_HOME"`
- [ -n "$JAVA_HOME" ] &&
- JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
- [ -n "$CLASSPATH" ] &&
- CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
-fi
-
-# traverses directory structure from process work directory to filesystem root
-# first directory with .mvn subdirectory is considered project base directory
-find_maven_basedir() {
- local basedir=$(pwd)
- local wdir=$(pwd)
- while [ "$wdir" != '/' ] ; do
- if [ -d "$wdir"/.mvn ] ; then
- basedir=$wdir
- break
- fi
- wdir=$(cd "$wdir/.."; pwd)
- done
- echo "${basedir}"
-}
-
-# concatenates all lines of a file
-concat_lines() {
- if [ -f "$1" ]; then
- echo "$(tr -s '\n' ' ' < "$1")"
- fi
-}
-
-export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)}
-MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
-
-# Provide a "standardized" way to retrieve the CLI args that will
-# work with both Windows and non-Windows executions.
-MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
-export MAVEN_CMD_LINE_ARGS
-
-WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
-
-echo "Running version check"
-VERSION=$( sed '\!//' -e 's!.*$!!' )
-echo "The found version is [${VERSION}]"
-
-if echo $VERSION | egrep -q 'M|RC'; then
- echo Activating \"milestone\" profile for version=\"$VERSION\"
- echo $MAVEN_ARGS | grep -q milestone || MAVEN_ARGS="$MAVEN_ARGS -Pmilestone"
-else
- echo Deactivating \"milestone\" profile for version=\"$VERSION\"
- echo $MAVEN_ARGS | grep -q milestone && MAVEN_ARGS=$(echo $MAVEN_ARGS | sed -e 's/-Pmilestone//')
-fi
-
-if echo $VERSION | egrep -q 'RELEASE'; then
- echo Activating \"central\" profile for version=\"$VERSION\"
- echo $MAVEN_ARGS | grep -q milestone || MAVEN_ARGS="$MAVEN_ARGS -Pcentral"
-else
- echo Deactivating \"central\" profile for version=\"$VERSION\"
- echo $MAVEN_ARGS | grep -q central && MAVEN_ARGS=$(echo $MAVEN_ARGS | sed -e 's/-Pcentral//')
-fi
-
-exec "$JAVACMD" \
- $MAVEN_OPTS \
- -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
- "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
- ${WRAPPER_LAUNCHER} ${MAVEN_ARGS} "$@"
diff --git a/mvnw.cmd b/mvnw.cmd
deleted file mode 100644
index eb9a292a..00000000
--- a/mvnw.cmd
+++ /dev/null
@@ -1,145 +0,0 @@
-@REM ----------------------------------------------------------------------------
-@REM Licensed to the Apache Software Foundation (ASF) under one
-@REM or more contributor license agreements. See the NOTICE file
-@REM distributed with this work for additional information
-@REM regarding copyright ownership. The ASF licenses this file
-@REM to you under the Apache License, Version 2.0 (the
-@REM "License"); you may not use this file except in compliance
-@REM with the License. You may obtain a copy of the License at
-@REM
-@REM https://www.apache.org/licenses/LICENSE-2.0
-@REM
-@REM Unless required by applicable law or agreed to in writing,
-@REM software distributed under the License is distributed on an
-@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-@REM KIND, either express or implied. See the License for the
-@REM specific language governing permissions and limitations
-@REM under the License.
-@REM ----------------------------------------------------------------------------
-
-@REM ----------------------------------------------------------------------------
-@REM Maven2 Start Up Batch script
-@REM
-@REM Required ENV vars:
-@REM JAVA_HOME - location of a JDK home dir
-@REM
-@REM Optional ENV vars
-@REM M2_HOME - location of maven2's installed home dir
-@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
-@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
-@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
-@REM e.g. to debug Maven itself, use
-@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
-@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
-@REM ----------------------------------------------------------------------------
-
-@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
-@echo off
-@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
-@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
-
-@REM set %HOME% to equivalent of $HOME
-if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
-
-@REM Execute a user defined script before this one
-if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
-@REM check for pre script, once with legacy .bat ending and once with .cmd ending
-if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
-if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
-:skipRcPre
-
-@setlocal
-
-set ERROR_CODE=0
-
-@REM To isolate internal variables from possible post scripts, we use another setlocal
-@setlocal
-
-@REM ==== START VALIDATION ====
-if not "%JAVA_HOME%" == "" goto OkJHome
-
-echo.
-echo Error: JAVA_HOME not found in your environment. >&2
-echo Please set the JAVA_HOME variable in your environment to match the >&2
-echo location of your Java installation. >&2
-echo.
-goto error
-
-:OkJHome
-if exist "%JAVA_HOME%\bin\java.exe" goto init
-
-echo.
-echo Error: JAVA_HOME is set to an invalid directory. >&2
-echo JAVA_HOME = "%JAVA_HOME%" >&2
-echo Please set the JAVA_HOME variable in your environment to match the >&2
-echo location of your Java installation. >&2
-echo.
-goto error
-
-@REM ==== END VALIDATION ====
-
-:init
-
-set MAVEN_CMD_LINE_ARGS=%*
-
-@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
-@REM Fallback to current working directory if not found.
-
-set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
-IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
-
-set EXEC_DIR=%CD%
-set WDIR=%EXEC_DIR%
-:findBaseDir
-IF EXIST "%WDIR%"\.mvn goto baseDirFound
-cd ..
-IF "%WDIR%"=="%CD%" goto baseDirNotFound
-set WDIR=%CD%
-goto findBaseDir
-
-:baseDirFound
-set MAVEN_PROJECTBASEDIR=%WDIR%
-cd "%EXEC_DIR%"
-goto endDetectBaseDir
-
-:baseDirNotFound
-set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
-cd "%EXEC_DIR%"
-
-:endDetectBaseDir
-
-IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
-
-@setlocal EnableExtensions EnableDelayedExpansion
-for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
-@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
-
-:endReadAdditionalConfig
-
-SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
-
-set WRAPPER_JAR="".\.mvn\wrapper\maven-wrapper.jar""
-set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
-
-%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS%
-if ERRORLEVEL 1 goto error
-goto end
-
-:error
-set ERROR_CODE=1
-
-:end
-@endlocal & set ERROR_CODE=%ERROR_CODE%
-
-if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
-@REM check for post script, once with legacy .bat ending and once with .cmd ending
-if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
-if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
-:skipRcPost
-
-@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
-if "%MAVEN_BATCH_PAUSE%" == "on" pause
-
-if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
-
-exit /B %ERROR_CODE%
diff --git a/pom.xml b/pom.xml
deleted file mode 100644
index a692c50b..00000000
--- a/pom.xml
+++ /dev/null
@@ -1,142 +0,0 @@
-
-
- 4.0.0
- org.springframework.cloud
- spring-cloud-cli-parent
- 3.1.2-SNAPSHOT
-
- org.springframework.cloud
- spring-cloud-build
- 3.1.4-SNAPSHOT
-
-
- pom
- Spring Cloud Cli Parent
- Spring Cloud Cli
- https://projects.spring.io/spring-cloud/
-
- https://github.com/spring-cloud/spring-cloud-cli
- scm:git:git://github.com/spring-cloud/spring-cloud-cli.git
-
-
- scm:git:ssh://git@github.com/spring-cloud/spring-cloud-cli.git
-
- HEAD
-
-
- cli
- spring-cloud-cli
- ${basedir}/..
- 2.6.8
- 2021.0.4-SNAPSHOT
-
-
- spring-cloud-launcher
- spring-cloud-cli
- spring-cloud-cli-integration-tests
- docs
-
-
-
-
- org.codehaus.mojo
- flatten-maven-plugin
-
-
-
-
-
- spring
-
-
- spring-snapshots
- Spring Snapshots
- https://repo.spring.io/snapshot
-
- true
-
-
- false
-
-
-
- spring-milestones
- Spring Milestones
- https://repo.spring.io/milestone
-
- false
-
-
-
- spring-releases
- Spring Releases
- https://repo.spring.io/release
-
- false
-
-
-
-
-
- spring-snapshots
- Spring Snapshots
- https://repo.spring.io/snapshot
-
- true
-
-
-
- spring-milestones
- Spring Milestones
- https://repo.spring.io/milestone
-
- false
-
-
-
- spring-releases
- Spring Releases
- https://repo.spring.io/release
-
- false
-
-
-
-
-
-
-
-
- org.springframework.boot
- spring-boot-dependencies
- ${spring-boot.version}
- pom
- import
-
-
- org.springframework.cloud
- spring-cloud-dependencies
- ${spring-cloud.version}
- pom
- import
-
-
- org.springframework.cloud
- spring-cloud-starter-stream-kafka
-
-
- org.apache.kafka
- kafka_2.11
-
-
-
-
- net.sf.jopt-simple
- jopt-simple
- 5.0.4
-
-
-
-
diff --git a/project-icon.md b/project-icon.md
new file mode 100644
index 00000000..56c63683
--- /dev/null
+++ b/project-icon.md
@@ -0,0 +1 @@
+{{include.link | markdownify }}
diff --git a/reference/html/README.html b/reference/html/README.html
new file mode 100644
index 00000000..fbe53246
--- /dev/null
+++ b/reference/html/README.html
@@ -0,0 +1,677 @@
+
+
+
+
+
+
+
+Installation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Spring Boot CLI provides Spring
+Boot command line features for Spring
+Cloud . You can write Groovy scripts to run Spring Cloud component
+applications (e.g. @EnableEurekaServer). You can also easily do
+things like encryption and decryption to support Spring Cloud Config
+clients with secret configuration values. With the Launcher CLI you
+can launch services like Eureka, Zipkin, Config Server
+conveniently all at once from the command line (very useful at
+development time).
+
+
+
+
+
+
+
+
+
+
$ spring version
+Spring CLI v2.2.0.BUILD-SNAPSHOT
+
+
+
+
+
+
$ sdk install springboot 2.2.0.BUILD-SNAPSHOT
+$ sdk use springboot 2.2.0.BUILD-SNAPSHOT
+
+
+
+
and install the Spring Cloud plugin
+
+
+
+
$ mvn install
+$ spring install org.springframework.cloud:spring-cloud-cli:2.2.0.BUILD-SNAPSHOT
+
+
+
+
+
+
+
+
+
+Prerequisites: to use the encryption and decryption features
+you need the full-strength JCE installed in your JVM (it’s not there by default).
+You can download the "Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files"
+from Oracle, and follow instructions for installation (essentially replace the 2 policy files
+in the JRE lib/security directory with the ones that you downloaded).
+
+
+
+
+
+
+
+
+
+
+
+
+
To build the source you will need to install JDK 1.7.
+
+
+
Spring Cloud uses Maven for most build-related activities, and you
+should be able to get off the ground quite quickly by cloning the
+project you are interested in and typing
+
+
+
+
+
+
+
+
+
+You can also install Maven (>=3.3.3) yourself and run the mvn command
+in place of ./mvnw in the examples below. If you do that you also
+might need to add -P spring if your local Maven settings do not
+contain repository declarations for spring pre-release artifacts.
+
+
+
+
+
+
+
+
+
+
+
+Be aware that you might need to increase the amount of memory
+available to Maven by setting a MAVEN_OPTS environment variable with
+a value like -Xmx512m -XX:MaxPermSize=128m. We try to cover this in
+the .mvn configuration, so if you find you have to do it to make a
+build succeed, please raise a ticket to get the settings added to
+source control.
+
+
+
+
+
+
For hints on how to build the project look in .travis.yml if there
+is one. There should be a "script" and maybe "install" command. Also
+look at the "services" section to see if any services need to be
+running locally (e.g. mongo or rabbit). Ignore the git-related bits
+that you might find in "before_install" since they’re related to setting git
+credentials and you already have those.
+
+
+
The projects that require middleware generally include a
+docker-compose.yml, so consider using
+Docker Compose to run the middeware servers
+in Docker containers. See the README in the
+scripts demo
+repository for specific instructions about the common cases of mongo,
+rabbit and redis.
+
+
+
+
+
+
+
+
+If all else fails, build with the command from .travis.yml (usually
+./mvnw install).
+
+
+
+
+
+
+
+
+
The spring-cloud-build module has a "docs" profile, and if you switch
+that on it will try to build asciidoc sources from
+src/main/asciidoc. As part of that process it will look for a
+README.adoc and process it by loading all the includes, but not
+parsing or rendering it, just copying it to ${main.basedir}
+(defaults to ${basedir}, i.e. the root of the project). If there are
+any changes in the README it will then show up after a Maven build as
+a modified file in the correct place. Just commit it and push the change.
+
+
+
+
+
+
If you don’t have an IDE preference we would recommend that you use
+Spring Tools Suite or
+Eclipse when working with the code. We use the
+m2eclipse eclipse plugin for maven support. Other IDEs and tools
+should also work without issue as long as they use Maven 3.3.3 or better.
+
+
+
+
+
Spring Cloud projects require the 'spring' Maven profile to be activated to resolve
+the spring milestone and snapshot repositories. Use your preferred IDE to set this
+profile to be active, or you may experience build errors.
+
+
+
+
+
+
We recommend the m2eclipse eclipse plugin when working with
+eclipse. If you don’t already have m2eclipse installed it is available from the "eclipse
+marketplace".
+
+
+
+
+
+
+
+
+Older versions of m2e do not support Maven 3.3, so once the
+projects are imported into Eclipse you will also need to tell
+m2eclipse to use the right profile for the projects. If you
+see many different errors related to the POMs in the projects, check
+that you have an up to date installation. If you can’t upgrade m2e,
+add the "spring" profile to your settings.xml. Alternatively you can
+copy the repository settings from the "spring" profile of the parent
+pom into your settings.xml.
+
+
+
+
+
+
+
+
+
If you prefer not to use m2eclipse you can generate eclipse project metadata using the
+following command:
+
+
+
+
$ ./mvnw eclipse:eclipse
+
+
+
+
The generated eclipse projects can be imported by selecting import existing projects
+from the file menu.
+
+
+
+
+
+
+
+
+
+
Spring Cloud is released under the non-restrictive Apache 2.0 license,
+and follows a very standard Github development process, using Github
+tracker for issues and merging pull requests into master. If you want
+to contribute even something trivial please do not hesitate, but
+follow the guidelines below.
+
+
+
+
+
Before we accept a non-trivial patch or pull request we will need you to sign the
+Contributor License Agreement .
+Signing the contributor’s agreement does not grant anyone commit rights to the main
+repository, but it does mean that we can accept your contributions, and you will get an
+author credit if we do. Active contributors might be asked to join the core team, and
+given the ability to merge pull requests.
+
+
+
+
+
+
+
None of these is essential for a pull request, but they will all help. They can also be
+added after the original pull request but before a merge.
+
+
+
+
+Use the Spring Framework code format conventions. If you use Eclipse
+you can import formatter settings using the
+eclipse-code-formatter.xml file from the
+Spring
+Cloud Build project. If using IntelliJ, you can use the
+Eclipse Code Formatter
+Plugin to import the same file.
+
+
+Make sure all new .java files to have a simple Javadoc class comment with at least an
+@author tag identifying you, and preferably at least a paragraph on what the class is
+for.
+
+
+Add the ASF license header comment to all new .java files (copy from existing files
+in the project)
+
+
+Add yourself as an @author to the .java files that you modify substantially (more
+than cosmetic changes).
+
+
+Add some Javadocs and, if you change the namespace, some XSD doc elements.
+
+
+A few unit tests would help a lot as well — someone has to do it.
+
+
+If no-one else is using your branch, please rebase it against the current master (or
+other target branch in the main project).
+
+
+When writing a commit message please follow these conventions ,
+if you are fixing an existing issue please add Fixes gh-XXXX at the end of the commit
+message (where XXXX is the issue number).
+
+
+
+
+
+
+
+
Spring Cloud Build comes with a set of checkstyle rules. You can find them in the spring-cloud-build-tools module. The most notable files under the module are:
+
+
+
spring-cloud-build-tools/
+
+
└── src
+ ├── checkstyle
+ │ └── checkstyle-suppressions.xml (3)
+ └── main
+ └── resources
+ ├── checkstyle-header.txt (2)
+ └── checkstyle.xml (1)
+
+
+
+
+
+1
+Default Checkstyle rules
+
+
+2
+File header setup
+
+
+3
+Default suppression rules
+
+
+
+
+
+
+
Checkstyle rules are disabled by default . To add checkstyle to your project just define the following properties and plugins.
+
+
+
pom.xml
+
+
<properties>
+<maven-checkstyle-plugin.failsOnError>true</maven-checkstyle-plugin.failsOnError> (1)
+ <maven-checkstyle-plugin.failsOnViolation>true
+ </maven-checkstyle-plugin.failsOnViolation> (2)
+ <maven-checkstyle-plugin.includeTestSourceDirectory>true
+ </maven-checkstyle-plugin.includeTestSourceDirectory> (3)
+</properties>
+
+<build>
+ <plugins>
+ <plugin> (4)
+ <groupId>io.spring.javaformat</groupId>
+ <artifactId>spring-javaformat-maven-plugin</artifactId>
+ </plugin>
+ <plugin> (5)
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ </plugin>
+ </plugins>
+
+ <reporting>
+ <plugins>
+ <plugin> (5)
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </reporting>
+</build>
+
+
+
+
+
+1
+Fails the build upon Checkstyle errors
+
+
+2
+Fails the build upon Checkstyle violations
+
+
+3
+Checkstyle analyzes also the test sources
+
+
+4
+Add the Spring Java Format plugin that will reformat your code to pass most of the Checkstyle formatting rules
+
+
+5
+Add checkstyle plugin to your build and reporting phases
+
+
+
+
+
If you need to suppress some rules (e.g. line length needs to be longer), then it’s enough for you to define a file under ${project.root}/src/checkstyle/checkstyle-suppressions.xml with your suppressions. Example:
+
+
+
projectRoot/src/checkstyle/checkstyle-suppresions.xml
+
+
<?xml version="1.0"?>
+<!DOCTYPE suppressions PUBLIC
+ "-//Puppy Crawl//DTD Suppressions 1.1//EN"
+ "https://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
+<suppressions>
+ <suppress files=".*ConfigServerApplication\.java" checks="HideUtilityClassConstructor"/>
+ <suppress files=".*ConfigClientWatch\.java" checks="LineLengthCheck"/>
+</suppressions>
+
+
+
+
It’s advisable to copy the ${spring-cloud-build.rootFolder}/.editorconfig and ${spring-cloud-build.rootFolder}/.springformat to your project. That way, some default formatting rules will be applied. You can do so by running this script:
+
+
+
+
$ curl https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/.editorconfig -o .editorconfig
+$ touch .springformat
+
+
+
+
+
+
+
+
+
+
In order to setup Intellij you should import our coding conventions, inspection profiles and set up the checkstyle plugin.
+The following files can be found in the Spring Cloud Build project.
+
+
+
spring-cloud-build-tools/
+
+
└── src
+ ├── checkstyle
+ │ └── checkstyle-suppressions.xml (3)
+ └── main
+ └── resources
+ ├── checkstyle-header.txt (2)
+ ├── checkstyle.xml (1)
+ └── intellij
+ ├── Intellij_Project_Defaults.xml (4)
+ └── Intellij_Spring_Boot_Java_Conventions.xml (5)
+
+
+
+
+
+1
+Default Checkstyle rules
+
+
+2
+File header setup
+
+
+3
+Default suppression rules
+
+
+4
+Project defaults for Intellij that apply most of Checkstyle rules
+
+
+5
+Project style conventions for Intellij that apply most of Checkstyle rules
+
+
+
+
+
+
+
+
Figure 1. Code style
+
+
+
Go to File → Settings → Editor → Code style. There click on the icon next to the Scheme section. There, click on the Import Scheme value and pick the Intellij IDEA code style XML option. Import the spring-cloud-build-tools/src/main/resources/intellij/Intellij_Spring_Boot_Java_Conventions.xml file.
+
+
+
+
+
+
Figure 2. Inspection profiles
+
+
+
Go to File → Settings → Editor → Inspections. There click on the icon next to the Profile section. There, click on the Import Profile and import the spring-cloud-build-tools/src/main/resources/intellij/Intellij_Project_Defaults.xml file.
+
+
+
Checkstyle
+
To have Intellij work with Checkstyle, you have to install the Checkstyle plugin. It’s advisable to also install the Assertions2Assertj to automatically convert the JUnit assertions
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Remember to set the Scan Scope to All sources since we apply checkstyle rules for production and test sources.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/reference/html/css/spring.css b/reference/html/css/spring.css
new file mode 100644
index 00000000..9366c397
--- /dev/null
+++ b/reference/html/css/spring.css
@@ -0,0 +1 @@
+@import url("https://fonts.googleapis.com/css?family=Open+Sans:400,700&display=swap");/*! normalize.css v2.1.2 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden],template{display:none}script{display:none !important}html,body{font-size:100%}html{font-family:'Open Sans', sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}*,*:before,*:after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}body{background:white;color:#000;padding:0;margin:0;font-size:16px;font-family:'Open Sans', sans-serif;font-weight:normal;font-style:normal;line-height:1.6em;position:relative;cursor:auto}a:hover{cursor:pointer}img,object,embed{max-width:100%;height:auto}object,embed{height:100%}img{-ms-interpolation-mode:bicubic}#map_canvas img,#map_canvas embed,#map_canvas object,.map_canvas img,.map_canvas embed,.map_canvas object{max-width:none !important}.left{float:left !important}.right{float:right !important}.text-left{text-align:left !important}.text-right{text-align:right !important}.text-center{text-align:center !important}.text-justify{text-align:justify !important}.hide{display:none}.antialiased{-webkit-font-smoothing:antialiased}img{display:inline-block;vertical-align:middle}textarea{height:auto;min-height:50px}select{width:100%}object,svg{display:inline-block;vertical-align:middle}.center{margin-left:auto;margin-right:auto}.spread,.stretch{width:100%}p.lead,.paragraph.lead>p,#preamble>.sectionbody>.paragraph:first-of-type p{line-height:1.6}.subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#0b0a0a;font-weight:bold;margin-top:0;margin-bottom:0.8em}div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0;direction:ltr}a{color:#086dc3;line-height:inherit;text-decoration:none}a:hover,a:focus{color:#086dc3;text-decoration:underline}a img{border:none}p{font-family:inherit;font-weight:normal;font-size:1em;line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility}p aside{font-size:0.875em;line-height:1.35;font-style:italic}h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:Montserrat, sans-serif;font-weight:400;font-style:normal;color:#000;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:0.5em;line-height:1.0125em}h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#867c74;line-height:0}h1{font-size:2.125em}h2{font-size:1.6875em}h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em}h4{font-size:1.125em}h5{font-size:1.125em}h6{font-size:1em}hr{border:solid #dce6e6;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em;height:0}em,i{font-style:italic;line-height:inherit}strong,b{font-weight:bold;line-height:inherit}small{font-size:60%;line-height:inherit}code{font-family:Monaco, Menlo, Consolas, "Courier New", monospace;font-weight:normal;color:#3d3d3c;word-break:break-word}a:not(pre)>code{border:1px solid #086dc3;color:#086dc3}ul,ol,dl{font-size:1em;line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit}ul,ol{margin-left:1.5em}ul.no-bullet,ol.no-bullet{margin-left:1.5em}ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0;font-size:1em}ul.square li ul,ul.circle li ul,ul.disc li ul{list-style:inherit}ul.square{list-style-type:square}ul.circle{list-style-type:circle}ul.disc{list-style-type:disc}ul.no-bullet{list-style:none}ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0}dl dt{margin-bottom:0.3125em;font-weight:bold}dl dd{margin-bottom:1.25em}abbr,acronym{text-transform:uppercase;font-size:90%;color:#000;border-bottom:1px dotted #dddddd;cursor:help}abbr{text-transform:none}blockquote{margin:0 0 1.25em;padding:0.5625em 1.25em 0 1.1875em;border-left:1px solid #dddddd}blockquote cite{display:block;font-size:0.9375em;color:rgba(0,0,0,0.6)}blockquote cite:before{content:"\2014 \0020"}blockquote cite a,blockquote cite a:visited{color:rgba(0,0,0,0.6)}blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,0.85)}.vcard{display:inline-block;margin:0 0 1.25em 0;border:1px solid #dddddd;padding:0.625em 0.75em}.vcard li{margin:0;display:block}.vcard .fn{font-weight:bold;font-size:0.9375em}.vevent .summary{font-weight:bold}.vevent abbr{cursor:auto;text-decoration:none;font-weight:bold;border:none;padding:0 0.0625em}#tocbot{padding:0 0 0.5rem 0;line-height:1.5rem;padding-left:10px}.mobile-toc{padding:0 0 1rem 0;line-height:1.5rem}.mobile-toc li a{display:block;padding:.3rem 0}#tocbot ol li{list-style:none;padding:0;margin:0}#tocbot ol{margin:0;padding:0}#tocbot ol ol{padding-left:0.6rem}#tocbot .toc-link{display:block;padding-top:.6rem;padding-bottom:.6rem;outline:none;border-radius:4px;font-size:15px;transition:all .15s}#tocbot .toc-link:hover{background:#ebf2f2;color:#06c;text-decoration:none}table{background:white;margin-bottom:1.25em;border:solid 1px #d4dfdf;border-spacing:0}table thead,table tfoot{background:#ebf2f2;font-weight:bold}table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:0.5em 0.625em 0.625em;font-size:inherit;color:#000;text-align:left}table tr th,table tr td{padding:0.5625em 0.625em;font-size:inherit;color:#000}table tr.even,table tr.alt,table tr:nth-child(even){background:#f5f9f9}table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{display:table-cell;line-height:1.6}body{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;tab-size:4}h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-0.05em}.clearfix:before,.clearfix:after,.float-group:before,.float-group:after{content:" ";display:table}.clearfix:after,.float-group:after{clear:both}*:not(pre)>code{background-color:#fff;border:1px solid #e1e1e8;color:#009;padding:2px 6px;font-size:.875rem;font-family:Monaco, Menlo, Consolas, "Courier New", monospace}pre,pre>code{line-height:1.85;color:rgba(0,0,0,0.9);font-family:Monaco, Menlo, Consolas, "Courier New", monospace;font-weight:normal;text-rendering:optimizeSpeed;word-break:normal}pre{overflow:auto}em em{font-style:normal}strong strong{font-weight:normal}.keyseq{color:#6b625c}kbd{font-family:Monaco, Menlo, Consolas, "Courier New", monospace;display:inline-block;color:#000;font-size:0.65em;line-height:1.45;background-color:#f7f7f7;border:1px solid #ccc;-webkit-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,0.2),0 0 0 0.1em white inset;box-shadow:0 1px 0 rgba(0,0,0,0.2),0 0 0 0.1em white inset;margin:0 0.15em;padding:0.2em 0.5em;vertical-align:middle;position:relative;top:-0.1em;white-space:nowrap}.keyseq kbd:first-child{margin-left:0}.keyseq kbd:last-child{margin-right:0}.menuseq,.menu{color:#191715}b.button:before,b.button:after{position:relative;top:-1px;font-weight:normal}b.button:before{content:"[";padding:0 3px 0 2px}b.button:after{content:"]";padding:0 2px 0 3px}p a>code:hover{color:rgba(0,0,0,0.9)}#toc{border-bottom:1px solid #dce6e6;padding-bottom:0.5em}#toc>ul{margin-left:0.125em}#toc ul.sectlevel0>li>a{font-style:italic}#toc ul.sectlevel0 ul.sectlevel1{margin:0.5em 0}#toc ul{list-style-type:none}#toc li{line-height:1.3334}#toc a{text-decoration:none}#toc a:active{text-decoration:underline}#toctitle{color:#0b0a0a;font-size:1.2em;display:none}body.toc2{padding-top:80px;text-rendering:optimizeLegibility}#content #toc{border-style:solid;border-width:1px;border-color:#dce6e6;margin-bottom:1.25em;padding:1.25em;background:#f1f1f1;-webkit-border-radius:4px;border-radius:4px}#content #toc>:first-child{margin-top:0}#content #toc>:last-child{margin-bottom:0}#footer{padding-bottom:2rem}#footer #footer-text{padding:2rem 0;border-top:1px solid #efefed}#footer-text{color:rgba(0,0,0,0.6);line-height:1.44}.sect1{padding-bottom:0.625em}.sect1+.sect1{border-top:1px solid #efefed}#content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;margin-top:0.1rem;display:block;visibility:hidden;text-align:center;font-weight:normal;color:rgba(0,0,0,0.2)}#content h1>a.anchor:hover,h2>a.anchor:hover,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4>a.anchor:hover,h5>a.anchor:hover,h6>a.anchor:hover{color:#097dff;text-decoration:none}#content h1>a.anchor:before,h2>a.anchor:before,h3>a.anchor:before,#toctitle>a.anchor:before,.sidebarblock>.content>.title>a.anchor:before,h4>a.anchor:before,h5>a.anchor:before,h6>a.anchor:before{content:"\0023";font-size:0.85em;display:block;padding-top:0.1em}#content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible}#content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#000;text-decoration:none}#content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#262321}.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em}.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:'Open Sans', sans-serif;font-size:1rem}table.tableblock>caption.title{white-space:nowrap;overflow:visible;max-width:0;padding:0.6rem 0}table.tableblock #preamble>.sectionbody>.paragraph:first-of-type p{font-size:inherit}.admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%}.admonitionblock>table td.icon{text-align:center;vertical-align:top;padding-top:0.8em;width:80px}.admonitionblock>table td.icon img{max-width:initial}.admonitionblock>table td.icon .title{font-weight:bold;font-family:Montserrat, sans-serif;text-transform:uppercase}.admonitionblock>table td.content{padding-left:0em;padding-right:1.25em;border-left:1px solid #dce6e6}.admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0}.exampleblock>.content{border-style:solid;border-width:0;border-color:#e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#f1f1f1;border-radius:4px}.exampleblock>.content>:first-child{margin-top:0}.exampleblock>.content>:last-child{margin-bottom:0}.sidebarblock{border-style:solid;border-width:0;border-color:#dce6e6;margin-bottom:1.25em;padding:1.25em;background:#ebf2f2;border-radius:4px;overflow:scroll}.sidebarblock>:first-child{margin-top:0}.sidebarblock>:last-child{margin-bottom:0}.sidebarblock>.content>.title{color:#0b0a0a;margin-top:0;text-align:center}.exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0}.literalblock pre,.listingblock pre:not(.highlight),.listingblock pre[class="highlight"],.listingblock pre[class^="highlight "],.listingblock pre.CodeRay,.listingblock pre.prettyprint{background:#fff;border:1px solid #d9d9d9;border-radius:4px}.sidebarblock .literalblock pre,.sidebarblock .listingblock pre:not(.highlight),.sidebarblock .listingblock pre[class="highlight"],.sidebarblock .listingblock pre[class^="highlight "],.sidebarblock .listingblock pre.CodeRay,.sidebarblock .listingblock pre.prettyprint{background:#fff;border:1px solid #d9d9d9;color:#222}.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class],.listingblock pre:not(.highlight){padding:1em 1.5rem;font-size:0.8125em}.literalblock pre.nowrap,.literalblock pre[class].nowrap,.listingblock pre.nowrap,.listingblock pre[class].nowrap{overflow-x:auto}.literalblock.output pre{color:whitesmoke;background-color:rgba(0,0,0,0.9)}.listingblock{white-space:nowrap}.listingblock pre.highlightjs>code{padding:1em 1.5rem;border-radius:4px}.listingblock>.content{position:relative}.listingblock code[data-lang]:before{display:none;content:attr(data-lang);position:absolute;font-size:0.8em;font-weight:bold;top:0.425rem;right:0.5rem;line-height:1;text-transform:uppercase;color:#999}.listingblock code[data-lang]:before{display:block}.listingblock.terminal pre .command:before{content:attr(data-prompt);padding-right:0.5em;color:#999}.listingblock.terminal pre .command:not([data-prompt]):before{content:"$"}table.pyhltable{border-collapse:separate;border:0;margin-bottom:0;background:none}table.pyhltable td{vertical-align:top;padding-top:0;padding-bottom:0;line-height:1.45}table.pyhltable td.code{padding-left:.75em;padding-right:0}pre.pygments .lineno,table.pyhltable td:not(.code){color:#999;padding-left:0;padding-right:.5em;border-right:1px solid #dce6e6}pre.pygments .lineno{display:block;margin-right:.25em}table.pyhltable .linenodiv{background:none !important;padding-right:0 !important}.quoteblock{margin:0 1em 1.25em 1.5em;display:block;text-align:left;padding-left:20px}.quoteblock blockquote,.quoteblock blockquote p{color:rgba(0,0,0,0.85);line-height:1.75;letter-spacing:0}.quoteblock blockquote{margin:0;padding:0;border:0;position:relative}.quoteblock blockquote:before{content:"\201c";font-size:2.75em;font-weight:bold;line-height:0.6em;margin-left:0em;margin-right:1rem;margin-top:0.8rem;color:rgba(0,0,0,0.1);position:absolute;top:0;left:-30px}.quoteblock blockquote>.paragraph:last-child p{margin-bottom:0}.quoteblock .attribution{margin-right:0.5ex}.quoteblock .quoteblock{margin-left:0;margin-right:0;padding:0.5em 0;border-left:3px solid rgba(0,0,0,0.6)}.quoteblock .quoteblock blockquote{padding:0 0 0 0.75em}.quoteblock .quoteblock blockquote:before{display:none}.verseblock{margin:0 1em 1.25em 0;background-color:#f1f1f1;padding:1rem 1.4rem;border-radius:4px}.verseblock pre{font-family:Monaco, Menlo, Consolas, "Courier New", monospace;font-size:0.9rem;color:rgba(0,0,0,0.85);font-weight:300;text-rendering:optimizeLegibility}.verseblock pre strong{font-weight:400}.verseblock .attribution{margin-top:1.25rem;margin-left:0.5ex}.quoteblock .attribution,.verseblock .attribution{font-size:0.9375em;line-height:1.45;font-style:italic}.quoteblock .attribution br,.verseblock .attribution br{display:none}.quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-0.025em;color:rgba(0,0,0,0.6)}.quoteblock.abstract{margin:0 0 1.25em 0;display:block}.quoteblock.abstract blockquote,.quoteblock.abstract blockquote p{text-align:left;word-spacing:0}.quoteblock.abstract blockquote:before,.quoteblock.abstract blockquote p:first-of-type:before{display:none}table.tableblock{max-width:100%;border-collapse:separate;overflow-x:scroll;display:block}table.tableblock td>.paragraph:last-child p>p:last-child,table.tableblock th>p:last-child,table.tableblock td>p:last-child{margin-bottom:0}table.tableblock,th.tableblock,td.tableblock{border:0 solid #d4dfdf}table.grid-all th.tableblock,table.grid-all td.tableblock{border-width:0 1px 1px 0}table.grid-all tfoot>tr>th.tableblock,table.grid-all tfoot>tr>td.tableblock{border-width:1px 1px 0 0}table.grid-cols th.tableblock,table.grid-cols td.tableblock{border-width:0 1px 0 0}table.grid-all *>tr>.tableblock:last-child,table.grid-cols *>tr>.tableblock:last-child{border-right-width:0}table.grid-rows th.tableblock,table.grid-rows td.tableblock{border-width:0 0 1px 0}table.grid-all tbody>tr:last-child>th.tableblock,table.grid-all tbody>tr:last-child>td.tableblock,table.grid-all thead:last-child>tr>th.tableblock,table.grid-rows tbody>tr:last-child>th.tableblock,table.grid-rows tbody>tr:last-child>td.tableblock,table.grid-rows thead:last-child>tr>th.tableblock{border-bottom-width:0}table.grid-rows tfoot>tr>th.tableblock,table.grid-rows tfoot>tr>td.tableblock{border-width:1px 0 0 0}table.frame-all{border-width:1px}table.frame-sides{border-width:0 1px}table.frame-topbot{border-width:1px 0}th.halign-left,td.halign-left{text-align:left}th.halign-right,td.halign-right{text-align:right}th.halign-center,td.halign-center{text-align:center}th.valign-top,td.valign-top{vertical-align:top}th.valign-bottom,td.valign-bottom{vertical-align:bottom}th.valign-middle,td.valign-middle{vertical-align:middle}table thead th,table tfoot th{font-weight:bold}tbody tr th{display:table-cell;line-height:1.6;background:#f7f8f7}tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:#34302d;font-weight:bold}p.tableblock{font-size:1em}td>div.verse{white-space:pre}ol{margin-left:1.75em}ul li ol{margin-left:1.5em}dl dd{margin-left:1.125em}dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0}ol>li p,ul>li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:0.625em}ul.unstyled,ol.unnumbered,ul.checklist,ul.none{list-style-type:none}ul.unstyled,ol.unnumbered,ul.checklist{margin-left:0.625em}ul.checklist li>p:first-child>.fa-square-o:first-child,ul.checklist li>p:first-child>.fa-check-square-o:first-child{width:1em;font-size:0.85em}ul.checklist li>p:first-child>input[type="checkbox"]:first-child{width:1em;position:relative;top:1px}ul.inline{margin:0 auto 0.625em auto;margin-left:-1.375em;margin-right:0;padding:0;list-style:none;overflow:hidden}ul.inline>li{list-style:none;float:left;margin-left:1.375em;display:block}ul.inline>li>*{display:block}.unstyled dl dt{font-weight:normal;font-style:normal}ol.arabic{list-style-type:decimal}ol.decimal{list-style-type:decimal-leading-zero}ol.loweralpha{list-style-type:lower-alpha}ol.upperalpha{list-style-type:upper-alpha}ol.lowerroman{list-style-type:lower-roman}ol.upperroman{list-style-type:upper-roman}ol.lowergreek{list-style-type:lower-greek}.hdlist>table,.colist>table{border:0;background:none}.hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none}td.hdlist1,td.hdlist2{vertical-align:top;padding:0 0.625em}td.hdlist1{font-weight:bold;padding-bottom:1.25em}.literalblock+.colist,.listingblock+.colist{margin-top:-0.5em}.colist>table tr>td:first-of-type{padding:0 0.75em;line-height:1}.colist>table tr>td:first-of-type img{max-width:initial}.colist>table tr>td:last-of-type{padding:0.25em 0}.colist>table tr>td{white-space:pre-wrap}.thumb,.th{line-height:0;display:inline-block;border:solid 4px white;-webkit-box-shadow:0 0 0 1px #dddddd;box-shadow:0 0 0 1px #dddddd}.imageblock.left,.imageblock[style*="float: left"]{margin:0.25em 0.625em 1.25em 0}.imageblock.right,.imageblock[style*="float: right"]{margin:0.25em 0 1.25em 0.625em}.imageblock>.title{margin-bottom:0}.imageblock.thumb,.imageblock.th{border-width:6px}.imageblock.thumb>.title,.imageblock.th>.title{padding:0 0.125em}.image.left,.image.right{margin-top:0.25em;margin-bottom:0.25em;display:inline-block;line-height:0}.image.left{margin-right:0.625em}.image.right{margin-left:0.625em}a.image{text-decoration:none;display:inline-block}a.image object{pointer-events:none}sup.footnote,sup.footnoteref{font-size:0.875em;position:static;vertical-align:super}sup.footnote a,sup.footnoteref a{text-decoration:none}sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline}#footnotes{padding-top:0.75em;padding-bottom:0.75em;margin-bottom:0.625em}#footnotes hr{width:20%;min-width:6.25em;margin:-0.25em 0 0.75em 0;border-width:1px 0 0 0}#footnotes .footnote{padding:0 0.375em 0 0.225em;line-height:1.3334;font-size:0.875em;margin-left:1.2em;text-indent:-1.05em;margin-bottom:0.2em}#footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none}#footnotes .footnote:last-of-type{margin-bottom:0}#content #footnotes{margin-top:-0.625em;margin-bottom:0;padding:0.75em 0}.gist .file-data>table{border:0;background:#fff;width:100%;margin-bottom:0}.gist .file-data>table td.line-data{width:99%}div.unbreakable{page-break-inside:avoid}.big{font-size:larger}.small{font-size:smaller}.underline{text-decoration:underline}.overline{text-decoration:overline}.line-through{text-decoration:line-through}.aqua{color:#00bfbf}.aqua-background{background-color:#00fafa}.black{color:black}.black-background{background-color:black}.blue{color:#0000bf}.blue-background{background-color:#0000fa}.fuchsia{color:#bf00bf}.fuchsia-background{background-color:#fa00fa}.gray{color:#606060}.gray-background{background-color:#7d7d7d}.green{color:#006000}.green-background{background-color:#007d00}.lime{color:#00bf00}.lime-background{background-color:#00fa00}.maroon{color:#600000}.maroon-background{background-color:#7d0000}.navy{color:#000060}.navy-background{background-color:#00007d}.olive{color:#606000}.olive-background{background-color:#7d7d00}.purple{color:#600060}.purple-background{background-color:#7d007d}.red{color:#bf0000}.red-background{background-color:#fa0000}.silver{color:#909090}.silver-background{background-color:#bcbcbc}.teal{color:#006060}.teal-background{background-color:#007d7d}.white{color:#bfbfbf}.white-background{background-color:#f5f9f9}.yellow{color:#bfbf00}.yellow-background{background-color:#fafa00}span.icon>.fa{cursor:default}.admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;cursor:default}.admonitionblock td.icon .icon-note:before{content:"\f05a";color:#3f6a22}.admonitionblock td.icon .icon-tip:before{content:"\f0eb";color:#0077b9}.admonitionblock td.icon .icon-warning:before{content:"\f071";color:#d88400}.admonitionblock td.icon .icon-caution:before{content:"\f06d";color:#bf3400}.admonitionblock td.icon .icon-important:before{content:"\f06a";color:#bf0000}.conum[data-value]{display:inline-block;color:#000 !important;background-color:#ffe157;-webkit-border-radius:100px;border-radius:100px;text-align:center;font-size:0.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans", "DejaVu Sans", sans-serif;font-style:normal;font-weight:bold}.conum[data-value] *{color:#fff !important}.conum[data-value]+b{display:none}.conum[data-value]:after{content:attr(data-value)}pre .conum[data-value]{position:relative;top:0;color:#000 !important;background-color:#ffe157;font-size:12px}b.conum *{color:inherit !important}.conum:not([data-value]):empty{display:none}.admonitionblock{background-color:#ecf1e8;padding:0.8em 0;margin:30px 0;width:auto;border-radius:4px;overflow-x:auto}.admonitionblock.important{border-left:0px solid #e20000;background-color:#f9ebeb}.admonitionblock.warning{border-left:0px solid #d88400;background-color:#fff9e4}.admonitionblock.tip{border-left:0px solid #0077b9;background-color:#e9f1f6}.admonitionblock.caution{border-left:0px solid #e20000;background-color:#f9ebeb}.admonitionblock .exampleblock>.content{border:0 none;background-color:#fff}#toc a:hover{text-decoration:underline}.admonitionblock>table{margin-bottom:0}.admonitionblock>table td.content{border-left:none}@media print{#tocbot a.toc-link.node-name--H4{display:none}}.is-collapsible{max-height:1000px;overflow:hidden;transition:all 200ms ease-in-out}.is-collapsed{max-height:0}#index-link{display:none}ul li>p>a>code{color:#086dc3}ul li>p>a:hover>code{color:#086dc3}#content .listingblock .switch{border-style:none;display:inline-block;position:relative;bottom:0;margin-bottom:4px}#content .listingblock .switch--item:not(:first-child){border:2px solid #000}#content .listingblock .switch--item{padding:6px 12px;background-color:#fff;color:#000;display:inline-block;cursor:pointer;border:2px solid #000;margin-right:2px;border-radius:0}#content .listingblock .switch--item:hover{color:#086dc3}#content .listingblock .switch--item.selected{background-color:#000;color:#fff;border-color:#000}#content .listingblock .switch--item.selected:hover{color:#fff}#content .listingblock pre.highlightjs{padding:0}div.back-action,#toc.toc2 div.back-action{padding:0.8rem 0 0 5px}div.back-action a,#toc.toc2 div.back-action a{position:relative;display:inline-block;padding:0.6rem 1.2rem;padding-left:35px}div.back-action a span,#toc.toc2 div.back-action a span{position:absolute;left:5px;top:5px;display:block;color:#333;height:26px;width:26px;border-radius:13px}div.back-action a i,#toc.toc2 div.back-action a i{position:absolute;top:10px;left:5px}div.back-action a:hover span,#toc.toc2 div.back-action a:hover span{color:#000}#tocbot.desktop-toc{padding:.5rem}#header-spring{position:absolute;text-rendering:optimizeLegibility;top:0;left:0;right:0;height:80px;margin:0 1rem;padding:0 1rem;border-bottom:1px solid #dce6e6}#header-spring h1{margin:0;padding:0;font-size:22px;text-align:left;line-height:76px;padding-left:0.6rem}#header-spring h1 svg{width:240px}#header-spring h1 svg .st0{fill:#6bb536}#header-spring h1 svg .st2{fill:#444}body.book #header-spring{position:relative;top:auto;left:auto;right:auto;margin:0}body.book #header>h1:only-child{border:0 none;padding-bottom:1.2rem;font-size:1.8rem}body.book #header,body.book #content,body.book #footnotes,body.book #footer{margin:0 auto}body.toc2 #header-spring{position:absolute;left:0;right:0;top:0}body.toc2 #header>h1:only-child{font-size:2.2rem}body.toc2 #header,body.toc2 #content,body.toc2 #footnotes,body.toc2 #footer{margin:0 auto}body.toc2 #content{padding-top:2rem}#header,#content,#footnotes,#footer{width:100%;margin-right:auto;margin-top:0;margin-bottom:0;max-width:62.5em;*zoom:1;position:relative;padding-left:0.9375em;padding-right:0.9375em}#header:before,#header:after,#content:before,#content:after,#footnotes:before,#footnotes:after,#footer:before,#footer:after{content:" ";display:table}#header:after,#content:after,#footnotes:after,#footer:after{clear:both}#content{margin-top:1.25em}#content:before{content:none}#header{position:relative}#header>h1:first-child{margin-top:2.55rem;margin-bottom:0.5em;margin-bottom:0.7em;font-size:2rem}#header>h1:first-child+#toc{margin-top:8px;border-top:0 none}#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #ebf2f2;padding-bottom:8px}#header .details{line-height:1.45;color:#222;display:-ms-flexbox;display:-webkit-flex;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap;background-color:#ebf2f2;padding:2rem 2.5rem}#header .details span:first-child{margin-left:-0.125em}#header .details span.email a{color:rgba(0,0,0,0.85)}#header .details br{display:none}#header .details br+span:before{content:"\00a0\2013\00a0"}#header .details br+span.author:before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,0.85)}#header .details br+span#revremark:before{content:"\00a0|\00a0"}#header #revnumber{text-transform:capitalize}#header #revnumber:after{content:"\00a0"}#content>h1:first-child:not([class]){color:rgba(0,0,0,0.85);border-bottom:1px solid #ebf2f2;padding-bottom:8px;margin-top:0;padding-top:1.5rem;margin-bottom:1.25rem}h1{font-size:2.2rem}h1,h2,h3,h4,h5,h6{font-weight:bold;font-family:Montserrat, Arial, Helvetica, sans-serif}h1:focus,h2:focus,h3:focus,h4:focus,h5:focus,h6:focus{box-shadow:none;outline:none}h2,h3,h4,h5,h6{padding:.8rem 0 .4rem}h1{font-size:1.75em}h2{font-size:1.6rem}h3{font-size:1.5rem}h4{font-size:1.4rem}h5{font-size:1.3rem}h6{font-size:1.2rem}pre.highlight{padding:20px;border:1px solid #d9d9d9;overflow-x:scroll;color:#222}pre.highlight code{color:#222}pre.highlight a,#toc.toc2 a{color:#000}pre.highlight ul.sectlevel1,#toc.toc2 ul.sectlevel1{padding-left:0.2rem}pre.highlight ul.sectlevel1 li,#toc.toc2 ul.sectlevel1 li{line-height:1.4rem}::selection{background-color:#d1ff79}.literalblock pre::selection,.listingblock pre[class="highlight"]::selection,.highlight::selection,pre::selection,.highlight code::selection,.highlight code span::selection{background:rgba(0,0,0,0.2) !important}body.book #header{margin-bottom:2rem}body.toc2 #header{margin-bottom:0}.desktop-toc{display:none}.admonitionblock td.icon{display:none}.admonitionblock>table td.content{padding-left:1.25em}@media only screen and (min-width: 768px){#toctitle{font-size:1.375em}.sect1{padding-bottom:1.25em}.mobile-toc{display:none}.desktop-toc{display:block}.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:0.90625em}.admonitionblock td.icon{display:table-cell}.admonitionblock>table td.content{padding-left:0}#header{position:relative;min-height:98px;padding-right:210px}#header::after{position:absolute;right:0;top:0;display:block;content:'';height:95px;width:203px;z-index:-1;background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA38AAAGjCAIAAAATtjulAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyVpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQ4IDc5LjE2NDAzNiwgMjAxOS8wOC8xMy0wMTowNjo1NyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIDIxLjEgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NTMxQjVFRkQ2NTNCMTFFQTlENDc5OTVFRUMxRUY0NTEiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NTMxQjVFRkU2NTNCMTFFQTlENDc5OTVFRUMxRUY0NTEiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo1MzFCNUVGQjY1M0IxMUVBOUQ0Nzk5NUVFQzFFRjQ1MSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo1MzFCNUVGQzY1M0IxMUVBOUQ0Nzk5NUVFQzFFRjQ1MSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PvrI2PUAAD6SSURBVHja7N13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");background-repeat:no-repeat;background-size:203px 95px;background-position:right -10px}body.toc2{padding-right:0}body.toc2 #toc.toc2{position:absolute;margin-top:0 !important;width:15em;top:0;border-top-width:0 !important;border-bottom-width:0 !important;margin-left:-15.9375em;z-index:1000;padding:0 1em 1.25em 0em;overflow:auto}body.toc2 #toc.toc2 #toctitle{margin-top:0;margin-bottom:0.8rem;font-size:1.2em}body.toc2 #toc.toc2>ul{font-size:0.9em;margin-bottom:0}body.toc2 #toc.toc2 ul ul{margin-left:0;padding-left:1em}body.toc2 #toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:0.5em;margin-bottom:0.5em}body.toc2 #header,body.toc2 #content,body.toc2 #footnotes,body.toc2 #footer{padding-left:15.9375em;max-width:none}body.book #header-spring h1{max-width:1400px;margin:0 auto}body.book #header,body.book #content,body.book #footnotes,body.book #footer{max-width:1400px}body.is-position-fixed #toc.toc2{position:fixed;height:100%}h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2}h1{font-size:1.75em}h2{font-size:1.6em}h3,#toctitle,.sidebarblock>.content>.title{font-size:1.5em}h4{font-size:1.4em}h5{font-size:1.2em}h6{font-size:1.2em}#tocbot a.toc-link.node-name--H1{font-style:italic}#tocbot ol{margin:0;padding:0}#tocbot ol li{list-style:none;padding:0 0;margin:0;display:block}#tocbot{z-index:999}#tocbot .toc-link{position:relative;display:block;z-index:999;padding:.4rem .6rem}#tocbot a.is-active-link{padding-right:3px;background:black;color:white}}@media only screen and (min-width: 768px){#tocbot>ul.toc-list{margin-bottom:0.5em;margin-left:0.125em}#tocbot ul.sectlevel0,#tocbot a.toc-link.node-name--H1+ul{padding-left:0}#tocbot a.toc-link{height:100%}.is-collapsible{max-height:3000px;overflow:hidden}.is-collapsed{max-height:0}}@media only screen and (min-width: 768px){body.toc2 #header,body.toc2 #content,body.toc2 #footer{background-repeat:repeat-y;background-position:14em 0;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAMAAAAoyzS7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQwIDc5LjE2MDQ1MSwgMjAxNy8wNS8wNi0wMTowODoyMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTggKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RDE0NUNENzNGMTVGMTFFODk5RjI5ODk3QURGRjcxMkEiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RDE0NUNENzRGMTVGMTFFODk5RjI5ODk3QURGRjcxMkEiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpEMTQ1Q0Q3MUYxNUYxMUU4OTlGMjk4OTdBREZGNzEyQSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpEMTQ1Q0Q3MkYxNUYxMUU4OTlGMjk4OTdBREZGNzEyQSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PjmGxxYAAAAGUExURd3d2AAAAJlCnKAAAAAMSURBVHjaYmAACDAAAAIAAU9tWeEAAAAASUVORK5CYII=);background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyVpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQ4IDc5LjE2NDAzNiwgMjAxOS8wOC8xMy0wMTowNjo1NyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIDIxLjEgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NDMyRDZERkQ1MEE4MTFFQTlCNTJBOEQwQTM2ODZEQjgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NDMyRDZERkU1MEE4MTFFQTlCNTJBOEQwQTM2ODZEQjgiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0MzJENkRGQjUwQTgxMUVBOUI1MkE4RDBBMzY4NkRCOCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0MzJENkRGQzUwQTgxMUVBOUI1MkE4RDBBMzY4NkRCOCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PjdyLKIAAAAPSURBVHjaYnj16RNAgAEABZgCz/xXiToAAAAASUVORK5CYII=");background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyVpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQ4IDc5LjE2NDAzNiwgMjAxOS8wOC8xMy0wMTowNjo1NyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIDIxLjEgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6ODRBOEI2NTI1MEI1MTFFQTlCNTJBOEQwQTM2ODZEQjgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6ODRBOEI2NTM1MEI1MTFFQTlCNTJBOEQwQTM2ODZEQjgiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0MzJENkRGRjUwQTgxMUVBOUI1MkE4RDBBMzY4NkRCOCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0MzJENkUwMDUwQTgxMUVBOUI1MkE4RDBBMzY4NkRCOCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pul87iAAAAAPSURBVHjaYrj17BlAgAEABUQCpxgONc4AAAAASUVORK5CYII=")}}@media only screen and (min-width: 1280px){body.toc2{padding-right:0}body.toc2 #toc.toc2{width:25em;left:auto;margin-left:-26.9375em}body.toc2 #toc.toc2 #toctitle{font-size:1.375em}body.toc2 #toc.toc2>ul{font-size:0.95em}body.toc2 #toc.toc2 ul ul{padding-left:1.25em}body.toc2 body.toc2.toc-right{padding-left:0;padding-right:20em}body.toc2 #header,body.toc2 #content,body.toc2 #footnotes,body.toc2 #footer{padding-left:26.9375em;max-width:1400px}body.toc2 #header-spring h1{margin:0 auto;max-width:1400px}.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:0.8125em}body.toc2 #header,body.toc2 #content,body.toc2 #footer{background-repeat:repeat-y;background-position:24em 0;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAMAAAAoyzS7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQwIDc5LjE2MDQ1MSwgMjAxNy8wNS8wNi0wMTowODoyMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTggKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RDE0NUNENzNGMTVGMTFFODk5RjI5ODk3QURGRjcxMkEiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RDE0NUNENzRGMTVGMTFFODk5RjI5ODk3QURGRjcxMkEiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpEMTQ1Q0Q3MUYxNUYxMUU4OTlGMjk4OTdBREZGNzEyQSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpEMTQ1Q0Q3MkYxNUYxMUU4OTlGMjk4OTdBREZGNzEyQSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PjmGxxYAAAAGUExURd3d2AAAAJlCnKAAAAAMSURBVHjaYmAACDAAAAIAAU9tWeEAAAAASUVORK5CYII=);background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyVpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQ4IDc5LjE2NDAzNiwgMjAxOS8wOC8xMy0wMTowNjo1NyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIDIxLjEgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NDMyRDZERkQ1MEE4MTFFQTlCNTJBOEQwQTM2ODZEQjgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NDMyRDZERkU1MEE4MTFFQTlCNTJBOEQwQTM2ODZEQjgiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0MzJENkRGQjUwQTgxMUVBOUI1MkE4RDBBMzY4NkRCOCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0MzJENkRGQzUwQTgxMUVBOUI1MkE4RDBBMzY4NkRCOCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PjdyLKIAAAAPSURBVHjaYnj16RNAgAEABZgCz/xXiToAAAAASUVORK5CYII=");background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyVpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQ4IDc5LjE2NDAzNiwgMjAxOS8wOC8xMy0wMTowNjo1NyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIDIxLjEgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6ODRBOEI2NTI1MEI1MTFFQTlCNTJBOEQwQTM2ODZEQjgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6ODRBOEI2NTM1MEI1MTFFQTlCNTJBOEQwQTM2ODZEQjgiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0MzJENkRGRjUwQTgxMUVBOUI1MkE4RDBBMzY4NkRCOCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0MzJENkUwMDUwQTgxMUVBOUI1MkE4RDBBMzY4NkRCOCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pul87iAAAAAPSURBVHjaYrj17BlAgAEABUQCpxgONc4AAAAASUVORK5CYII=")}#header{min-height:150px;padding-right:310px}#header::after{height:147px;width:305px;background-size:305px 147px}}
diff --git a/reference/html/favicon.ico b/reference/html/favicon.ico
new file mode 100644
index 00000000..1a4956e6
Binary files /dev/null and b/reference/html/favicon.ico differ
diff --git a/reference/html/images/spring-cloud-launcher-eureka-dashboard.png b/reference/html/images/spring-cloud-launcher-eureka-dashboard.png
new file mode 100644
index 00000000..dbd12c59
Binary files /dev/null and b/reference/html/images/spring-cloud-launcher-eureka-dashboard.png differ
diff --git a/reference/html/images/spring-cloud-launcher-log.png b/reference/html/images/spring-cloud-launcher-log.png
new file mode 100644
index 00000000..916ce243
Binary files /dev/null and b/reference/html/images/spring-cloud-launcher-log.png differ
diff --git a/reference/html/index.html b/reference/html/index.html
new file mode 100644
index 00000000..bc8f3466
--- /dev/null
+++ b/reference/html/index.html
@@ -0,0 +1,432 @@
+
+
+
+
+
+
+
+Spring Boot Cloud CLI
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Spring Boot CLI provides Spring
+Boot command line features for Spring
+Cloud . You can write Groovy scripts to run Spring Cloud component
+applications (e.g. @EnableEurekaServer). You can also easily do
+things like encryption and decryption to support Spring Cloud Config
+clients with secret configuration values. With the Launcher CLI you
+can launch services like Eureka, Zipkin, Config Server
+conveniently all at once from the command line (very useful at
+development time).
+
+
+
+
+
+
+
+
+Spring Cloud is released under the non-restrictive Apache 2.0 license. If you would like to contribute to this section of the documentation or if you find an error, please find the source code and issue trackers in the project at github .
+
+
+
+
+
+
+
+
+
+
+
+
+
$ spring version
+Spring CLI v2.2.0.BUILD-SNAPSHOT
+
+
+
+
+
+
$ sdk install springboot 2.2.0.BUILD-SNAPSHOT
+$ sdk use springboot 2.2.0.BUILD-SNAPSHOT
+
+
+
+
and install the Spring Cloud plugin
+
+
+
+
$ mvn install
+$ spring install org.springframework.cloud:spring-cloud-cli:2.2.0.BUILD-SNAPSHOT
+
+
+
+
+
+
+
+
+
+Prerequisites: to use the encryption and decryption features
+you need the full-strength JCE installed in your JVM (it’s not there by default).
+You can download the "Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files"
+from Oracle, and follow instructions for installation (essentially replace the 2 policy files
+in the JRE lib/security directory with the ones that you downloaded).
+
+
+
+
+
+
+
+
+
+
+
The Launcher CLI can be used to run common services like Eureka,
+Config Server etc. from the command line. To list the available
+services you can do spring cloud --list, and to launch a default set
+of services just spring cloud. To choose the services to deploy,
+just list them on the command line, e.g.
+
+
+
+
$ spring cloud eureka configserver h2 kafka stubrunner zipkin
+
+
+
+
Summary of supported deployables:
+
+
+
+
+
+
+
+
+
+
+Service
+Name
+Address
+Description
+
+
+
+
+eureka
+Eureka Server
+http://localhost:8761
+Eureka server for service registration and discovery. All the other services show up in its catalog by default.
+
+
+configserver
+Config Server
+http://localhost:8888
+Spring Cloud Config Server running in the "native" profile and serving configuration from the local directory ./launcher
+
+
+h2
+H2 Database
+http://localhost:9095 (console), jdbc:h2:tcp://localhost:9096/{data}
+Relation database service. Use a file path for {data} (e.g. ./target/test) when you connect. Remember that you can add ;MODE=MYSQL or ;MODE=POSTGRESQL to connect with compatibility to other server types.
+
+
+kafka
+Kafka Broker
+http://localhost:9091 (actuator endpoints), localhost:9092
+
+
+
+dataflow
+Dataflow Server
+http://localhost:9393
+Spring Cloud Dataflow server with UI at /admin-ui. Connect the Dataflow shell to target at root path.
+
+
+zipkin
+Zipkin Server
+http://localhost:9411
+Zipkin Server with UI for visualizing traces. Stores span data in memory and accepts them via HTTP POST of JSON data.
+
+
+stubrunner
+Stub Runner Boot
+http://localhost:8750
+Downloads WireMock stubs, starts WireMock and feeds the started servers with stored stubs. Pass stubrunner.ids to pass stub coordinates and then go to http://localhost:8750/stubs .
+
+
+
+
+
Each of these apps can be configured using a local YAML file with the same name (in the current
+working directory or a subdirectory called "config" or in ~/.spring-cloud). E.g. in configserver.yml you might want to
+do something like this to locate a local git repository for the backend:
+
+
+
configserver.yml
+
+
spring:
+ profiles:
+ active: git
+ cloud:
+ config:
+ server:
+ git:
+ uri: file://${user.home}/dev/demo/config-repo
+
+
+
+
E.g. in Stub Runner app you could fetch stubs from your local .m2 in the following way.
+
+
+
stubrunner.yml
+
+
stubrunner:
+ workOffline: true
+ ids:
+ - com.example:beer-api-producer:+:9876
+
+
+
+
+
+
Additional applications can be added to ./config/cloud.yml (not
+./config.yml because that would replace the defaults), e.g. with
+
+
+
config/cloud.yml
+
+
spring:
+ cloud:
+ launcher:
+ deployables:
+ source:
+ coordinates: maven://com.example:source:0.0.1-SNAPSHOT
+ port: 7000
+ sink:
+ coordinates: maven://com.example:sink:0.0.1-SNAPSHOT
+ port: 7001
+
+
+
+
when you list the apps:
+
+
+
+
$ spring cloud --list
+source sink configserver dataflow eureka h2 kafka stubrunner zipkin
+
+
+
+
(notice the additional apps at the start of the list).
+
+
+
+
+
+
+
+
+
Spring Cloud CLI has support for most of the Spring Cloud declarative
+features, such as the @Enable* class of annotations. For example,
+here is a fully functional Eureka server
+
+
+
app.groovy
+
+
@EnableEurekaServer
+class Eureka {}
+
+
+
+
which you can run from the command line like this
+
+
+
+
$ spring run app.groovy
+
+
+
+
To include additional dependencies, often it suffices just to add the
+appropriate feature-enabling annotation, e.g. @EnableConfigServer,
+@EnableOAuth2Sso or @EnableEurekaClient. To manually include a
+dependency you can use a @Grab with the special "Spring Boot" short
+style artifact co-ordinates, i.e. with just the artifact ID (no need
+for group or version information), e.g. to set up a client app to
+listen on AMQP for management events from the Spring CLoud Bus:
+
+
+
app.groovy
+
+
@Grab('spring-cloud-starter-bus-amqp')
+@RestController
+class Service {
+ @RequestMapping('/')
+ def home() { [message: 'Hello'] }
+}
+
+
+
+
+
+
+
+
+
The Spring Cloud CLI comes with an "encrypt" and a "decrypt"
+command. Both accept arguments in the same form with a key specified
+as a mandatory "--key", e.g.
+
+
+
+
$ spring encrypt mysecret --key foo
+682bc583f4641835fa2db009355293665d2647dade3375c0ee201de2a49f7bda
+$ spring decrypt --key foo 682bc583f4641835fa2db009355293665d2647dade3375c0ee201de2a49f7bda
+mysecret
+
+
+
+
To use a key in a file (e.g. an RSA public key for encyption) prepend
+the key value with "@" and provide the file path, e.g.
+
+
+
+
$ spring encrypt mysecret --key @${HOME}/.ssh/id_rsa.pub
+AQAjPgt3eFZQXwt8tsHAVv/QHiY5sI2dRcR+...
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/reference/html/install.html b/reference/html/install.html
new file mode 100644
index 00000000..faf8ea2f
--- /dev/null
+++ b/reference/html/install.html
@@ -0,0 +1,173 @@
+
+
+
+
+
+
+
+Untitled
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
$ spring version
+Spring CLI v2.2.0.BUILD-SNAPSHOT
+
+
+
+
+
+
$ sdk install springboot 2.2.0.BUILD-SNAPSHOT
+$ sdk use springboot 2.2.0.BUILD-SNAPSHOT
+
+
+
+
and install the Spring Cloud plugin
+
+
+
+
$ mvn install
+$ spring install org.springframework.cloud:spring-cloud-cli:2.2.0.BUILD-SNAPSHOT
+
+
+
+
+
+
+
+
+
+Prerequisites: to use the encryption and decryption features
+you need the full-strength JCE installed in your JVM (it’s not there by default).
+You can download the "Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files"
+from Oracle, and follow instructions for installation (essentially replace the 2 policy files
+in the JRE lib/security directory with the ones that you downloaded).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/reference/html/intro.html b/reference/html/intro.html
new file mode 100644
index 00000000..d5880b7f
--- /dev/null
+++ b/reference/html/intro.html
@@ -0,0 +1,138 @@
+
+
+
+
+
+
+
+Untitled
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Spring Boot CLI provides Spring
+Boot command line features for Spring
+Cloud . You can write Groovy scripts to run Spring Cloud component
+applications (e.g. @EnableEurekaServer). You can also easily do
+things like encryption and decryption to support Spring Cloud Config
+clients with secret configuration values. With the Launcher CLI you
+can launch services like Eureka, Zipkin, Config Server
+conveniently all at once from the command line (very useful at
+development time).
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/reference/html/js/highlight/highlight.min.js b/reference/html/js/highlight/highlight.min.js
new file mode 100644
index 00000000..dcbbb4c7
--- /dev/null
+++ b/reference/html/js/highlight/highlight.min.js
@@ -0,0 +1,2 @@
+/*! highlight.js v9.13.1 | BSD3 License | git.io/hljslicense */
+!function(e){var n="object"==typeof window&&window||"object"==typeof self&&self;"undefined"!=typeof exports?e(exports):n&&(n.hljs=e({}),"function"==typeof define&&define.amd&&define([],function(){return n.hljs}))}(function(e){function n(e){return e.replace(/&/g,"&").replace(//g,">")}function t(e){return e.nodeName.toLowerCase()}function r(e,n){var t=e&&e.exec(n);return t&&0===t.index}function a(e){return k.test(e)}function i(e){var n,t,r,i,o=e.className+" ";if(o+=e.parentNode?e.parentNode.className:"",t=M.exec(o))return w(t[1])?t[1]:"no-highlight";for(o=o.split(/\s+/),n=0,r=o.length;r>n;n++)if(i=o[n],a(i)||w(i))return i}function o(e){var n,t={},r=Array.prototype.slice.call(arguments,1);for(n in e)t[n]=e[n];return r.forEach(function(e){for(n in e)t[n]=e[n]}),t}function c(e){var n=[];return function r(e,a){for(var i=e.firstChild;i;i=i.nextSibling)3===i.nodeType?a+=i.nodeValue.length:1===i.nodeType&&(n.push({event:"start",offset:a,node:i}),a=r(i,a),t(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:a,node:i}));return a}(e,0),n}function u(e,r,a){function i(){return e.length&&r.length?e[0].offset!==r[0].offset?e[0].offset"}function c(e){l+=""+t(e)+">"}function u(e){("start"===e.event?o:c)(e.node)}for(var s=0,l="",f=[];e.length||r.length;){var g=i();if(l+=n(a.substring(s,g[0].offset)),s=g[0].offset,g===e){f.reverse().forEach(c);do u(g.splice(0,1)[0]),g=i();while(g===e&&g.length&&g[0].offset===s);f.reverse().forEach(o)}else"start"===g[0].event?f.push(g[0].node):f.pop(),u(g.splice(0,1)[0])}return l+n(a.substr(s))}function s(e){return e.v&&!e.cached_variants&&(e.cached_variants=e.v.map(function(n){return o(e,{v:null},n)})),e.cached_variants||e.eW&&[o(e)]||[e]}function l(e){function n(e){return e&&e.source||e}function t(t,r){return new RegExp(n(t),"m"+(e.cI?"i":"")+(r?"g":""))}function r(a,i){if(!a.compiled){if(a.compiled=!0,a.k=a.k||a.bK,a.k){var o={},c=function(n,t){e.cI&&(t=t.toLowerCase()),t.split(" ").forEach(function(e){var t=e.split("|");o[t[0]]=[n,t[1]?Number(t[1]):1]})};"string"==typeof a.k?c("keyword",a.k):B(a.k).forEach(function(e){c(e,a.k[e])}),a.k=o}a.lR=t(a.l||/\w+/,!0),i&&(a.bK&&(a.b="\\b("+a.bK.split(" ").join("|")+")\\b"),a.b||(a.b=/\B|\b/),a.bR=t(a.b),a.endSameAsBegin&&(a.e=a.b),a.e||a.eW||(a.e=/\B|\b/),a.e&&(a.eR=t(a.e)),a.tE=n(a.e)||"",a.eW&&i.tE&&(a.tE+=(a.e?"|":"")+i.tE)),a.i&&(a.iR=t(a.i)),null==a.r&&(a.r=1),a.c||(a.c=[]),a.c=Array.prototype.concat.apply([],a.c.map(function(e){return s("self"===e?a:e)})),a.c.forEach(function(e){r(e,a)}),a.starts&&r(a.starts,i);var u=a.c.map(function(e){return e.bK?"\\.?("+e.b+")\\.?":e.b}).concat([a.tE,a.i]).map(n).filter(Boolean);a.t=u.length?t(u.join("|"),!0):{exec:function(){return null}}}}r(e)}function f(e,t,a,i){function o(e){return new RegExp(e.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&"),"m")}function c(e,n){var t,a;for(t=0,a=n.c.length;a>t;t++)if(r(n.c[t].bR,e))return n.c[t].endSameAsBegin&&(n.c[t].eR=o(n.c[t].bR.exec(e)[0])),n.c[t]}function u(e,n){if(r(e.eR,n)){for(;e.endsParent&&e.parent;)e=e.parent;return e}return e.eW?u(e.parent,n):void 0}function s(e,n){return!a&&r(n.iR,e)}function p(e,n){var t=R.cI?n[0].toLowerCase():n[0];return e.k.hasOwnProperty(t)&&e.k[t]}function d(e,n,t,r){var a=r?"":j.classPrefix,i='',i+n+o}function h(){var e,t,r,a;if(!E.k)return n(k);for(a="",t=0,E.lR.lastIndex=0,r=E.lR.exec(k);r;)a+=n(k.substring(t,r.index)),e=p(E,r),e?(M+=e[1],a+=d(e[0],n(r[0]))):a+=n(r[0]),t=E.lR.lastIndex,r=E.lR.exec(k);return a+n(k.substr(t))}function b(){var e="string"==typeof E.sL;if(e&&!L[E.sL])return n(k);var t=e?f(E.sL,k,!0,B[E.sL]):g(k,E.sL.length?E.sL:void 0);return E.r>0&&(M+=t.r),e&&(B[E.sL]=t.top),d(t.language,t.value,!1,!0)}function v(){y+=null!=E.sL?b():h(),k=""}function m(e){y+=e.cN?d(e.cN,"",!0):"",E=Object.create(e,{parent:{value:E}})}function N(e,n){if(k+=e,null==n)return v(),0;var t=c(n,E);if(t)return t.skip?k+=n:(t.eB&&(k+=n),v(),t.rB||t.eB||(k=n)),m(t,n),t.rB?0:n.length;var r=u(E,n);if(r){var a=E;a.skip?k+=n:(a.rE||a.eE||(k+=n),v(),a.eE&&(k=n));do E.cN&&(y+=I),E.skip||E.sL||(M+=E.r),E=E.parent;while(E!==r.parent);return r.starts&&(r.endSameAsBegin&&(r.starts.eR=r.eR),m(r.starts,"")),a.rE?0:n.length}if(s(n,E))throw new Error('Illegal lexeme "'+n+'" for mode "'+(E.cN||"")+'"');return k+=n,n.length||1}var R=w(e);if(!R)throw new Error('Unknown language: "'+e+'"');l(R);var x,E=i||R,B={},y="";for(x=E;x!==R;x=x.parent)x.cN&&(y=d(x.cN,"",!0)+y);var k="",M=0;try{for(var C,A,S=0;;){if(E.t.lastIndex=S,C=E.t.exec(t),!C)break;A=N(t.substring(S,C.index),C[0]),S=C.index+A}for(N(t.substr(S)),x=E;x.parent;x=x.parent)x.cN&&(y+=I);return{r:M,value:y,language:e,top:E}}catch(O){if(O.message&&-1!==O.message.indexOf("Illegal"))return{r:0,value:n(t)};throw O}}function g(e,t){t=t||j.languages||B(L);var r={r:0,value:n(e)},a=r;return t.filter(w).filter(x).forEach(function(n){var t=f(n,e,!1);t.language=n,t.r>a.r&&(a=t),t.r>r.r&&(a=r,r=t)}),a.language&&(r.second_best=a),r}function p(e){return j.tabReplace||j.useBR?e.replace(C,function(e,n){return j.useBR&&"\n"===e?" ":j.tabReplace?n.replace(/\t/g,j.tabReplace):""}):e}function d(e,n,t){var r=n?y[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),-1===e.indexOf(r)&&a.push(r),a.join(" ").trim()}function h(e){var n,t,r,o,s,l=i(e);a(l)||(j.useBR?(n=document.createElementNS("http://www.w3.org/1999/xhtml","div"),n.innerHTML=e.innerHTML.replace(/\n/g,"").replace(/ /g,"\n")):n=e,s=n.textContent,r=l?f(l,s,!0):g(s),t=c(n),t.length&&(o=document.createElementNS("http://www.w3.org/1999/xhtml","div"),o.innerHTML=r.value,r.value=u(t,c(o),s)),r.value=p(r.value),e.innerHTML=r.value,e.className=d(e.className,l,r.language),e.result={language:r.language,re:r.r},r.second_best&&(e.second_best={language:r.second_best.language,re:r.second_best.r}))}function b(e){j=o(j,e)}function v(){if(!v.called){v.called=!0;var e=document.querySelectorAll("pre code");E.forEach.call(e,h)}}function m(){addEventListener("DOMContentLoaded",v,!1),addEventListener("load",v,!1)}function N(n,t){var r=L[n]=t(e);r.aliases&&r.aliases.forEach(function(e){y[e]=n})}function R(){return B(L)}function w(e){return e=(e||"").toLowerCase(),L[e]||L[y[e]]}function x(e){var n=w(e);return n&&!n.disableAutodetect}var E=[],B=Object.keys,L={},y={},k=/^(no-?highlight|plain|text)$/i,M=/\blang(?:uage)?-([\w-]+)\b/i,C=/((^(<[^>]+>|\t|)+|(?:\n)))/gm,I=" ",j={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0};return e.highlight=f,e.highlightAuto=g,e.fixMarkup=p,e.highlightBlock=h,e.configure=b,e.initHighlighting=v,e.initHighlightingOnLoad=m,e.registerLanguage=N,e.listLanguages=R,e.getLanguage=w,e.autoDetection=x,e.inherit=o,e.IR="[a-zA-Z]\\w*",e.UIR="[a-zA-Z_]\\w*",e.NR="\\b\\d+(\\.\\d+)?",e.CNR="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",e.BNR="\\b(0b[01]+)",e.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",e.BE={b:"\\\\[\\s\\S]",r:0},e.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[e.BE]},e.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[e.BE]},e.PWM={b:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},e.C=function(n,t,r){var a=e.inherit({cN:"comment",b:n,e:t,c:[]},r||{});return a.c.push(e.PWM),a.c.push({cN:"doctag",b:"(?:TODO|FIXME|NOTE|BUG|XXX):",r:0}),a},e.CLCM=e.C("//","$"),e.CBCM=e.C("/\\*","\\*/"),e.HCM=e.C("#","$"),e.NM={cN:"number",b:e.NR,r:0},e.CNM={cN:"number",b:e.CNR,r:0},e.BNM={cN:"number",b:e.BNR,r:0},e.CSSNM={cN:"number",b:e.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0},e.RM={cN:"regexp",b:/\//,e:/\/[gimuy]*/,i:/\n/,c:[e.BE,{b:/\[/,e:/\]/,r:0,c:[e.BE]}]},e.TM={cN:"title",b:e.IR,r:0},e.UTM={cN:"title",b:e.UIR,r:0},e.METHOD_GUARD={b:"\\.\\s*"+e.UIR,r:0},e});hljs.registerLanguage("bash",function(e){var t={cN:"variable",v:[{b:/\$[\w\d#@][\w\d_]*/},{b:/\$\{(.*?)}/}]},s={cN:"string",b:/"/,e:/"/,c:[e.BE,t,{cN:"variable",b:/\$\(/,e:/\)/,c:[e.BE]}]},a={cN:"string",b:/'/,e:/'/};return{aliases:["sh","zsh"],l:/\b-?[a-z\._]+\b/,k:{keyword:"if then else elif fi for while in do done case esac function",literal:"true false",built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp",_:"-ne -eq -lt -gt -f -d -e -s -l -a"},c:[{cN:"meta",b:/^#![^\n]+sh\s*$/,r:10},{cN:"function",b:/\w[\w\d_]*\s*\(\s*\)\s*\{/,rB:!0,c:[e.inherit(e.TM,{b:/\w[\w\d_]*/})],r:0},e.HCM,s,a,t]}});hljs.registerLanguage("dockerfile",function(e){return{aliases:["docker"],cI:!0,k:"from maintainer expose env arg user onbuild stopsignal",c:[e.HCM,e.ASM,e.QSM,e.NM,{bK:"run cmd entrypoint volume add copy workdir label healthcheck shell",starts:{e:/[^\\]\n/,sL:"bash"}}],i:""}});hljs.registerLanguage("kotlin",function(e){var t={keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit init interface annotation data sealed internal infix operator out by constructor super tailrec where const inner suspend typealias external expect actual trait volatile transient native default",built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing",literal:"true false null"},r={cN:"keyword",b:/\b(break|continue|return|this)\b/,starts:{c:[{cN:"symbol",b:/@\w+/}]}},a={cN:"symbol",b:e.UIR+"@"},i={cN:"subst",b:"\\${",e:"}",c:[e.ASM,e.CNM]},n={cN:"variable",b:"\\$"+e.UIR},c={cN:"string",v:[{b:'"""',e:'"""',c:[n,i]},{b:"'",e:"'",i:/\n/,c:[e.BE]},{b:'"',e:'"',i:/\n/,c:[e.BE,n,i]}]},s={cN:"meta",b:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+e.UIR+")?"},l={cN:"meta",b:"@"+e.UIR,c:[{b:/\(/,e:/\)/,c:[e.inherit(c,{cN:"meta-string"})]}]},b="\\b(0[bB]([01]+[01_]+[01]+|[01]+)|0[xX]([a-fA-F0-9]+[a-fA-F0-9_]+[a-fA-F0-9]+|[a-fA-F0-9]+)|(([\\d]+[\\d_]+[\\d]+|[\\d]+)(\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))?|\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))([eE][-+]?\\d+)?)[lLfF]?",o={cN:"number",b:b,r:0};return{aliases:["kt"],k:t,c:[e.C("/\\*\\*","\\*/",{r:0,c:[{cN:"doctag",b:"@[A-Za-z]+"}]}),e.CLCM,e.CBCM,r,a,s,l,{cN:"function",bK:"fun",e:"[(]|$",rB:!0,eE:!0,k:t,i:/fun\s+(<.*>)?[^\s\(]+(\s+[^\s\(]+)\s*=/,r:5,c:[{b:e.UIR+"\\s*\\(",rB:!0,r:0,c:[e.UTM]},{cN:"type",b:/,e:/>/,k:"reified",r:0},{cN:"params",b:/\(/,e:/\)/,endsParent:!0,k:t,r:0,c:[{b:/:/,e:/[=,\/]/,eW:!0,c:[{cN:"type",b:e.UIR},e.CLCM,e.CBCM],r:0},e.CLCM,e.CBCM,s,l,c,e.CNM]},e.CBCM]},{cN:"class",bK:"class interface trait",e:/[:\{(]|$/,eE:!0,i:"extends implements",c:[{bK:"public protected internal private constructor"},e.UTM,{cN:"type",b:/,e:/>/,eB:!0,eE:!0,r:0},{cN:"type",b:/[,:]\s*/,e:/[<\(,]|$/,eB:!0,rE:!0},s,l]},c,{cN:"meta",b:"^#!/usr/bin/env",e:"$",i:"\n"},o]}});hljs.registerLanguage("java",function(e){var a="[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*",t=a+"(<"+a+"(\\s*,\\s*"+a+")*>)?",r="false synchronized int abstract float private char boolean var static null if const for true while long strictfp finally protected import native final void enum else break transient catch instanceof byte super volatile case assert short package default double public try this switch continue throws protected public private module requires exports do",s="\\b(0[bB]([01]+[01_]+[01]+|[01]+)|0[xX]([a-fA-F0-9]+[a-fA-F0-9_]+[a-fA-F0-9]+|[a-fA-F0-9]+)|(([\\d]+[\\d_]+[\\d]+|[\\d]+)(\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))?|\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))([eE][-+]?\\d+)?)[lLfF]?",c={cN:"number",b:s,r:0};return{aliases:["jsp"],k:r,i:/<\/|#/,c:[e.C("/\\*\\*","\\*/",{r:0,c:[{b:/\w+@/,r:0},{cN:"doctag",b:"@[A-Za-z]+"}]}),e.CLCM,e.CBCM,e.ASM,e.QSM,{cN:"class",bK:"class interface",e:/[{;=]/,eE:!0,k:"class interface",i:/[:"\[\]]/,c:[{bK:"extends implements"},e.UTM]},{bK:"new throw return else",r:0},{cN:"function",b:"("+t+"\\s+)+"+e.UIR+"\\s*\\(",rB:!0,e:/[{;=]/,eE:!0,k:r,c:[{b:e.UIR+"\\s*\\(",rB:!0,r:0,c:[e.UTM]},{cN:"params",b:/\(/,e:/\)/,k:r,r:0,c:[e.ASM,e.QSM,e.CNM,e.CBCM]},e.CLCM,e.CBCM]},c,{cN:"meta",b:"@[A-Za-z]+"}]}});hljs.registerLanguage("xml",function(s){var e="[A-Za-z0-9\\._:-]+",t={eW:!0,i:/,r:0,c:[{cN:"attr",b:e,r:0},{b:/=\s*/,r:0,c:[{cN:"string",endsParent:!0,v:[{b:/"/,e:/"/},{b:/'/,e:/'/},{b:/[^\s"'=<>`]+/}]}]}]};return{aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist"],cI:!0,c:[{cN:"meta",b:"",r:10,c:[{b:"\\[",e:"\\]"}]},s.C("",{r:10}),{b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{cN:"meta",b:/<\?xml/,e:/\?>/,r:10},{b:/<\?(php)?/,e:/\?>/,sL:"php",c:[{b:"/\\*",e:"\\*/",skip:!0},{b:'b"',e:'"',skip:!0},{b:"b'",e:"'",skip:!0},s.inherit(s.ASM,{i:null,cN:null,c:null,skip:!0}),s.inherit(s.QSM,{i:null,cN:null,c:null,skip:!0})]},{cN:"tag",b:"",rE:!0,sL:["css","xml"]}},{cN:"tag",b:"",rE:!0,sL:["actionscript","javascript","handlebars","xml"]}},{cN:"tag",b:"?",e:"/?>",c:[{cN:"name",b:/[^\/><\s]+/,r:0},t]}]}});hljs.registerLanguage("properties",function(r){var t="[ \\t\\f]*",e="[ \\t\\f]+",s="("+t+"[:=]"+t+"|"+e+")",n="([^\\\\\\W:= \\t\\f\\n]|\\\\.)+",a="([^\\\\:= \\t\\f\\n]|\\\\.)+",c={e:s,r:0,starts:{cN:"string",e:/$/,r:0,c:[{b:"\\\\\\n"}]}};return{cI:!0,i:/\S/,c:[r.C("^\\s*[!#]","$"),{b:n+s,rB:!0,c:[{cN:"attr",b:n,endsParent:!0,r:0}],starts:c},{b:a+s,rB:!0,r:0,c:[{cN:"meta",b:a,endsParent:!0,r:0}],starts:c},{cN:"attr",r:0,b:a+t+"$"}]}});hljs.registerLanguage("diff",function(e){return{aliases:["patch"],c:[{cN:"meta",r:10,v:[{b:/^@@ +\-\d+,\d+ +\+\d+,\d+ +@@$/},{b:/^\*\*\* +\d+,\d+ +\*\*\*\*$/},{b:/^\-\-\- +\d+,\d+ +\-\-\-\-$/}]},{cN:"comment",v:[{b:/Index: /,e:/$/},{b:/={3,}/,e:/$/},{b:/^\-{3}/,e:/$/},{b:/^\*{3} /,e:/$/},{b:/^\+{3}/,e:/$/},{b:/\*{5}/,e:/\*{5}$/}]},{cN:"addition",b:"^\\+",e:"$"},{cN:"deletion",b:"^\\-",e:"$"},{cN:"addition",b:"^\\!",e:"$"}]}});hljs.registerLanguage("shell",function(s){return{aliases:["console"],c:[{cN:"meta",b:"^\\s{0,3}[\\w\\d\\[\\]()@-]*[>%$#]",starts:{e:"$",sL:"bash"}}]}});hljs.registerLanguage("asciidoc",function(e){return{aliases:["adoc"],c:[e.C("^/{4,}\\n","\\n/{4,}$",{r:10}),e.C("^//","$",{r:0}),{cN:"title",b:"^\\.\\w.*$"},{b:"^[=\\*]{4,}\\n",e:"\\n^[=\\*]{4,}$",r:10},{cN:"section",r:10,v:[{b:"^(={1,5}) .+?( \\1)?$"},{b:"^[^\\[\\]\\n]+?\\n[=\\-~\\^\\+]{2,}$"}]},{cN:"meta",b:"^:.+?:",e:"\\s",eE:!0,r:10},{cN:"meta",b:"^\\[.+?\\]$",r:0},{cN:"quote",b:"^_{4,}\\n",e:"\\n_{4,}$",r:10},{cN:"code",b:"^[\\-\\.]{4,}\\n",e:"\\n[\\-\\.]{4,}$",r:10},{b:"^\\+{4,}\\n",e:"\\n\\+{4,}$",c:[{b:"<",e:">",sL:"xml",r:0}],r:10},{cN:"bullet",b:"^(\\*+|\\-+|\\.+|[^\\n]+?::)\\s+"},{cN:"symbol",b:"^(NOTE|TIP|IMPORTANT|WARNING|CAUTION):\\s+",r:10},{cN:"strong",b:"\\B\\*(?![\\*\\s])",e:"(\\n{2}|\\*)",c:[{b:"\\\\*\\w",r:0}]},{cN:"emphasis",b:"\\B'(?!['\\s])",e:"(\\n{2}|')",c:[{b:"\\\\'\\w",r:0}],r:0},{cN:"emphasis",b:"_(?![_\\s])",e:"(\\n{2}|_)",r:0},{cN:"string",v:[{b:"``.+?''"},{b:"`.+?'"}]},{cN:"code",b:"(`.+?`|\\+.+?\\+)",r:0},{cN:"code",b:"^[ \\t]",e:"$",r:0},{b:"^'{3,}[ \\t]*$",r:10},{b:"(link:)?(http|https|ftp|file|irc|image:?):\\S+\\[.*?\\]",rB:!0,c:[{b:"(link|image:?):",r:0},{cN:"link",b:"\\w",e:"[^\\[]+",r:0},{cN:"string",b:"\\[",e:"\\]",eB:!0,eE:!0,r:0}],r:10}]}});hljs.registerLanguage("aspectj",function(e){var t="false synchronized int abstract float private char boolean static null if const for true while long throw strictfp finally protected import native final return void enum else extends implements break transient new catch instanceof byte super volatile case assert short package default double public try this switch continue throws privileged aspectOf adviceexecution proceed cflowbelow cflow initialization preinitialization staticinitialization withincode target within execution getWithinTypeName handler thisJoinPoint thisJoinPointStaticPart thisEnclosingJoinPointStaticPart declare parents warning error soft precedence thisAspectInstance",i="get set args call";return{k:t,i:/<\/|#/,c:[e.C("/\\*\\*","\\*/",{r:0,c:[{b:/\w+@/,r:0},{cN:"doctag",b:"@[A-Za-z]+"}]}),e.CLCM,e.CBCM,e.ASM,e.QSM,{cN:"class",bK:"aspect",e:/[{;=]/,eE:!0,i:/[:;"\[\]]/,c:[{bK:"extends implements pertypewithin perthis pertarget percflowbelow percflow issingleton"},e.UTM,{b:/\([^\)]*/,e:/[)]+/,k:t+" "+i,eE:!1}]},{cN:"class",bK:"class interface",e:/[{;=]/,eE:!0,r:0,k:"class interface",i:/[:"\[\]]/,c:[{bK:"extends implements"},e.UTM]},{bK:"pointcut after before around throwing returning",e:/[)]/,eE:!1,i:/["\[\]]/,c:[{b:e.UIR+"\\s*\\(",rB:!0,c:[e.UTM]}]},{b:/[:]/,rB:!0,e:/[{;]/,r:0,eE:!1,k:t,i:/["\[\]]/,c:[{b:e.UIR+"\\s*\\(",k:t+" "+i,r:0},e.QSM]},{bK:"new throw",r:0},{cN:"function",b:/\w+ +\w+(\.)?\w+\s*\([^\)]*\)\s*((throws)[\w\s,]+)?[\{;]/,rB:!0,e:/[{;=]/,k:t,eE:!0,c:[{b:e.UIR+"\\s*\\(",rB:!0,r:0,c:[e.UTM]},{cN:"params",b:/\(/,e:/\)/,r:0,k:t,c:[e.ASM,e.QSM,e.CNM,e.CBCM]},e.CLCM,e.CBCM]},e.CNM,{cN:"meta",b:"@[A-Za-z]+"}]}});hljs.registerLanguage("gradle",function(e){return{cI:!0,k:{keyword:"task project allprojects subprojects artifacts buildscript configurations dependencies repositories sourceSets description delete from into include exclude source classpath destinationDir includes options sourceCompatibility targetCompatibility group flatDir doLast doFirst flatten todir fromdir ant def abstract break case catch continue default do else extends final finally for if implements instanceof native new private protected public return static switch synchronized throw throws transient try volatile while strictfp package import false null super this true antlrtask checkstyle codenarc copy boolean byte char class double float int interface long short void compile runTime file fileTree abs any append asList asWritable call collect compareTo count div dump each eachByte eachFile eachLine every find findAll flatten getAt getErr getIn getOut getText grep immutable inject inspect intersect invokeMethods isCase join leftShift minus multiply newInputStream newOutputStream newPrintWriter newReader newWriter next plus pop power previous print println push putAt read readBytes readLines reverse reverseEach round size sort splitEachLine step subMap times toInteger toList tokenize upto waitForOrKill withPrintWriter withReader withStream withWriter withWriterAppend write writeLine"},c:[e.CLCM,e.CBCM,e.ASM,e.QSM,e.NM,e.RM]}});hljs.registerLanguage("json",function(e){var i={literal:"true false null"},n=[e.QSM,e.CNM],r={e:",",eW:!0,eE:!0,c:n,k:i},t={b:"{",e:"}",c:[{cN:"attr",b:/"/,e:/"/,c:[e.BE],i:"\\n"},e.inherit(r,{b:/:/})],i:"\\S"},c={b:"\\[",e:"\\]",c:[e.inherit(r)],i:"\\S"};return n.splice(n.length,0,t,c),{c:n,k:i,i:"\\S"}});hljs.registerLanguage("sql",function(e){var t=e.C("--","$");return{cI:!0,i:/[<>{}*]/,c:[{bK:"begin end start commit rollback savepoint lock alter create drop rename call delete do handler insert load replace select truncate update set show pragma grant merge describe use explain help declare prepare execute deallocate release unlock purge reset change stop analyze cache flush optimize repair kill install uninstall checksum restore check backup revoke comment with",e:/;/,eW:!0,l:/[\w\.]+/,k:{keyword:"as abort abs absolute acc acce accep accept access accessed accessible account acos action activate add addtime admin administer advanced advise aes_decrypt aes_encrypt after agent aggregate ali alia alias allocate allow alter always analyze ancillary and any anydata anydataset anyschema anytype apply archive archived archivelog are as asc ascii asin assembly assertion associate asynchronous at atan atn2 attr attri attrib attribu attribut attribute attributes audit authenticated authentication authid authors auto autoallocate autodblink autoextend automatic availability avg backup badfile basicfile before begin beginning benchmark between bfile bfile_base big bigfile bin binary_double binary_float binlog bit_and bit_count bit_length bit_or bit_xor bitmap blob_base block blocksize body both bound buffer_cache buffer_pool build bulk by byte byteordermark bytes cache caching call calling cancel capacity cascade cascaded case cast catalog category ceil ceiling chain change changed char_base char_length character_length characters characterset charindex charset charsetform charsetid check checksum checksum_agg child choose chr chunk class cleanup clear client clob clob_base clone close cluster_id cluster_probability cluster_set clustering coalesce coercibility col collate collation collect colu colum column column_value columns columns_updated comment commit compact compatibility compiled complete composite_limit compound compress compute concat concat_ws concurrent confirm conn connec connect connect_by_iscycle connect_by_isleaf connect_by_root connect_time connection consider consistent constant constraint constraints constructor container content contents context contributors controlfile conv convert convert_tz corr corr_k corr_s corresponding corruption cos cost count count_big counted covar_pop covar_samp cpu_per_call cpu_per_session crc32 create creation critical cross cube cume_dist curdate current current_date current_time current_timestamp current_user cursor curtime customdatum cycle data database databases datafile datafiles datalength date_add date_cache date_format date_sub dateadd datediff datefromparts datename datepart datetime2fromparts day day_to_second dayname dayofmonth dayofweek dayofyear days db_role_change dbtimezone ddl deallocate declare decode decompose decrement decrypt deduplicate def defa defau defaul default defaults deferred defi defin define degrees delayed delegate delete delete_all delimited demand dense_rank depth dequeue des_decrypt des_encrypt des_key_file desc descr descri describ describe descriptor deterministic diagnostics difference dimension direct_load directory disable disable_all disallow disassociate discardfile disconnect diskgroup distinct distinctrow distribute distributed div do document domain dotnet double downgrade drop dumpfile duplicate duration each edition editionable editions element ellipsis else elsif elt empty enable enable_all enclosed encode encoding encrypt end end-exec endian enforced engine engines enqueue enterprise entityescaping eomonth error errors escaped evalname evaluate event eventdata events except exception exceptions exchange exclude excluding execu execut execute exempt exists exit exp expire explain export export_set extended extent external external_1 external_2 externally extract failed failed_login_attempts failover failure far fast feature_set feature_value fetch field fields file file_name_convert filesystem_like_logging final finish first first_value fixed flash_cache flashback floor flush following follows for forall force foreign form forma format found found_rows freelist freelists freepools fresh from from_base64 from_days ftp full function general generated get get_format get_lock getdate getutcdate global global_name globally go goto grant grants greatest group group_concat group_id grouping grouping_id groups gtid_subtract guarantee guard handler hash hashkeys having hea head headi headin heading heap help hex hierarchy high high_priority hosts hour http id ident_current ident_incr ident_seed identified identity idle_time if ifnull ignore iif ilike ilm immediate import in include including increment index indexes indexing indextype indicator indices inet6_aton inet6_ntoa inet_aton inet_ntoa infile initial initialized initially initrans inmemory inner innodb input insert install instance instantiable instr interface interleaved intersect into invalidate invisible is is_free_lock is_ipv4 is_ipv4_compat is_not is_not_null is_used_lock isdate isnull isolation iterate java join json json_exists keep keep_duplicates key keys kill language large last last_day last_insert_id last_value lax lcase lead leading least leaves left len lenght length less level levels library like like2 like4 likec limit lines link list listagg little ln load load_file lob lobs local localtime localtimestamp locate locator lock locked log log10 log2 logfile logfiles logging logical logical_reads_per_call logoff logon logs long loop low low_priority lower lpad lrtrim ltrim main make_set makedate maketime managed management manual map mapping mask master master_pos_wait match matched materialized max maxextents maximize maxinstances maxlen maxlogfiles maxloghistory maxlogmembers maxsize maxtrans md5 measures median medium member memcompress memory merge microsecond mid migration min minextents minimum mining minus minute minvalue missing mod mode model modification modify module monitoring month months mount move movement multiset mutex name name_const names nan national native natural nav nchar nclob nested never new newline next nextval no no_write_to_binlog noarchivelog noaudit nobadfile nocheck nocompress nocopy nocycle nodelay nodiscardfile noentityescaping noguarantee nokeep nologfile nomapping nomaxvalue nominimize nominvalue nomonitoring none noneditionable nonschema noorder nopr nopro noprom nopromp noprompt norely noresetlogs noreverse normal norowdependencies noschemacheck noswitch not nothing notice notnull notrim novalidate now nowait nth_value nullif nulls num numb numbe nvarchar nvarchar2 object ocicoll ocidate ocidatetime ociduration ociinterval ociloblocator ocinumber ociref ocirefcursor ocirowid ocistring ocitype oct octet_length of off offline offset oid oidindex old on online only opaque open operations operator optimal optimize option optionally or oracle oracle_date oradata ord ordaudio orddicom orddoc order ordimage ordinality ordvideo organization orlany orlvary out outer outfile outline output over overflow overriding package pad parallel parallel_enable parameters parent parse partial partition partitions pascal passing password password_grace_time password_lock_time password_reuse_max password_reuse_time password_verify_function patch path patindex pctincrease pctthreshold pctused pctversion percent percent_rank percentile_cont percentile_disc performance period period_add period_diff permanent physical pi pipe pipelined pivot pluggable plugin policy position post_transaction pow power pragma prebuilt precedes preceding precision prediction prediction_cost prediction_details prediction_probability prediction_set prepare present preserve prior priority private private_sga privileges procedural procedure procedure_analyze processlist profiles project prompt protection public publishingservername purge quarter query quick quiesce quota quotename radians raise rand range rank raw read reads readsize rebuild record records recover recovery recursive recycle redo reduced ref reference referenced references referencing refresh regexp_like register regr_avgx regr_avgy regr_count regr_intercept regr_r2 regr_slope regr_sxx regr_sxy reject rekey relational relative relaylog release release_lock relies_on relocate rely rem remainder rename repair repeat replace replicate replication required reset resetlogs resize resource respect restore restricted result result_cache resumable resume retention return returning returns reuse reverse revoke right rlike role roles rollback rolling rollup round row row_count rowdependencies rowid rownum rows rtrim rules safe salt sample save savepoint sb1 sb2 sb4 scan schema schemacheck scn scope scroll sdo_georaster sdo_topo_geometry search sec_to_time second section securefile security seed segment select self sequence sequential serializable server servererror session session_user sessions_per_user set sets settings sha sha1 sha2 share shared shared_pool short show shrink shutdown si_averagecolor si_colorhistogram si_featurelist si_positionalcolor si_stillimage si_texture siblings sid sign sin size size_t sizes skip slave sleep smalldatetimefromparts smallfile snapshot some soname sort soundex source space sparse spfile split sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_small_result sql_variant_property sqlcode sqldata sqlerror sqlname sqlstate sqrt square standalone standby start starting startup statement static statistics stats_binomial_test stats_crosstab stats_ks_test stats_mode stats_mw_test stats_one_way_anova stats_t_test_ stats_t_test_indep stats_t_test_one stats_t_test_paired stats_wsr_test status std stddev stddev_pop stddev_samp stdev stop storage store stored str str_to_date straight_join strcmp strict string struct stuff style subdate subpartition subpartitions substitutable substr substring subtime subtring_index subtype success sum suspend switch switchoffset switchover sync synchronous synonym sys sys_xmlagg sysasm sysaux sysdate sysdatetimeoffset sysdba sysoper system system_user sysutcdatetime table tables tablespace tan tdo template temporary terminated tertiary_weights test than then thread through tier ties time time_format time_zone timediff timefromparts timeout timestamp timestampadd timestampdiff timezone_abbr timezone_minute timezone_region to to_base64 to_date to_days to_seconds todatetimeoffset trace tracking transaction transactional translate translation treat trigger trigger_nestlevel triggers trim truncate try_cast try_convert try_parse type ub1 ub2 ub4 ucase unarchived unbounded uncompress under undo unhex unicode uniform uninstall union unique unix_timestamp unknown unlimited unlock unnest unpivot unrecoverable unsafe unsigned until untrusted unusable unused update updated upgrade upped upper upsert url urowid usable usage use use_stored_outlines user user_data user_resources users using utc_date utc_timestamp uuid uuid_short validate validate_password_strength validation valist value values var var_samp varcharc vari varia variab variabl variable variables variance varp varraw varrawc varray verify version versions view virtual visible void wait wallet warning warnings week weekday weekofyear wellformed when whene whenev wheneve whenever where while whitespace with within without work wrapped xdb xml xmlagg xmlattributes xmlcast xmlcolattval xmlelement xmlexists xmlforest xmlindex xmlnamespaces xmlpi xmlquery xmlroot xmlschema xmlserialize xmltable xmltype xor year year_to_month years yearweek",literal:"true false null unknown",built_in:"array bigint binary bit blob bool boolean char character date dec decimal float int int8 integer interval number numeric real record serial serial8 smallint text time timestamp varchar varying void"},c:[{cN:"string",b:"'",e:"'",c:[e.BE,{b:"''"}]},{cN:"string",b:'"',e:'"',c:[e.BE,{b:'""'}]},{cN:"string",b:"`",e:"`",c:[e.BE]},e.CNM,e.CBCM,t,e.HCM]},e.CBCM,t,e.HCM]}});hljs.registerLanguage("go",function(e){var t={keyword:"break default func interface select case map struct chan else goto package switch const fallthrough if range type continue for import return var go defer bool byte complex64 complex128 float32 float64 int8 int16 int32 int64 string uint8 uint16 uint32 uint64 int uint uintptr rune",literal:"true false iota nil",built_in:"append cap close complex copy imag len make new panic print println real recover delete"};return{aliases:["golang"],k:t,i:"",c:[e.CLCM,e.CBCM,{cN:"string",v:[e.QSM,{b:"'",e:"[^\\\\]'"},{b:"`",e:"`"}]},{cN:"number",v:[{b:e.CNR+"[dflsi]",r:1},e.CNM]},{b:/:=/},{cN:"function",bK:"func",e:/\s*\{/,eE:!0,c:[e.TM,{cN:"params",b:/\(/,e:/\)/,k:t,i:/["']/}]}]}});hljs.registerLanguage("http",function(e){var t="HTTP/[0-9\\.]+";return{aliases:["https"],i:"\\S",c:[{b:"^"+t,e:"$",c:[{cN:"number",b:"\\b\\d{3}\\b"}]},{b:"^[A-Z]+ (.*?) "+t+"$",rB:!0,e:"$",c:[{cN:"string",b:" ",e:" ",eB:!0,eE:!0},{b:t},{cN:"keyword",b:"[A-Z]+"}]},{cN:"attribute",b:"^\\w",e:": ",eE:!0,i:"\\n|\\s|=",starts:{e:"$",r:0}},{b:"\\n\\n",starts:{sL:[],eW:!0}}]}});hljs.registerLanguage("groovy",function(e){return{k:{literal:"true false null",keyword:"byte short char int long boolean float double void def as in assert trait super this abstract static volatile transient public private protected synchronized final class interface enum if else for while switch case break default continue throw throws try catch finally implements extends new import package return instanceof"},c:[e.C("/\\*\\*","\\*/",{r:0,c:[{b:/\w+@/,r:0},{cN:"doctag",b:"@[A-Za-z]+"}]}),e.CLCM,e.CBCM,{cN:"string",b:'"""',e:'"""'},{cN:"string",b:"'''",e:"'''"},{cN:"string",b:"\\$/",e:"/\\$",r:10},e.ASM,{cN:"regexp",b:/~?\/[^\/\n]+\//,c:[e.BE]},e.QSM,{cN:"meta",b:"^#!/usr/bin/env",e:"$",i:"\n"},e.BNM,{cN:"class",bK:"class interface trait enum",e:"{",i:":",c:[{bK:"extends implements"},e.UTM]},e.CNM,{cN:"meta",b:"@[A-Za-z]+"},{cN:"string",b:/[^\?]{0}[A-Za-z0-9_$]+ *:/},{b:/\?/,e:/\:/},{cN:"symbol",b:"^\\s*[A-Za-z0-9_$]+:",r:0}],i:/#|<\//}});hljs.registerLanguage("plaintext",function(e){return{disableAutodetect:!0}});hljs.registerLanguage("css",function(e){var c="[a-zA-Z-][a-zA-Z0-9_-]*",t={b:/[A-Z\_\.\-]+\s*:/,rB:!0,e:";",eW:!0,c:[{cN:"attribute",b:/\S/,e:":",eE:!0,starts:{eW:!0,eE:!0,c:[{b:/[\w-]+\(/,rB:!0,c:[{cN:"built_in",b:/[\w-]+/},{b:/\(/,e:/\)/,c:[e.ASM,e.QSM]}]},e.CSSNM,e.QSM,e.ASM,e.CBCM,{cN:"number",b:"#[0-9A-Fa-f]+"},{cN:"meta",b:"!important"}]}}]};return{cI:!0,i:/[=\/|'\$]/,c:[e.CBCM,{cN:"selector-id",b:/#[A-Za-z0-9_-]+/},{cN:"selector-class",b:/\.[A-Za-z0-9_-]+/},{cN:"selector-attr",b:/\[/,e:/\]/,i:"$"},{cN:"selector-pseudo",b:/:(:)?[a-zA-Z0-9\_\-\+\(\)"'.]+/},{b:"@(font-face|page)",l:"[a-z-]+",k:"font-face page"},{b:"@",e:"[{;]",i:/:/,c:[{cN:"keyword",b:/\w+/},{b:/\s/,eW:!0,eE:!0,r:0,c:[e.ASM,e.QSM,e.CSSNM]}]},{cN:"selector-tag",b:c,r:0},{b:"{",e:"}",i:/\S/,c:[e.CBCM,t]}]}});hljs.registerLanguage("javascript",function(e){var r="[A-Za-z$_][0-9A-Za-z$_]*",t={keyword:"in of if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const export super debugger as async await static import from as",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document Symbol Set Map WeakSet WeakMap Proxy Reflect Promise"},a={cN:"number",v:[{b:"\\b(0[bB][01]+)"},{b:"\\b(0[oO][0-7]+)"},{b:e.CNR}],r:0},n={cN:"subst",b:"\\$\\{",e:"\\}",k:t,c:[]},c={cN:"string",b:"`",e:"`",c:[e.BE,n]};n.c=[e.ASM,e.QSM,c,a,e.RM];var s=n.c.concat([e.CBCM,e.CLCM]);return{aliases:["js","jsx"],k:t,c:[{cN:"meta",r:10,b:/^\s*['"]use (strict|asm)['"]/},{cN:"meta",b:/^#!/,e:/$/},e.ASM,e.QSM,c,e.CLCM,e.CBCM,a,{b:/[{,]\s*/,r:0,c:[{b:r+"\\s*:",rB:!0,r:0,c:[{cN:"attr",b:r,r:0}]}]},{b:"("+e.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[e.CLCM,e.CBCM,e.RM,{cN:"function",b:"(\\(.*?\\)|"+r+")\\s*=>",rB:!0,e:"\\s*=>",c:[{cN:"params",v:[{b:r},{b:/\(\s*\)/},{b:/\(/,e:/\)/,eB:!0,eE:!0,k:t,c:s}]}]},{b:/,e:/(\/\w+|\w+\/)>/,sL:"xml",c:[{b:/<\w+\s*\/>/,skip:!0},{b:/<\w+/,e:/(\/\w+|\w+\/)>/,skip:!0,c:[{b:/<\w+\s*\/>/,skip:!0},"self"]}]}],r:0},{cN:"function",bK:"function",e:/\{/,eE:!0,c:[e.inherit(e.TM,{b:r}),{cN:"params",b:/\(/,e:/\)/,eB:!0,eE:!0,c:s}],i:/\[|%/},{b:/\$[(.]/},e.METHOD_GUARD,{cN:"class",bK:"class",e:/[{;=]/,eE:!0,i:/[:"\[\]]/,c:[{bK:"extends"},e.UTM]},{bK:"constructor",e:/\{/,eE:!0}],i:/#(?!!)/}});
\ No newline at end of file
diff --git a/reference/html/js/highlight/styles/a11y-dark.min.css b/reference/html/js/highlight/styles/a11y-dark.min.css
new file mode 100644
index 00000000..b93b742a
--- /dev/null
+++ b/reference/html/js/highlight/styles/a11y-dark.min.css
@@ -0,0 +1,99 @@
+/* a11y-dark theme */
+/* Based on the Tomorrow Night Eighties theme: https://github.com/isagalaev/highlight.js/blob/master/src/styles/tomorrow-night-eighties.css */
+/* @author: ericwbailey */
+
+/* Comment */
+.hljs-comment,
+.hljs-quote {
+ color: #d4d0ab;
+}
+
+/* Red */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-tag,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-regexp,
+.hljs-deletion {
+ color: #ffa07a;
+}
+
+/* Orange */
+.hljs-number,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-type,
+.hljs-params,
+.hljs-meta,
+.hljs-link {
+ color: #f5ab35;
+}
+
+/* Yellow */
+.hljs-attribute {
+ color: #ffd700;
+}
+
+/* Green */
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-addition {
+ color: #abe338;
+}
+
+/* Blue */
+.hljs-title,
+.hljs-section {
+ color: #00e0e0;
+}
+
+/* Purple */
+.hljs-keyword,
+.hljs-selector-tag {
+ color: #dcc6e0;
+}
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ background: #2b2b2b;
+ color: #f8f8f2;
+ padding: 0.5em;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
+
+@media screen and (-ms-high-contrast: active) {
+ .hljs-addition,
+ .hljs-attribute,
+ .hljs-built_in,
+ .hljs-builtin-name,
+ .hljs-bullet,
+ .hljs-comment,
+ .hljs-link,
+ .hljs-literal,
+ .hljs-meta,
+ .hljs-number,
+ .hljs-params,
+ .hljs-string,
+ .hljs-symbol,
+ .hljs-type,
+ .hljs-quote {
+ color: highlight;
+ }
+
+ .hljs-keyword,
+ .hljs-selector-tag {
+ font-weight: bold;
+ }
+}
diff --git a/reference/html/js/highlight/styles/an-old-hope.min.css b/reference/html/js/highlight/styles/an-old-hope.min.css
new file mode 100644
index 00000000..a6d56f4b
--- /dev/null
+++ b/reference/html/js/highlight/styles/an-old-hope.min.css
@@ -0,0 +1,89 @@
+/*
+
+An Old Hope – Star Wars Syntax (c) Gustavo Costa
+Original theme - Ocean Dark Theme – by https://github.com/gavsiu
+Based on Jesse Leite's Atom syntax theme 'An Old Hope' – https://github.com/JesseLeite/an-old-hope-syntax-atom
+
+*/
+
+/* Death Star Comment */
+.hljs-comment,
+.hljs-quote
+{
+ color: #B6B18B;
+}
+
+/* Darth Vader */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-tag,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-regexp,
+.hljs-deletion
+{
+ color: #EB3C54;
+}
+
+/* Threepio */
+.hljs-number,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-type,
+.hljs-params,
+.hljs-meta,
+.hljs-link
+{
+ color: #E7CE56;
+}
+
+/* Luke Skywalker */
+.hljs-attribute
+{
+ color: #EE7C2B;
+}
+
+/* Obi Wan Kenobi */
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-addition
+{
+ color: #4FB4D7;
+}
+
+/* Yoda */
+.hljs-title,
+.hljs-section
+{
+ color: #78BB65;
+}
+
+/* Mace Windu */
+.hljs-keyword,
+.hljs-selector-tag
+{
+ color: #B45EA4;
+}
+
+/* Millenium Falcon */
+.hljs
+{
+ display: block;
+ overflow-x: auto;
+ background: #1C1D21;
+ color: #c0c5ce;
+ padding: 0.5em;
+}
+
+.hljs-emphasis
+{
+ font-style: italic;
+}
+
+.hljs-strong
+{
+ font-weight: bold;
+}
diff --git a/reference/html/js/highlight/styles/atom-one-dark-reasonable.min.css b/reference/html/js/highlight/styles/atom-one-dark-reasonable.min.css
new file mode 100644
index 00000000..fd41c996
--- /dev/null
+++ b/reference/html/js/highlight/styles/atom-one-dark-reasonable.min.css
@@ -0,0 +1,77 @@
+/*
+
+Atom One Dark With support for ReasonML by Gidi Morris, based off work by Daniel Gamage
+
+Original One Dark Syntax theme from https://github.com/atom/one-dark-syntax
+
+*/
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ line-height: 1.3em;
+ color: #abb2bf;
+ background: #282c34;
+ border-radius: 5px;
+}
+.hljs-keyword, .hljs-operator {
+ color: #F92672;
+}
+.hljs-pattern-match {
+ color: #F92672;
+}
+.hljs-pattern-match .hljs-constructor {
+ color: #61aeee;
+}
+.hljs-function {
+ color: #61aeee;
+}
+.hljs-function .hljs-params {
+ color: #A6E22E;
+}
+.hljs-function .hljs-params .hljs-typing {
+ color: #FD971F;
+}
+.hljs-module-access .hljs-module {
+ color: #7e57c2;
+}
+.hljs-constructor {
+ color: #e2b93d;
+}
+.hljs-constructor .hljs-string {
+ color: #9CCC65;
+}
+.hljs-comment, .hljs-quote {
+ color: #b18eb1;
+ font-style: italic;
+}
+.hljs-doctag, .hljs-formula {
+ color: #c678dd;
+}
+.hljs-section, .hljs-name, .hljs-selector-tag, .hljs-deletion, .hljs-subst {
+ color: #e06c75;
+}
+.hljs-literal {
+ color: #56b6c2;
+}
+.hljs-string, .hljs-regexp, .hljs-addition, .hljs-attribute, .hljs-meta-string {
+ color: #98c379;
+}
+.hljs-built_in, .hljs-class .hljs-title {
+ color: #e6c07b;
+}
+.hljs-attr, .hljs-variable, .hljs-template-variable, .hljs-type, .hljs-selector-class, .hljs-selector-attr, .hljs-selector-pseudo, .hljs-number {
+ color: #d19a66;
+}
+.hljs-symbol, .hljs-bullet, .hljs-link, .hljs-meta, .hljs-selector-id, .hljs-title {
+ color: #61aeee;
+}
+.hljs-emphasis {
+ font-style: italic;
+}
+.hljs-strong {
+ font-weight: bold;
+}
+.hljs-link {
+ text-decoration: underline;
+}
diff --git a/reference/html/js/highlight/styles/atom-one-dark.min.css b/reference/html/js/highlight/styles/atom-one-dark.min.css
new file mode 100644
index 00000000..1616aafe
--- /dev/null
+++ b/reference/html/js/highlight/styles/atom-one-dark.min.css
@@ -0,0 +1,96 @@
+/*
+
+Atom One Dark by Daniel Gamage
+Original One Dark Syntax theme from https://github.com/atom/one-dark-syntax
+
+base: #282c34
+mono-1: #abb2bf
+mono-2: #818896
+mono-3: #5c6370
+hue-1: #56b6c2
+hue-2: #61aeee
+hue-3: #c678dd
+hue-4: #98c379
+hue-5: #e06c75
+hue-5-2: #be5046
+hue-6: #d19a66
+hue-6-2: #e6c07b
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ color: #abb2bf;
+ background: #282c34;
+}
+
+.hljs-comment,
+.hljs-quote {
+ color: #5c6370;
+ font-style: italic;
+}
+
+.hljs-doctag,
+.hljs-keyword,
+.hljs-formula {
+ color: #c678dd;
+}
+
+.hljs-section,
+.hljs-name,
+.hljs-selector-tag,
+.hljs-deletion,
+.hljs-subst {
+ color: #e06c75;
+}
+
+.hljs-literal {
+ color: #56b6c2;
+}
+
+.hljs-string,
+.hljs-regexp,
+.hljs-addition,
+.hljs-attribute,
+.hljs-meta-string {
+ color: #98c379;
+}
+
+.hljs-built_in,
+.hljs-class .hljs-title {
+ color: #e6c07b;
+}
+
+.hljs-attr,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-type,
+.hljs-selector-class,
+.hljs-selector-attr,
+.hljs-selector-pseudo,
+.hljs-number {
+ color: #d19a66;
+}
+
+.hljs-symbol,
+.hljs-bullet,
+.hljs-link,
+.hljs-meta,
+.hljs-selector-id,
+.hljs-title {
+ color: #61aeee;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
+
+.hljs-link {
+ text-decoration: underline;
+}
diff --git a/reference/html/js/highlight/styles/atom-one-light.min.css b/reference/html/js/highlight/styles/atom-one-light.min.css
new file mode 100644
index 00000000..d5bd1d2a
--- /dev/null
+++ b/reference/html/js/highlight/styles/atom-one-light.min.css
@@ -0,0 +1,96 @@
+/*
+
+Atom One Light by Daniel Gamage
+Original One Light Syntax theme from https://github.com/atom/one-light-syntax
+
+base: #fafafa
+mono-1: #383a42
+mono-2: #686b77
+mono-3: #a0a1a7
+hue-1: #0184bb
+hue-2: #4078f2
+hue-3: #a626a4
+hue-4: #50a14f
+hue-5: #e45649
+hue-5-2: #c91243
+hue-6: #986801
+hue-6-2: #c18401
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ color: #383a42;
+ background: #fafafa;
+}
+
+.hljs-comment,
+.hljs-quote {
+ color: #a0a1a7;
+ font-style: italic;
+}
+
+.hljs-doctag,
+.hljs-keyword,
+.hljs-formula {
+ color: #a626a4;
+}
+
+.hljs-section,
+.hljs-name,
+.hljs-selector-tag,
+.hljs-deletion,
+.hljs-subst {
+ color: #e45649;
+}
+
+.hljs-literal {
+ color: #0184bb;
+}
+
+.hljs-string,
+.hljs-regexp,
+.hljs-addition,
+.hljs-attribute,
+.hljs-meta-string {
+ color: #50a14f;
+}
+
+.hljs-built_in,
+.hljs-class .hljs-title {
+ color: #c18401;
+}
+
+.hljs-attr,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-type,
+.hljs-selector-class,
+.hljs-selector-attr,
+.hljs-selector-pseudo,
+.hljs-number {
+ color: #986801;
+}
+
+.hljs-symbol,
+.hljs-bullet,
+.hljs-link,
+.hljs-meta,
+.hljs-selector-id,
+.hljs-title {
+ color: #4078f2;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
+
+.hljs-link {
+ text-decoration: underline;
+}
diff --git a/reference/html/js/highlight/styles/dracula.min.css b/reference/html/js/highlight/styles/dracula.min.css
new file mode 100644
index 00000000..578f0b40
--- /dev/null
+++ b/reference/html/js/highlight/styles/dracula.min.css
@@ -0,0 +1,76 @@
+/*
+
+Dracula Theme v1.2.0
+
+https://github.com/zenorocha/dracula-theme
+
+Copyright 2015, All rights reserved
+
+Code licensed under the MIT license
+https://zenorocha.mit-license.org/
+
+@author Éverton Ribeiro
+@author Zeno Rocha
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: #282a36;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-literal,
+.hljs-section,
+.hljs-link {
+ color: #8be9fd;
+}
+
+.hljs-function .hljs-keyword {
+ color: #ff79c6;
+}
+
+.hljs,
+.hljs-subst {
+ color: #f8f8f2;
+}
+
+.hljs-string,
+.hljs-title,
+.hljs-name,
+.hljs-type,
+.hljs-attribute,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-addition,
+.hljs-variable,
+.hljs-template-tag,
+.hljs-template-variable {
+ color: #f1fa8c;
+}
+
+.hljs-comment,
+.hljs-quote,
+.hljs-deletion,
+.hljs-meta {
+ color: #6272a4;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-literal,
+.hljs-title,
+.hljs-section,
+.hljs-doctag,
+.hljs-type,
+.hljs-name,
+.hljs-strong {
+ font-weight: bold;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
diff --git a/reference/html/js/highlight/styles/github-gist.css b/reference/html/js/highlight/styles/github-gist.css
new file mode 100644
index 00000000..2706084a
--- /dev/null
+++ b/reference/html/js/highlight/styles/github-gist.css
@@ -0,0 +1,79 @@
+/**
+ * GitHub Gist Theme
+ * Author : Anthony Attard - https://github.com/AnthonyAttard
+ * Author : Louis Barranqueiro - https://github.com/LouisBarranqueiro
+ */
+
+.hljs {
+ display: block;
+ background: white;
+ padding: 0.5em;
+ color: #333333;
+ overflow-x: auto;
+}
+
+.hljs-comment,
+.hljs-meta {
+ color: #969896;
+}
+
+.hljs-variable,
+.hljs-template-variable,
+.hljs-strong,
+.hljs-emphasis,
+.hljs-quote {
+ color: #df5000;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-type {
+ color: #d73a49;
+}
+
+.hljs-literal,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-attribute {
+ color: #0086b3;
+}
+
+.hljs-section,
+.hljs-name {
+ color: #63a35c;
+}
+
+.hljs-tag {
+ color: #333333;
+}
+
+.hljs-title,
+.hljs-attr,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-selector-attr,
+.hljs-selector-pseudo {
+ color: #6f42c1;
+}
+
+.hljs-addition {
+ color: #55a532;
+ background-color: #eaffea;
+}
+
+.hljs-deletion {
+ color: #bd2c00;
+ background-color: #ffecec;
+}
+
+.hljs-link {
+ text-decoration: underline;
+}
+
+.hljs-number {
+ color: #005cc5;
+}
+
+.hljs-string {
+ color: #032f62;
+}
diff --git a/reference/html/js/highlight/styles/github-gist.min.css b/reference/html/js/highlight/styles/github-gist.min.css
new file mode 100644
index 00000000..2706084a
--- /dev/null
+++ b/reference/html/js/highlight/styles/github-gist.min.css
@@ -0,0 +1,79 @@
+/**
+ * GitHub Gist Theme
+ * Author : Anthony Attard - https://github.com/AnthonyAttard
+ * Author : Louis Barranqueiro - https://github.com/LouisBarranqueiro
+ */
+
+.hljs {
+ display: block;
+ background: white;
+ padding: 0.5em;
+ color: #333333;
+ overflow-x: auto;
+}
+
+.hljs-comment,
+.hljs-meta {
+ color: #969896;
+}
+
+.hljs-variable,
+.hljs-template-variable,
+.hljs-strong,
+.hljs-emphasis,
+.hljs-quote {
+ color: #df5000;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-type {
+ color: #d73a49;
+}
+
+.hljs-literal,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-attribute {
+ color: #0086b3;
+}
+
+.hljs-section,
+.hljs-name {
+ color: #63a35c;
+}
+
+.hljs-tag {
+ color: #333333;
+}
+
+.hljs-title,
+.hljs-attr,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-selector-attr,
+.hljs-selector-pseudo {
+ color: #6f42c1;
+}
+
+.hljs-addition {
+ color: #55a532;
+ background-color: #eaffea;
+}
+
+.hljs-deletion {
+ color: #bd2c00;
+ background-color: #ffecec;
+}
+
+.hljs-link {
+ text-decoration: underline;
+}
+
+.hljs-number {
+ color: #005cc5;
+}
+
+.hljs-string {
+ color: #032f62;
+}
diff --git a/reference/html/js/highlight/styles/github.min.css b/reference/html/js/highlight/styles/github.min.css
new file mode 100644
index 00000000..791932b8
--- /dev/null
+++ b/reference/html/js/highlight/styles/github.min.css
@@ -0,0 +1,99 @@
+/*
+
+github.com style (c) Vasily Polovnyov
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ color: #333;
+ background: #f8f8f8;
+}
+
+.hljs-comment,
+.hljs-quote {
+ color: #998;
+ font-style: italic;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-subst {
+ color: #333;
+ font-weight: bold;
+}
+
+.hljs-number,
+.hljs-literal,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-tag .hljs-attr {
+ color: #008080;
+}
+
+.hljs-string,
+.hljs-doctag {
+ color: #d14;
+}
+
+.hljs-title,
+.hljs-section,
+.hljs-selector-id {
+ color: #900;
+ font-weight: bold;
+}
+
+.hljs-subst {
+ font-weight: normal;
+}
+
+.hljs-type,
+.hljs-class .hljs-title {
+ color: #458;
+ font-weight: bold;
+}
+
+.hljs-tag,
+.hljs-name,
+.hljs-attribute {
+ color: #000080;
+ font-weight: normal;
+}
+
+.hljs-regexp,
+.hljs-link {
+ color: #009926;
+}
+
+.hljs-symbol,
+.hljs-bullet {
+ color: #990073;
+}
+
+.hljs-built_in,
+.hljs-builtin-name {
+ color: #0086b3;
+}
+
+.hljs-meta {
+ color: #999;
+ font-weight: bold;
+}
+
+.hljs-deletion {
+ background: #fdd;
+}
+
+.hljs-addition {
+ background: #dfd;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/reference/html/js/highlight/styles/googlecode.css b/reference/html/js/highlight/styles/googlecode.css
new file mode 100644
index 00000000..0cf18a04
--- /dev/null
+++ b/reference/html/js/highlight/styles/googlecode.css
@@ -0,0 +1,89 @@
+/*
+
+Google Code style (c) Aahan Krish
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: white;
+ color: black;
+}
+
+.hljs-comment,
+.hljs-quote {
+ color: #800;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-section,
+.hljs-title,
+.hljs-name {
+ color: #008;
+}
+
+.hljs-variable,
+.hljs-template-variable {
+ color: #660;
+}
+
+.hljs-string,
+.hljs-selector-attr,
+.hljs-selector-pseudo,
+.hljs-regexp {
+ color: #080;
+}
+
+.hljs-literal,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-meta,
+.hljs-number,
+.hljs-link {
+ color: #066;
+}
+
+.hljs-title,
+.hljs-doctag,
+.hljs-type,
+.hljs-attr,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-params {
+ color: #606;
+}
+
+.hljs-attribute,
+.hljs-subst {
+ color: #000;
+}
+
+.hljs-formula {
+ background-color: #eee;
+ font-style: italic;
+}
+
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #9B703F
+}
+
+.hljs-addition {
+ background-color: #baeeba;
+}
+
+.hljs-deletion {
+ background-color: #ffc8bd;
+}
+
+.hljs-doctag,
+.hljs-strong {
+ font-weight: bold;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
diff --git a/reference/html/js/highlight/styles/googlecode.min.css b/reference/html/js/highlight/styles/googlecode.min.css
new file mode 100644
index 00000000..0cf18a04
--- /dev/null
+++ b/reference/html/js/highlight/styles/googlecode.min.css
@@ -0,0 +1,89 @@
+/*
+
+Google Code style (c) Aahan Krish
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: white;
+ color: black;
+}
+
+.hljs-comment,
+.hljs-quote {
+ color: #800;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-section,
+.hljs-title,
+.hljs-name {
+ color: #008;
+}
+
+.hljs-variable,
+.hljs-template-variable {
+ color: #660;
+}
+
+.hljs-string,
+.hljs-selector-attr,
+.hljs-selector-pseudo,
+.hljs-regexp {
+ color: #080;
+}
+
+.hljs-literal,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-meta,
+.hljs-number,
+.hljs-link {
+ color: #066;
+}
+
+.hljs-title,
+.hljs-doctag,
+.hljs-type,
+.hljs-attr,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-params {
+ color: #606;
+}
+
+.hljs-attribute,
+.hljs-subst {
+ color: #000;
+}
+
+.hljs-formula {
+ background-color: #eee;
+ font-style: italic;
+}
+
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #9B703F
+}
+
+.hljs-addition {
+ background-color: #baeeba;
+}
+
+.hljs-deletion {
+ background-color: #ffc8bd;
+}
+
+.hljs-doctag,
+.hljs-strong {
+ font-weight: bold;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
diff --git a/reference/html/js/highlight/styles/monokai-sublime.min.css b/reference/html/js/highlight/styles/monokai-sublime.min.css
new file mode 100644
index 00000000..ed52c92e
--- /dev/null
+++ b/reference/html/js/highlight/styles/monokai-sublime.min.css
@@ -0,0 +1,83 @@
+/*
+
+Monokai Sublime style. Derived from Monokai by noformnocontent https://nn.mit-license.org/
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: #23241f;
+}
+
+.hljs,
+.hljs-tag,
+.hljs-subst {
+ color: #f8f8f2;
+}
+
+.hljs-strong,
+.hljs-emphasis {
+ color: #a8a8a2;
+}
+
+.hljs-bullet,
+.hljs-quote,
+.hljs-number,
+.hljs-regexp,
+.hljs-literal,
+.hljs-link {
+ color: #ae81ff;
+}
+
+.hljs-code,
+.hljs-title,
+.hljs-section,
+.hljs-selector-class {
+ color: #a6e22e;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-name,
+.hljs-attr {
+ color: #f92672;
+}
+
+.hljs-symbol,
+.hljs-attribute {
+ color: #66d9ef;
+}
+
+.hljs-params,
+.hljs-class .hljs-title {
+ color: #f8f8f2;
+}
+
+.hljs-string,
+.hljs-type,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-selector-id,
+.hljs-selector-attr,
+.hljs-selector-pseudo,
+.hljs-addition,
+.hljs-variable,
+.hljs-template-variable {
+ color: #e6db74;
+}
+
+.hljs-comment,
+.hljs-deletion,
+.hljs-meta {
+ color: #75715e;
+}
diff --git a/reference/html/js/highlight/styles/monokai.min.css b/reference/html/js/highlight/styles/monokai.min.css
new file mode 100644
index 00000000..a5735585
--- /dev/null
+++ b/reference/html/js/highlight/styles/monokai.min.css
@@ -0,0 +1,70 @@
+/*
+Monokai style - ported by Luigi Maselli - https://grigio.org
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: #272822; color: #ddd;
+}
+
+.hljs-tag,
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-literal,
+.hljs-strong,
+.hljs-name {
+ color: #f92672;
+}
+
+.hljs-code {
+ color: #66d9ef;
+}
+
+.hljs-class .hljs-title {
+ color: white;
+}
+
+.hljs-attribute,
+.hljs-symbol,
+.hljs-regexp,
+.hljs-link {
+ color: #bf79db;
+}
+
+.hljs-string,
+.hljs-bullet,
+.hljs-subst,
+.hljs-title,
+.hljs-section,
+.hljs-emphasis,
+.hljs-type,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-selector-attr,
+.hljs-selector-pseudo,
+.hljs-addition,
+.hljs-variable,
+.hljs-template-tag,
+.hljs-template-variable {
+ color: #a6e22e;
+}
+
+.hljs-comment,
+.hljs-quote,
+.hljs-deletion,
+.hljs-meta {
+ color: #75715e;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-literal,
+.hljs-doctag,
+.hljs-title,
+.hljs-section,
+.hljs-type,
+.hljs-selector-id {
+ font-weight: bold;
+}
diff --git a/reference/html/js/highlight/styles/solarized-light.min.css b/reference/html/js/highlight/styles/solarized-light.min.css
new file mode 100644
index 00000000..fdcfcc72
--- /dev/null
+++ b/reference/html/js/highlight/styles/solarized-light.min.css
@@ -0,0 +1,84 @@
+/*
+
+Orginal Style from ethanschoonover.com/solarized (c) Jeremy Hull
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: #fdf6e3;
+ color: #657b83;
+}
+
+.hljs-comment,
+.hljs-quote {
+ color: #93a1a1;
+}
+
+/* Solarized Green */
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-addition {
+ color: #859900;
+}
+
+/* Solarized Cyan */
+.hljs-number,
+.hljs-string,
+.hljs-meta .hljs-meta-string,
+.hljs-literal,
+.hljs-doctag,
+.hljs-regexp {
+ color: #2aa198;
+}
+
+/* Solarized Blue */
+.hljs-title,
+.hljs-section,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #268bd2;
+}
+
+/* Solarized Yellow */
+.hljs-attribute,
+.hljs-attr,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-class .hljs-title,
+.hljs-type {
+ color: #b58900;
+}
+
+/* Solarized Orange */
+.hljs-symbol,
+.hljs-bullet,
+.hljs-subst,
+.hljs-meta,
+.hljs-meta .hljs-keyword,
+.hljs-selector-attr,
+.hljs-selector-pseudo,
+.hljs-link {
+ color: #cb4b16;
+}
+
+/* Solarized Red */
+.hljs-built_in,
+.hljs-deletion {
+ color: #dc322f;
+}
+
+.hljs-formula {
+ background: #eee8d5;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/reference/html/js/highlight/styles/zenburn.min.css b/reference/html/js/highlight/styles/zenburn.min.css
new file mode 100644
index 00000000..07be5020
--- /dev/null
+++ b/reference/html/js/highlight/styles/zenburn.min.css
@@ -0,0 +1,80 @@
+/*
+
+Zenburn style from voldmar.ru (c) Vladimir Epifanov
+based on dark.css by Ivan Sagalaev
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: #3f3f3f;
+ color: #dcdcdc;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-tag {
+ color: #e3ceab;
+}
+
+.hljs-template-tag {
+ color: #dcdcdc;
+}
+
+.hljs-number {
+ color: #8cd0d3;
+}
+
+.hljs-variable,
+.hljs-template-variable,
+.hljs-attribute {
+ color: #efdcbc;
+}
+
+.hljs-literal {
+ color: #efefaf;
+}
+
+.hljs-subst {
+ color: #8f8f8f;
+}
+
+.hljs-title,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-section,
+.hljs-type {
+ color: #efef8f;
+}
+
+.hljs-symbol,
+.hljs-bullet,
+.hljs-link {
+ color: #dca3a3;
+}
+
+.hljs-deletion,
+.hljs-string,
+.hljs-built_in,
+.hljs-builtin-name {
+ color: #cc9393;
+}
+
+.hljs-addition,
+.hljs-comment,
+.hljs-quote,
+.hljs-meta {
+ color: #7f9f7f;
+}
+
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/reference/html/js/toc.js b/reference/html/js/toc.js
new file mode 100644
index 00000000..0b6fcd65
--- /dev/null
+++ b/reference/html/js/toc.js
@@ -0,0 +1,80 @@
+var toctitle = document.getElementById('toctitle');
+var path = window.location.pathname;
+if (toctitle != null) {
+ var oldtoc = toctitle.nextElementSibling;
+ var newtoc = document.createElement('div');
+ newtoc.setAttribute('id', 'tocbot');
+ newtoc.setAttribute('class', 'js-toc desktop-toc');
+ oldtoc.setAttribute('class', 'mobile-toc');
+ oldtoc.parentNode.appendChild(newtoc);
+ tocbot.init({
+ contentSelector: '#content',
+ headingSelector: 'h1, h2, h3, h4, h5',
+ positionFixedSelector: 'body',
+ fixedSidebarOffset: 90,
+ smoothScroll: false
+ });
+ if (!path.endsWith("index.html") && !path.endsWith("/")) {
+ var link = document.createElement("a");
+ if (document.getElementById('index-link')) {
+ indexLinkElement = document.querySelector('#index-link > p > a');
+ linkHref = indexLinkElement.getAttribute("href");
+ link.setAttribute("href", linkHref);
+ } else {
+ link.setAttribute("href", "index.html");
+ }
+ link.innerHTML = " Back to index";
+ var block = document.createElement("div");
+ block.setAttribute('class', 'back-action');
+ block.appendChild(link);
+ var toc = document.getElementById('toc');
+ var next = document.getElementById('toctitle').nextElementSibling;
+ toc.insertBefore(block, next);
+ }
+}
+
+var headerHtml = '';
+
+var header = document.createElement("div");
+header.innerHTML = headerHtml;
+document.body.insertBefore(header, document.body.firstChild);
diff --git a/reference/html/js/tocbot/tocbot.css b/reference/html/js/tocbot/tocbot.css
new file mode 100644
index 00000000..0632de23
--- /dev/null
+++ b/reference/html/js/tocbot/tocbot.css
@@ -0,0 +1 @@
+.toc{overflow-y:auto}.toc>.toc-list{overflow:hidden;position:relative}.toc>.toc-list li{list-style:none}.toc-list{margin:0;padding-left:10px}a.toc-link{color:currentColor;height:100%}.is-collapsible{max-height:1000px;overflow:hidden;transition:all 300ms ease-in-out}.is-collapsed{max-height:0}.is-position-fixed{position:fixed !important;top:0}.is-active-link{font-weight:700}.toc-link::before{background-color:#EEE;content:' ';display:inline-block;height:inherit;left:0;margin-top:-1px;position:absolute;width:2px}.is-active-link::before{background-color:#54BC4B}
diff --git a/reference/html/js/tocbot/tocbot.min.js b/reference/html/js/tocbot/tocbot.min.js
new file mode 100644
index 00000000..943d8fdb
--- /dev/null
+++ b/reference/html/js/tocbot/tocbot.min.js
@@ -0,0 +1 @@
+!function(e){function t(o){if(n[o])return n[o].exports;var l=n[o]={i:o,l:!1,exports:{}};return e[o].call(l.exports,l,l.exports,t),l.l=!0,l.exports}var n={};t.m=e,t.c=n,t.d=function(e,n,o){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:o})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=0)}([function(e,t,n){(function(o){var l,i,s;!function(n,o){i=[],l=o(n),void 0!==(s="function"==typeof l?l.apply(t,i):l)&&(e.exports=s)}(void 0!==o?o:this.window||this.global,function(e){"use strict";function t(){for(var e={},t=0;te.fixedSidebarOffset?-1===n.className.indexOf(e.positionFixedClass)&&(n.className+=h+e.positionFixedClass):n.className=n.className.split(h+e.positionFixedClass).join("")}function s(t){var n=document.documentElement.scrollTop||f.scrollTop;e.positionFixedSelector&&i();var o,l=t;if(m&&null!==document.querySelector(e.tocSelector)&&l.length>0){d.call(l,function(t,i){if(t.offsetTop>n+e.headingsOffset+10){return o=l[0===i?i:i-1],!0}if(i===l.length-1)return o=l[l.length-1],!0});var s=document.querySelector(e.tocSelector).querySelectorAll("."+e.linkClass);u.call(s,function(t){t.className=t.className.split(h+e.activeLinkClass).join("")});var c=document.querySelector(e.tocSelector).querySelectorAll("."+e.listItemClass);u.call(c,function(t){t.className=t.className.split(h+e.activeListItemClass).join("")});var a=document.querySelector(e.tocSelector).querySelector("."+e.linkClass+".node-name--"+o.nodeName+'[href="#'+o.id+'"]');-1===a.className.indexOf(e.activeLinkClass)&&(a.className+=h+e.activeLinkClass);var p=a.parentNode;p&&-1===p.className.indexOf(e.activeListItemClass)&&(p.className+=h+e.activeListItemClass);var C=document.querySelector(e.tocSelector).querySelectorAll("."+e.listClass+"."+e.collapsibleClass);u.call(C,function(t){-1===t.className.indexOf(e.isCollapsedClass)&&(t.className+=h+e.isCollapsedClass)}),a.nextSibling&&-1!==a.nextSibling.className.indexOf(e.isCollapsedClass)&&(a.nextSibling.className=a.nextSibling.className.split(h+e.isCollapsedClass).join("")),r(a.parentNode.parentNode)}}function r(t){return-1!==t.className.indexOf(e.collapsibleClass)&&-1!==t.className.indexOf(e.isCollapsedClass)?(t.className=t.className.split(h+e.isCollapsedClass).join(""),r(t.parentNode.parentNode)):t}function c(t){var n=t.target||t.srcElement;"string"==typeof n.className&&-1!==n.className.indexOf(e.linkClass)&&(m=!1)}function a(){m=!0}var u=[].forEach,d=[].some,f=document.body,m=!0,h=" ";return{enableTocAnimation:a,disableTocAnimation:c,render:n,updateToc:s}}},function(e,t){e.exports=function(e){function t(e){return e[e.length-1]}function n(e){return+e.nodeName.split("H").join("")}function o(t){var o={id:t.id,children:[],nodeName:t.nodeName,headingLevel:n(t),textContent:t.textContent.trim()};return e.includeHtml&&(o.childNodes=t.childNodes),o}function l(l,i){for(var s=o(l),r=n(l),c=i,a=t(c),u=a?a.headingLevel:0,d=r-u;d>0;)a=t(c),a&&void 0!==a.children&&(c=a.children),d--;return r>=e.collapseDepth&&(s.isCollapsed=!0),c.push(s),c}function i(t,n){var o=n;e.ignoreSelector&&(o=n.split(",").map(function(t){return t.trim()+":not("+e.ignoreSelector+")"}));try{return document.querySelector(t).querySelectorAll(o)}catch(e){return console.warn("Element not found: "+t),null}}function s(e){return r.call(e,function(e,t){return l(o(t),e.nest),e},{nest:[]})}var r=[].reduce;return{nestHeadingsArray:s,selectHeadings:i}}},function(e,t){function n(e){function t(e){return"a"===e.tagName.toLowerCase()&&(e.hash.length>0||"#"===e.href.charAt(e.href.length-1))&&(n(e.href)===s||n(e.href)+"#"===s)}function n(e){return e.slice(0,e.lastIndexOf("#"))}function l(e){var t=document.getElementById(e.substring(1));t&&(/^(?:a|select|input|button|textarea)$/i.test(t.tagName)||(t.tabIndex=-1),t.focus())}!function(){document.documentElement.style}();var i=e.duration,s=location.hash?n(location.href):location.href;!function(){function n(n){!t(n.target)||n.target.className.indexOf("no-smooth-scroll")>-1||"#"===n.target.href.charAt(n.target.href.length-2)&&"!"===n.target.href.charAt(n.target.href.length-1)||-1===n.target.className.indexOf(e.linkClass)||o(n.target.hash,{duration:i,callback:function(){l(n.target.hash)}})}document.body.addEventListener("click",n,!1)}()}function o(e,t){function n(e){s=e-i,window.scrollTo(0,c.easing(s,r,u,d)),s
+
+
+
+
+
+
+Untitled
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/reference/html/sagan-index.html b/reference/html/sagan-index.html
new file mode 100644
index 00000000..fc29fad9
--- /dev/null
+++ b/reference/html/sagan-index.html
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
+Untitled
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/reference/html/spring-cloud-cli.html b/reference/html/spring-cloud-cli.html
new file mode 100644
index 00000000..bc8f3466
--- /dev/null
+++ b/reference/html/spring-cloud-cli.html
@@ -0,0 +1,432 @@
+
+
+
+
+
+
+
+Spring Boot Cloud CLI
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Spring Boot CLI provides Spring
+Boot command line features for Spring
+Cloud . You can write Groovy scripts to run Spring Cloud component
+applications (e.g. @EnableEurekaServer). You can also easily do
+things like encryption and decryption to support Spring Cloud Config
+clients with secret configuration values. With the Launcher CLI you
+can launch services like Eureka, Zipkin, Config Server
+conveniently all at once from the command line (very useful at
+development time).
+
+
+
+
+
+
+
+
+Spring Cloud is released under the non-restrictive Apache 2.0 license. If you would like to contribute to this section of the documentation or if you find an error, please find the source code and issue trackers in the project at github .
+
+
+
+
+
+
+
+
+
+
+
+
+
$ spring version
+Spring CLI v2.2.0.BUILD-SNAPSHOT
+
+
+
+
+
+
$ sdk install springboot 2.2.0.BUILD-SNAPSHOT
+$ sdk use springboot 2.2.0.BUILD-SNAPSHOT
+
+
+
+
and install the Spring Cloud plugin
+
+
+
+
$ mvn install
+$ spring install org.springframework.cloud:spring-cloud-cli:2.2.0.BUILD-SNAPSHOT
+
+
+
+
+
+
+
+
+
+Prerequisites: to use the encryption and decryption features
+you need the full-strength JCE installed in your JVM (it’s not there by default).
+You can download the "Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files"
+from Oracle, and follow instructions for installation (essentially replace the 2 policy files
+in the JRE lib/security directory with the ones that you downloaded).
+
+
+
+
+
+
+
+
+
+
+
The Launcher CLI can be used to run common services like Eureka,
+Config Server etc. from the command line. To list the available
+services you can do spring cloud --list, and to launch a default set
+of services just spring cloud. To choose the services to deploy,
+just list them on the command line, e.g.
+
+
+
+
$ spring cloud eureka configserver h2 kafka stubrunner zipkin
+
+
+
+
Summary of supported deployables:
+
+
+
+
+
+
+
+
+
+
+Service
+Name
+Address
+Description
+
+
+
+
+eureka
+Eureka Server
+http://localhost:8761
+Eureka server for service registration and discovery. All the other services show up in its catalog by default.
+
+
+configserver
+Config Server
+http://localhost:8888
+Spring Cloud Config Server running in the "native" profile and serving configuration from the local directory ./launcher
+
+
+h2
+H2 Database
+http://localhost:9095 (console), jdbc:h2:tcp://localhost:9096/{data}
+Relation database service. Use a file path for {data} (e.g. ./target/test) when you connect. Remember that you can add ;MODE=MYSQL or ;MODE=POSTGRESQL to connect with compatibility to other server types.
+
+
+kafka
+Kafka Broker
+http://localhost:9091 (actuator endpoints), localhost:9092
+
+
+
+dataflow
+Dataflow Server
+http://localhost:9393
+Spring Cloud Dataflow server with UI at /admin-ui. Connect the Dataflow shell to target at root path.
+
+
+zipkin
+Zipkin Server
+http://localhost:9411
+Zipkin Server with UI for visualizing traces. Stores span data in memory and accepts them via HTTP POST of JSON data.
+
+
+stubrunner
+Stub Runner Boot
+http://localhost:8750
+Downloads WireMock stubs, starts WireMock and feeds the started servers with stored stubs. Pass stubrunner.ids to pass stub coordinates and then go to http://localhost:8750/stubs .
+
+
+
+
+
Each of these apps can be configured using a local YAML file with the same name (in the current
+working directory or a subdirectory called "config" or in ~/.spring-cloud). E.g. in configserver.yml you might want to
+do something like this to locate a local git repository for the backend:
+
+
+
configserver.yml
+
+
spring:
+ profiles:
+ active: git
+ cloud:
+ config:
+ server:
+ git:
+ uri: file://${user.home}/dev/demo/config-repo
+
+
+
+
E.g. in Stub Runner app you could fetch stubs from your local .m2 in the following way.
+
+
+
stubrunner.yml
+
+
stubrunner:
+ workOffline: true
+ ids:
+ - com.example:beer-api-producer:+:9876
+
+
+
+
+
+
Additional applications can be added to ./config/cloud.yml (not
+./config.yml because that would replace the defaults), e.g. with
+
+
+
config/cloud.yml
+
+
spring:
+ cloud:
+ launcher:
+ deployables:
+ source:
+ coordinates: maven://com.example:source:0.0.1-SNAPSHOT
+ port: 7000
+ sink:
+ coordinates: maven://com.example:sink:0.0.1-SNAPSHOT
+ port: 7001
+
+
+
+
when you list the apps:
+
+
+
+
$ spring cloud --list
+source sink configserver dataflow eureka h2 kafka stubrunner zipkin
+
+
+
+
(notice the additional apps at the start of the list).
+
+
+
+
+
+
+
+
+
Spring Cloud CLI has support for most of the Spring Cloud declarative
+features, such as the @Enable* class of annotations. For example,
+here is a fully functional Eureka server
+
+
+
app.groovy
+
+
@EnableEurekaServer
+class Eureka {}
+
+
+
+
which you can run from the command line like this
+
+
+
+
$ spring run app.groovy
+
+
+
+
To include additional dependencies, often it suffices just to add the
+appropriate feature-enabling annotation, e.g. @EnableConfigServer,
+@EnableOAuth2Sso or @EnableEurekaClient. To manually include a
+dependency you can use a @Grab with the special "Spring Boot" short
+style artifact co-ordinates, i.e. with just the artifact ID (no need
+for group or version information), e.g. to set up a client app to
+listen on AMQP for management events from the Spring CLoud Bus:
+
+
+
app.groovy
+
+
@Grab('spring-cloud-starter-bus-amqp')
+@RestController
+class Service {
+ @RequestMapping('/')
+ def home() { [message: 'Hello'] }
+}
+
+
+
+
+
+
+
+
+
The Spring Cloud CLI comes with an "encrypt" and a "decrypt"
+command. Both accept arguments in the same form with a key specified
+as a mandatory "--key", e.g.
+
+
+
+
$ spring encrypt mysecret --key foo
+682bc583f4641835fa2db009355293665d2647dade3375c0ee201de2a49f7bda
+$ spring decrypt --key foo 682bc583f4641835fa2db009355293665d2647dade3375c0ee201de2a49f7bda
+mysecret
+
+
+
+
To use a key in a file (e.g. an RSA public key for encyption) prepend
+the key value with "@" and provide the file path, e.g.
+
+
+
+
$ spring encrypt mysecret --key @${HOME}/.ssh/id_rsa.pub
+AQAjPgt3eFZQXwt8tsHAVv/QHiY5sI2dRcR+...
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/reference/htmlsingle/css/spring.css b/reference/htmlsingle/css/spring.css
new file mode 100644
index 00000000..9366c397
--- /dev/null
+++ b/reference/htmlsingle/css/spring.css
@@ -0,0 +1 @@
+@import url("https://fonts.googleapis.com/css?family=Open+Sans:400,700&display=swap");/*! normalize.css v2.1.2 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden],template{display:none}script{display:none !important}html,body{font-size:100%}html{font-family:'Open Sans', sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}*,*:before,*:after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}body{background:white;color:#000;padding:0;margin:0;font-size:16px;font-family:'Open Sans', sans-serif;font-weight:normal;font-style:normal;line-height:1.6em;position:relative;cursor:auto}a:hover{cursor:pointer}img,object,embed{max-width:100%;height:auto}object,embed{height:100%}img{-ms-interpolation-mode:bicubic}#map_canvas img,#map_canvas embed,#map_canvas object,.map_canvas img,.map_canvas embed,.map_canvas object{max-width:none !important}.left{float:left !important}.right{float:right !important}.text-left{text-align:left !important}.text-right{text-align:right !important}.text-center{text-align:center !important}.text-justify{text-align:justify !important}.hide{display:none}.antialiased{-webkit-font-smoothing:antialiased}img{display:inline-block;vertical-align:middle}textarea{height:auto;min-height:50px}select{width:100%}object,svg{display:inline-block;vertical-align:middle}.center{margin-left:auto;margin-right:auto}.spread,.stretch{width:100%}p.lead,.paragraph.lead>p,#preamble>.sectionbody>.paragraph:first-of-type p{line-height:1.6}.subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#0b0a0a;font-weight:bold;margin-top:0;margin-bottom:0.8em}div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0;direction:ltr}a{color:#086dc3;line-height:inherit;text-decoration:none}a:hover,a:focus{color:#086dc3;text-decoration:underline}a img{border:none}p{font-family:inherit;font-weight:normal;font-size:1em;line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility}p aside{font-size:0.875em;line-height:1.35;font-style:italic}h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:Montserrat, sans-serif;font-weight:400;font-style:normal;color:#000;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:0.5em;line-height:1.0125em}h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#867c74;line-height:0}h1{font-size:2.125em}h2{font-size:1.6875em}h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em}h4{font-size:1.125em}h5{font-size:1.125em}h6{font-size:1em}hr{border:solid #dce6e6;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em;height:0}em,i{font-style:italic;line-height:inherit}strong,b{font-weight:bold;line-height:inherit}small{font-size:60%;line-height:inherit}code{font-family:Monaco, Menlo, Consolas, "Courier New", monospace;font-weight:normal;color:#3d3d3c;word-break:break-word}a:not(pre)>code{border:1px solid #086dc3;color:#086dc3}ul,ol,dl{font-size:1em;line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit}ul,ol{margin-left:1.5em}ul.no-bullet,ol.no-bullet{margin-left:1.5em}ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0;font-size:1em}ul.square li ul,ul.circle li ul,ul.disc li ul{list-style:inherit}ul.square{list-style-type:square}ul.circle{list-style-type:circle}ul.disc{list-style-type:disc}ul.no-bullet{list-style:none}ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0}dl dt{margin-bottom:0.3125em;font-weight:bold}dl dd{margin-bottom:1.25em}abbr,acronym{text-transform:uppercase;font-size:90%;color:#000;border-bottom:1px dotted #dddddd;cursor:help}abbr{text-transform:none}blockquote{margin:0 0 1.25em;padding:0.5625em 1.25em 0 1.1875em;border-left:1px solid #dddddd}blockquote cite{display:block;font-size:0.9375em;color:rgba(0,0,0,0.6)}blockquote cite:before{content:"\2014 \0020"}blockquote cite a,blockquote cite a:visited{color:rgba(0,0,0,0.6)}blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,0.85)}.vcard{display:inline-block;margin:0 0 1.25em 0;border:1px solid #dddddd;padding:0.625em 0.75em}.vcard li{margin:0;display:block}.vcard .fn{font-weight:bold;font-size:0.9375em}.vevent .summary{font-weight:bold}.vevent abbr{cursor:auto;text-decoration:none;font-weight:bold;border:none;padding:0 0.0625em}#tocbot{padding:0 0 0.5rem 0;line-height:1.5rem;padding-left:10px}.mobile-toc{padding:0 0 1rem 0;line-height:1.5rem}.mobile-toc li a{display:block;padding:.3rem 0}#tocbot ol li{list-style:none;padding:0;margin:0}#tocbot ol{margin:0;padding:0}#tocbot ol ol{padding-left:0.6rem}#tocbot .toc-link{display:block;padding-top:.6rem;padding-bottom:.6rem;outline:none;border-radius:4px;font-size:15px;transition:all .15s}#tocbot .toc-link:hover{background:#ebf2f2;color:#06c;text-decoration:none}table{background:white;margin-bottom:1.25em;border:solid 1px #d4dfdf;border-spacing:0}table thead,table tfoot{background:#ebf2f2;font-weight:bold}table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:0.5em 0.625em 0.625em;font-size:inherit;color:#000;text-align:left}table tr th,table tr td{padding:0.5625em 0.625em;font-size:inherit;color:#000}table tr.even,table tr.alt,table tr:nth-child(even){background:#f5f9f9}table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{display:table-cell;line-height:1.6}body{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;tab-size:4}h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-0.05em}.clearfix:before,.clearfix:after,.float-group:before,.float-group:after{content:" ";display:table}.clearfix:after,.float-group:after{clear:both}*:not(pre)>code{background-color:#fff;border:1px solid #e1e1e8;color:#009;padding:2px 6px;font-size:.875rem;font-family:Monaco, Menlo, Consolas, "Courier New", monospace}pre,pre>code{line-height:1.85;color:rgba(0,0,0,0.9);font-family:Monaco, Menlo, Consolas, "Courier New", monospace;font-weight:normal;text-rendering:optimizeSpeed;word-break:normal}pre{overflow:auto}em em{font-style:normal}strong strong{font-weight:normal}.keyseq{color:#6b625c}kbd{font-family:Monaco, Menlo, Consolas, "Courier New", monospace;display:inline-block;color:#000;font-size:0.65em;line-height:1.45;background-color:#f7f7f7;border:1px solid #ccc;-webkit-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,0.2),0 0 0 0.1em white inset;box-shadow:0 1px 0 rgba(0,0,0,0.2),0 0 0 0.1em white inset;margin:0 0.15em;padding:0.2em 0.5em;vertical-align:middle;position:relative;top:-0.1em;white-space:nowrap}.keyseq kbd:first-child{margin-left:0}.keyseq kbd:last-child{margin-right:0}.menuseq,.menu{color:#191715}b.button:before,b.button:after{position:relative;top:-1px;font-weight:normal}b.button:before{content:"[";padding:0 3px 0 2px}b.button:after{content:"]";padding:0 2px 0 3px}p a>code:hover{color:rgba(0,0,0,0.9)}#toc{border-bottom:1px solid #dce6e6;padding-bottom:0.5em}#toc>ul{margin-left:0.125em}#toc ul.sectlevel0>li>a{font-style:italic}#toc ul.sectlevel0 ul.sectlevel1{margin:0.5em 0}#toc ul{list-style-type:none}#toc li{line-height:1.3334}#toc a{text-decoration:none}#toc a:active{text-decoration:underline}#toctitle{color:#0b0a0a;font-size:1.2em;display:none}body.toc2{padding-top:80px;text-rendering:optimizeLegibility}#content #toc{border-style:solid;border-width:1px;border-color:#dce6e6;margin-bottom:1.25em;padding:1.25em;background:#f1f1f1;-webkit-border-radius:4px;border-radius:4px}#content #toc>:first-child{margin-top:0}#content #toc>:last-child{margin-bottom:0}#footer{padding-bottom:2rem}#footer #footer-text{padding:2rem 0;border-top:1px solid #efefed}#footer-text{color:rgba(0,0,0,0.6);line-height:1.44}.sect1{padding-bottom:0.625em}.sect1+.sect1{border-top:1px solid #efefed}#content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;margin-top:0.1rem;display:block;visibility:hidden;text-align:center;font-weight:normal;color:rgba(0,0,0,0.2)}#content h1>a.anchor:hover,h2>a.anchor:hover,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4>a.anchor:hover,h5>a.anchor:hover,h6>a.anchor:hover{color:#097dff;text-decoration:none}#content h1>a.anchor:before,h2>a.anchor:before,h3>a.anchor:before,#toctitle>a.anchor:before,.sidebarblock>.content>.title>a.anchor:before,h4>a.anchor:before,h5>a.anchor:before,h6>a.anchor:before{content:"\0023";font-size:0.85em;display:block;padding-top:0.1em}#content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible}#content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#000;text-decoration:none}#content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#262321}.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em}.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:'Open Sans', sans-serif;font-size:1rem}table.tableblock>caption.title{white-space:nowrap;overflow:visible;max-width:0;padding:0.6rem 0}table.tableblock #preamble>.sectionbody>.paragraph:first-of-type p{font-size:inherit}.admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%}.admonitionblock>table td.icon{text-align:center;vertical-align:top;padding-top:0.8em;width:80px}.admonitionblock>table td.icon img{max-width:initial}.admonitionblock>table td.icon .title{font-weight:bold;font-family:Montserrat, sans-serif;text-transform:uppercase}.admonitionblock>table td.content{padding-left:0em;padding-right:1.25em;border-left:1px solid #dce6e6}.admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0}.exampleblock>.content{border-style:solid;border-width:0;border-color:#e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#f1f1f1;border-radius:4px}.exampleblock>.content>:first-child{margin-top:0}.exampleblock>.content>:last-child{margin-bottom:0}.sidebarblock{border-style:solid;border-width:0;border-color:#dce6e6;margin-bottom:1.25em;padding:1.25em;background:#ebf2f2;border-radius:4px;overflow:scroll}.sidebarblock>:first-child{margin-top:0}.sidebarblock>:last-child{margin-bottom:0}.sidebarblock>.content>.title{color:#0b0a0a;margin-top:0;text-align:center}.exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0}.literalblock pre,.listingblock pre:not(.highlight),.listingblock pre[class="highlight"],.listingblock pre[class^="highlight "],.listingblock pre.CodeRay,.listingblock pre.prettyprint{background:#fff;border:1px solid #d9d9d9;border-radius:4px}.sidebarblock .literalblock pre,.sidebarblock .listingblock pre:not(.highlight),.sidebarblock .listingblock pre[class="highlight"],.sidebarblock .listingblock pre[class^="highlight "],.sidebarblock .listingblock pre.CodeRay,.sidebarblock .listingblock pre.prettyprint{background:#fff;border:1px solid #d9d9d9;color:#222}.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class],.listingblock pre:not(.highlight){padding:1em 1.5rem;font-size:0.8125em}.literalblock pre.nowrap,.literalblock pre[class].nowrap,.listingblock pre.nowrap,.listingblock pre[class].nowrap{overflow-x:auto}.literalblock.output pre{color:whitesmoke;background-color:rgba(0,0,0,0.9)}.listingblock{white-space:nowrap}.listingblock pre.highlightjs>code{padding:1em 1.5rem;border-radius:4px}.listingblock>.content{position:relative}.listingblock code[data-lang]:before{display:none;content:attr(data-lang);position:absolute;font-size:0.8em;font-weight:bold;top:0.425rem;right:0.5rem;line-height:1;text-transform:uppercase;color:#999}.listingblock code[data-lang]:before{display:block}.listingblock.terminal pre .command:before{content:attr(data-prompt);padding-right:0.5em;color:#999}.listingblock.terminal pre .command:not([data-prompt]):before{content:"$"}table.pyhltable{border-collapse:separate;border:0;margin-bottom:0;background:none}table.pyhltable td{vertical-align:top;padding-top:0;padding-bottom:0;line-height:1.45}table.pyhltable td.code{padding-left:.75em;padding-right:0}pre.pygments .lineno,table.pyhltable td:not(.code){color:#999;padding-left:0;padding-right:.5em;border-right:1px solid #dce6e6}pre.pygments .lineno{display:block;margin-right:.25em}table.pyhltable .linenodiv{background:none !important;padding-right:0 !important}.quoteblock{margin:0 1em 1.25em 1.5em;display:block;text-align:left;padding-left:20px}.quoteblock blockquote,.quoteblock blockquote p{color:rgba(0,0,0,0.85);line-height:1.75;letter-spacing:0}.quoteblock blockquote{margin:0;padding:0;border:0;position:relative}.quoteblock blockquote:before{content:"\201c";font-size:2.75em;font-weight:bold;line-height:0.6em;margin-left:0em;margin-right:1rem;margin-top:0.8rem;color:rgba(0,0,0,0.1);position:absolute;top:0;left:-30px}.quoteblock blockquote>.paragraph:last-child p{margin-bottom:0}.quoteblock .attribution{margin-right:0.5ex}.quoteblock .quoteblock{margin-left:0;margin-right:0;padding:0.5em 0;border-left:3px solid rgba(0,0,0,0.6)}.quoteblock .quoteblock blockquote{padding:0 0 0 0.75em}.quoteblock .quoteblock blockquote:before{display:none}.verseblock{margin:0 1em 1.25em 0;background-color:#f1f1f1;padding:1rem 1.4rem;border-radius:4px}.verseblock pre{font-family:Monaco, Menlo, Consolas, "Courier New", monospace;font-size:0.9rem;color:rgba(0,0,0,0.85);font-weight:300;text-rendering:optimizeLegibility}.verseblock pre strong{font-weight:400}.verseblock .attribution{margin-top:1.25rem;margin-left:0.5ex}.quoteblock .attribution,.verseblock .attribution{font-size:0.9375em;line-height:1.45;font-style:italic}.quoteblock .attribution br,.verseblock .attribution br{display:none}.quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-0.025em;color:rgba(0,0,0,0.6)}.quoteblock.abstract{margin:0 0 1.25em 0;display:block}.quoteblock.abstract blockquote,.quoteblock.abstract blockquote p{text-align:left;word-spacing:0}.quoteblock.abstract blockquote:before,.quoteblock.abstract blockquote p:first-of-type:before{display:none}table.tableblock{max-width:100%;border-collapse:separate;overflow-x:scroll;display:block}table.tableblock td>.paragraph:last-child p>p:last-child,table.tableblock th>p:last-child,table.tableblock td>p:last-child{margin-bottom:0}table.tableblock,th.tableblock,td.tableblock{border:0 solid #d4dfdf}table.grid-all th.tableblock,table.grid-all td.tableblock{border-width:0 1px 1px 0}table.grid-all tfoot>tr>th.tableblock,table.grid-all tfoot>tr>td.tableblock{border-width:1px 1px 0 0}table.grid-cols th.tableblock,table.grid-cols td.tableblock{border-width:0 1px 0 0}table.grid-all *>tr>.tableblock:last-child,table.grid-cols *>tr>.tableblock:last-child{border-right-width:0}table.grid-rows th.tableblock,table.grid-rows td.tableblock{border-width:0 0 1px 0}table.grid-all tbody>tr:last-child>th.tableblock,table.grid-all tbody>tr:last-child>td.tableblock,table.grid-all thead:last-child>tr>th.tableblock,table.grid-rows tbody>tr:last-child>th.tableblock,table.grid-rows tbody>tr:last-child>td.tableblock,table.grid-rows thead:last-child>tr>th.tableblock{border-bottom-width:0}table.grid-rows tfoot>tr>th.tableblock,table.grid-rows tfoot>tr>td.tableblock{border-width:1px 0 0 0}table.frame-all{border-width:1px}table.frame-sides{border-width:0 1px}table.frame-topbot{border-width:1px 0}th.halign-left,td.halign-left{text-align:left}th.halign-right,td.halign-right{text-align:right}th.halign-center,td.halign-center{text-align:center}th.valign-top,td.valign-top{vertical-align:top}th.valign-bottom,td.valign-bottom{vertical-align:bottom}th.valign-middle,td.valign-middle{vertical-align:middle}table thead th,table tfoot th{font-weight:bold}tbody tr th{display:table-cell;line-height:1.6;background:#f7f8f7}tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:#34302d;font-weight:bold}p.tableblock{font-size:1em}td>div.verse{white-space:pre}ol{margin-left:1.75em}ul li ol{margin-left:1.5em}dl dd{margin-left:1.125em}dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0}ol>li p,ul>li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:0.625em}ul.unstyled,ol.unnumbered,ul.checklist,ul.none{list-style-type:none}ul.unstyled,ol.unnumbered,ul.checklist{margin-left:0.625em}ul.checklist li>p:first-child>.fa-square-o:first-child,ul.checklist li>p:first-child>.fa-check-square-o:first-child{width:1em;font-size:0.85em}ul.checklist li>p:first-child>input[type="checkbox"]:first-child{width:1em;position:relative;top:1px}ul.inline{margin:0 auto 0.625em auto;margin-left:-1.375em;margin-right:0;padding:0;list-style:none;overflow:hidden}ul.inline>li{list-style:none;float:left;margin-left:1.375em;display:block}ul.inline>li>*{display:block}.unstyled dl dt{font-weight:normal;font-style:normal}ol.arabic{list-style-type:decimal}ol.decimal{list-style-type:decimal-leading-zero}ol.loweralpha{list-style-type:lower-alpha}ol.upperalpha{list-style-type:upper-alpha}ol.lowerroman{list-style-type:lower-roman}ol.upperroman{list-style-type:upper-roman}ol.lowergreek{list-style-type:lower-greek}.hdlist>table,.colist>table{border:0;background:none}.hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none}td.hdlist1,td.hdlist2{vertical-align:top;padding:0 0.625em}td.hdlist1{font-weight:bold;padding-bottom:1.25em}.literalblock+.colist,.listingblock+.colist{margin-top:-0.5em}.colist>table tr>td:first-of-type{padding:0 0.75em;line-height:1}.colist>table tr>td:first-of-type img{max-width:initial}.colist>table tr>td:last-of-type{padding:0.25em 0}.colist>table tr>td{white-space:pre-wrap}.thumb,.th{line-height:0;display:inline-block;border:solid 4px white;-webkit-box-shadow:0 0 0 1px #dddddd;box-shadow:0 0 0 1px #dddddd}.imageblock.left,.imageblock[style*="float: left"]{margin:0.25em 0.625em 1.25em 0}.imageblock.right,.imageblock[style*="float: right"]{margin:0.25em 0 1.25em 0.625em}.imageblock>.title{margin-bottom:0}.imageblock.thumb,.imageblock.th{border-width:6px}.imageblock.thumb>.title,.imageblock.th>.title{padding:0 0.125em}.image.left,.image.right{margin-top:0.25em;margin-bottom:0.25em;display:inline-block;line-height:0}.image.left{margin-right:0.625em}.image.right{margin-left:0.625em}a.image{text-decoration:none;display:inline-block}a.image object{pointer-events:none}sup.footnote,sup.footnoteref{font-size:0.875em;position:static;vertical-align:super}sup.footnote a,sup.footnoteref a{text-decoration:none}sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline}#footnotes{padding-top:0.75em;padding-bottom:0.75em;margin-bottom:0.625em}#footnotes hr{width:20%;min-width:6.25em;margin:-0.25em 0 0.75em 0;border-width:1px 0 0 0}#footnotes .footnote{padding:0 0.375em 0 0.225em;line-height:1.3334;font-size:0.875em;margin-left:1.2em;text-indent:-1.05em;margin-bottom:0.2em}#footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none}#footnotes .footnote:last-of-type{margin-bottom:0}#content #footnotes{margin-top:-0.625em;margin-bottom:0;padding:0.75em 0}.gist .file-data>table{border:0;background:#fff;width:100%;margin-bottom:0}.gist .file-data>table td.line-data{width:99%}div.unbreakable{page-break-inside:avoid}.big{font-size:larger}.small{font-size:smaller}.underline{text-decoration:underline}.overline{text-decoration:overline}.line-through{text-decoration:line-through}.aqua{color:#00bfbf}.aqua-background{background-color:#00fafa}.black{color:black}.black-background{background-color:black}.blue{color:#0000bf}.blue-background{background-color:#0000fa}.fuchsia{color:#bf00bf}.fuchsia-background{background-color:#fa00fa}.gray{color:#606060}.gray-background{background-color:#7d7d7d}.green{color:#006000}.green-background{background-color:#007d00}.lime{color:#00bf00}.lime-background{background-color:#00fa00}.maroon{color:#600000}.maroon-background{background-color:#7d0000}.navy{color:#000060}.navy-background{background-color:#00007d}.olive{color:#606000}.olive-background{background-color:#7d7d00}.purple{color:#600060}.purple-background{background-color:#7d007d}.red{color:#bf0000}.red-background{background-color:#fa0000}.silver{color:#909090}.silver-background{background-color:#bcbcbc}.teal{color:#006060}.teal-background{background-color:#007d7d}.white{color:#bfbfbf}.white-background{background-color:#f5f9f9}.yellow{color:#bfbf00}.yellow-background{background-color:#fafa00}span.icon>.fa{cursor:default}.admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;cursor:default}.admonitionblock td.icon .icon-note:before{content:"\f05a";color:#3f6a22}.admonitionblock td.icon .icon-tip:before{content:"\f0eb";color:#0077b9}.admonitionblock td.icon .icon-warning:before{content:"\f071";color:#d88400}.admonitionblock td.icon .icon-caution:before{content:"\f06d";color:#bf3400}.admonitionblock td.icon .icon-important:before{content:"\f06a";color:#bf0000}.conum[data-value]{display:inline-block;color:#000 !important;background-color:#ffe157;-webkit-border-radius:100px;border-radius:100px;text-align:center;font-size:0.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans", "DejaVu Sans", sans-serif;font-style:normal;font-weight:bold}.conum[data-value] *{color:#fff !important}.conum[data-value]+b{display:none}.conum[data-value]:after{content:attr(data-value)}pre .conum[data-value]{position:relative;top:0;color:#000 !important;background-color:#ffe157;font-size:12px}b.conum *{color:inherit !important}.conum:not([data-value]):empty{display:none}.admonitionblock{background-color:#ecf1e8;padding:0.8em 0;margin:30px 0;width:auto;border-radius:4px;overflow-x:auto}.admonitionblock.important{border-left:0px solid #e20000;background-color:#f9ebeb}.admonitionblock.warning{border-left:0px solid #d88400;background-color:#fff9e4}.admonitionblock.tip{border-left:0px solid #0077b9;background-color:#e9f1f6}.admonitionblock.caution{border-left:0px solid #e20000;background-color:#f9ebeb}.admonitionblock .exampleblock>.content{border:0 none;background-color:#fff}#toc a:hover{text-decoration:underline}.admonitionblock>table{margin-bottom:0}.admonitionblock>table td.content{border-left:none}@media print{#tocbot a.toc-link.node-name--H4{display:none}}.is-collapsible{max-height:1000px;overflow:hidden;transition:all 200ms ease-in-out}.is-collapsed{max-height:0}#index-link{display:none}ul li>p>a>code{color:#086dc3}ul li>p>a:hover>code{color:#086dc3}#content .listingblock .switch{border-style:none;display:inline-block;position:relative;bottom:0;margin-bottom:4px}#content .listingblock .switch--item:not(:first-child){border:2px solid #000}#content .listingblock .switch--item{padding:6px 12px;background-color:#fff;color:#000;display:inline-block;cursor:pointer;border:2px solid #000;margin-right:2px;border-radius:0}#content .listingblock .switch--item:hover{color:#086dc3}#content .listingblock .switch--item.selected{background-color:#000;color:#fff;border-color:#000}#content .listingblock .switch--item.selected:hover{color:#fff}#content .listingblock pre.highlightjs{padding:0}div.back-action,#toc.toc2 div.back-action{padding:0.8rem 0 0 5px}div.back-action a,#toc.toc2 div.back-action a{position:relative;display:inline-block;padding:0.6rem 1.2rem;padding-left:35px}div.back-action a span,#toc.toc2 div.back-action a span{position:absolute;left:5px;top:5px;display:block;color:#333;height:26px;width:26px;border-radius:13px}div.back-action a i,#toc.toc2 div.back-action a i{position:absolute;top:10px;left:5px}div.back-action a:hover span,#toc.toc2 div.back-action a:hover span{color:#000}#tocbot.desktop-toc{padding:.5rem}#header-spring{position:absolute;text-rendering:optimizeLegibility;top:0;left:0;right:0;height:80px;margin:0 1rem;padding:0 1rem;border-bottom:1px solid #dce6e6}#header-spring h1{margin:0;padding:0;font-size:22px;text-align:left;line-height:76px;padding-left:0.6rem}#header-spring h1 svg{width:240px}#header-spring h1 svg .st0{fill:#6bb536}#header-spring h1 svg .st2{fill:#444}body.book #header-spring{position:relative;top:auto;left:auto;right:auto;margin:0}body.book #header>h1:only-child{border:0 none;padding-bottom:1.2rem;font-size:1.8rem}body.book #header,body.book #content,body.book #footnotes,body.book #footer{margin:0 auto}body.toc2 #header-spring{position:absolute;left:0;right:0;top:0}body.toc2 #header>h1:only-child{font-size:2.2rem}body.toc2 #header,body.toc2 #content,body.toc2 #footnotes,body.toc2 #footer{margin:0 auto}body.toc2 #content{padding-top:2rem}#header,#content,#footnotes,#footer{width:100%;margin-right:auto;margin-top:0;margin-bottom:0;max-width:62.5em;*zoom:1;position:relative;padding-left:0.9375em;padding-right:0.9375em}#header:before,#header:after,#content:before,#content:after,#footnotes:before,#footnotes:after,#footer:before,#footer:after{content:" ";display:table}#header:after,#content:after,#footnotes:after,#footer:after{clear:both}#content{margin-top:1.25em}#content:before{content:none}#header{position:relative}#header>h1:first-child{margin-top:2.55rem;margin-bottom:0.5em;margin-bottom:0.7em;font-size:2rem}#header>h1:first-child+#toc{margin-top:8px;border-top:0 none}#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #ebf2f2;padding-bottom:8px}#header .details{line-height:1.45;color:#222;display:-ms-flexbox;display:-webkit-flex;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap;background-color:#ebf2f2;padding:2rem 2.5rem}#header .details span:first-child{margin-left:-0.125em}#header .details span.email a{color:rgba(0,0,0,0.85)}#header .details br{display:none}#header .details br+span:before{content:"\00a0\2013\00a0"}#header .details br+span.author:before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,0.85)}#header .details br+span#revremark:before{content:"\00a0|\00a0"}#header #revnumber{text-transform:capitalize}#header #revnumber:after{content:"\00a0"}#content>h1:first-child:not([class]){color:rgba(0,0,0,0.85);border-bottom:1px solid #ebf2f2;padding-bottom:8px;margin-top:0;padding-top:1.5rem;margin-bottom:1.25rem}h1{font-size:2.2rem}h1,h2,h3,h4,h5,h6{font-weight:bold;font-family:Montserrat, Arial, Helvetica, sans-serif}h1:focus,h2:focus,h3:focus,h4:focus,h5:focus,h6:focus{box-shadow:none;outline:none}h2,h3,h4,h5,h6{padding:.8rem 0 .4rem}h1{font-size:1.75em}h2{font-size:1.6rem}h3{font-size:1.5rem}h4{font-size:1.4rem}h5{font-size:1.3rem}h6{font-size:1.2rem}pre.highlight{padding:20px;border:1px solid #d9d9d9;overflow-x:scroll;color:#222}pre.highlight code{color:#222}pre.highlight a,#toc.toc2 a{color:#000}pre.highlight ul.sectlevel1,#toc.toc2 ul.sectlevel1{padding-left:0.2rem}pre.highlight ul.sectlevel1 li,#toc.toc2 ul.sectlevel1 li{line-height:1.4rem}::selection{background-color:#d1ff79}.literalblock pre::selection,.listingblock pre[class="highlight"]::selection,.highlight::selection,pre::selection,.highlight code::selection,.highlight code span::selection{background:rgba(0,0,0,0.2) !important}body.book #header{margin-bottom:2rem}body.toc2 #header{margin-bottom:0}.desktop-toc{display:none}.admonitionblock td.icon{display:none}.admonitionblock>table td.content{padding-left:1.25em}@media only screen and (min-width: 768px){#toctitle{font-size:1.375em}.sect1{padding-bottom:1.25em}.mobile-toc{display:none}.desktop-toc{display:block}.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:0.90625em}.admonitionblock td.icon{display:table-cell}.admonitionblock>table td.content{padding-left:0}#header{position:relative;min-height:98px;padding-right:210px}#header::after{position:absolute;right:0;top:0;display:block;content:'';height:95px;width:203px;z-index:-1;background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA38AAAGjCAIAAAATtjulAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyVpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQ4IDc5LjE2NDAzNiwgMjAxOS8wOC8xMy0wMTowNjo1NyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIDIxLjEgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NTMxQjVFRkQ2NTNCMTFFQTlENDc5OTVFRUMxRUY0NTEiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NTMxQjVFRkU2NTNCMTFFQTlENDc5OTVFRUMxRUY0NTEiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo1MzFCNUVGQjY1M0IxMUVBOUQ0Nzk5NUVFQzFFRjQ1MSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo1MzFCNUVGQzY1M0IxMUVBOUQ0Nzk5NUVFQzFFRjQ1MSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PvrI2PUAAD6SSURBVHja7N13lJzlneD7enOo1FJ3K7VyRKCcJcBgTDRgY4wNNmAbY2QEmGDPjj3J9nidcZixvXPvP3v2nnN3770z5545O7M7Z4NnJ9gzzgEnJKHQQhISyt0V3hz27RIGDELq+FT6fk4fjcY2Qv17u6q+9db7Po+UpmluYn7mff+/VP+/HIBxSZOktu/5YKjCKABhFEl9/4Y/WTf7miRNhx0nThJmAggg5XJFy1In+KdEafhP9f/GNIFxpmccV/cOhtU6owCE0RTjoU2fvax/cxadWXomEz4LA2BU6SlJJcvSFGWi9fkT71+ryTADBcYhCaPq3oNR3WUUgDCmmt+19UuLpq2KkqRCegKiyFl62rYqy9nvJ1SfQep/x/mfDBQYT3oGYWX3gdjzGQUgTEHveWzbV+eUloRxXHHdlPQExKSnLJctS2mk50Tr84fud9yETwyBMcuis7r7YBwEjAIQZpo147FtX+/PDwRRVM3Sk4kAQmTRWbZtWZJe/k/GX59B6v+r87+YKTBWkeNWdw8mUcgoAGFmFOY9tu1rPWa/30hPBgKIoSpKybJenZ4Tqs8fud/1Ux7AwBjTs1qv7h1M4phRAMLMKy/ftfXLBb3HC8Oa5zEQQAytkZ7S76bn+OszTIPvuf/AWIGxPXCGqrV9hxLWdgEEWjJ9zc4tX7DUvBsEdZ8rrQFBdFUtZul5of9qnPX5U+97XPEJjElwZqh24Eiakp6AOJfP2PbBjZ/WFTPrTpcrrQFRDE0rmuYb/bfjqc84F3PFJzAm3skz9cGjzAEQacOc6+5f9weKrNU8zwu50hoQxNL1vGFc5H8wnvr8pffjWsK+LMBoucdPOoePMwdApB3zb3/36qdkSa56nk96AqLYhmHr+sX/N+Ooz/T7zj8yXGCUnCPH3WMnmQMg0vVL3nP7yp25NFdx3SCKGAggRt4wrEul53jqc1/w7Kn4ReYLjOKdWlo/9IJ38gyTAES6/bKdNyx9b5qmWXqGrC8BiFI0TUPTRvO/HHN9fo8Tn8Do0rN24LB/ZohJAMJIkvyuVU9eteBtSSM9I9ITEPPQy9LTsnR1tFU5tvo8Eb1wKNzHlIFLlGeSVPcdCoeqjAIQRpHUe9d9YtPA9Vl6DjtOzNJmgKB3fVLJsjRFGf0/Mrb6/JH7XaYMXCI947iydzCqsiQZII6mGA9s+PSqmduz6MzSM2EDd0AIuZGe6ljSc2z16abOL/2fMGjgIpIwqu45GDlsAwaIY6r5nZs/v7R3bZQkFdITEJieZdtWZHms/+AY6vMZ74dRyqIVwBunZxBWdh+IPTZTAcTJ6+VdW788v7wijOOK66akJyBEFp1ZesqSNI5/dvT1mfKxO3ARWXRWdx+M2UwFEKhs9j227aszCwuCKKpm6clEACFUWS6NNz3HUJ+Dwb6hmIVjgAuL6m51z2AS8eEAIE6fPeex7V+fbs30G+nJQAAxNEUpWZY03vQcQ33+1Pse4wYuKKzWa3sHE9Z2AQSaXVz02LavFY1pXhjWPI+BAGLoqlo0zYmk52jr00nqe/xfMnHg9YKhSn3f8wlruwACLZx2+a6tT1tq3g2Cus+V1oAghqZl6TnxP2dU9fkL/0dxjvM6wGv5Z4bqB46kKekJiLOib+NDmz+nK2bWnS5XWgOimJpWmIz0HHV9ej9i6MBreCfP1AePMgdApLWz3vSBDX+iyFrN87yQK60BQWxdtw1jsv60S9fnieiFE9Ex5g68mnvspHPkOHMARNo275Z71vwbWZKrrutHEQMBxMgbhqXrk/gHXro+WWEeeA3n8HH3+EnmAIh07aK73nHFo7k0V3HdgPQERCmYpqlpk/tnXqI+01zyS4/6BF5+SKT1Qy94J1l9DBDqrcsfuHn5+9M0zdIzZH0JQJSSZemqOul/7CX+xEPB/lpSYfrA+fSsHjgcnBliEoBId616/E0L70yy9HSciPUlACGkxgbu2hg3cJ+c+vy1/zMOADBSnklS3XcoHKoyCkDg659879qPb5l7U5aew44Tk56AEHIjPdWpSc9L1GeSi5/1f8ExANI4ruwdjKp1RgEIo8jaBzd8evWsK7PozNIzYQN3QFR6lm1bkeWp+1dcrD4PBs95qcNhQJdLwqi652DksI8fII6umDs3f35534YoSSqkJyDuXZ9csqwpTc9L1Oez/jMcBnR7egZhdffBiH38AIFsrbRr65cW9KwM47jiuinpCQihZulp2/LEdtGcUH2muWRv8CuOBLpZ7PlZesZspgIIVDb7dm398pzi4iCKqll6MhFACE1RSpYlTX16Xqw+j4aHnISr3NC9orpb3TOYRGymAojTa895ZOvT/fkBv5GeDAQQQ1fVommKSc+L1eee4NccDHStsFqv7R1MWFYQEGh2cdGurV/uMfu9MKxxuQsgipGlp2WJ/De+YX3u9fnYHV0qGKrU9z2fsLYLINCCnpUf3vKFgt7jBkHd9xkIIIapaQXTFPwvvXB9no1PnYnZSBDdyD8zVD9wJE1JT0CcZb3rH9r8WVPNZ93pcqU1IIql63nDEP/vvXB97gue5ZCgC3knz9QHjzIHQKRVM3c8sPHTmqzXPM8LudIaECTrzqw+m/KvvnB9Hgj2cFTQbdxjJ50jx5kDINKmgRvuW/cJWVKqrutHEQMBxCiYpqlpzfq3X6A+4zQaDPdxYNBVnMPH3eNcbQIIdfXCd9y16vFcmqu4bkB6AqIULctQ1Sb+BS7w734+PBClfPaBrpGm9UMveCfPMAlApBuX3X/bigfTNM3SM2R9CUAIKZcrWZbW1PS8cH0eDJ/j8KB70rN64HBwZohJACLdcfmu6xbfnWTp6TgR60sAYtJTksqWpSpK0/8mF6jPQ3zsji4pzySp7jsUDlUZBSDw9U++Z/XHts+/NUvPYceJSU9ACFmSSratTvEG7uOszyD1j4VHOEjo/PSM48rewajKhl6AOIqkvm/DH6+ffW0WnVl6JmzgDoh56MlyybKU1kjPC9Tn4fBgmuOdKDpcEkbVPQcjh338AHE0xfjQps+u7N8cJUmF9AQEpmfZtmVRu2iOpz4Phfs5Tujw9AzC6u4DkcdmKoA4pprftfVLi6atCuO44rop6QmI6TxFKVuW1ErpeYH6PBIe5FChg8WeX919MGYzFUCgvF5+bNvXBkpLgiiqZunJRAAhNEUptV56vrY+k1x8LOKiT3SsqO5W9wwmEQuKAeJMs2Y8tu3r/fkBv5GeDAQQQ1fVLD1b8+/2O/V5PDrKSp/oVGG1Xts7mLCsICDQjPy8x7Z/rcfs98Kw5nkMBBDD1LSCabbsX+936vNoeIgDho4UDFXq+55PWNsFEGhuedkjW58u6D1uENR9rrQGBLF0PW8Yrfw3/J36fCF8nmOGzuOfGaofOJKmpCcgzpLpa3Zu+YKl5rPudLnSGhDFNgxb11v8L/k79clFn+g83skz9cGjzAEQ6fIZWz+48U91xax5nhdyQRcgSME0TU1r/b/nK/UZpP6Z+BRHDp3EPXbSOXKcOQAibZhz3f3r/kCRtarr+lHEQAAxipZlNHsD9zHX5/HoaC7HOhjoHM7h4+7xk8wBEGnH/NvfvfopKSdVXDcgPQEhpEZ66m2Snq+pTz52R6dI0/qhF7yTZ5gEINJbltzztpUfzqW5LD1D1pcAxKSnJJUsS1OUNvo7v1KfJ6JjHEJ0RnpWDxwOzgwxCUCk2y976Ial9yZpWnGciPUlACHkLD1tW22ZDdzHXJ8nIy6PQ/uXZ5JU9x0Kh6qMAhBGkuR3rXriqgVvz9Jz2HFi0hMQk56yXLYspd3S89X1mZ6KX+RAor3TM44rewejap1RAMIoknrvuk9sGrg+i84sPRM2cAfEPPSy9LRtufV20RxDfQ7F58KU9djQxpIwqu45GDns4weIoynGAxs+tWrmjihJKqQnIKzeGhu4t2l6vlKfJ2Mu+kQ7p2cQVncfiDw2UwHEMdX8Q5s/t6x3XRjHFddNSU9A0Lu+kfSU2jY9X6nPs/FpDifaVOz51d0HYzZTAQTK6+VdW788v7wiiKJqlp5MBBBCV9Vilp5t/l28XJ+sM4+2FNXd6p7BJGIzFUCcstn36NavzCou9BvpyUAAMQxNK5pmB3wjL9UnuxyhHYXVem3vYMKygoBAffacx7Z9bbo9ywvDmucxEEAMS9fzhtEZ38tv6zNiSxi0mWCoUt/3fMLaLoBAs4uLsvQsGtPcIKj7XGkNCGIbhq3rHfPtjNRnkosrCUtzo534Z87VDxxNU9ITEGdBz8pHtj5taYWsO12utAZEKRiG2UHp+VJ9VuLhlB3e0T68E2fqh44yB0CkFX0bH9r8OV0xa57nhVxpDQhSNE1D0zrsmxqpz+HkLEcX7cI9dtI5wr5cgFBrZl39wIZPKrJWdV0/ihgIIICUpadl6araed9aoz7jcxxjtAXn8DH3OHfIAUJtnXfze9b8vpSTKq4bkJ6AmPSUpJJlaYrSkd/d+XOfXPSJlpemtUNH/ZOcpweEunbRXe+44tFcmsvSM2R9CUAIuZGeaoem50v1WaU+0fLpWd1/ODjLDyog1C3LP5B9JWlacZyI9SUAUelZtm1Fljv4exypz3pS42CjdcszSarPHQqHq4wCEOmdV3zkmkXvzNJz2HFi0hMQIovOLD1lSersb/P8uc9hjjdaND3juLJ3MKrWGQUgjCTJ9679+Ja5N2XRmaVnwgbugJgma2zg3vHpmePcJ1pZEkaVPQdih81UAHEUSX1g46fXzLoqyt77uS7pCYihNdJT6oL0fKk+a0mFo46WS88gqD57MGYzFUAgXTF3bv788r4NYSM9U9ITEPPQU9WiaXZJeo7UZ5K9yqe8wKO1xK5f3XMwZjMVQCBbK+7a+uUFPSuDKKpm6clEACEMTcvSs6u+ZdVLHA48WkpUd6t7BpOIzVQAcUpG7yPbnp5TXOyHYdXjchdAEFPXC4bRbd+16qbUJ1pIWKnVnjuUsKwgIFCvPfuRrV/pzw94YVgjPQFRbF23uy89c41zny6HHy0iGKrU9z2fsLYLINDs4sJdW5/uMfvdIKhzpTUgSt4wLF3vzu9dDXI816Al+GfO1Q8cTVPSExBnQc/KD2/5QkHvybrT5UprQJSiaRqa1rXfvuon1Ceazztxpn7oKHMARFrWu/5Dmz9rqfma53khV1oDIkhZelqWrqrdPAQ1zPFmF03mHjvpHDnOHACRVs3c8cCGT2mKUXVdP4oYCCAiPRsbuGudu4H7aOszSnm/i2ZyDh9zj59iDoBImwauv2/dH0g5ueK6AekJCCE30lPt+vQcqU8/5fZGNEma1g4d9U+eZRKASFcvvOOuVU/k0lyWniHrSwCi0rNs24osM4rc+b2OgKakZ3X/4eDsEJMARLpx2f23rXgwSdOK40SsLwEIkUVn2bJk0vPl+oxT3vhCeHkmSfW5Q+FwlVEAIt2xctd1S+7O0nPYcWLSExBTWrJcsm25a3bRHNVMwpS7jiA2PeO4sncwqtYZBSCMJMn3rP7Y9vm3ZtGZpWfCBu6AEJqilCxLIj1fU5+MACIlYVTZcyB2uNoYEEeR1Pdt+OP1s6+Nsvd+rkt6AmLoqlo0TdKT+kSz03P3gdglPQFxNMX40KZ/u7J/S9hIz5T0BIQwsvS0LOZAfaKp6RmE1WcPxOzjBwhkqvmHt3xp8fRVQRRVs/RkIoCYh56mFUyTOVCfaG56BtVnD0akJyBQXi8/tu1rA6UlfhhWPT5zAASxdd02DOZAfaKZYs+v7j4Ys4U0IFCP2f+R7V/vz8/1wrBGegLC3vUZhqXrzOES9alKBChIT6CjzMjPe2z717IAdYLA4TMHQJSCaZqaxhxGU5+MCVNl5FrPvYOkJyDSQGnpo9u+UtB76r7v8ugDRClalqFyRm909anw4TumKD1DbjMCRFs8ffWHt3zRUvM1z/PCkIEAAkiNDdw1NnAffX1qnPvElKRnVN0zyG1GgEgr+7c8uOkzumJWXdePIgYCiEnPsmWppOcY65NrYzHJ0jiu7jkYOS6jAIRZP+fN71v3h7KkVlw3ID0BIWRJKtm2ygbuY61PlU/eMbnpmSTVvYdIT0CkHfNve/fqj0o5KUvPMI4ZCCCAIssly1JIz3HUpyGzED8msT3T2v7nw2qNSQDCXLfk7revfDhNc8OOEyUJAwHEpGfZtmV20RxffZoS9YlJUxs8GpyrMAdAmNsu+9CNS+9LkmTYdWPSExATT4pStiw2cKc+0XzO0Rf9U2eZAyCGlJPetfrJqxa8PYvOYcdJ2MAdEEJT1ZJpkp4Tq08+ecdk8E6cdl84wRwAMRRJvXfdxzcN3BDFccV1SU9ADENVixbhNPH6lMzsDXSa45kL4xcMVZxDx5gDIIamGA9s+NSqmTvCRnqmpCcghKlpBdNkDpNQn7mcZMuFelJlFhif2PGc/Ud4AwMIev1T8w9t/uyy3vVBFFWz9GQigBCWrucNgzlMVn3mbDlPfWJ8kjCqPfd8HLO4ICBCXi/v2vKl+T2X+WFY9TwGAgh66BlGVp/MYbKMLFJVlMsMAuOQJkn9uecjn5dAQISy2ffE9j/P0tMjPQGBCqZJek6uxrlPKc8gMA71g0eDGkt7AiL02XMe3fbVXnu2EwQOe9gCohQty1DZl2cK6pNznxgH99hJ/8w55gAIMLu4KEvPkjG97vtuEDAQQACpkZ466TlF9VlWpjEIjEk4XHWPvMgcAAEW9Kx8ZOvTllaoeZ4XhgwEEJGeklSyLE1RGMVU1WdJ7mEQGL3ED+r7j3KTOyDA8r4NOzd/XlfMquv6Ebf3ASLIWXratsoG7tQnWsTInUb7jsQRn/0BU27NrKsf2PBJWVIrrhuQnoAQiiyXLEshPae6PvnkHaPnDL4Q1LnTCJhyW+be/N61vy/lpCw9wzhmIICY9CzbtswumgLqsyCXNEkPU85m4RL8k2e90+zkDky5axfd9Y4rHk3T3LDjREnCQAARSaQoJcsiPQV46cTyNKWPWeDiYtdzD7OdJjDlbln+gTuveCxNUtITEEZTlDLpKbg+pyu9zAIXkSaJs/9ozMd/wBTLujOrzzhJhhwnJj0BIXRVLdu2RHqKov62PvuZBS7Cff544NSZAzB1JEm+d+3vb5l7cxTHFddNUpaVAEQwNa1gmsyhCfXZq8xgFngjwZkh9+Rp5gBMHUVSH9j4qTWzrg4b6ZmSnoAQlq7nDYM5NKc++5WZzAIXlASBM8jlnsAU0hVz5+bPL+/bEERRNUtPJgIIYRuGzQbuzaxPdTazwAU5B47FMdurAFPF0gqPbH16Qc9KPwyrnsdAADEKpmlqGnNoipfuOjIlqyCXGAdew3vxtF8ZZg7AFCkZ05/Y8Y0sPT3SExCoSHq2Qn3mRj58n8U48Gqx67tHTjAHYIr02rOf2PHNOcXFThDUSE9ACCl712dZBunZIvU5U53DOPCKNHUPHksSNvcDpsSs4sIndnyjPz9Q933H9xkIICI9Gxu466rKKJrrlQMwW53HOPAy79gpv1ZhDsBUmN9z2cNbvljQe2qe54VcVw2IIDfSU2UD9xarz7mMA+eNbGt07CRzAKbCst71H9r8WUvNV13Xj/h4ARCUnmXbVkjPVqvPXnWGKmlRyrtw5PzBE0nCtkbA5Fs1c8cHNnxSk41h1w1JT0CILDqz9GQXzRZ6M/Cq38lc+omR9Dxx1q0OMQdg0m0auP7BTZ8hPQGRVEUhPVu3PjNz1YVMpMslQegdfZE5AJPuqgVvv3/9H0k5ZdhxopjPFgARtCw9LYv0bO361BYwkS4XPH8yirj6AphkNy69792rn0qTdCQ9k4SBAALoqlqybYn0bD2/s+gA5z67PT3PVepn2c8dmGR3rNx13ZK74yTJ0jNhA3dACEPTiqbJHNqgPnuU3rxcrCdV5tKF0iQND59iDsAkkiT57tUf3TH/tiiOK65LegJiWLqeNwzm0LJeu/TAfG0xQ+lOwfHTnldjDsBkUST1A+v/JEvPMI6HSU9AFJv0pD7RFhI/cI9x4hOYNJpi7Nzy+fVz3hxEUcVxUtITECLrTpv0bHmv3WxqobaMoXSh6MiZOOFmI2BymGr+4S1fXDx9tR+GVTZwB0QpmiYbuLdlfc5U55iS7aUOo+keYaVWPcPORsDkyOvlx7Z9daC01AvDGukJCCFl6WlZbODeLuTXHT9pgb6EuXSV+MhZhgBMirLZ99SV38rS0wkC0hMQlJ6NDdxJzzauz8xibTlz6R7B6aF67RxzACauPz/3Y1f9HzPy8+q+7/g+AwFEdIwklS1LUxRG0UYu8EZhiX4Zc+kSI6ssHeXEJzAJBkpLHt321YLeU/M8L+QqakBUetq2IsuMos0O3Ov/o15lRlmexmi6QXRiyPNZ3hWYqMXTVz2+4xtZelZdl/QExMiis4f07Jj6zHH6szukUewdO8EcgAla2b/lka1fMRV72HX9KGIggACqLJdtWyY9O6k+l+mXM5qOFx0fCiIuTQMmZP3sa3du/pwmG1l6hqQnIISmKCPpyQbu7fvm4YL/6WJ9hZJT4lzMgDpVGkX1E5z4BCZk+/xb7179sVxOGnacKEkYCCCArqpF05RIz3Z24XOfumQs1Fl2vpMlL1bimKvTgPG7bsnd96z5vTTNkZ6AMIamlSyL9OzM+sys0FcznY5NzzCsHn+ROQDjdtuKB+9YuStJ0iw9Y9ITEMLUtKJpMoeOrk9jFdPpVOnxKvtqAuMj5aR3rXryxmX3R3GcpWfCBu6AELauF0jPjq/PktwzoC1gQJ1n5MTnCU58AuN6xpSU+9f/4dUL7wiz9HRd0hMQI28YtmEwh86vz8xKfQ0D6jzpizVOfALjoCnGg5s+s2nghiCKKo6Tkp6AEAXTtHSdOXRLfV5urGNAnZaeccyt7sA4mGr+4S1fXD3zSj8MK65LeAJilCzL1DTm0EX1OU3pm63OZUadJDlZC2PW+ATGJq+XH932lWW9670wrHoeAwEEkBq7aOqqyii6qz4zVxgbmFHnSFPvxGnGAIxJ2ex7fPufL+hZ6QRBjfQEhKWnZWmKwii6sT5XmxtHbvFER4hOVz2/xhyA0euz5zy545uziwvrvu/4fG4ACEmTxllPlfTs2vosyT0LtaWMqTMkLw4zBGD0ZhcXPXnlN3vt2TXPc4OAgQACKI0N3FU2cO/m+sysMTcxpg4QDdWqzlnmAIzSgp6VT+z4RsnorbquF7JMBCAuPRXSk/q83FirStxu1v4P6dOcuQFGa3nfho9s/7qlFoZd148iBgIIoCpKj23L7KJJfWYMyVqpr2VSbS3xg3NnjjIHYDTWzLpq15YvabKRpWdIegJCaKpaZgN36vPVNljbmFRbU075aY4FCoFL2zL3pg9u/IwkqUOOE8UxAwEEMEhP6vP1FmpLpyl9DKtNpUlSPXmcOQCXdM2id9677hNpmht2nDhJGAgggKlpRctiDtTn60nrTU5/tm19nnX90GUOwMXdsvwD77ziI0mSkp6AMJauF0yTOVCfF7be3CrnWHmrLUmnHYYAXNydVzyW1WcUx1l6JmzgDgiRN4zsizlQn2+oIJdWGmuYV9uJPf/s8DHmALzh2zNJvnftJ65ddFeYpafrkp6AGAXTtHSdOVCfl7DZupp5tR39NHfsAm9IkdQHN/7p1nk3B1FUcZyU9ASEKFqWqbGYI/U5Cgu0JTPVOYysnaRp7dQJxgBckKYYD2/90ppZV/thWHFdwhMQQMrlypZlqCqjoD5Ha4v1JkbWRpJh1wmqzAF4PUsrPL79z1b0bfTCsOp5DAQQkZ6NDdw10pP6HNP/eo2xyZbzTK1dqGf52B24gKIx7Ykd31jQs9IJghrpCYgJjkZ6qgp3MGOM9alK2maTqz/bQxonZ9nfCHid6fasJ3d8a05xcd33Hd9nIIAA5zdwV9nAHeOoz9zIvUdXse17W5CGvDgJmQPwarOKC5/c8c3+/EDN89wgYCCAsPRUSE+Muz7zcnGNsYnBtcGj/RzpCfyO+eUVj2//sx6zv+q6XsgDBBBBVZQe25bZRRMTqc/Mlfb1jbvW0LrSKD599ghzAF62rHfdo9u/ltfKw67rR1wSDYigKQobuGNy6nO60neFsY7ZtTJlKEzSmDkA562auePDW75oKnaWniHpCQihq2rZtklPTE59Zt5k38jsWpl0jnspgJdsGrj+wY1/qsrGkONEMe/KABFMTStZFnPAZNbnDHXOCmM142tNaRyfPneYOQCZqxa8/f51f5jLKcOOEycJAwEEsHS9YJrMAZNcn5lr7JsYX4se1EqUpLzKArkblt777tVPJWmO9ASEsQ0jbxjMAVNSn7PVeZz+bE3aMJ8tArm3r3z49sseiuI4S8+EDdwBIQqmaes6c8BU1WfmWvtmbn5vOWl6hkXm0d0kSb5nzcfesuSeMEtP1yU9ATGKpmlqrAiOKa7PWepcbn5vufisBUHkMgd0LUVS37/+j3fMvz2IoorjpKQnIOAtXy5XsiyD9ISA+sxcm79FyrF7QQuxhjkbje6lKcZDmz+3Yc51fhhWXJfwBESkpySVbFtXVUYBQfXZp8xcb25ljq2jPnSWIaA7mWr+ka1PXz5jqxcEVc9jIICIjJCksm1risIoIK4+M2/Ov1WTuMS4JSRhOFQ/wRzQhfJ6+fHtf7Zk+honCGo+690CQhqisYG7ygbuEF+fBbm03Xozo2wFepWP3dGNymbfU1d+a255Wd33HdITEEKR5R7bVkhPNKU+cyM7v7/FlgtMs+nUCmstoev05wc+euVfzMjPq3meGwQMBBDxcqMoZduW2UUTTaxPXTLekr+NaTbd0NBxhoCuMlBa8tSV/26aNaPiul4YMhBAAC1LT8siPdHk+sysN7fNUucy0CZKXL/uDzMHdI9F01Y9vuMbea087DhBFDEQQABdVUu2LZGeaIX6lHLSLYV3MtAmsh0WWkMXWdm/+dFtXzEVe9h1w5hrTgARDE0rWRbhiVapz8x8bfEqYwMzbRapyseO6BbrZ1+7c/PnVdkYcpyI9ASEsHS9aJrMAa1Vn5kbC3foksFYm6JSOckQ0A22z7/1/Rs+mcspw44TJwkDAQSwDSNv8PqOlqzPolx+c/6tjFW8ZGRnF9aZR+e7bvHd96z5vTTNkZ6AMFl32joLe6NV6zOzxXrTLHWAyQpm1tniDJ3vthUP3nH5rjhOsvRM2MAdEKJomhbpiRavTzkn31a4e+Q2JAik1XklRod716onblx2fxjHw65LegICZC/kJcsyNG5pRcvXZ2ZAW7DFuorhiuRWWWsJnfs8JSnvW/9HVy98RxBFFcdJSU9AQHpKUsm2dZUP1tAm9Zl5S/72sjKd+QozVGN7d3QmTdYf3PSZTQM3+CMXN7uEJyDkLZ9UtixNURgF2qk+dcm4feTzd4iQumEYs7c1OpCp5j+85YurZ17pBUHV8xgIICg9bVslPdF29ZlZol+21tzCiAWwPVbBQAfK6+VHt31led8GJwhqPu+vABEUWe7J57NfGQXasj4zNxfuLMplpjzlTxYO686g05TNvse3/9mCnpV133dIT0AIVZbLts0G7mjv+jQl647ivUx5qnn1KkNAJ+mz5zy54xuzi4tqnucGAQMBBNAUhfREJ9RnZrG+YrN1NYOeUpUauxyhc2TR+cSOb/Tacyqu64XsHwuIoKvqyAbupCc6oz4zN+TfNl3pZ9ZTJI0iN6wxB3SGBT0rn9jx5yWjd9hxgihiIIAAhqaRnui0+tQk/Z2l98k5LmGemvF6DBYdYlnv+o9s/7qlFoddN4xjBgIIYGpa0TSZAzqtPjNz1PnX5W9l3FPyxOGzARo6wepZVz6y9cuqbAw5TkR6AkLYul4gPdGp9ZnZYb9lsb6CiU86yePTSbS9LXNvenDjv83llGHHiRPWcABEyBuGbbBgHzq6PqWc9I7ifbZcYOiTK3AdhoC29qaFd9677hNpmiM9AWEKpmnpfHSGTq/PkZ91uXRn8f6REMXkqTvnGALa183L33/XqsfjOMnSM2EDd0CIkmWZmsYc0BX1mWtsgHSNfRNznzRpWvXOMga0qTuveOytyx8I43jYdUlPQACpsYumrqqMAl1Un5lr8jdxAeikxWcYJSmfVKIdXwLl9679+LWL7gqiqOI4KekJCHjJz9LTsjQ2cEcX1qeUk99ZfD87cE4KI+CqHbQfRVI/uPHT2+bd4odhxXUJT0BQetq2SnqiO+szY8v5u0sPKjkeAxOuz5BPT9BmNMV4eOuX1s56kxsEVc9jIICIt3yNDdyzXxkFurc+MwPagtuKd3MAJkgKOG2EdmKp+Y9s+/qKvo1OENR9n4EAAqikJ6jPl60zt261ruEYTEQasNgn2kbRmPbEld9cOO3yrDsd0hMQQlOULD1ldtEE9fmyGwt3LNSWchjGLQr44BLtYbo188kd35pTXFzzPDcIGAgggK6qbOAO6vP1/3r53aUPTlf6ORLj41OfaAczCwuevPJb/fmBiut6YchAAAEM0hPU5xux5Px7yztNyeZgjKs+KwwBLW5+ecUTO/68bPQNO04Qca0IIIKpaUXLYg6gPt9QrzLjnvKDMrfAj13drzIEtLKlvWsf3f61vFYedt0wjhkIIICl6wXTZA6gPi9hgbb0dm6BH6M0juOUM0loXatmbn94y5cMxR5ynIj0BITIG0b2xRxAfY7KOnPrtflbOCRjOHghV/OgdW0auP7BjZ9RJH3YceKEHbkAEQqmaensQgLqcyyusW/eaF7JURklI9EYAlrTVQvedt+6P8zlFNITEKZoWabG6wLaQMvtlHNr8a56Wtnj/4pjc+m3DgnnPtGKblj63tsv2xnFccV1EzZwB6Ze9mJQsixNZfc7tEnAtN5DSL6z+L552mKOzSUpMRtXoOW8beWHs/QM43iY9ATEvG42NnAnPUF9Togm6feWd85W53J4LnHwOPeJ1noJlO9Z87Hrl7wniKKK46SkJyDghaCRnqrCojGgPifMkKz7yrv6lVkcoYu92HMPMVqGIqnvX//HO+bf7odhxXUJT0DE466xgbvKBu6gPieLLRfu69k1TenjIL2hmJd4tARNMR7a/NkNc65zg6Dqsf8WIC49FdIT1OfkKsk995V3FeUyx+nCiE+0AFPNP7L16ctnbHOCoO77DAQQQFWUHtuW2UUT1OdUmK70faDncQL0gpKYpebRZHm9/JHtX18yfU3WnQ7pCQihKUqZDdxBfRKgTTp4XGaOZiqbfU/t+Na88vKq57lBwEAAAQxVLds26QnqkwBtjjTltiM0TZ8956NX/sWMwryK6/phyEAAAUxNK1oWcwD1KTRAS3IPx+xlMRtno0nmlJZ89Kq/6DH7hx0niLgCBBDB0vWCaTIHUJ+iA/TBaU9xF/zLFIlbHdEEi6atemLHN/Jaedh1Q94CAULYhpE3DOYA6rMJSnLPB3uemKHO5sgBTXFZ/+ZHt33FUOwhx4lIT0CIgmnaus4cQH0270Eol95ffmy2Oo+DBwi2bvY1H978eUXShx0nThIGAghQtCxT05gDqM8ms+XCAz2PL9VXcvwAYa5ddNcDGz6V5hTSExBDyuVKlmWwgTuozxahSfp7yzvXm9u6+eDFOT73hCDvuPyRO694LErSLD0TNnAHBKSnJJVsWyc90Yna+MdayslvK76nrEz7p/p/686Dp8g8K2Hqf8wk9X3r/2j9nDf7UVR1XQYCCCA30pMN3EF9tqhr7JtLcs9/rf5lkuu6jwIlidXmMbVMNb9z8+eX9q512UUTEJaesly2LDZwB/XZ0tab23qU6X81/B+81OGIApOl157z8JYvzCwsyLqTrYwAMbLoLLOBOzr+LVZnfBuLtOUPTftorzKjy56leHrCVFnWu+73rvo/Z+TnV1yX9ATEUBWF9AT12U6mK/1ZgHbVjfAyn8tgaly54G2PbPuKpRbYyggQRsvS07JIT1CfbcaQrPeWd26zru2Sg5cSn5hskiTfterxu1d/NEmkkfXkWVkJEEJX1ZJtS6QnukOn3TQt5eSbCu+YpQ7819pfRWnY4UdPIT8xmWyt9MDGT63o2+iFYc3zGAgghqFpRTZwB/XZ7taaW7IA/cvKvz8Xn+ngg5coLLuISTO/vOKDmz4z3ZrJPUaASJaus4E7uo2Udu7C0V7q/ufKf9wb/LpTv8FizTz0mx/yQ4yJ2zH/trtWPSFLatV1Q3ZvB0SxDYMN3EF9dp70u87f/2P979JcB36btqMf+dWP+SHGRGiy/q7VT22bd0sWnVl6so8RIEzBMEzSE9RnpxoMn/vryv9dSyod9n2pvnTimWf4Ica49ecHHtjw6bnlZSwmDwhWNE1D05gDqM9O5iT1/1z9T/uC33TSN5XGydmf/IofYozP5oEb3r36KV2xqp7HskqAuNfdLD0tiw3cQX12ifSH7ne+XfubONc5l7UN/fjZOAn5OcaY6Ip59+qPbp5748in7Z6XsKwSIOxFV5JKlqUp7JMM6rObvBi98P9X/q8z8cnO+HaCZw5X/XP8HGP05pWXf2DDJ/vzcx3fd7i3HRBIbqSnSnqC+ky77yaDMA2+Xf+bH7v/0gHfi7L73MnKYX6OMapHe066bsndt614UMopVc/j3nZAcHqWbVthjzqgO+vzvIPB3r+p/j+VZKitvwtrv3/0zB5+jnFJvfac+9Z9Ysn0NX4U1Twv5d52QOSZAllmA3eA+hzhp95/r/31M14bL5nZc0Q+cOzn/Bzj4q5a8La3r9ylKWbd83xuMALEUhWlxAbuAPX5as8Fv/nb6v9bT6rt+JefdtLYP/gjfo7xRspm371rP35Z/+agccqT5TwBwbRGerKBO0B9vpaXOv+z9jc/937Qdn/zniHrwN4fcARxQdvn33rHyl2mmq/5vh+yNgIgmq6qRdMkPQHq8w09H+7/L9W/bK/b4Qt14/lfc+4Tr9Wfn3vPmt9b1rvOj6I6pzyBZjA0LUtP5gBQn5cQpeF3nW//i/PtJNceKyAqgXTy52x3hFfIknL9kvfctPx9Sk6t+T7LyANNYep6wTCYA0B9jtbJ6Pjf1f7qcHiwDf6uaXr2x79OU1YLx4gFPSvfs/bfzCkudoPACQIe3UBT2Lpuk54A9TmOrPuV/9Nv1/62mgy3+F80+uULw+5pDliXK+g9t132oe3z3honac33I9byBJokbxiWrjMHgPocpyD1/9n5Hz9w/ilp4c05WfKz2x/DknzVgrfduuJBUy04vu9xdxHQPEXTNDSNOQDU50Sdjk/899pfHwhatPB6jqkHjvyUw9SdFk9f9a5VTw2UlnhBUOejdqCJr6ZZelqWrqqMAqA+J82+4Nm/r//tyeh4q/3Fpp219u9j0aWuM92aedtlD20ceEsUJ3XPixKu/QWa91La2MBdYwN3gPqcdGkuecb70T/U/66WVFrnb8WiS93GUvM3Lrv/TYvulHNqnbvagWaTG+mpkp4A9Tl1wjT4vvuP/+L8ffablnjiC9NTP/slx6UbKJJ61cK337zs/ZZW5BJPoEXSs2zbiiwzCoD6nHL1pPpd59s/9b4Xpc0vgNpP9/mRw0Hp5AdqTlo/5823rvhgnz3ghqHLJZ5AK7whlOWyZcmkJ0B9Cs2+pPId53/81P1+c2+KN56rHzu3n8PRqVbPuvLWFQ/OKS72wtDxfTYuAlqBKssl25bZRROgPptiODn33fq3f+79oFkNOu2Ytv/ITzgQnWdl/+bbL9s5t7yM7gRaiqYoJctiA3eA+myyc/Hpf3X+4Rf+j8R/Ft9zzj7w3Pc5BB3Wnbcsf2DhtMvpTqDV6KpaNE3SE6A+W0UtqfzA/ecfu98NUl/Yv9Tw1GO/YMnPjnhA5qS1s6++Yel9c8vLfboTaD1Glp6WxRwA6rPleKn7Y/dffuD+k5PURPz70nToJ7vjhDug25giqRsHrr9h6Xtm5Od7jfuK6E6g1ZiaVjBN5gBQn60rSsNf+D/+kfsdAWvUy8+eO1U9zMzbkaHa2+e99c2L31U2Z2TRmaUnj0qgBdm6bhsGcwCoz7aQDgb7fuD+83PBb0ZWrJ8a5aPywRd+zqzbS689+5pF78zSU5FNr9GdzARoTXnDsHSdOQDUZ5s5F5/+ofudZ7wf+ak76X94z5B9YC83HrWNpb1rr130rtUzdwRxknVnGMfMBGhZBdM0NY05ANRnuwrT4Df+z3/qfe9oeGgS/1jVl0488wzjbXGGam+Ze9OVC26fXVjExZ1AWyhalqGqzAGgPjvBqejFrEF/4f3YSydnmyL354NOUGGwrWl+z2VXzr9948BbpJyWdafPh+xA679ANjZw19jAHaA+O0yUhruDX/7S+8mBYE+aSybyR+UPhodPPctIW4qlFTYNXL9j/m2zi0uy4sy6M04SxgK0RXqWLUslPQHqs4PVk+qv/Z9lGXosGuet69NOmfsP/pBJtgJZUq6YsW3z3JuumLktTeQsOoMoYixA+zyEpZJtq2zgDlCfXeJMfDJr0N/4P89+M6Z/0HK0o79iv80mm19esWXeTRvmXGcoRT8M/SjiIQa0F0WWS5alkJ4A9dmFTscnnvWf2e3/4sXohVH9A2la+9k+P3IZnXjzysvXzb52/Zxre8xZQSM6+YQdaNP0LNu2zC6aAPXZ5c7Fp7MG3RP8+mg4mF50xVAu/WxadBozs+IMiE6gnamKUrYsNnAHqE+8wk2dA8HufcHu/cHuC+7hOe20tf/ADxjUlFJkbXnvulUzd1wxc3tR7w+ITqAjaKpaMk3SE6A+cWFpLj0eHdkXPDsY7DsaHYrTl+5o0T35+C/Y8WhKFI1pl8/Yunrmlcv7Nko5/Xx08vABOoOhqkXLYg4A9YlRCdPgSDh4KNyffb0QPu88c6DuDzOWSaEpxtLpa1f0b1zRt3FmflEYx1lxsi8R0GFMTSuYJnMAqE+Ms0QHz/1m36mfHTj7y0Pnno0SljQfM1XW5pVXLOtbnxXngvLKJJXDKArimEcK0JEsXc8bBnMAqE9MyPnLECUpeaG678CZZ7ISPXjuN37kMJk3YmvFRdOuWDx9zeLpqweKy3I5JYzjLDrZBhPobFl3ZvXJHADqExMVxfGQM9KaUuMWTk3JyOfcY4eH9zw/tOfw0J6jlf1xd58W1WR9TmnJ/J4V88orFvSs7LUGstLM5hZyjhPoGgXTNDWNOQDUJybH2Vrt9eftFFlWsy9FkaT0xdrBY9UDxyoHj1ez3xysd/oG8Xm9PLu4cHZx8bzysqw4+6x5STqS6VGScLs60IWKlmWoKnMAqE9Mmrrvu0Fw8f+NLEnqyFnRkSSth0Mn6oderA6+WHv+dP2FU/UXhrxT7fvt95j9ffk5M/LzZhcXZV/9+fm2Ws4q83xrkptAV7/sNdJTJz0B6hOTK4zjYWfMF3pmJfryV5KGZ93jZ9xjWYyedV8cck9lPZp9Vf1zrfNtFo1pWWiOfFn9ffZArz2715ozzZot55Q4TWNaE8BrXvMkqWRZmqIwCoD6xOQ7U6tNysGVsxiVpOxXWZKy3yS5uOKfrvpnasFQPRyuB5Wqf7YeVurByO/dsBbEnp99TewmJ1PN64qhKWZeL+W1Yl4vZ18FvSf7f22tVDb6ikZvQZ8m5ZQkTUe+Mo3c5LgDeMNnsyw9bVtlA3eA+sQUqXmeF07trUVSVqWS9PKvI79p/IdS478LYjeMvSgNsyzMevT8PxLGfvLbtfE12czK9vzvFUnVFEOXzexXVTbO/1imjf+TjPyf9NW/cnABjJUiyyXLUkhPgPrE1AmjaNh1mQMAZNFZtm2ZXTSB1sC7wI6lqSpPtQCgKgrpCVCfEMRgKTsAXf4+PEtPyyI9AeoTouqTJUUAdDFdVcu2LZGeAPUJYc4v58kcAHQhU9NKlsUcAOoTovHhO4AuZOl6wTSZA0B9ohnv/vnwHUCXsQ0jbxjMAaA+0aQDLMtsKAegexRM09Z15gBQn2gmPnwH0CWKpmnyjAdQn2h+fbLwJ4BOlz3HlSyLN9sA9YmWCVCekQF0cHo2NnDnKiOA+kQL4aMoAB37MiZJZdvWFIVRANQnWojCvUcAOjc9VRY2BqhPtCBOfwLovPfVPfk8e2oA1CdalK6qPEcD6BiqopRtm1sqAeoTLc1iDTwAHUHL0tOySE+A+kSrM1RV4skaQJvTVbVk2zybAdQn2kD2ZM3VnwDa+120ppUsi/AEqE+0DUvXedYG0L7PYEXTZA4A9Ym2Ot6SxMrzANqRret5w2AOAPWJ9sO9RwDaTtadNukJUJ9oU4osc/oTQBspmiZvmwHqE+2N53EAbUHK5UqWxRtmgPpE21PZeBNA66enJJVsmycrgPpEh+DifQAt/eIkSWXL0hSFUQDUJzrEyNWfnFEA0LLpadsq6QlQn+gw3EAKoDXfG/fYdvYrowCoT3TgUzzX8gNoKaosl21bJj0B6hOdyubmdwAtQ1OUkfRkA3eA+kQHU2SZ1ZcAtAJdVUc2cCc9AeoTHc/WdZ7uATSXoWmkJ0B9oltkT/d8/g6giUxNK5omcwCoT3QRS9e5vRRAU2TvfgukJ0B9ohtfAFh9CYBwecPgyQegPtGlDFVlTxEAIhVMk7seAeoT3f5KwBAAiFGyLJP1hgHqE12O1ZcACCA1dtHU2ekXoD6BXOPyf9Z5BjC16WlZXOcDUJ/AKy8Mee4AADBFrzeS1GPbKukJ8GzACPBqhqZxWgLApFMaG7izuBsA6hMXUDBNPn0HQHoCoD4h7nWCFfgATBZVUXpsm2vKAVCfuBhL17k2C8DE6apaZgN3ANQnRoPlPwFMkKGqJdITAPWJUVJZ/hPABJiaVrQs5gCA+sQY2IbBXQIAxiF778rnJwCoT4yZlMtx6gLAWOUNg5WDAVCfGCdVlnkVATB6BdPkoh0A1CcmJHshYf15AKNRtCxT05gDAOoTEzWy/jx3rQJ4Y9kTRNmyDFVlFACoT0wCRZYLfP4O4I3SU5LKtq2RngCoT0wiQ9MMPlAD8PpXkUZ6sj8FAOoTk6/AAkwAftf5DdxVnhkAUJ+YCpIkFS2Lyz8BvDo9eVMKgPrEFBpZgIkVpAFkzwaK0mPbMvcjAqA+MdVMLgAFup6mKGU2cAdAfUKYgmFwmRfQtXRVLds26QmA+oQ4L10AymsP0H1MTSuxAS8A6hPiKbLMKxDQbSxdL3DlNwDqE82iKQpbwAPdwzYMHvIAqE80maXrbKwHdIOCadq6zhwAUJ9ogdcky2KPE6CzFU3TZKULANQnWoSUy5Usi+WmgQ5+gLPIGgDqEy32MyRJJW6BBzovPbOHtm3rXF0DgPpEC+IWeKDz3lWWbVvjuhoA1CdaVvYqxVIsQIe8MDQ2cGdTCQDUJ1qdqWk2C7IAbU6R5R7b5mJuANQn2oOt6xbLsgBtS1WUsm3LXMYNgPpEG8kbBnfIAu1Iy9LTskhPAFP+RpcRYNIVTTNN0yCKGAXQLnRVLVoW4QlAAM59YqoClLtlgXZhaFqJ9ARAfaKtSY1FQNkGCWh9lq4XWbACAPWJzgjQMgEKtDbbMPIsVQGA+gQBCkCArDttFqkAID4P0jRlCphS2c/YsOtGccwogNZRNE2WpwBAfYIABTD1z/tZeloWG7gDoD7R+QFacd2QAAWa+6TfuCOQJSkAUJ/olgCteh7rgALNIrMYBQDqE12o6ro+AQo0Iz3LbOAOgPpEd6p5nheGzAEQJotONnAHQH2iq9V93w0C5gAIoCpKiQ3cAVCfQFafWYMyB2BKaapaMk2J9ARAfQIZPwyrnsccgCliaBq7aAKgPoHfEUZRxfP4OQQmnaXr7KIJgPoELiBOkmHXTZKEUQCTpWCaJlsZAaA+gTeSNNaiZzMkYBKe1iWpaJpsZQSA+gQugbXogYmTZXlkPXkW9QRAfQKj5Pi+w0pMwLhoilJkZSUA1CcwVn4U1VyXn0tgTExNK3B7OwDqExifKI4rrpvwwwmMTt4wLF1nDgCoT2D8svSsum7IfUjARcmSVLQsTVEYBQDqE5gEbMgJXAQXegKgPoHJF0RRleXogddhMXkA1CcwVeIkyQKU1UCBl564JalgmgYregKgPoEpxafwQEZVlKJpKqzoCYD6BATgU3h0OT5tB0B9AqJxLzy6k9zYP1Pj03YA1CfQFG4QOL7Pzy66hKGqBdOUuLcdAPUJNNHIrUiuGyUJo0AnP0dLUt4wTE1jFACoT6D5sp9dl33h0bk0VS0ahswNRgCoT6ClRElS4yQoOuypmVOeAKhPoMU5nARFp+CUJwDqE2gPLEqPdic3TnkanPIEQH0CbcQLw7rv84ONtpNFZ8EwuLEdAPUJtJ8kTeue50cRo0BbUGS5YJqaojAKANQn0MbCOK55XszdSGjlp2BJsnXd0nVGAYD6BDrEyLr0QcDPOVqQoap505T5qB0A9Ql0mCRNHd/3wpBRoEWoipI3DD5qB0B9Ap0sSpK657FBPJqLu9oBgPpEdwmiqO77XAyKJjzbSpKl65amcVc7AOqT+kTX8cLQ8f2EH36IYjVuLeISTwCgPtG9sp97jxuSMPUMTbN1XWHjIgCgPoGRBk1TNwjcMOSBgMnvTlW1DYPuBADqE6BBQXcCAPUJtEKDhqHLZ/GYSHfyOTsAUJ/AWBvUazQo9yRhDM+kje606E4AoD6BcTvfoKzNhEs8h0qS2ehO7mcHAOoTmARhFLlhGEQRo8BrKLKcRaehqqzfCQDUJzDJ4iRxg8CPIh4vyGiKknWnrqqMAgCoT2AKnb8kNPvi4/gufbpsfMiefXFxJwBQn4BQYRx7jVOhjKJLqIqSRScfsgMA9Qk0U5KmPqdCO/v5sXGy09A0lZOdAEB9Aq0jiuOsQbkqtJPoqppFZ/YrpzoBgPoEWlcQRX7jBnkeVG1KVRSj0Z0snwQA1CfQNrLH1EiGRhHrNLVXdOqqyu1EAEB9Ap2QoSFnQ1s1Okc+YSc6AYD6BDovQ8M4Pn82lEdc02nnz3Ty8ToAUJ9AN8gyNGicDY24U16gLDR1VdWy6FQUVk0CAOoT6EZJ43P5LEazEk14GE7Fs9tvP1vPopMlkwCA+gTwijhJXirROOYhOUEjxakoI8WpKJzkBADqE8ClS/R8hnJOdLTPYpKUhabW+FJlmQ/WAYD6BDBOWX1GjRLNfo2ShEfry7LKzIrzfHRyxzoAUJ8ApkScJFmDZiUaN37tnjOjkiRliflSccqywkfqAEB9AhAve/BmMRo3vkaSNE2TjriP/nxrns9N5bdfHG4AoD4BtF6P5nLJb3s0SdORX7Pfp2nLPsyzrJQbrZlRfhudXLgJANQngDav0jRNzn81qjRp9OjLvzn/+8l/cmmQG1/Sq34d+WpEJ4u9AwD1CaCLC7URqS+dJm38+tJvf/ubCzx9NBIz96pfpVf9ykgBABf0vwUYAOtw8VRWXOXhAAAAAElFTkSuQmCC");background-repeat:no-repeat;background-size:203px 95px;background-position:right -10px}body.toc2{padding-right:0}body.toc2 #toc.toc2{position:absolute;margin-top:0 !important;width:15em;top:0;border-top-width:0 !important;border-bottom-width:0 !important;margin-left:-15.9375em;z-index:1000;padding:0 1em 1.25em 0em;overflow:auto}body.toc2 #toc.toc2 #toctitle{margin-top:0;margin-bottom:0.8rem;font-size:1.2em}body.toc2 #toc.toc2>ul{font-size:0.9em;margin-bottom:0}body.toc2 #toc.toc2 ul ul{margin-left:0;padding-left:1em}body.toc2 #toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:0.5em;margin-bottom:0.5em}body.toc2 #header,body.toc2 #content,body.toc2 #footnotes,body.toc2 #footer{padding-left:15.9375em;max-width:none}body.book #header-spring h1{max-width:1400px;margin:0 auto}body.book #header,body.book #content,body.book #footnotes,body.book #footer{max-width:1400px}body.is-position-fixed #toc.toc2{position:fixed;height:100%}h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2}h1{font-size:1.75em}h2{font-size:1.6em}h3,#toctitle,.sidebarblock>.content>.title{font-size:1.5em}h4{font-size:1.4em}h5{font-size:1.2em}h6{font-size:1.2em}#tocbot a.toc-link.node-name--H1{font-style:italic}#tocbot ol{margin:0;padding:0}#tocbot ol li{list-style:none;padding:0 0;margin:0;display:block}#tocbot{z-index:999}#tocbot .toc-link{position:relative;display:block;z-index:999;padding:.4rem .6rem}#tocbot a.is-active-link{padding-right:3px;background:black;color:white}}@media only screen and (min-width: 768px){#tocbot>ul.toc-list{margin-bottom:0.5em;margin-left:0.125em}#tocbot ul.sectlevel0,#tocbot a.toc-link.node-name--H1+ul{padding-left:0}#tocbot a.toc-link{height:100%}.is-collapsible{max-height:3000px;overflow:hidden}.is-collapsed{max-height:0}}@media only screen and (min-width: 768px){body.toc2 #header,body.toc2 #content,body.toc2 #footer{background-repeat:repeat-y;background-position:14em 0;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAMAAAAoyzS7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQwIDc5LjE2MDQ1MSwgMjAxNy8wNS8wNi0wMTowODoyMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTggKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RDE0NUNENzNGMTVGMTFFODk5RjI5ODk3QURGRjcxMkEiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RDE0NUNENzRGMTVGMTFFODk5RjI5ODk3QURGRjcxMkEiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpEMTQ1Q0Q3MUYxNUYxMUU4OTlGMjk4OTdBREZGNzEyQSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpEMTQ1Q0Q3MkYxNUYxMUU4OTlGMjk4OTdBREZGNzEyQSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PjmGxxYAAAAGUExURd3d2AAAAJlCnKAAAAAMSURBVHjaYmAACDAAAAIAAU9tWeEAAAAASUVORK5CYII=);background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyVpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQ4IDc5LjE2NDAzNiwgMjAxOS8wOC8xMy0wMTowNjo1NyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIDIxLjEgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NDMyRDZERkQ1MEE4MTFFQTlCNTJBOEQwQTM2ODZEQjgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NDMyRDZERkU1MEE4MTFFQTlCNTJBOEQwQTM2ODZEQjgiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0MzJENkRGQjUwQTgxMUVBOUI1MkE4RDBBMzY4NkRCOCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0MzJENkRGQzUwQTgxMUVBOUI1MkE4RDBBMzY4NkRCOCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PjdyLKIAAAAPSURBVHjaYnj16RNAgAEABZgCz/xXiToAAAAASUVORK5CYII=");background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyVpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQ4IDc5LjE2NDAzNiwgMjAxOS8wOC8xMy0wMTowNjo1NyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIDIxLjEgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6ODRBOEI2NTI1MEI1MTFFQTlCNTJBOEQwQTM2ODZEQjgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6ODRBOEI2NTM1MEI1MTFFQTlCNTJBOEQwQTM2ODZEQjgiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0MzJENkRGRjUwQTgxMUVBOUI1MkE4RDBBMzY4NkRCOCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0MzJENkUwMDUwQTgxMUVBOUI1MkE4RDBBMzY4NkRCOCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pul87iAAAAAPSURBVHjaYrj17BlAgAEABUQCpxgONc4AAAAASUVORK5CYII=")}}@media only screen and (min-width: 1280px){body.toc2{padding-right:0}body.toc2 #toc.toc2{width:25em;left:auto;margin-left:-26.9375em}body.toc2 #toc.toc2 #toctitle{font-size:1.375em}body.toc2 #toc.toc2>ul{font-size:0.95em}body.toc2 #toc.toc2 ul ul{padding-left:1.25em}body.toc2 body.toc2.toc-right{padding-left:0;padding-right:20em}body.toc2 #header,body.toc2 #content,body.toc2 #footnotes,body.toc2 #footer{padding-left:26.9375em;max-width:1400px}body.toc2 #header-spring h1{margin:0 auto;max-width:1400px}.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:0.8125em}body.toc2 #header,body.toc2 #content,body.toc2 #footer{background-repeat:repeat-y;background-position:24em 0;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAMAAAAoyzS7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQwIDc5LjE2MDQ1MSwgMjAxNy8wNS8wNi0wMTowODoyMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTggKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RDE0NUNENzNGMTVGMTFFODk5RjI5ODk3QURGRjcxMkEiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RDE0NUNENzRGMTVGMTFFODk5RjI5ODk3QURGRjcxMkEiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpEMTQ1Q0Q3MUYxNUYxMUU4OTlGMjk4OTdBREZGNzEyQSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpEMTQ1Q0Q3MkYxNUYxMUU4OTlGMjk4OTdBREZGNzEyQSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PjmGxxYAAAAGUExURd3d2AAAAJlCnKAAAAAMSURBVHjaYmAACDAAAAIAAU9tWeEAAAAASUVORK5CYII=);background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyVpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQ4IDc5LjE2NDAzNiwgMjAxOS8wOC8xMy0wMTowNjo1NyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIDIxLjEgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NDMyRDZERkQ1MEE4MTFFQTlCNTJBOEQwQTM2ODZEQjgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NDMyRDZERkU1MEE4MTFFQTlCNTJBOEQwQTM2ODZEQjgiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0MzJENkRGQjUwQTgxMUVBOUI1MkE4RDBBMzY4NkRCOCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0MzJENkRGQzUwQTgxMUVBOUI1MkE4RDBBMzY4NkRCOCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PjdyLKIAAAAPSURBVHjaYnj16RNAgAEABZgCz/xXiToAAAAASUVORK5CYII=");background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyVpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQ4IDc5LjE2NDAzNiwgMjAxOS8wOC8xMy0wMTowNjo1NyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIDIxLjEgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6ODRBOEI2NTI1MEI1MTFFQTlCNTJBOEQwQTM2ODZEQjgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6ODRBOEI2NTM1MEI1MTFFQTlCNTJBOEQwQTM2ODZEQjgiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0MzJENkRGRjUwQTgxMUVBOUI1MkE4RDBBMzY4NkRCOCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0MzJENkUwMDUwQTgxMUVBOUI1MkE4RDBBMzY4NkRCOCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pul87iAAAAAPSURBVHjaYrj17BlAgAEABUQCpxgONc4AAAAASUVORK5CYII=")}#header{min-height:150px;padding-right:310px}#header::after{height:147px;width:305px;background-size:305px 147px}}
diff --git a/reference/htmlsingle/favicon.ico b/reference/htmlsingle/favicon.ico
new file mode 100644
index 00000000..1a4956e6
Binary files /dev/null and b/reference/htmlsingle/favicon.ico differ
diff --git a/reference/htmlsingle/images/spring-cloud-launcher-eureka-dashboard.png b/reference/htmlsingle/images/spring-cloud-launcher-eureka-dashboard.png
new file mode 100644
index 00000000..dbd12c59
Binary files /dev/null and b/reference/htmlsingle/images/spring-cloud-launcher-eureka-dashboard.png differ
diff --git a/reference/htmlsingle/images/spring-cloud-launcher-log.png b/reference/htmlsingle/images/spring-cloud-launcher-log.png
new file mode 100644
index 00000000..916ce243
Binary files /dev/null and b/reference/htmlsingle/images/spring-cloud-launcher-log.png differ
diff --git a/reference/htmlsingle/js/highlight/highlight.min.js b/reference/htmlsingle/js/highlight/highlight.min.js
new file mode 100644
index 00000000..dcbbb4c7
--- /dev/null
+++ b/reference/htmlsingle/js/highlight/highlight.min.js
@@ -0,0 +1,2 @@
+/*! highlight.js v9.13.1 | BSD3 License | git.io/hljslicense */
+!function(e){var n="object"==typeof window&&window||"object"==typeof self&&self;"undefined"!=typeof exports?e(exports):n&&(n.hljs=e({}),"function"==typeof define&&define.amd&&define([],function(){return n.hljs}))}(function(e){function n(e){return e.replace(/&/g,"&").replace(//g,">")}function t(e){return e.nodeName.toLowerCase()}function r(e,n){var t=e&&e.exec(n);return t&&0===t.index}function a(e){return k.test(e)}function i(e){var n,t,r,i,o=e.className+" ";if(o+=e.parentNode?e.parentNode.className:"",t=M.exec(o))return w(t[1])?t[1]:"no-highlight";for(o=o.split(/\s+/),n=0,r=o.length;r>n;n++)if(i=o[n],a(i)||w(i))return i}function o(e){var n,t={},r=Array.prototype.slice.call(arguments,1);for(n in e)t[n]=e[n];return r.forEach(function(e){for(n in e)t[n]=e[n]}),t}function c(e){var n=[];return function r(e,a){for(var i=e.firstChild;i;i=i.nextSibling)3===i.nodeType?a+=i.nodeValue.length:1===i.nodeType&&(n.push({event:"start",offset:a,node:i}),a=r(i,a),t(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:a,node:i}));return a}(e,0),n}function u(e,r,a){function i(){return e.length&&r.length?e[0].offset!==r[0].offset?e[0].offset"}function c(e){l+=""+t(e)+">"}function u(e){("start"===e.event?o:c)(e.node)}for(var s=0,l="",f=[];e.length||r.length;){var g=i();if(l+=n(a.substring(s,g[0].offset)),s=g[0].offset,g===e){f.reverse().forEach(c);do u(g.splice(0,1)[0]),g=i();while(g===e&&g.length&&g[0].offset===s);f.reverse().forEach(o)}else"start"===g[0].event?f.push(g[0].node):f.pop(),u(g.splice(0,1)[0])}return l+n(a.substr(s))}function s(e){return e.v&&!e.cached_variants&&(e.cached_variants=e.v.map(function(n){return o(e,{v:null},n)})),e.cached_variants||e.eW&&[o(e)]||[e]}function l(e){function n(e){return e&&e.source||e}function t(t,r){return new RegExp(n(t),"m"+(e.cI?"i":"")+(r?"g":""))}function r(a,i){if(!a.compiled){if(a.compiled=!0,a.k=a.k||a.bK,a.k){var o={},c=function(n,t){e.cI&&(t=t.toLowerCase()),t.split(" ").forEach(function(e){var t=e.split("|");o[t[0]]=[n,t[1]?Number(t[1]):1]})};"string"==typeof a.k?c("keyword",a.k):B(a.k).forEach(function(e){c(e,a.k[e])}),a.k=o}a.lR=t(a.l||/\w+/,!0),i&&(a.bK&&(a.b="\\b("+a.bK.split(" ").join("|")+")\\b"),a.b||(a.b=/\B|\b/),a.bR=t(a.b),a.endSameAsBegin&&(a.e=a.b),a.e||a.eW||(a.e=/\B|\b/),a.e&&(a.eR=t(a.e)),a.tE=n(a.e)||"",a.eW&&i.tE&&(a.tE+=(a.e?"|":"")+i.tE)),a.i&&(a.iR=t(a.i)),null==a.r&&(a.r=1),a.c||(a.c=[]),a.c=Array.prototype.concat.apply([],a.c.map(function(e){return s("self"===e?a:e)})),a.c.forEach(function(e){r(e,a)}),a.starts&&r(a.starts,i);var u=a.c.map(function(e){return e.bK?"\\.?("+e.b+")\\.?":e.b}).concat([a.tE,a.i]).map(n).filter(Boolean);a.t=u.length?t(u.join("|"),!0):{exec:function(){return null}}}}r(e)}function f(e,t,a,i){function o(e){return new RegExp(e.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&"),"m")}function c(e,n){var t,a;for(t=0,a=n.c.length;a>t;t++)if(r(n.c[t].bR,e))return n.c[t].endSameAsBegin&&(n.c[t].eR=o(n.c[t].bR.exec(e)[0])),n.c[t]}function u(e,n){if(r(e.eR,n)){for(;e.endsParent&&e.parent;)e=e.parent;return e}return e.eW?u(e.parent,n):void 0}function s(e,n){return!a&&r(n.iR,e)}function p(e,n){var t=R.cI?n[0].toLowerCase():n[0];return e.k.hasOwnProperty(t)&&e.k[t]}function d(e,n,t,r){var a=r?"":j.classPrefix,i='',i+n+o}function h(){var e,t,r,a;if(!E.k)return n(k);for(a="",t=0,E.lR.lastIndex=0,r=E.lR.exec(k);r;)a+=n(k.substring(t,r.index)),e=p(E,r),e?(M+=e[1],a+=d(e[0],n(r[0]))):a+=n(r[0]),t=E.lR.lastIndex,r=E.lR.exec(k);return a+n(k.substr(t))}function b(){var e="string"==typeof E.sL;if(e&&!L[E.sL])return n(k);var t=e?f(E.sL,k,!0,B[E.sL]):g(k,E.sL.length?E.sL:void 0);return E.r>0&&(M+=t.r),e&&(B[E.sL]=t.top),d(t.language,t.value,!1,!0)}function v(){y+=null!=E.sL?b():h(),k=""}function m(e){y+=e.cN?d(e.cN,"",!0):"",E=Object.create(e,{parent:{value:E}})}function N(e,n){if(k+=e,null==n)return v(),0;var t=c(n,E);if(t)return t.skip?k+=n:(t.eB&&(k+=n),v(),t.rB||t.eB||(k=n)),m(t,n),t.rB?0:n.length;var r=u(E,n);if(r){var a=E;a.skip?k+=n:(a.rE||a.eE||(k+=n),v(),a.eE&&(k=n));do E.cN&&(y+=I),E.skip||E.sL||(M+=E.r),E=E.parent;while(E!==r.parent);return r.starts&&(r.endSameAsBegin&&(r.starts.eR=r.eR),m(r.starts,"")),a.rE?0:n.length}if(s(n,E))throw new Error('Illegal lexeme "'+n+'" for mode "'+(E.cN||"")+'"');return k+=n,n.length||1}var R=w(e);if(!R)throw new Error('Unknown language: "'+e+'"');l(R);var x,E=i||R,B={},y="";for(x=E;x!==R;x=x.parent)x.cN&&(y=d(x.cN,"",!0)+y);var k="",M=0;try{for(var C,A,S=0;;){if(E.t.lastIndex=S,C=E.t.exec(t),!C)break;A=N(t.substring(S,C.index),C[0]),S=C.index+A}for(N(t.substr(S)),x=E;x.parent;x=x.parent)x.cN&&(y+=I);return{r:M,value:y,language:e,top:E}}catch(O){if(O.message&&-1!==O.message.indexOf("Illegal"))return{r:0,value:n(t)};throw O}}function g(e,t){t=t||j.languages||B(L);var r={r:0,value:n(e)},a=r;return t.filter(w).filter(x).forEach(function(n){var t=f(n,e,!1);t.language=n,t.r>a.r&&(a=t),t.r>r.r&&(a=r,r=t)}),a.language&&(r.second_best=a),r}function p(e){return j.tabReplace||j.useBR?e.replace(C,function(e,n){return j.useBR&&"\n"===e?" ":j.tabReplace?n.replace(/\t/g,j.tabReplace):""}):e}function d(e,n,t){var r=n?y[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),-1===e.indexOf(r)&&a.push(r),a.join(" ").trim()}function h(e){var n,t,r,o,s,l=i(e);a(l)||(j.useBR?(n=document.createElementNS("http://www.w3.org/1999/xhtml","div"),n.innerHTML=e.innerHTML.replace(/\n/g,"").replace(/ /g,"\n")):n=e,s=n.textContent,r=l?f(l,s,!0):g(s),t=c(n),t.length&&(o=document.createElementNS("http://www.w3.org/1999/xhtml","div"),o.innerHTML=r.value,r.value=u(t,c(o),s)),r.value=p(r.value),e.innerHTML=r.value,e.className=d(e.className,l,r.language),e.result={language:r.language,re:r.r},r.second_best&&(e.second_best={language:r.second_best.language,re:r.second_best.r}))}function b(e){j=o(j,e)}function v(){if(!v.called){v.called=!0;var e=document.querySelectorAll("pre code");E.forEach.call(e,h)}}function m(){addEventListener("DOMContentLoaded",v,!1),addEventListener("load",v,!1)}function N(n,t){var r=L[n]=t(e);r.aliases&&r.aliases.forEach(function(e){y[e]=n})}function R(){return B(L)}function w(e){return e=(e||"").toLowerCase(),L[e]||L[y[e]]}function x(e){var n=w(e);return n&&!n.disableAutodetect}var E=[],B=Object.keys,L={},y={},k=/^(no-?highlight|plain|text)$/i,M=/\blang(?:uage)?-([\w-]+)\b/i,C=/((^(<[^>]+>|\t|)+|(?:\n)))/gm,I=" ",j={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0};return e.highlight=f,e.highlightAuto=g,e.fixMarkup=p,e.highlightBlock=h,e.configure=b,e.initHighlighting=v,e.initHighlightingOnLoad=m,e.registerLanguage=N,e.listLanguages=R,e.getLanguage=w,e.autoDetection=x,e.inherit=o,e.IR="[a-zA-Z]\\w*",e.UIR="[a-zA-Z_]\\w*",e.NR="\\b\\d+(\\.\\d+)?",e.CNR="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",e.BNR="\\b(0b[01]+)",e.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",e.BE={b:"\\\\[\\s\\S]",r:0},e.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[e.BE]},e.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[e.BE]},e.PWM={b:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},e.C=function(n,t,r){var a=e.inherit({cN:"comment",b:n,e:t,c:[]},r||{});return a.c.push(e.PWM),a.c.push({cN:"doctag",b:"(?:TODO|FIXME|NOTE|BUG|XXX):",r:0}),a},e.CLCM=e.C("//","$"),e.CBCM=e.C("/\\*","\\*/"),e.HCM=e.C("#","$"),e.NM={cN:"number",b:e.NR,r:0},e.CNM={cN:"number",b:e.CNR,r:0},e.BNM={cN:"number",b:e.BNR,r:0},e.CSSNM={cN:"number",b:e.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0},e.RM={cN:"regexp",b:/\//,e:/\/[gimuy]*/,i:/\n/,c:[e.BE,{b:/\[/,e:/\]/,r:0,c:[e.BE]}]},e.TM={cN:"title",b:e.IR,r:0},e.UTM={cN:"title",b:e.UIR,r:0},e.METHOD_GUARD={b:"\\.\\s*"+e.UIR,r:0},e});hljs.registerLanguage("bash",function(e){var t={cN:"variable",v:[{b:/\$[\w\d#@][\w\d_]*/},{b:/\$\{(.*?)}/}]},s={cN:"string",b:/"/,e:/"/,c:[e.BE,t,{cN:"variable",b:/\$\(/,e:/\)/,c:[e.BE]}]},a={cN:"string",b:/'/,e:/'/};return{aliases:["sh","zsh"],l:/\b-?[a-z\._]+\b/,k:{keyword:"if then else elif fi for while in do done case esac function",literal:"true false",built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp",_:"-ne -eq -lt -gt -f -d -e -s -l -a"},c:[{cN:"meta",b:/^#![^\n]+sh\s*$/,r:10},{cN:"function",b:/\w[\w\d_]*\s*\(\s*\)\s*\{/,rB:!0,c:[e.inherit(e.TM,{b:/\w[\w\d_]*/})],r:0},e.HCM,s,a,t]}});hljs.registerLanguage("dockerfile",function(e){return{aliases:["docker"],cI:!0,k:"from maintainer expose env arg user onbuild stopsignal",c:[e.HCM,e.ASM,e.QSM,e.NM,{bK:"run cmd entrypoint volume add copy workdir label healthcheck shell",starts:{e:/[^\\]\n/,sL:"bash"}}],i:""}});hljs.registerLanguage("kotlin",function(e){var t={keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit init interface annotation data sealed internal infix operator out by constructor super tailrec where const inner suspend typealias external expect actual trait volatile transient native default",built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing",literal:"true false null"},r={cN:"keyword",b:/\b(break|continue|return|this)\b/,starts:{c:[{cN:"symbol",b:/@\w+/}]}},a={cN:"symbol",b:e.UIR+"@"},i={cN:"subst",b:"\\${",e:"}",c:[e.ASM,e.CNM]},n={cN:"variable",b:"\\$"+e.UIR},c={cN:"string",v:[{b:'"""',e:'"""',c:[n,i]},{b:"'",e:"'",i:/\n/,c:[e.BE]},{b:'"',e:'"',i:/\n/,c:[e.BE,n,i]}]},s={cN:"meta",b:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+e.UIR+")?"},l={cN:"meta",b:"@"+e.UIR,c:[{b:/\(/,e:/\)/,c:[e.inherit(c,{cN:"meta-string"})]}]},b="\\b(0[bB]([01]+[01_]+[01]+|[01]+)|0[xX]([a-fA-F0-9]+[a-fA-F0-9_]+[a-fA-F0-9]+|[a-fA-F0-9]+)|(([\\d]+[\\d_]+[\\d]+|[\\d]+)(\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))?|\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))([eE][-+]?\\d+)?)[lLfF]?",o={cN:"number",b:b,r:0};return{aliases:["kt"],k:t,c:[e.C("/\\*\\*","\\*/",{r:0,c:[{cN:"doctag",b:"@[A-Za-z]+"}]}),e.CLCM,e.CBCM,r,a,s,l,{cN:"function",bK:"fun",e:"[(]|$",rB:!0,eE:!0,k:t,i:/fun\s+(<.*>)?[^\s\(]+(\s+[^\s\(]+)\s*=/,r:5,c:[{b:e.UIR+"\\s*\\(",rB:!0,r:0,c:[e.UTM]},{cN:"type",b:/,e:/>/,k:"reified",r:0},{cN:"params",b:/\(/,e:/\)/,endsParent:!0,k:t,r:0,c:[{b:/:/,e:/[=,\/]/,eW:!0,c:[{cN:"type",b:e.UIR},e.CLCM,e.CBCM],r:0},e.CLCM,e.CBCM,s,l,c,e.CNM]},e.CBCM]},{cN:"class",bK:"class interface trait",e:/[:\{(]|$/,eE:!0,i:"extends implements",c:[{bK:"public protected internal private constructor"},e.UTM,{cN:"type",b:/,e:/>/,eB:!0,eE:!0,r:0},{cN:"type",b:/[,:]\s*/,e:/[<\(,]|$/,eB:!0,rE:!0},s,l]},c,{cN:"meta",b:"^#!/usr/bin/env",e:"$",i:"\n"},o]}});hljs.registerLanguage("java",function(e){var a="[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*",t=a+"(<"+a+"(\\s*,\\s*"+a+")*>)?",r="false synchronized int abstract float private char boolean var static null if const for true while long strictfp finally protected import native final void enum else break transient catch instanceof byte super volatile case assert short package default double public try this switch continue throws protected public private module requires exports do",s="\\b(0[bB]([01]+[01_]+[01]+|[01]+)|0[xX]([a-fA-F0-9]+[a-fA-F0-9_]+[a-fA-F0-9]+|[a-fA-F0-9]+)|(([\\d]+[\\d_]+[\\d]+|[\\d]+)(\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))?|\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))([eE][-+]?\\d+)?)[lLfF]?",c={cN:"number",b:s,r:0};return{aliases:["jsp"],k:r,i:/<\/|#/,c:[e.C("/\\*\\*","\\*/",{r:0,c:[{b:/\w+@/,r:0},{cN:"doctag",b:"@[A-Za-z]+"}]}),e.CLCM,e.CBCM,e.ASM,e.QSM,{cN:"class",bK:"class interface",e:/[{;=]/,eE:!0,k:"class interface",i:/[:"\[\]]/,c:[{bK:"extends implements"},e.UTM]},{bK:"new throw return else",r:0},{cN:"function",b:"("+t+"\\s+)+"+e.UIR+"\\s*\\(",rB:!0,e:/[{;=]/,eE:!0,k:r,c:[{b:e.UIR+"\\s*\\(",rB:!0,r:0,c:[e.UTM]},{cN:"params",b:/\(/,e:/\)/,k:r,r:0,c:[e.ASM,e.QSM,e.CNM,e.CBCM]},e.CLCM,e.CBCM]},c,{cN:"meta",b:"@[A-Za-z]+"}]}});hljs.registerLanguage("xml",function(s){var e="[A-Za-z0-9\\._:-]+",t={eW:!0,i:/,r:0,c:[{cN:"attr",b:e,r:0},{b:/=\s*/,r:0,c:[{cN:"string",endsParent:!0,v:[{b:/"/,e:/"/},{b:/'/,e:/'/},{b:/[^\s"'=<>`]+/}]}]}]};return{aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist"],cI:!0,c:[{cN:"meta",b:"",r:10,c:[{b:"\\[",e:"\\]"}]},s.C("",{r:10}),{b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{cN:"meta",b:/<\?xml/,e:/\?>/,r:10},{b:/<\?(php)?/,e:/\?>/,sL:"php",c:[{b:"/\\*",e:"\\*/",skip:!0},{b:'b"',e:'"',skip:!0},{b:"b'",e:"'",skip:!0},s.inherit(s.ASM,{i:null,cN:null,c:null,skip:!0}),s.inherit(s.QSM,{i:null,cN:null,c:null,skip:!0})]},{cN:"tag",b:"",rE:!0,sL:["css","xml"]}},{cN:"tag",b:"",rE:!0,sL:["actionscript","javascript","handlebars","xml"]}},{cN:"tag",b:"?",e:"/?>",c:[{cN:"name",b:/[^\/><\s]+/,r:0},t]}]}});hljs.registerLanguage("properties",function(r){var t="[ \\t\\f]*",e="[ \\t\\f]+",s="("+t+"[:=]"+t+"|"+e+")",n="([^\\\\\\W:= \\t\\f\\n]|\\\\.)+",a="([^\\\\:= \\t\\f\\n]|\\\\.)+",c={e:s,r:0,starts:{cN:"string",e:/$/,r:0,c:[{b:"\\\\\\n"}]}};return{cI:!0,i:/\S/,c:[r.C("^\\s*[!#]","$"),{b:n+s,rB:!0,c:[{cN:"attr",b:n,endsParent:!0,r:0}],starts:c},{b:a+s,rB:!0,r:0,c:[{cN:"meta",b:a,endsParent:!0,r:0}],starts:c},{cN:"attr",r:0,b:a+t+"$"}]}});hljs.registerLanguage("diff",function(e){return{aliases:["patch"],c:[{cN:"meta",r:10,v:[{b:/^@@ +\-\d+,\d+ +\+\d+,\d+ +@@$/},{b:/^\*\*\* +\d+,\d+ +\*\*\*\*$/},{b:/^\-\-\- +\d+,\d+ +\-\-\-\-$/}]},{cN:"comment",v:[{b:/Index: /,e:/$/},{b:/={3,}/,e:/$/},{b:/^\-{3}/,e:/$/},{b:/^\*{3} /,e:/$/},{b:/^\+{3}/,e:/$/},{b:/\*{5}/,e:/\*{5}$/}]},{cN:"addition",b:"^\\+",e:"$"},{cN:"deletion",b:"^\\-",e:"$"},{cN:"addition",b:"^\\!",e:"$"}]}});hljs.registerLanguage("shell",function(s){return{aliases:["console"],c:[{cN:"meta",b:"^\\s{0,3}[\\w\\d\\[\\]()@-]*[>%$#]",starts:{e:"$",sL:"bash"}}]}});hljs.registerLanguage("asciidoc",function(e){return{aliases:["adoc"],c:[e.C("^/{4,}\\n","\\n/{4,}$",{r:10}),e.C("^//","$",{r:0}),{cN:"title",b:"^\\.\\w.*$"},{b:"^[=\\*]{4,}\\n",e:"\\n^[=\\*]{4,}$",r:10},{cN:"section",r:10,v:[{b:"^(={1,5}) .+?( \\1)?$"},{b:"^[^\\[\\]\\n]+?\\n[=\\-~\\^\\+]{2,}$"}]},{cN:"meta",b:"^:.+?:",e:"\\s",eE:!0,r:10},{cN:"meta",b:"^\\[.+?\\]$",r:0},{cN:"quote",b:"^_{4,}\\n",e:"\\n_{4,}$",r:10},{cN:"code",b:"^[\\-\\.]{4,}\\n",e:"\\n[\\-\\.]{4,}$",r:10},{b:"^\\+{4,}\\n",e:"\\n\\+{4,}$",c:[{b:"<",e:">",sL:"xml",r:0}],r:10},{cN:"bullet",b:"^(\\*+|\\-+|\\.+|[^\\n]+?::)\\s+"},{cN:"symbol",b:"^(NOTE|TIP|IMPORTANT|WARNING|CAUTION):\\s+",r:10},{cN:"strong",b:"\\B\\*(?![\\*\\s])",e:"(\\n{2}|\\*)",c:[{b:"\\\\*\\w",r:0}]},{cN:"emphasis",b:"\\B'(?!['\\s])",e:"(\\n{2}|')",c:[{b:"\\\\'\\w",r:0}],r:0},{cN:"emphasis",b:"_(?![_\\s])",e:"(\\n{2}|_)",r:0},{cN:"string",v:[{b:"``.+?''"},{b:"`.+?'"}]},{cN:"code",b:"(`.+?`|\\+.+?\\+)",r:0},{cN:"code",b:"^[ \\t]",e:"$",r:0},{b:"^'{3,}[ \\t]*$",r:10},{b:"(link:)?(http|https|ftp|file|irc|image:?):\\S+\\[.*?\\]",rB:!0,c:[{b:"(link|image:?):",r:0},{cN:"link",b:"\\w",e:"[^\\[]+",r:0},{cN:"string",b:"\\[",e:"\\]",eB:!0,eE:!0,r:0}],r:10}]}});hljs.registerLanguage("aspectj",function(e){var t="false synchronized int abstract float private char boolean static null if const for true while long throw strictfp finally protected import native final return void enum else extends implements break transient new catch instanceof byte super volatile case assert short package default double public try this switch continue throws privileged aspectOf adviceexecution proceed cflowbelow cflow initialization preinitialization staticinitialization withincode target within execution getWithinTypeName handler thisJoinPoint thisJoinPointStaticPart thisEnclosingJoinPointStaticPart declare parents warning error soft precedence thisAspectInstance",i="get set args call";return{k:t,i:/<\/|#/,c:[e.C("/\\*\\*","\\*/",{r:0,c:[{b:/\w+@/,r:0},{cN:"doctag",b:"@[A-Za-z]+"}]}),e.CLCM,e.CBCM,e.ASM,e.QSM,{cN:"class",bK:"aspect",e:/[{;=]/,eE:!0,i:/[:;"\[\]]/,c:[{bK:"extends implements pertypewithin perthis pertarget percflowbelow percflow issingleton"},e.UTM,{b:/\([^\)]*/,e:/[)]+/,k:t+" "+i,eE:!1}]},{cN:"class",bK:"class interface",e:/[{;=]/,eE:!0,r:0,k:"class interface",i:/[:"\[\]]/,c:[{bK:"extends implements"},e.UTM]},{bK:"pointcut after before around throwing returning",e:/[)]/,eE:!1,i:/["\[\]]/,c:[{b:e.UIR+"\\s*\\(",rB:!0,c:[e.UTM]}]},{b:/[:]/,rB:!0,e:/[{;]/,r:0,eE:!1,k:t,i:/["\[\]]/,c:[{b:e.UIR+"\\s*\\(",k:t+" "+i,r:0},e.QSM]},{bK:"new throw",r:0},{cN:"function",b:/\w+ +\w+(\.)?\w+\s*\([^\)]*\)\s*((throws)[\w\s,]+)?[\{;]/,rB:!0,e:/[{;=]/,k:t,eE:!0,c:[{b:e.UIR+"\\s*\\(",rB:!0,r:0,c:[e.UTM]},{cN:"params",b:/\(/,e:/\)/,r:0,k:t,c:[e.ASM,e.QSM,e.CNM,e.CBCM]},e.CLCM,e.CBCM]},e.CNM,{cN:"meta",b:"@[A-Za-z]+"}]}});hljs.registerLanguage("gradle",function(e){return{cI:!0,k:{keyword:"task project allprojects subprojects artifacts buildscript configurations dependencies repositories sourceSets description delete from into include exclude source classpath destinationDir includes options sourceCompatibility targetCompatibility group flatDir doLast doFirst flatten todir fromdir ant def abstract break case catch continue default do else extends final finally for if implements instanceof native new private protected public return static switch synchronized throw throws transient try volatile while strictfp package import false null super this true antlrtask checkstyle codenarc copy boolean byte char class double float int interface long short void compile runTime file fileTree abs any append asList asWritable call collect compareTo count div dump each eachByte eachFile eachLine every find findAll flatten getAt getErr getIn getOut getText grep immutable inject inspect intersect invokeMethods isCase join leftShift minus multiply newInputStream newOutputStream newPrintWriter newReader newWriter next plus pop power previous print println push putAt read readBytes readLines reverse reverseEach round size sort splitEachLine step subMap times toInteger toList tokenize upto waitForOrKill withPrintWriter withReader withStream withWriter withWriterAppend write writeLine"},c:[e.CLCM,e.CBCM,e.ASM,e.QSM,e.NM,e.RM]}});hljs.registerLanguage("json",function(e){var i={literal:"true false null"},n=[e.QSM,e.CNM],r={e:",",eW:!0,eE:!0,c:n,k:i},t={b:"{",e:"}",c:[{cN:"attr",b:/"/,e:/"/,c:[e.BE],i:"\\n"},e.inherit(r,{b:/:/})],i:"\\S"},c={b:"\\[",e:"\\]",c:[e.inherit(r)],i:"\\S"};return n.splice(n.length,0,t,c),{c:n,k:i,i:"\\S"}});hljs.registerLanguage("sql",function(e){var t=e.C("--","$");return{cI:!0,i:/[<>{}*]/,c:[{bK:"begin end start commit rollback savepoint lock alter create drop rename call delete do handler insert load replace select truncate update set show pragma grant merge describe use explain help declare prepare execute deallocate release unlock purge reset change stop analyze cache flush optimize repair kill install uninstall checksum restore check backup revoke comment with",e:/;/,eW:!0,l:/[\w\.]+/,k:{keyword:"as abort abs absolute acc acce accep accept access accessed accessible account acos action activate add addtime admin administer advanced advise aes_decrypt aes_encrypt after agent aggregate ali alia alias allocate allow alter always analyze ancillary and any anydata anydataset anyschema anytype apply archive archived archivelog are as asc ascii asin assembly assertion associate asynchronous at atan atn2 attr attri attrib attribu attribut attribute attributes audit authenticated authentication authid authors auto autoallocate autodblink autoextend automatic availability avg backup badfile basicfile before begin beginning benchmark between bfile bfile_base big bigfile bin binary_double binary_float binlog bit_and bit_count bit_length bit_or bit_xor bitmap blob_base block blocksize body both bound buffer_cache buffer_pool build bulk by byte byteordermark bytes cache caching call calling cancel capacity cascade cascaded case cast catalog category ceil ceiling chain change changed char_base char_length character_length characters characterset charindex charset charsetform charsetid check checksum checksum_agg child choose chr chunk class cleanup clear client clob clob_base clone close cluster_id cluster_probability cluster_set clustering coalesce coercibility col collate collation collect colu colum column column_value columns columns_updated comment commit compact compatibility compiled complete composite_limit compound compress compute concat concat_ws concurrent confirm conn connec connect connect_by_iscycle connect_by_isleaf connect_by_root connect_time connection consider consistent constant constraint constraints constructor container content contents context contributors controlfile conv convert convert_tz corr corr_k corr_s corresponding corruption cos cost count count_big counted covar_pop covar_samp cpu_per_call cpu_per_session crc32 create creation critical cross cube cume_dist curdate current current_date current_time current_timestamp current_user cursor curtime customdatum cycle data database databases datafile datafiles datalength date_add date_cache date_format date_sub dateadd datediff datefromparts datename datepart datetime2fromparts day day_to_second dayname dayofmonth dayofweek dayofyear days db_role_change dbtimezone ddl deallocate declare decode decompose decrement decrypt deduplicate def defa defau defaul default defaults deferred defi defin define degrees delayed delegate delete delete_all delimited demand dense_rank depth dequeue des_decrypt des_encrypt des_key_file desc descr descri describ describe descriptor deterministic diagnostics difference dimension direct_load directory disable disable_all disallow disassociate discardfile disconnect diskgroup distinct distinctrow distribute distributed div do document domain dotnet double downgrade drop dumpfile duplicate duration each edition editionable editions element ellipsis else elsif elt empty enable enable_all enclosed encode encoding encrypt end end-exec endian enforced engine engines enqueue enterprise entityescaping eomonth error errors escaped evalname evaluate event eventdata events except exception exceptions exchange exclude excluding execu execut execute exempt exists exit exp expire explain export export_set extended extent external external_1 external_2 externally extract failed failed_login_attempts failover failure far fast feature_set feature_value fetch field fields file file_name_convert filesystem_like_logging final finish first first_value fixed flash_cache flashback floor flush following follows for forall force foreign form forma format found found_rows freelist freelists freepools fresh from from_base64 from_days ftp full function general generated get get_format get_lock getdate getutcdate global global_name globally go goto grant grants greatest group group_concat group_id grouping grouping_id groups gtid_subtract guarantee guard handler hash hashkeys having hea head headi headin heading heap help hex hierarchy high high_priority hosts hour http id ident_current ident_incr ident_seed identified identity idle_time if ifnull ignore iif ilike ilm immediate import in include including increment index indexes indexing indextype indicator indices inet6_aton inet6_ntoa inet_aton inet_ntoa infile initial initialized initially initrans inmemory inner innodb input insert install instance instantiable instr interface interleaved intersect into invalidate invisible is is_free_lock is_ipv4 is_ipv4_compat is_not is_not_null is_used_lock isdate isnull isolation iterate java join json json_exists keep keep_duplicates key keys kill language large last last_day last_insert_id last_value lax lcase lead leading least leaves left len lenght length less level levels library like like2 like4 likec limit lines link list listagg little ln load load_file lob lobs local localtime localtimestamp locate locator lock locked log log10 log2 logfile logfiles logging logical logical_reads_per_call logoff logon logs long loop low low_priority lower lpad lrtrim ltrim main make_set makedate maketime managed management manual map mapping mask master master_pos_wait match matched materialized max maxextents maximize maxinstances maxlen maxlogfiles maxloghistory maxlogmembers maxsize maxtrans md5 measures median medium member memcompress memory merge microsecond mid migration min minextents minimum mining minus minute minvalue missing mod mode model modification modify module monitoring month months mount move movement multiset mutex name name_const names nan national native natural nav nchar nclob nested never new newline next nextval no no_write_to_binlog noarchivelog noaudit nobadfile nocheck nocompress nocopy nocycle nodelay nodiscardfile noentityescaping noguarantee nokeep nologfile nomapping nomaxvalue nominimize nominvalue nomonitoring none noneditionable nonschema noorder nopr nopro noprom nopromp noprompt norely noresetlogs noreverse normal norowdependencies noschemacheck noswitch not nothing notice notnull notrim novalidate now nowait nth_value nullif nulls num numb numbe nvarchar nvarchar2 object ocicoll ocidate ocidatetime ociduration ociinterval ociloblocator ocinumber ociref ocirefcursor ocirowid ocistring ocitype oct octet_length of off offline offset oid oidindex old on online only opaque open operations operator optimal optimize option optionally or oracle oracle_date oradata ord ordaudio orddicom orddoc order ordimage ordinality ordvideo organization orlany orlvary out outer outfile outline output over overflow overriding package pad parallel parallel_enable parameters parent parse partial partition partitions pascal passing password password_grace_time password_lock_time password_reuse_max password_reuse_time password_verify_function patch path patindex pctincrease pctthreshold pctused pctversion percent percent_rank percentile_cont percentile_disc performance period period_add period_diff permanent physical pi pipe pipelined pivot pluggable plugin policy position post_transaction pow power pragma prebuilt precedes preceding precision prediction prediction_cost prediction_details prediction_probability prediction_set prepare present preserve prior priority private private_sga privileges procedural procedure procedure_analyze processlist profiles project prompt protection public publishingservername purge quarter query quick quiesce quota quotename radians raise rand range rank raw read reads readsize rebuild record records recover recovery recursive recycle redo reduced ref reference referenced references referencing refresh regexp_like register regr_avgx regr_avgy regr_count regr_intercept regr_r2 regr_slope regr_sxx regr_sxy reject rekey relational relative relaylog release release_lock relies_on relocate rely rem remainder rename repair repeat replace replicate replication required reset resetlogs resize resource respect restore restricted result result_cache resumable resume retention return returning returns reuse reverse revoke right rlike role roles rollback rolling rollup round row row_count rowdependencies rowid rownum rows rtrim rules safe salt sample save savepoint sb1 sb2 sb4 scan schema schemacheck scn scope scroll sdo_georaster sdo_topo_geometry search sec_to_time second section securefile security seed segment select self sequence sequential serializable server servererror session session_user sessions_per_user set sets settings sha sha1 sha2 share shared shared_pool short show shrink shutdown si_averagecolor si_colorhistogram si_featurelist si_positionalcolor si_stillimage si_texture siblings sid sign sin size size_t sizes skip slave sleep smalldatetimefromparts smallfile snapshot some soname sort soundex source space sparse spfile split sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_small_result sql_variant_property sqlcode sqldata sqlerror sqlname sqlstate sqrt square standalone standby start starting startup statement static statistics stats_binomial_test stats_crosstab stats_ks_test stats_mode stats_mw_test stats_one_way_anova stats_t_test_ stats_t_test_indep stats_t_test_one stats_t_test_paired stats_wsr_test status std stddev stddev_pop stddev_samp stdev stop storage store stored str str_to_date straight_join strcmp strict string struct stuff style subdate subpartition subpartitions substitutable substr substring subtime subtring_index subtype success sum suspend switch switchoffset switchover sync synchronous synonym sys sys_xmlagg sysasm sysaux sysdate sysdatetimeoffset sysdba sysoper system system_user sysutcdatetime table tables tablespace tan tdo template temporary terminated tertiary_weights test than then thread through tier ties time time_format time_zone timediff timefromparts timeout timestamp timestampadd timestampdiff timezone_abbr timezone_minute timezone_region to to_base64 to_date to_days to_seconds todatetimeoffset trace tracking transaction transactional translate translation treat trigger trigger_nestlevel triggers trim truncate try_cast try_convert try_parse type ub1 ub2 ub4 ucase unarchived unbounded uncompress under undo unhex unicode uniform uninstall union unique unix_timestamp unknown unlimited unlock unnest unpivot unrecoverable unsafe unsigned until untrusted unusable unused update updated upgrade upped upper upsert url urowid usable usage use use_stored_outlines user user_data user_resources users using utc_date utc_timestamp uuid uuid_short validate validate_password_strength validation valist value values var var_samp varcharc vari varia variab variabl variable variables variance varp varraw varrawc varray verify version versions view virtual visible void wait wallet warning warnings week weekday weekofyear wellformed when whene whenev wheneve whenever where while whitespace with within without work wrapped xdb xml xmlagg xmlattributes xmlcast xmlcolattval xmlelement xmlexists xmlforest xmlindex xmlnamespaces xmlpi xmlquery xmlroot xmlschema xmlserialize xmltable xmltype xor year year_to_month years yearweek",literal:"true false null unknown",built_in:"array bigint binary bit blob bool boolean char character date dec decimal float int int8 integer interval number numeric real record serial serial8 smallint text time timestamp varchar varying void"},c:[{cN:"string",b:"'",e:"'",c:[e.BE,{b:"''"}]},{cN:"string",b:'"',e:'"',c:[e.BE,{b:'""'}]},{cN:"string",b:"`",e:"`",c:[e.BE]},e.CNM,e.CBCM,t,e.HCM]},e.CBCM,t,e.HCM]}});hljs.registerLanguage("go",function(e){var t={keyword:"break default func interface select case map struct chan else goto package switch const fallthrough if range type continue for import return var go defer bool byte complex64 complex128 float32 float64 int8 int16 int32 int64 string uint8 uint16 uint32 uint64 int uint uintptr rune",literal:"true false iota nil",built_in:"append cap close complex copy imag len make new panic print println real recover delete"};return{aliases:["golang"],k:t,i:"",c:[e.CLCM,e.CBCM,{cN:"string",v:[e.QSM,{b:"'",e:"[^\\\\]'"},{b:"`",e:"`"}]},{cN:"number",v:[{b:e.CNR+"[dflsi]",r:1},e.CNM]},{b:/:=/},{cN:"function",bK:"func",e:/\s*\{/,eE:!0,c:[e.TM,{cN:"params",b:/\(/,e:/\)/,k:t,i:/["']/}]}]}});hljs.registerLanguage("http",function(e){var t="HTTP/[0-9\\.]+";return{aliases:["https"],i:"\\S",c:[{b:"^"+t,e:"$",c:[{cN:"number",b:"\\b\\d{3}\\b"}]},{b:"^[A-Z]+ (.*?) "+t+"$",rB:!0,e:"$",c:[{cN:"string",b:" ",e:" ",eB:!0,eE:!0},{b:t},{cN:"keyword",b:"[A-Z]+"}]},{cN:"attribute",b:"^\\w",e:": ",eE:!0,i:"\\n|\\s|=",starts:{e:"$",r:0}},{b:"\\n\\n",starts:{sL:[],eW:!0}}]}});hljs.registerLanguage("groovy",function(e){return{k:{literal:"true false null",keyword:"byte short char int long boolean float double void def as in assert trait super this abstract static volatile transient public private protected synchronized final class interface enum if else for while switch case break default continue throw throws try catch finally implements extends new import package return instanceof"},c:[e.C("/\\*\\*","\\*/",{r:0,c:[{b:/\w+@/,r:0},{cN:"doctag",b:"@[A-Za-z]+"}]}),e.CLCM,e.CBCM,{cN:"string",b:'"""',e:'"""'},{cN:"string",b:"'''",e:"'''"},{cN:"string",b:"\\$/",e:"/\\$",r:10},e.ASM,{cN:"regexp",b:/~?\/[^\/\n]+\//,c:[e.BE]},e.QSM,{cN:"meta",b:"^#!/usr/bin/env",e:"$",i:"\n"},e.BNM,{cN:"class",bK:"class interface trait enum",e:"{",i:":",c:[{bK:"extends implements"},e.UTM]},e.CNM,{cN:"meta",b:"@[A-Za-z]+"},{cN:"string",b:/[^\?]{0}[A-Za-z0-9_$]+ *:/},{b:/\?/,e:/\:/},{cN:"symbol",b:"^\\s*[A-Za-z0-9_$]+:",r:0}],i:/#|<\//}});hljs.registerLanguage("plaintext",function(e){return{disableAutodetect:!0}});hljs.registerLanguage("css",function(e){var c="[a-zA-Z-][a-zA-Z0-9_-]*",t={b:/[A-Z\_\.\-]+\s*:/,rB:!0,e:";",eW:!0,c:[{cN:"attribute",b:/\S/,e:":",eE:!0,starts:{eW:!0,eE:!0,c:[{b:/[\w-]+\(/,rB:!0,c:[{cN:"built_in",b:/[\w-]+/},{b:/\(/,e:/\)/,c:[e.ASM,e.QSM]}]},e.CSSNM,e.QSM,e.ASM,e.CBCM,{cN:"number",b:"#[0-9A-Fa-f]+"},{cN:"meta",b:"!important"}]}}]};return{cI:!0,i:/[=\/|'\$]/,c:[e.CBCM,{cN:"selector-id",b:/#[A-Za-z0-9_-]+/},{cN:"selector-class",b:/\.[A-Za-z0-9_-]+/},{cN:"selector-attr",b:/\[/,e:/\]/,i:"$"},{cN:"selector-pseudo",b:/:(:)?[a-zA-Z0-9\_\-\+\(\)"'.]+/},{b:"@(font-face|page)",l:"[a-z-]+",k:"font-face page"},{b:"@",e:"[{;]",i:/:/,c:[{cN:"keyword",b:/\w+/},{b:/\s/,eW:!0,eE:!0,r:0,c:[e.ASM,e.QSM,e.CSSNM]}]},{cN:"selector-tag",b:c,r:0},{b:"{",e:"}",i:/\S/,c:[e.CBCM,t]}]}});hljs.registerLanguage("javascript",function(e){var r="[A-Za-z$_][0-9A-Za-z$_]*",t={keyword:"in of if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const export super debugger as async await static import from as",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document Symbol Set Map WeakSet WeakMap Proxy Reflect Promise"},a={cN:"number",v:[{b:"\\b(0[bB][01]+)"},{b:"\\b(0[oO][0-7]+)"},{b:e.CNR}],r:0},n={cN:"subst",b:"\\$\\{",e:"\\}",k:t,c:[]},c={cN:"string",b:"`",e:"`",c:[e.BE,n]};n.c=[e.ASM,e.QSM,c,a,e.RM];var s=n.c.concat([e.CBCM,e.CLCM]);return{aliases:["js","jsx"],k:t,c:[{cN:"meta",r:10,b:/^\s*['"]use (strict|asm)['"]/},{cN:"meta",b:/^#!/,e:/$/},e.ASM,e.QSM,c,e.CLCM,e.CBCM,a,{b:/[{,]\s*/,r:0,c:[{b:r+"\\s*:",rB:!0,r:0,c:[{cN:"attr",b:r,r:0}]}]},{b:"("+e.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[e.CLCM,e.CBCM,e.RM,{cN:"function",b:"(\\(.*?\\)|"+r+")\\s*=>",rB:!0,e:"\\s*=>",c:[{cN:"params",v:[{b:r},{b:/\(\s*\)/},{b:/\(/,e:/\)/,eB:!0,eE:!0,k:t,c:s}]}]},{b:/,e:/(\/\w+|\w+\/)>/,sL:"xml",c:[{b:/<\w+\s*\/>/,skip:!0},{b:/<\w+/,e:/(\/\w+|\w+\/)>/,skip:!0,c:[{b:/<\w+\s*\/>/,skip:!0},"self"]}]}],r:0},{cN:"function",bK:"function",e:/\{/,eE:!0,c:[e.inherit(e.TM,{b:r}),{cN:"params",b:/\(/,e:/\)/,eB:!0,eE:!0,c:s}],i:/\[|%/},{b:/\$[(.]/},e.METHOD_GUARD,{cN:"class",bK:"class",e:/[{;=]/,eE:!0,i:/[:"\[\]]/,c:[{bK:"extends"},e.UTM]},{bK:"constructor",e:/\{/,eE:!0}],i:/#(?!!)/}});
\ No newline at end of file
diff --git a/reference/htmlsingle/js/highlight/styles/a11y-dark.min.css b/reference/htmlsingle/js/highlight/styles/a11y-dark.min.css
new file mode 100644
index 00000000..b93b742a
--- /dev/null
+++ b/reference/htmlsingle/js/highlight/styles/a11y-dark.min.css
@@ -0,0 +1,99 @@
+/* a11y-dark theme */
+/* Based on the Tomorrow Night Eighties theme: https://github.com/isagalaev/highlight.js/blob/master/src/styles/tomorrow-night-eighties.css */
+/* @author: ericwbailey */
+
+/* Comment */
+.hljs-comment,
+.hljs-quote {
+ color: #d4d0ab;
+}
+
+/* Red */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-tag,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-regexp,
+.hljs-deletion {
+ color: #ffa07a;
+}
+
+/* Orange */
+.hljs-number,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-type,
+.hljs-params,
+.hljs-meta,
+.hljs-link {
+ color: #f5ab35;
+}
+
+/* Yellow */
+.hljs-attribute {
+ color: #ffd700;
+}
+
+/* Green */
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-addition {
+ color: #abe338;
+}
+
+/* Blue */
+.hljs-title,
+.hljs-section {
+ color: #00e0e0;
+}
+
+/* Purple */
+.hljs-keyword,
+.hljs-selector-tag {
+ color: #dcc6e0;
+}
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ background: #2b2b2b;
+ color: #f8f8f2;
+ padding: 0.5em;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
+
+@media screen and (-ms-high-contrast: active) {
+ .hljs-addition,
+ .hljs-attribute,
+ .hljs-built_in,
+ .hljs-builtin-name,
+ .hljs-bullet,
+ .hljs-comment,
+ .hljs-link,
+ .hljs-literal,
+ .hljs-meta,
+ .hljs-number,
+ .hljs-params,
+ .hljs-string,
+ .hljs-symbol,
+ .hljs-type,
+ .hljs-quote {
+ color: highlight;
+ }
+
+ .hljs-keyword,
+ .hljs-selector-tag {
+ font-weight: bold;
+ }
+}
diff --git a/reference/htmlsingle/js/highlight/styles/an-old-hope.min.css b/reference/htmlsingle/js/highlight/styles/an-old-hope.min.css
new file mode 100644
index 00000000..a6d56f4b
--- /dev/null
+++ b/reference/htmlsingle/js/highlight/styles/an-old-hope.min.css
@@ -0,0 +1,89 @@
+/*
+
+An Old Hope – Star Wars Syntax (c) Gustavo Costa
+Original theme - Ocean Dark Theme – by https://github.com/gavsiu
+Based on Jesse Leite's Atom syntax theme 'An Old Hope' – https://github.com/JesseLeite/an-old-hope-syntax-atom
+
+*/
+
+/* Death Star Comment */
+.hljs-comment,
+.hljs-quote
+{
+ color: #B6B18B;
+}
+
+/* Darth Vader */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-tag,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-regexp,
+.hljs-deletion
+{
+ color: #EB3C54;
+}
+
+/* Threepio */
+.hljs-number,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-type,
+.hljs-params,
+.hljs-meta,
+.hljs-link
+{
+ color: #E7CE56;
+}
+
+/* Luke Skywalker */
+.hljs-attribute
+{
+ color: #EE7C2B;
+}
+
+/* Obi Wan Kenobi */
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-addition
+{
+ color: #4FB4D7;
+}
+
+/* Yoda */
+.hljs-title,
+.hljs-section
+{
+ color: #78BB65;
+}
+
+/* Mace Windu */
+.hljs-keyword,
+.hljs-selector-tag
+{
+ color: #B45EA4;
+}
+
+/* Millenium Falcon */
+.hljs
+{
+ display: block;
+ overflow-x: auto;
+ background: #1C1D21;
+ color: #c0c5ce;
+ padding: 0.5em;
+}
+
+.hljs-emphasis
+{
+ font-style: italic;
+}
+
+.hljs-strong
+{
+ font-weight: bold;
+}
diff --git a/reference/htmlsingle/js/highlight/styles/atom-one-dark-reasonable.min.css b/reference/htmlsingle/js/highlight/styles/atom-one-dark-reasonable.min.css
new file mode 100644
index 00000000..fd41c996
--- /dev/null
+++ b/reference/htmlsingle/js/highlight/styles/atom-one-dark-reasonable.min.css
@@ -0,0 +1,77 @@
+/*
+
+Atom One Dark With support for ReasonML by Gidi Morris, based off work by Daniel Gamage
+
+Original One Dark Syntax theme from https://github.com/atom/one-dark-syntax
+
+*/
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ line-height: 1.3em;
+ color: #abb2bf;
+ background: #282c34;
+ border-radius: 5px;
+}
+.hljs-keyword, .hljs-operator {
+ color: #F92672;
+}
+.hljs-pattern-match {
+ color: #F92672;
+}
+.hljs-pattern-match .hljs-constructor {
+ color: #61aeee;
+}
+.hljs-function {
+ color: #61aeee;
+}
+.hljs-function .hljs-params {
+ color: #A6E22E;
+}
+.hljs-function .hljs-params .hljs-typing {
+ color: #FD971F;
+}
+.hljs-module-access .hljs-module {
+ color: #7e57c2;
+}
+.hljs-constructor {
+ color: #e2b93d;
+}
+.hljs-constructor .hljs-string {
+ color: #9CCC65;
+}
+.hljs-comment, .hljs-quote {
+ color: #b18eb1;
+ font-style: italic;
+}
+.hljs-doctag, .hljs-formula {
+ color: #c678dd;
+}
+.hljs-section, .hljs-name, .hljs-selector-tag, .hljs-deletion, .hljs-subst {
+ color: #e06c75;
+}
+.hljs-literal {
+ color: #56b6c2;
+}
+.hljs-string, .hljs-regexp, .hljs-addition, .hljs-attribute, .hljs-meta-string {
+ color: #98c379;
+}
+.hljs-built_in, .hljs-class .hljs-title {
+ color: #e6c07b;
+}
+.hljs-attr, .hljs-variable, .hljs-template-variable, .hljs-type, .hljs-selector-class, .hljs-selector-attr, .hljs-selector-pseudo, .hljs-number {
+ color: #d19a66;
+}
+.hljs-symbol, .hljs-bullet, .hljs-link, .hljs-meta, .hljs-selector-id, .hljs-title {
+ color: #61aeee;
+}
+.hljs-emphasis {
+ font-style: italic;
+}
+.hljs-strong {
+ font-weight: bold;
+}
+.hljs-link {
+ text-decoration: underline;
+}
diff --git a/reference/htmlsingle/js/highlight/styles/atom-one-dark.min.css b/reference/htmlsingle/js/highlight/styles/atom-one-dark.min.css
new file mode 100644
index 00000000..1616aafe
--- /dev/null
+++ b/reference/htmlsingle/js/highlight/styles/atom-one-dark.min.css
@@ -0,0 +1,96 @@
+/*
+
+Atom One Dark by Daniel Gamage
+Original One Dark Syntax theme from https://github.com/atom/one-dark-syntax
+
+base: #282c34
+mono-1: #abb2bf
+mono-2: #818896
+mono-3: #5c6370
+hue-1: #56b6c2
+hue-2: #61aeee
+hue-3: #c678dd
+hue-4: #98c379
+hue-5: #e06c75
+hue-5-2: #be5046
+hue-6: #d19a66
+hue-6-2: #e6c07b
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ color: #abb2bf;
+ background: #282c34;
+}
+
+.hljs-comment,
+.hljs-quote {
+ color: #5c6370;
+ font-style: italic;
+}
+
+.hljs-doctag,
+.hljs-keyword,
+.hljs-formula {
+ color: #c678dd;
+}
+
+.hljs-section,
+.hljs-name,
+.hljs-selector-tag,
+.hljs-deletion,
+.hljs-subst {
+ color: #e06c75;
+}
+
+.hljs-literal {
+ color: #56b6c2;
+}
+
+.hljs-string,
+.hljs-regexp,
+.hljs-addition,
+.hljs-attribute,
+.hljs-meta-string {
+ color: #98c379;
+}
+
+.hljs-built_in,
+.hljs-class .hljs-title {
+ color: #e6c07b;
+}
+
+.hljs-attr,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-type,
+.hljs-selector-class,
+.hljs-selector-attr,
+.hljs-selector-pseudo,
+.hljs-number {
+ color: #d19a66;
+}
+
+.hljs-symbol,
+.hljs-bullet,
+.hljs-link,
+.hljs-meta,
+.hljs-selector-id,
+.hljs-title {
+ color: #61aeee;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
+
+.hljs-link {
+ text-decoration: underline;
+}
diff --git a/reference/htmlsingle/js/highlight/styles/atom-one-light.min.css b/reference/htmlsingle/js/highlight/styles/atom-one-light.min.css
new file mode 100644
index 00000000..d5bd1d2a
--- /dev/null
+++ b/reference/htmlsingle/js/highlight/styles/atom-one-light.min.css
@@ -0,0 +1,96 @@
+/*
+
+Atom One Light by Daniel Gamage
+Original One Light Syntax theme from https://github.com/atom/one-light-syntax
+
+base: #fafafa
+mono-1: #383a42
+mono-2: #686b77
+mono-3: #a0a1a7
+hue-1: #0184bb
+hue-2: #4078f2
+hue-3: #a626a4
+hue-4: #50a14f
+hue-5: #e45649
+hue-5-2: #c91243
+hue-6: #986801
+hue-6-2: #c18401
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ color: #383a42;
+ background: #fafafa;
+}
+
+.hljs-comment,
+.hljs-quote {
+ color: #a0a1a7;
+ font-style: italic;
+}
+
+.hljs-doctag,
+.hljs-keyword,
+.hljs-formula {
+ color: #a626a4;
+}
+
+.hljs-section,
+.hljs-name,
+.hljs-selector-tag,
+.hljs-deletion,
+.hljs-subst {
+ color: #e45649;
+}
+
+.hljs-literal {
+ color: #0184bb;
+}
+
+.hljs-string,
+.hljs-regexp,
+.hljs-addition,
+.hljs-attribute,
+.hljs-meta-string {
+ color: #50a14f;
+}
+
+.hljs-built_in,
+.hljs-class .hljs-title {
+ color: #c18401;
+}
+
+.hljs-attr,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-type,
+.hljs-selector-class,
+.hljs-selector-attr,
+.hljs-selector-pseudo,
+.hljs-number {
+ color: #986801;
+}
+
+.hljs-symbol,
+.hljs-bullet,
+.hljs-link,
+.hljs-meta,
+.hljs-selector-id,
+.hljs-title {
+ color: #4078f2;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
+
+.hljs-link {
+ text-decoration: underline;
+}
diff --git a/reference/htmlsingle/js/highlight/styles/dracula.min.css b/reference/htmlsingle/js/highlight/styles/dracula.min.css
new file mode 100644
index 00000000..578f0b40
--- /dev/null
+++ b/reference/htmlsingle/js/highlight/styles/dracula.min.css
@@ -0,0 +1,76 @@
+/*
+
+Dracula Theme v1.2.0
+
+https://github.com/zenorocha/dracula-theme
+
+Copyright 2015, All rights reserved
+
+Code licensed under the MIT license
+https://zenorocha.mit-license.org/
+
+@author Éverton Ribeiro
+@author Zeno Rocha
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: #282a36;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-literal,
+.hljs-section,
+.hljs-link {
+ color: #8be9fd;
+}
+
+.hljs-function .hljs-keyword {
+ color: #ff79c6;
+}
+
+.hljs,
+.hljs-subst {
+ color: #f8f8f2;
+}
+
+.hljs-string,
+.hljs-title,
+.hljs-name,
+.hljs-type,
+.hljs-attribute,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-addition,
+.hljs-variable,
+.hljs-template-tag,
+.hljs-template-variable {
+ color: #f1fa8c;
+}
+
+.hljs-comment,
+.hljs-quote,
+.hljs-deletion,
+.hljs-meta {
+ color: #6272a4;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-literal,
+.hljs-title,
+.hljs-section,
+.hljs-doctag,
+.hljs-type,
+.hljs-name,
+.hljs-strong {
+ font-weight: bold;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
diff --git a/reference/htmlsingle/js/highlight/styles/github-gist.css b/reference/htmlsingle/js/highlight/styles/github-gist.css
new file mode 100644
index 00000000..2706084a
--- /dev/null
+++ b/reference/htmlsingle/js/highlight/styles/github-gist.css
@@ -0,0 +1,79 @@
+/**
+ * GitHub Gist Theme
+ * Author : Anthony Attard - https://github.com/AnthonyAttard
+ * Author : Louis Barranqueiro - https://github.com/LouisBarranqueiro
+ */
+
+.hljs {
+ display: block;
+ background: white;
+ padding: 0.5em;
+ color: #333333;
+ overflow-x: auto;
+}
+
+.hljs-comment,
+.hljs-meta {
+ color: #969896;
+}
+
+.hljs-variable,
+.hljs-template-variable,
+.hljs-strong,
+.hljs-emphasis,
+.hljs-quote {
+ color: #df5000;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-type {
+ color: #d73a49;
+}
+
+.hljs-literal,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-attribute {
+ color: #0086b3;
+}
+
+.hljs-section,
+.hljs-name {
+ color: #63a35c;
+}
+
+.hljs-tag {
+ color: #333333;
+}
+
+.hljs-title,
+.hljs-attr,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-selector-attr,
+.hljs-selector-pseudo {
+ color: #6f42c1;
+}
+
+.hljs-addition {
+ color: #55a532;
+ background-color: #eaffea;
+}
+
+.hljs-deletion {
+ color: #bd2c00;
+ background-color: #ffecec;
+}
+
+.hljs-link {
+ text-decoration: underline;
+}
+
+.hljs-number {
+ color: #005cc5;
+}
+
+.hljs-string {
+ color: #032f62;
+}
diff --git a/reference/htmlsingle/js/highlight/styles/github-gist.min.css b/reference/htmlsingle/js/highlight/styles/github-gist.min.css
new file mode 100644
index 00000000..2706084a
--- /dev/null
+++ b/reference/htmlsingle/js/highlight/styles/github-gist.min.css
@@ -0,0 +1,79 @@
+/**
+ * GitHub Gist Theme
+ * Author : Anthony Attard - https://github.com/AnthonyAttard
+ * Author : Louis Barranqueiro - https://github.com/LouisBarranqueiro
+ */
+
+.hljs {
+ display: block;
+ background: white;
+ padding: 0.5em;
+ color: #333333;
+ overflow-x: auto;
+}
+
+.hljs-comment,
+.hljs-meta {
+ color: #969896;
+}
+
+.hljs-variable,
+.hljs-template-variable,
+.hljs-strong,
+.hljs-emphasis,
+.hljs-quote {
+ color: #df5000;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-type {
+ color: #d73a49;
+}
+
+.hljs-literal,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-attribute {
+ color: #0086b3;
+}
+
+.hljs-section,
+.hljs-name {
+ color: #63a35c;
+}
+
+.hljs-tag {
+ color: #333333;
+}
+
+.hljs-title,
+.hljs-attr,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-selector-attr,
+.hljs-selector-pseudo {
+ color: #6f42c1;
+}
+
+.hljs-addition {
+ color: #55a532;
+ background-color: #eaffea;
+}
+
+.hljs-deletion {
+ color: #bd2c00;
+ background-color: #ffecec;
+}
+
+.hljs-link {
+ text-decoration: underline;
+}
+
+.hljs-number {
+ color: #005cc5;
+}
+
+.hljs-string {
+ color: #032f62;
+}
diff --git a/reference/htmlsingle/js/highlight/styles/github.min.css b/reference/htmlsingle/js/highlight/styles/github.min.css
new file mode 100644
index 00000000..791932b8
--- /dev/null
+++ b/reference/htmlsingle/js/highlight/styles/github.min.css
@@ -0,0 +1,99 @@
+/*
+
+github.com style (c) Vasily Polovnyov
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ color: #333;
+ background: #f8f8f8;
+}
+
+.hljs-comment,
+.hljs-quote {
+ color: #998;
+ font-style: italic;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-subst {
+ color: #333;
+ font-weight: bold;
+}
+
+.hljs-number,
+.hljs-literal,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-tag .hljs-attr {
+ color: #008080;
+}
+
+.hljs-string,
+.hljs-doctag {
+ color: #d14;
+}
+
+.hljs-title,
+.hljs-section,
+.hljs-selector-id {
+ color: #900;
+ font-weight: bold;
+}
+
+.hljs-subst {
+ font-weight: normal;
+}
+
+.hljs-type,
+.hljs-class .hljs-title {
+ color: #458;
+ font-weight: bold;
+}
+
+.hljs-tag,
+.hljs-name,
+.hljs-attribute {
+ color: #000080;
+ font-weight: normal;
+}
+
+.hljs-regexp,
+.hljs-link {
+ color: #009926;
+}
+
+.hljs-symbol,
+.hljs-bullet {
+ color: #990073;
+}
+
+.hljs-built_in,
+.hljs-builtin-name {
+ color: #0086b3;
+}
+
+.hljs-meta {
+ color: #999;
+ font-weight: bold;
+}
+
+.hljs-deletion {
+ background: #fdd;
+}
+
+.hljs-addition {
+ background: #dfd;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/reference/htmlsingle/js/highlight/styles/googlecode.css b/reference/htmlsingle/js/highlight/styles/googlecode.css
new file mode 100644
index 00000000..0cf18a04
--- /dev/null
+++ b/reference/htmlsingle/js/highlight/styles/googlecode.css
@@ -0,0 +1,89 @@
+/*
+
+Google Code style (c) Aahan Krish
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: white;
+ color: black;
+}
+
+.hljs-comment,
+.hljs-quote {
+ color: #800;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-section,
+.hljs-title,
+.hljs-name {
+ color: #008;
+}
+
+.hljs-variable,
+.hljs-template-variable {
+ color: #660;
+}
+
+.hljs-string,
+.hljs-selector-attr,
+.hljs-selector-pseudo,
+.hljs-regexp {
+ color: #080;
+}
+
+.hljs-literal,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-meta,
+.hljs-number,
+.hljs-link {
+ color: #066;
+}
+
+.hljs-title,
+.hljs-doctag,
+.hljs-type,
+.hljs-attr,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-params {
+ color: #606;
+}
+
+.hljs-attribute,
+.hljs-subst {
+ color: #000;
+}
+
+.hljs-formula {
+ background-color: #eee;
+ font-style: italic;
+}
+
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #9B703F
+}
+
+.hljs-addition {
+ background-color: #baeeba;
+}
+
+.hljs-deletion {
+ background-color: #ffc8bd;
+}
+
+.hljs-doctag,
+.hljs-strong {
+ font-weight: bold;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
diff --git a/reference/htmlsingle/js/highlight/styles/googlecode.min.css b/reference/htmlsingle/js/highlight/styles/googlecode.min.css
new file mode 100644
index 00000000..0cf18a04
--- /dev/null
+++ b/reference/htmlsingle/js/highlight/styles/googlecode.min.css
@@ -0,0 +1,89 @@
+/*
+
+Google Code style (c) Aahan Krish
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: white;
+ color: black;
+}
+
+.hljs-comment,
+.hljs-quote {
+ color: #800;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-section,
+.hljs-title,
+.hljs-name {
+ color: #008;
+}
+
+.hljs-variable,
+.hljs-template-variable {
+ color: #660;
+}
+
+.hljs-string,
+.hljs-selector-attr,
+.hljs-selector-pseudo,
+.hljs-regexp {
+ color: #080;
+}
+
+.hljs-literal,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-meta,
+.hljs-number,
+.hljs-link {
+ color: #066;
+}
+
+.hljs-title,
+.hljs-doctag,
+.hljs-type,
+.hljs-attr,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-params {
+ color: #606;
+}
+
+.hljs-attribute,
+.hljs-subst {
+ color: #000;
+}
+
+.hljs-formula {
+ background-color: #eee;
+ font-style: italic;
+}
+
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #9B703F
+}
+
+.hljs-addition {
+ background-color: #baeeba;
+}
+
+.hljs-deletion {
+ background-color: #ffc8bd;
+}
+
+.hljs-doctag,
+.hljs-strong {
+ font-weight: bold;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
diff --git a/reference/htmlsingle/js/highlight/styles/monokai-sublime.min.css b/reference/htmlsingle/js/highlight/styles/monokai-sublime.min.css
new file mode 100644
index 00000000..ed52c92e
--- /dev/null
+++ b/reference/htmlsingle/js/highlight/styles/monokai-sublime.min.css
@@ -0,0 +1,83 @@
+/*
+
+Monokai Sublime style. Derived from Monokai by noformnocontent https://nn.mit-license.org/
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: #23241f;
+}
+
+.hljs,
+.hljs-tag,
+.hljs-subst {
+ color: #f8f8f2;
+}
+
+.hljs-strong,
+.hljs-emphasis {
+ color: #a8a8a2;
+}
+
+.hljs-bullet,
+.hljs-quote,
+.hljs-number,
+.hljs-regexp,
+.hljs-literal,
+.hljs-link {
+ color: #ae81ff;
+}
+
+.hljs-code,
+.hljs-title,
+.hljs-section,
+.hljs-selector-class {
+ color: #a6e22e;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-name,
+.hljs-attr {
+ color: #f92672;
+}
+
+.hljs-symbol,
+.hljs-attribute {
+ color: #66d9ef;
+}
+
+.hljs-params,
+.hljs-class .hljs-title {
+ color: #f8f8f2;
+}
+
+.hljs-string,
+.hljs-type,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-selector-id,
+.hljs-selector-attr,
+.hljs-selector-pseudo,
+.hljs-addition,
+.hljs-variable,
+.hljs-template-variable {
+ color: #e6db74;
+}
+
+.hljs-comment,
+.hljs-deletion,
+.hljs-meta {
+ color: #75715e;
+}
diff --git a/reference/htmlsingle/js/highlight/styles/monokai.min.css b/reference/htmlsingle/js/highlight/styles/monokai.min.css
new file mode 100644
index 00000000..a5735585
--- /dev/null
+++ b/reference/htmlsingle/js/highlight/styles/monokai.min.css
@@ -0,0 +1,70 @@
+/*
+Monokai style - ported by Luigi Maselli - https://grigio.org
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: #272822; color: #ddd;
+}
+
+.hljs-tag,
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-literal,
+.hljs-strong,
+.hljs-name {
+ color: #f92672;
+}
+
+.hljs-code {
+ color: #66d9ef;
+}
+
+.hljs-class .hljs-title {
+ color: white;
+}
+
+.hljs-attribute,
+.hljs-symbol,
+.hljs-regexp,
+.hljs-link {
+ color: #bf79db;
+}
+
+.hljs-string,
+.hljs-bullet,
+.hljs-subst,
+.hljs-title,
+.hljs-section,
+.hljs-emphasis,
+.hljs-type,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-selector-attr,
+.hljs-selector-pseudo,
+.hljs-addition,
+.hljs-variable,
+.hljs-template-tag,
+.hljs-template-variable {
+ color: #a6e22e;
+}
+
+.hljs-comment,
+.hljs-quote,
+.hljs-deletion,
+.hljs-meta {
+ color: #75715e;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-literal,
+.hljs-doctag,
+.hljs-title,
+.hljs-section,
+.hljs-type,
+.hljs-selector-id {
+ font-weight: bold;
+}
diff --git a/reference/htmlsingle/js/highlight/styles/solarized-light.min.css b/reference/htmlsingle/js/highlight/styles/solarized-light.min.css
new file mode 100644
index 00000000..fdcfcc72
--- /dev/null
+++ b/reference/htmlsingle/js/highlight/styles/solarized-light.min.css
@@ -0,0 +1,84 @@
+/*
+
+Orginal Style from ethanschoonover.com/solarized (c) Jeremy Hull
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: #fdf6e3;
+ color: #657b83;
+}
+
+.hljs-comment,
+.hljs-quote {
+ color: #93a1a1;
+}
+
+/* Solarized Green */
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-addition {
+ color: #859900;
+}
+
+/* Solarized Cyan */
+.hljs-number,
+.hljs-string,
+.hljs-meta .hljs-meta-string,
+.hljs-literal,
+.hljs-doctag,
+.hljs-regexp {
+ color: #2aa198;
+}
+
+/* Solarized Blue */
+.hljs-title,
+.hljs-section,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #268bd2;
+}
+
+/* Solarized Yellow */
+.hljs-attribute,
+.hljs-attr,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-class .hljs-title,
+.hljs-type {
+ color: #b58900;
+}
+
+/* Solarized Orange */
+.hljs-symbol,
+.hljs-bullet,
+.hljs-subst,
+.hljs-meta,
+.hljs-meta .hljs-keyword,
+.hljs-selector-attr,
+.hljs-selector-pseudo,
+.hljs-link {
+ color: #cb4b16;
+}
+
+/* Solarized Red */
+.hljs-built_in,
+.hljs-deletion {
+ color: #dc322f;
+}
+
+.hljs-formula {
+ background: #eee8d5;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/reference/htmlsingle/js/highlight/styles/zenburn.min.css b/reference/htmlsingle/js/highlight/styles/zenburn.min.css
new file mode 100644
index 00000000..07be5020
--- /dev/null
+++ b/reference/htmlsingle/js/highlight/styles/zenburn.min.css
@@ -0,0 +1,80 @@
+/*
+
+Zenburn style from voldmar.ru (c) Vladimir Epifanov
+based on dark.css by Ivan Sagalaev
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: #3f3f3f;
+ color: #dcdcdc;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-tag {
+ color: #e3ceab;
+}
+
+.hljs-template-tag {
+ color: #dcdcdc;
+}
+
+.hljs-number {
+ color: #8cd0d3;
+}
+
+.hljs-variable,
+.hljs-template-variable,
+.hljs-attribute {
+ color: #efdcbc;
+}
+
+.hljs-literal {
+ color: #efefaf;
+}
+
+.hljs-subst {
+ color: #8f8f8f;
+}
+
+.hljs-title,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-section,
+.hljs-type {
+ color: #efef8f;
+}
+
+.hljs-symbol,
+.hljs-bullet,
+.hljs-link {
+ color: #dca3a3;
+}
+
+.hljs-deletion,
+.hljs-string,
+.hljs-built_in,
+.hljs-builtin-name {
+ color: #cc9393;
+}
+
+.hljs-addition,
+.hljs-comment,
+.hljs-quote,
+.hljs-meta {
+ color: #7f9f7f;
+}
+
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/reference/htmlsingle/js/toc.js b/reference/htmlsingle/js/toc.js
new file mode 100644
index 00000000..0b6fcd65
--- /dev/null
+++ b/reference/htmlsingle/js/toc.js
@@ -0,0 +1,80 @@
+var toctitle = document.getElementById('toctitle');
+var path = window.location.pathname;
+if (toctitle != null) {
+ var oldtoc = toctitle.nextElementSibling;
+ var newtoc = document.createElement('div');
+ newtoc.setAttribute('id', 'tocbot');
+ newtoc.setAttribute('class', 'js-toc desktop-toc');
+ oldtoc.setAttribute('class', 'mobile-toc');
+ oldtoc.parentNode.appendChild(newtoc);
+ tocbot.init({
+ contentSelector: '#content',
+ headingSelector: 'h1, h2, h3, h4, h5',
+ positionFixedSelector: 'body',
+ fixedSidebarOffset: 90,
+ smoothScroll: false
+ });
+ if (!path.endsWith("index.html") && !path.endsWith("/")) {
+ var link = document.createElement("a");
+ if (document.getElementById('index-link')) {
+ indexLinkElement = document.querySelector('#index-link > p > a');
+ linkHref = indexLinkElement.getAttribute("href");
+ link.setAttribute("href", linkHref);
+ } else {
+ link.setAttribute("href", "index.html");
+ }
+ link.innerHTML = " Back to index";
+ var block = document.createElement("div");
+ block.setAttribute('class', 'back-action');
+ block.appendChild(link);
+ var toc = document.getElementById('toc');
+ var next = document.getElementById('toctitle').nextElementSibling;
+ toc.insertBefore(block, next);
+ }
+}
+
+var headerHtml = '';
+
+var header = document.createElement("div");
+header.innerHTML = headerHtml;
+document.body.insertBefore(header, document.body.firstChild);
diff --git a/reference/htmlsingle/js/tocbot/tocbot.css b/reference/htmlsingle/js/tocbot/tocbot.css
new file mode 100644
index 00000000..0632de23
--- /dev/null
+++ b/reference/htmlsingle/js/tocbot/tocbot.css
@@ -0,0 +1 @@
+.toc{overflow-y:auto}.toc>.toc-list{overflow:hidden;position:relative}.toc>.toc-list li{list-style:none}.toc-list{margin:0;padding-left:10px}a.toc-link{color:currentColor;height:100%}.is-collapsible{max-height:1000px;overflow:hidden;transition:all 300ms ease-in-out}.is-collapsed{max-height:0}.is-position-fixed{position:fixed !important;top:0}.is-active-link{font-weight:700}.toc-link::before{background-color:#EEE;content:' ';display:inline-block;height:inherit;left:0;margin-top:-1px;position:absolute;width:2px}.is-active-link::before{background-color:#54BC4B}
diff --git a/reference/htmlsingle/js/tocbot/tocbot.min.js b/reference/htmlsingle/js/tocbot/tocbot.min.js
new file mode 100644
index 00000000..943d8fdb
--- /dev/null
+++ b/reference/htmlsingle/js/tocbot/tocbot.min.js
@@ -0,0 +1 @@
+!function(e){function t(o){if(n[o])return n[o].exports;var l=n[o]={i:o,l:!1,exports:{}};return e[o].call(l.exports,l,l.exports,t),l.l=!0,l.exports}var n={};t.m=e,t.c=n,t.d=function(e,n,o){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:o})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=0)}([function(e,t,n){(function(o){var l,i,s;!function(n,o){i=[],l=o(n),void 0!==(s="function"==typeof l?l.apply(t,i):l)&&(e.exports=s)}(void 0!==o?o:this.window||this.global,function(e){"use strict";function t(){for(var e={},t=0;te.fixedSidebarOffset?-1===n.className.indexOf(e.positionFixedClass)&&(n.className+=h+e.positionFixedClass):n.className=n.className.split(h+e.positionFixedClass).join("")}function s(t){var n=document.documentElement.scrollTop||f.scrollTop;e.positionFixedSelector&&i();var o,l=t;if(m&&null!==document.querySelector(e.tocSelector)&&l.length>0){d.call(l,function(t,i){if(t.offsetTop>n+e.headingsOffset+10){return o=l[0===i?i:i-1],!0}if(i===l.length-1)return o=l[l.length-1],!0});var s=document.querySelector(e.tocSelector).querySelectorAll("."+e.linkClass);u.call(s,function(t){t.className=t.className.split(h+e.activeLinkClass).join("")});var c=document.querySelector(e.tocSelector).querySelectorAll("."+e.listItemClass);u.call(c,function(t){t.className=t.className.split(h+e.activeListItemClass).join("")});var a=document.querySelector(e.tocSelector).querySelector("."+e.linkClass+".node-name--"+o.nodeName+'[href="#'+o.id+'"]');-1===a.className.indexOf(e.activeLinkClass)&&(a.className+=h+e.activeLinkClass);var p=a.parentNode;p&&-1===p.className.indexOf(e.activeListItemClass)&&(p.className+=h+e.activeListItemClass);var C=document.querySelector(e.tocSelector).querySelectorAll("."+e.listClass+"."+e.collapsibleClass);u.call(C,function(t){-1===t.className.indexOf(e.isCollapsedClass)&&(t.className+=h+e.isCollapsedClass)}),a.nextSibling&&-1!==a.nextSibling.className.indexOf(e.isCollapsedClass)&&(a.nextSibling.className=a.nextSibling.className.split(h+e.isCollapsedClass).join("")),r(a.parentNode.parentNode)}}function r(t){return-1!==t.className.indexOf(e.collapsibleClass)&&-1!==t.className.indexOf(e.isCollapsedClass)?(t.className=t.className.split(h+e.isCollapsedClass).join(""),r(t.parentNode.parentNode)):t}function c(t){var n=t.target||t.srcElement;"string"==typeof n.className&&-1!==n.className.indexOf(e.linkClass)&&(m=!1)}function a(){m=!0}var u=[].forEach,d=[].some,f=document.body,m=!0,h=" ";return{enableTocAnimation:a,disableTocAnimation:c,render:n,updateToc:s}}},function(e,t){e.exports=function(e){function t(e){return e[e.length-1]}function n(e){return+e.nodeName.split("H").join("")}function o(t){var o={id:t.id,children:[],nodeName:t.nodeName,headingLevel:n(t),textContent:t.textContent.trim()};return e.includeHtml&&(o.childNodes=t.childNodes),o}function l(l,i){for(var s=o(l),r=n(l),c=i,a=t(c),u=a?a.headingLevel:0,d=r-u;d>0;)a=t(c),a&&void 0!==a.children&&(c=a.children),d--;return r>=e.collapseDepth&&(s.isCollapsed=!0),c.push(s),c}function i(t,n){var o=n;e.ignoreSelector&&(o=n.split(",").map(function(t){return t.trim()+":not("+e.ignoreSelector+")"}));try{return document.querySelector(t).querySelectorAll(o)}catch(e){return console.warn("Element not found: "+t),null}}function s(e){return r.call(e,function(e,t){return l(o(t),e.nest),e},{nest:[]})}var r=[].reduce;return{nestHeadingsArray:s,selectHeadings:i}}},function(e,t){function n(e){function t(e){return"a"===e.tagName.toLowerCase()&&(e.hash.length>0||"#"===e.href.charAt(e.href.length-1))&&(n(e.href)===s||n(e.href)+"#"===s)}function n(e){return e.slice(0,e.lastIndexOf("#"))}function l(e){var t=document.getElementById(e.substring(1));t&&(/^(?:a|select|input|button|textarea)$/i.test(t.tagName)||(t.tabIndex=-1),t.focus())}!function(){document.documentElement.style}();var i=e.duration,s=location.hash?n(location.href):location.href;!function(){function n(n){!t(n.target)||n.target.className.indexOf("no-smooth-scroll")>-1||"#"===n.target.href.charAt(n.target.href.length-2)&&"!"===n.target.href.charAt(n.target.href.length-1)||-1===n.target.className.indexOf(e.linkClass)||o(n.target.hash,{duration:i,callback:function(){l(n.target.hash)}})}document.body.addEventListener("click",n,!1)}()}function o(e,t){function n(e){s=e-i,window.scrollTo(0,c.easing(s,r,u,d)),scode {
+ color: #6D180B;
+}
+
+:not(pre)>code {
+ background-color: #F2F2F2;
+ border: 1px solid #CCCCCC;
+ border-radius: 4px;
+ padding: 1px 3px 0;
+ text-shadow: none;
+ white-space: nowrap;
+}
+
+body>*:first-child {
+ margin-top: 0 !important;
+}
+
+div {
+ margin: 0pt;
+}
+
+hr {
+ border: 1px solid #CCCCCC;
+ background: #CCCCCC;
+}
+
+h1,h2,h3,h4,h5,h6 {
+ color: #000000;
+ cursor: text;
+ font-weight: bold;
+ margin: 30px 0 10px;
+ padding: 0;
+}
+
+h1,h2,h3 {
+ margin: 40px 0 10px;
+}
+
+h1 {
+ margin: 70px 0 30px;
+ padding-top: 20px;
+}
+
+div.part h1 {
+ border-top: 1px dotted #CCCCCC;
+}
+
+h1,h1 code {
+ font-size: 32px;
+}
+
+h2,h2 code {
+ font-size: 24px;
+}
+
+h3,h3 code {
+ font-size: 20px;
+}
+
+h4,h1 code,h5,h5 code,h6,h6 code {
+ font-size: 18px;
+}
+
+div.book,div.chapter,div.appendix,div.part,div.preface {
+ min-width: 300px;
+ max-width: 1200px;
+ margin: 0 auto;
+}
+
+p.releaseinfo {
+ font-weight: bold;
+ margin-bottom: 40px;
+ margin-top: 40px;
+}
+
+div.authorgroup {
+ line-height: 1;
+}
+
+p.copyright {
+ line-height: 1;
+ margin-bottom: -5px;
+}
+
+.legalnotice p {
+ font-style: italic;
+ font-size: 14px;
+ line-height: 1;
+}
+
+div.titlepage+p,div.titlepage+p {
+ margin-top: 0;
+}
+
+pre {
+ line-height: 1.0;
+ color: black;
+}
+
+a {
+ color: #4183C4;
+ text-decoration: none;
+}
+
+p {
+ margin: 15px 0;
+ text-align: left;
+}
+
+ul,ol {
+ padding-left: 30px;
+}
+
+li p {
+ margin: 0;
+}
+
+div.table {
+ margin: 1em;
+ padding: 0.5em;
+ text-align: center;
+}
+
+div.table table,div.informaltable table {
+ display: table;
+ width: 100%;
+}
+
+div.table td {
+ padding-left: 7px;
+ padding-right: 7px;
+}
+
+.sidebar {
+ line-height: 1.4;
+ padding: 0 20px;
+ background-color: #F8F8F8;
+ border: 1px solid #CCCCCC;
+ border-radius: 3px 3px 3px 3px;
+}
+
+.sidebar p.title {
+ color: #6D180B;
+}
+
+pre.programlisting,pre.screen {
+ font-size: 15px;
+ padding: 6px 10px;
+ background-color: #F8F8F8;
+ border: 1px solid #CCCCCC;
+ border-radius: 3px 3px 3px 3px;
+ clear: both;
+ overflow: auto;
+ line-height: 1.4;
+ font-family: Consolas, "Liberation Mono", Courier, monospace;
+}
+
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+ border: 1px solid #DDDDDD !important;
+ border-radius: 4px !important;
+ border-collapse: separate !important;
+ line-height: 1.6;
+}
+
+table thead {
+ background: #F5F5F5;
+}
+
+table tr {
+ border: none;
+ border-bottom: none;
+}
+
+table th {
+ font-weight: bold;
+}
+
+table th,table td {
+ border: none !important;
+ padding: 6px 13px;
+}
+
+table tr:nth-child(2n) {
+ background-color: #F8F8F8;
+}
+
+td p {
+ margin: 0 0 15px 0;
+}
+
+div.table-contents td p {
+ margin: 0;
+}
+
+div.important *,div.note *,div.tip *,div.warning *,div.navheader *,div.navfooter *,div.calloutlist *
+ {
+ border: none !important;
+ background: none !important;
+ margin: 0;
+}
+
+div.important p,div.note p,div.tip p,div.warning p {
+ color: #6F6F6F;
+ line-height: 1.6;
+}
+
+div.important code,div.note code,div.tip code,div.warning code {
+ background-color: #F2F2F2 !important;
+ border: 1px solid #CCCCCC !important;
+ border-radius: 4px !important;
+ padding: 1px 3px 0 !important;
+ text-shadow: none !important;
+ white-space: nowrap !important;
+}
+
+.note th,.tip th,.warning th {
+ display: none;
+}
+
+.note tr:first-child td,.tip tr:first-child td,.warning tr:first-child td
+ {
+ border-right: 1px solid #CCCCCC !important;
+ padding-top: 10px;
+}
+
+div.calloutlist p,div.calloutlist td {
+ padding: 0;
+ margin: 0;
+}
+
+div.calloutlist>table>tbody>tr>td:first-child {
+ padding-left: 10px;
+ width: 30px !important;
+}
+
+div.important,div.note,div.tip,div.warning {
+ margin-left: 0px !important;
+ margin-right: 20px !important;
+ margin-top: 20px;
+ margin-bottom: 20px;
+ padding-top: 10px;
+ padding-bottom: 10px;
+}
+
+div.toc {
+ line-height: 1.2;
+}
+
+dl,dt {
+ margin-top: 1px;
+ margin-bottom: 0;
+}
+
+div.toc>dl>dt {
+ font-size: 32px;
+ font-weight: bold;
+ margin: 30px 0 10px 0;
+ display: block;
+}
+
+div.toc>dl>dd>dl>dt {
+ font-size: 24px;
+ font-weight: bold;
+ margin: 20px 0 10px 0;
+ display: block;
+}
+
+div.toc>dl>dd>dl>dd>dl>dt {
+ font-weight: bold;
+ font-size: 20px;
+ margin: 10px 0 0 0;
+}
+
+tbody.footnotes * {
+ border: none !important;
+}
+
+div.footnote p {
+ margin: 0;
+ line-height: 1;
+}
+
+div.footnote p sup {
+ margin-right: 6px;
+ vertical-align: middle;
+}
+
+div.navheader {
+ border-bottom: 1px solid #CCCCCC;
+}
+
+div.navfooter {
+ border-top: 1px solid #CCCCCC;
+}
+
+.title {
+ margin-left: -1em;
+ padding-left: 1em;
+}
+
+.title>a {
+ position: absolute;
+ visibility: hidden;
+ display: block;
+ font-size: 0.85em;
+ margin-top: 0.05em;
+ margin-left: -1em;
+ vertical-align: text-top;
+ color: black;
+}
+
+.title>a:before {
+ content: "\00A7";
+}
+
+.title:hover>a,.title>a:hover,.title:hover>a:hover {
+ visibility: visible;
+}
+
+.title:focus>a,.title>a:focus,.title:focus>a:focus {
+ outline: 0;
+}
diff --git a/single/images/background.png b/single/images/background.png
new file mode 100644
index 00000000..15dca6fb
Binary files /dev/null and b/single/images/background.png differ
diff --git a/single/images/callouts/1.png b/single/images/callouts/1.png
new file mode 100644
index 00000000..7d473430
Binary files /dev/null and b/single/images/callouts/1.png differ
diff --git a/single/images/callouts/2.png b/single/images/callouts/2.png
new file mode 100644
index 00000000..5d09341b
Binary files /dev/null and b/single/images/callouts/2.png differ
diff --git a/single/images/callouts/3.png b/single/images/callouts/3.png
new file mode 100644
index 00000000..ef7b7004
Binary files /dev/null and b/single/images/callouts/3.png differ
diff --git a/single/images/caution.png b/single/images/caution.png
new file mode 100644
index 00000000..8a5e4fca
Binary files /dev/null and b/single/images/caution.png differ
diff --git a/single/images/important.png b/single/images/important.png
new file mode 100644
index 00000000..ec54df65
Binary files /dev/null and b/single/images/important.png differ
diff --git a/single/images/logo.png b/single/images/logo.png
new file mode 100644
index 00000000..ade2ce6e
Binary files /dev/null and b/single/images/logo.png differ
diff --git a/single/images/note.png b/single/images/note.png
new file mode 100644
index 00000000..88d997b1
Binary files /dev/null and b/single/images/note.png differ
diff --git a/single/images/sts_exception.png b/single/images/sts_exception.png
new file mode 100644
index 00000000..8607c38a
Binary files /dev/null and b/single/images/sts_exception.png differ
diff --git a/single/images/tip.png b/single/images/tip.png
new file mode 100644
index 00000000..6530abb4
Binary files /dev/null and b/single/images/tip.png differ
diff --git a/single/images/warning.png b/single/images/warning.png
new file mode 100644
index 00000000..0d5b5244
Binary files /dev/null and b/single/images/warning.png differ
diff --git a/single/images/web-selected.png b/single/images/web-selected.png
new file mode 100644
index 00000000..aa6b2da6
Binary files /dev/null and b/single/images/web-selected.png differ
diff --git a/single/index.html b/single/index.html
new file mode 100644
index 00000000..48e6a8f9
--- /dev/null
+++ b/single/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+Page Redirection
+
+If you are not redirected automatically, follow the link to latest snapshot documentation
diff --git a/single/spring-cloud-cli.html b/single/spring-cloud-cli.html
new file mode 100644
index 00000000..48e6a8f9
--- /dev/null
+++ b/single/spring-cloud-cli.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+Page Redirection
+
+If you are not redirected automatically, follow the link to latest snapshot documentation
diff --git a/spring-cloud-cli-integration-tests/.gitignore b/spring-cloud-cli-integration-tests/.gitignore
deleted file mode 100644
index b83d2226..00000000
--- a/spring-cloud-cli-integration-tests/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/target/
diff --git a/spring-cloud-cli-integration-tests/README.md b/spring-cloud-cli-integration-tests/README.md
deleted file mode 100644
index 5e4c10c4..00000000
--- a/spring-cloud-cli-integration-tests/README.md
+++ /dev/null
@@ -1,9 +0,0 @@
-Spring Boot command line features for
-[Spring Cloud](https://github.com/spring-cloud). To install, make
-sure you have
-[Spring Boot CLI](https://github.com/spring-projects/spring-boot)
-(1.1.x with x>=5):
-
- $ spring version
- Spring CLI v1.1.5.RELEASE
-
diff --git a/spring-cloud-cli-integration-tests/pom.xml b/spring-cloud-cli-integration-tests/pom.xml
deleted file mode 100644
index b6b891a4..00000000
--- a/spring-cloud-cli-integration-tests/pom.xml
+++ /dev/null
@@ -1,137 +0,0 @@
-
-
- 4.0.0
-
- spring-cloud-cli-integration-tests
- jar
-
- spring-cloud-cli-integration-tests
- Spring Patform Cli integration project
-
-
- org.springframework.cloud
- spring-cloud-cli-parent
- 3.1.2-SNAPSHOT
-
-
-
-
-
- org.apache.maven
- maven-settings-builder
- ${maven.version}
-
-
-
-
-
-
- org.springframework.cloud
- spring-cloud-cli
- ${project.version}
- provided
-
-
- org.springframework.boot
- spring-boot-cli
- ${spring-boot.version}
- provided
-
-
- commons-logging
- commons-logging
- 1.2
- provided
-
-
- org.springframework.boot
- spring-boot-starter-test
- test
-
-
- junit
- junit
- test
-
-
-
-
- UTF-8
- 1.8
- 1.8
- 3.6.3
-
-
-
-
-
- maven-deploy-plugin
-
- true
-
-
-
- org.sonatype.plugins
- nexus-staging-maven-plugin
-
- true
-
-
-
- maven-jar-plugin
-
- true
-
-
-
- maven-install-plugin
-
- true
-
-
-
- maven-gpg-plugin
-
- true
-
-
-
-
-
-
-
- org.eclipse.m2e
- lifecycle-mapping
- 1.0.0
-
-
-
-
-
-
- org.codehaus.mojo
-
-
- exec-maven-plugin
-
-
- [1.6.0,)
-
-
- exec
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/spring-cloud-cli-integration-tests/samples/app.groovy b/spring-cloud-cli-integration-tests/samples/app.groovy
deleted file mode 100644
index 38a9d36f..00000000
--- a/spring-cloud-cli-integration-tests/samples/app.groovy
+++ /dev/null
@@ -1,22 +0,0 @@
-package org.test
-
-@Component
-class Example implements CommandLineRunner {
-
- @Autowired
- private MyService myService
-
- void run(String... args) {
- println "Hello ${this.myService.sayWorld()} From ${getClass().getClassLoader().getResource('samples/app.groovy')}"
- }
-}
-
-
-@Service
-class MyService {
-
- String sayWorld() {
- return "World!"
- }
-}
-
diff --git a/spring-cloud-cli-integration-tests/samples/configserver.groovy b/spring-cloud-cli-integration-tests/samples/configserver.groovy
deleted file mode 100644
index 3605efd5..00000000
--- a/spring-cloud-cli-integration-tests/samples/configserver.groovy
+++ /dev/null
@@ -1,6 +0,0 @@
-package org.test
-
-@EnableConfigServer
-class Example {
-}
-
diff --git a/spring-cloud-cli-integration-tests/samples/eureka.groovy b/spring-cloud-cli-integration-tests/samples/eureka.groovy
deleted file mode 100644
index ae2d2b46..00000000
--- a/spring-cloud-cli-integration-tests/samples/eureka.groovy
+++ /dev/null
@@ -1,6 +0,0 @@
-package org.test
-
-@EnableDiscoveryClient
-class Example {
-}
-
diff --git a/spring-cloud-cli-integration-tests/samples/eurekaserver.groovy b/spring-cloud-cli-integration-tests/samples/eurekaserver.groovy
deleted file mode 100644
index c2daa837..00000000
--- a/spring-cloud-cli-integration-tests/samples/eurekaserver.groovy
+++ /dev/null
@@ -1,6 +0,0 @@
-package org.test
-
-@EnableEurekaServer
-class Example {
-}
-
diff --git a/spring-cloud-cli-integration-tests/samples/rabbit.groovy b/spring-cloud-cli-integration-tests/samples/rabbit.groovy
deleted file mode 100644
index 1739317c..00000000
--- a/spring-cloud-cli-integration-tests/samples/rabbit.groovy
+++ /dev/null
@@ -1,6 +0,0 @@
-package org.test
-
-@EnableBinding(value=Source, transport="rabbit")
-class Example {
-}
-
diff --git a/spring-cloud-cli-integration-tests/samples/stubrunner.groovy b/spring-cloud-cli-integration-tests/samples/stubrunner.groovy
deleted file mode 100644
index 992ad994..00000000
--- a/spring-cloud-cli-integration-tests/samples/stubrunner.groovy
+++ /dev/null
@@ -1,6 +0,0 @@
-package org.test
-
-@EnableStubRunnerServer
-class Example {
-}
-
diff --git a/spring-cloud-cli-integration-tests/src/test/java/org/springframework/cloud/cli/CliTester.java b/spring-cloud-cli-integration-tests/src/test/java/org/springframework/cloud/cli/CliTester.java
deleted file mode 100644
index bd3e0f32..00000000
--- a/spring-cloud-cli-integration-tests/src/test/java/org/springframework/cloud/cli/CliTester.java
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * Copyright 2012-2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.cli;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.lang.reflect.Field;
-import java.net.URI;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.Callable;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-
-import org.junit.Assume;
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-import org.springframework.boot.cli.command.AbstractCommand;
-import org.springframework.boot.cli.command.OptionParsingCommand;
-import org.springframework.boot.cli.command.archive.JarCommand;
-import org.springframework.boot.cli.command.grab.GrabCommand;
-import org.springframework.boot.cli.command.run.RunCommand;
-import org.springframework.boot.test.system.OutputCaptureRule;
-import org.springframework.util.SocketUtils;
-
-/**
- * {@link TestRule} that can be used to invoke CLI commands.
- *
- * @author Phillip Webb
- * @author Dave Syer
- * @author Andy Wilkinson
- */
-public class CliTester implements TestRule {
-
- private final OutputCaptureRule outputCapture = new OutputCaptureRule();
-
- private long timeout = TimeUnit.MINUTES.toMillis(6);
-
- private final List commands = new ArrayList();
-
- private final String prefix;
-
- private final int port = SocketUtils.findAvailableTcpPort();
-
- public CliTester(String prefix) {
- this.prefix = prefix;
- }
-
- public void setTimeout(long timeout) {
- this.timeout = timeout;
- }
-
- public String run(String... args) throws Exception {
- Future future = submitCommand(new RunCommand(), args);
- this.commands.add(future.get(this.timeout, TimeUnit.MILLISECONDS));
- return getOutput();
- }
-
- public String grab(String... args) throws Exception {
- Future future = submitCommand(new GrabCommand(), args);
- this.commands.add(future.get(this.timeout, TimeUnit.MILLISECONDS));
- return getOutput();
- }
-
- public String jar(String... args) throws Exception {
- Future future = submitCommand(new JarCommand(), args);
- this.commands.add(future.get(this.timeout, TimeUnit.MILLISECONDS));
- return getOutput();
- }
-
- private Future submitCommand(final T command,
- String... args) {
- clearUrlHandler();
- final String[] sources = getSources(args);
- return Executors.newSingleThreadExecutor().submit(new Callable() {
- @Override
- public T call() throws Exception {
- ClassLoader loader = Thread.currentThread().getContextClassLoader();
- System.setProperty("server.port", String.valueOf(CliTester.this.port));
- try {
- command.run(sources);
- return command;
- }
- finally {
- System.clearProperty("server.port");
- Thread.currentThread().setContextClassLoader(loader);
- }
- }
- });
- }
-
- /**
- * The TomcatURLStreamHandlerFactory fails if the factory is already set, use
- * reflection to reset it.
- */
- private void clearUrlHandler() {
- try {
- Field field = URL.class.getDeclaredField("factory");
- field.setAccessible(true);
- field.set(null, null);
- }
- catch (Exception ex) {
- throw new IllegalStateException(ex);
- }
- }
-
- protected String[] getSources(String... args) {
- final String[] sources = new String[args.length];
- for (int i = 0; i < args.length; i++) {
- String arg = args[i];
- if (!arg.endsWith(".groovy") && !arg.endsWith(".xml")) {
- if (new File(this.prefix + arg).isDirectory()) {
- sources[i] = this.prefix + arg;
- }
- else {
- sources[i] = arg;
- }
- }
- else {
- sources[i] = this.prefix + arg;
- }
- }
- return sources;
- }
-
- public String getOutput() {
- return this.outputCapture.toString();
- }
-
- @Override
- public Statement apply(final Statement base, final Description description) {
- final Statement statement = CliTester.this.outputCapture
- .apply(new RunLauncherStatement(base), description);
- return new Statement() {
-
- @Override
- public void evaluate() throws Throwable {
- Assume.assumeTrue(
- "Not running sample integration tests because integration profile not active",
- System.getProperty("spring.profiles.active", "integration")
- .contains("integration"));
- statement.evaluate();
- }
- };
- }
-
- public String getHttpOutput() {
- return getHttpOutput("/");
- }
-
- public String getHttpOutput(String uri) {
- try {
- InputStream stream = URI.create("http://localhost:" + this.port + uri).toURL()
- .openStream();
- BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
- String line;
- StringBuilder result = new StringBuilder();
- while ((line = reader.readLine()) != null) {
- result.append(line);
- }
- return result.toString();
- }
- catch (Exception ex) {
- throw new IllegalStateException(ex);
- }
- }
-
- private final class RunLauncherStatement extends Statement {
-
- private final Statement base;
-
- private RunLauncherStatement(Statement base) {
- this.base = base;
- }
-
- @Override
- public void evaluate() throws Throwable {
- System.setProperty("disableSpringSnapshotRepos", "false");
- try {
- try {
- this.base.evaluate();
- }
- finally {
- for (AbstractCommand command : CliTester.this.commands) {
- if (command != null && command instanceof RunCommand) {
- ((RunCommand) command).stop();
- }
- }
- System.clearProperty("disableSpringSnapshotRepos");
- }
- }
- catch (Exception ex) {
- throw new IllegalStateException(ex);
- }
- }
- }
-
-}
diff --git a/spring-cloud-cli-integration-tests/src/test/java/org/springframework/cloud/cli/OutputCapture.java b/spring-cloud-cli-integration-tests/src/test/java/org/springframework/cloud/cli/OutputCapture.java
deleted file mode 100644
index f976ca30..00000000
--- a/spring-cloud-cli-integration-tests/src/test/java/org/springframework/cloud/cli/OutputCapture.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright 2012-2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.cli;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.PrintStream;
-
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-/**
- * Capture output from System.out and System.err.
- *
- * @author Phillip Webb
- */
-public class OutputCapture implements TestRule {
-
- private CaptureOutputStream captureOut;
-
- private CaptureOutputStream captureErr;
-
- private ByteArrayOutputStream copy;
-
- @Override
- public Statement apply(final Statement base, Description description) {
- return new Statement() {
- @Override
- public void evaluate() throws Throwable {
- captureOutput();
- try {
- base.evaluate();
- }
- finally {
- releaseOutput();
- }
- }
- };
- }
-
- protected void captureOutput() {
- this.copy = new ByteArrayOutputStream();
- this.captureOut = new CaptureOutputStream(System.out, this.copy);
- this.captureErr = new CaptureOutputStream(System.err, this.copy);
- System.setOut(new PrintStream(this.captureOut));
- System.setErr(new PrintStream(this.captureErr));
- }
-
- protected void releaseOutput() {
- System.setOut(this.captureOut.getOriginal());
- System.setErr(this.captureErr.getOriginal());
- this.copy = null;
- }
-
- public void flush() {
- try {
- this.captureOut.flush();
- this.captureErr.flush();
- }
- catch (IOException ex) {
- // ignore
- }
- }
-
- @Override
- public String toString() {
- flush();
- return this.copy.toString();
- }
-
- private static class CaptureOutputStream extends OutputStream {
-
- private final PrintStream original;
-
- private final OutputStream copy;
-
- CaptureOutputStream(PrintStream original, OutputStream copy) {
- this.original = original;
- this.copy = copy;
- }
-
- @Override
- public void write(int b) throws IOException {
- this.copy.write(b);
- this.original.write(b);
- this.original.flush();
- }
-
- @Override
- public void write(byte[] b) throws IOException {
- write(b, 0, b.length);
- }
-
- @Override
- public void write(byte[] b, int off, int len) throws IOException {
- this.copy.write(b, off, len);
- this.original.write(b, off, len);
- }
-
- public PrintStream getOriginal() {
- return this.original;
- }
-
- @Override
- public void flush() throws IOException {
- this.copy.flush();
- this.original.flush();
- }
- }
-
-}
diff --git a/spring-cloud-cli-integration-tests/src/test/java/org/springframework/cloud/cli/SampleIntegrationTests.java b/spring-cloud-cli-integration-tests/src/test/java/org/springframework/cloud/cli/SampleIntegrationTests.java
deleted file mode 100644
index 60b114a5..00000000
--- a/spring-cloud-cli-integration-tests/src/test/java/org/springframework/cloud/cli/SampleIntegrationTests.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright 2013-2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.cloud.cli;
-
-import java.io.File;
-import java.net.URI;
-
-import org.junit.BeforeClass;
-import org.junit.Ignore;
-import org.junit.Rule;
-import org.junit.Test;
-
-import static org.junit.Assert.assertTrue;
-
-/**
- * @author Dave Syer
- *
- */
-public class SampleIntegrationTests {
-
- @Rule
- public CliTester cli = new CliTester("samples/");
-
- @BeforeClass
- public static void setup() {
- System.setProperty("spring.main.allow-bean-definition-overriding", "true");
- }
-
- @Test
- @Ignore // FIXME: 3.0.0
- public void appSample() throws Exception {
- String output = this.cli.run("app.groovy");
- URI scriptUri = new File("samples/app.groovy").toURI();
- assertTrue("Wrong output: " + output,
- output.contains("Hello World! From " + scriptUri));
- }
-
- @Test
- @Ignore // FIXME: 3.0.0
- public void eurekaSample() throws Exception {
- String output = this.cli.run("eureka.groovy");
- assertTrue("Wrong output: " + output,
- output.contains("Setting initial instance status as: STARTING"));
- }
-
- @Test
- @Ignore // FIXME: 3.0.0
- public void eurekaServerSample() throws Exception {
- String output = this.cli.run("eurekaserver.groovy", "--", "--debug");
- assertTrue("Wrong output: " + output,
- output.contains("Setting the eureka configuration.."));
- }
-
- @Test
- @Ignore // FIXME: 3.0.0
- public void rabbitSample() throws Exception {
- String output = this.cli.run("rabbit.groovy");
- assertTrue("Wrong output: " + output,
- output.contains("subscriber to the 'errorChannel' channel"));
- }
-
- @Test
- @Ignore // FIXME: 3.0.0
- public void configServerSample() throws Exception {
- String output = this.cli.run("configserver.groovy", "--",
- "--spring.config.name=configserver", "--logging.level.org.springframework=DEBUG");
- assertTrue("Wrong output: " + output,
- output.contains("ConfigServerAutoConfiguration matched"));
- }
-
- @Test
- @Ignore // FIXME: 3.0.0
- public void stubRunnerSample() throws Exception {
- String output = this.cli.run("stubrunner.groovy");
- assertTrue("Wrong output: " + output,
- output.contains("No stubs to download have been passed"));
- }
-
-}
diff --git a/spring-cloud-cli.html b/spring-cloud-cli.html
new file mode 100644
index 00000000..48e6a8f9
--- /dev/null
+++ b/spring-cloud-cli.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+Page Redirection
+
+If you are not redirected automatically, follow the link to latest snapshot documentation
diff --git a/spring-cloud-cli.xml b/spring-cloud-cli.xml
new file mode 100644
index 00000000..bf4ce6d6
--- /dev/null
+++ b/spring-cloud-cli.xml
@@ -0,0 +1,219 @@
+
+
+
+
+
+Spring Boot Cloud CLI
+2019-06-06
+
+
+
+Spring Boot CLI provides Spring
+Boot command line features for Spring
+Cloud. You can write Groovy scripts to run Spring Cloud component
+applications (e.g. @EnableEurekaServer ). You can also easily do
+things like encryption and decryption to support Spring Cloud Config
+clients with secret configuration values. With the Launcher CLI you
+can launch services like Eureka, Zipkin, Config Server
+conveniently all at once from the command line (very useful at
+development time).
+
+Spring Cloud is released under the non-restrictive Apache 2.0 license. If you would like to contribute to this section of the documentation or if you find an error, please find the source code and issue trackers in the project at github.
+
+
+
+Installation
+To install, make
+sure you have
+ Spring Boot CLI
+(2.0.0 or better):
+$ spring version
+Spring CLI v2.1.0.M4
+E.g. for SDKMan users
+$ sdk install springboot 2.1.0.M4
+$ sdk use springboot 2.1.0.M4
+and install the Spring Cloud plugin
+$ mvn install
+$ spring install org.springframework.cloud:spring-cloud-cli:2.1.0.BUILD-SNAPSHOT
+
+Prerequisites: to use the encryption and decryption features
+you need the full-strength JCE installed in your JVM (it’s not there by default).
+You can download the "Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files"
+from Oracle, and follow instructions for installation (essentially replace the 2 policy files
+in the JRE lib/security directory with the ones that you downloaded).
+
+
+
+Running Spring Cloud Services in Development
+The Launcher CLI can be used to run common services like Eureka,
+Config Server etc. from the command line. To list the available
+services you can do spring cloud --list , and to launch a default set
+of services just spring cloud . To choose the services to deploy,
+just list them on the command line, e.g.
+$ spring cloud eureka configserver h2 kafka stubrunner zipkin
+Summary of supported deployables:
+
+
+
+
+
+
+
+
+Service
+Name
+Address
+Description
+
+
+
+
+eureka
+Eureka Server
+ http://localhost:8761
+Eureka server for service registration and discovery. All the other services show up in its catalog by default.
+
+
+configserver
+Config Server
+ http://localhost:8888
+Spring Cloud Config Server running in the "native" profile and serving configuration from the local directory ./launcher
+
+
+h2
+H2 Database
+ http://localhost:9095 (console), jdbc:h2:tcp://localhost:9096/{data}
+Relation database service. Use a file path for {data} (e.g. ./target/test ) when you connect. Remember that you can add ;MODE=MYSQL or ;MODE=POSTGRESQL to connect with compatibility to other server types.
+
+
+kafka
+Kafka Broker
+ http://localhost:9091 (actuator endpoints), localhost:9092
+
+
+
+hystrixdashboard
+Hystrix Dashboard
+ http://localhost:7979
+Any Spring Cloud app that declares Hystrix circuit breakers publishes metrics on /hystrix.stream . Type that address into the dashboard to visualize all the metrics,
+
+
+dataflow
+Dataflow Server
+ http://localhost:9393
+Spring Cloud Dataflow server with UI at /admin-ui. Connect the Dataflow shell to target at root path.
+
+
+zipkin
+Zipkin Server
+ http://localhost:9411
+Zipkin Server with UI for visualizing traces. Stores span data in memory and accepts them via HTTP POST of JSON data.
+
+
+stubrunner
+Stub Runner Boot
+ http://localhost:8750
+Downloads WireMock stubs, starts WireMock and feeds the started servers with stored stubs. Pass stubrunner.ids to pass stub coordinates and then go to http://localhost:8750/stubs .
+
+
+
+
+Each of these apps can be configured using a local YAML file with the same name (in the current
+working directory or a subdirectory called "config" or in ~/.spring-cloud ). E.g. in configserver.yml you might want to
+do something like this to locate a local git repository for the backend:
+
+configserver.yml
+
+spring:
+ profiles:
+ active: git
+ cloud:
+ config:
+ server:
+ git:
+ uri: file://${user.home}/dev/demo/config-repo
+
+
+E.g. in Stub Runner app you could fetch stubs from your local .m2 in the following way.
+
+stubrunner.yml
+
+stubrunner:
+ workOffline: true
+ ids:
+ - com.example:beer-api-producer:+:9876
+
+
+
+Adding Additional Applications
+Additional applications can be added to ./config/cloud.yml (not
+./config.yml because that would replace the defaults), e.g. with
+
+config/cloud.yml
+
+spring:
+ cloud:
+ launcher:
+ deployables:
+ source:
+ coordinates: maven://com.example:source:0.0.1-SNAPSHOT
+ port: 7000
+ sink:
+ coordinates: maven://com.example:sink:0.0.1-SNAPSHOT
+ port: 7001
+
+
+when you list the apps:
+$ spring cloud --list
+source sink configserver dataflow eureka h2 hystrixdashboard kafka stubrunner zipkin
+(notice the additional apps at the start of the list).
+
+
+
+Writing Groovy Scripts and Running Applications
+Spring Cloud CLI has support for most of the Spring Cloud declarative
+features, such as the @Enable* class of annotations. For example,
+here is a fully functional Eureka server
+
+app.groovy
+
+@EnableEurekaServer
+class Eureka {}
+
+
+which you can run from the command line like this
+$ spring run app.groovy
+To include additional dependencies, often it suffices just to add the
+appropriate feature-enabling annotation, e.g. @EnableConfigServer ,
+@EnableOAuth2Sso or @EnableEurekaClient . To manually include a
+dependency you can use a @Grab with the special "Spring Boot" short
+style artifact co-ordinates, i.e. with just the artifact ID (no need
+for group or version information), e.g. to set up a client app to
+listen on AMQP for management events from the Spring CLoud Bus:
+
+app.groovy
+
+@Grab('spring-cloud-starter-bus-amqp')
+@RestController
+class Service {
+ @RequestMapping('/')
+ def home() { [message: 'Hello'] }
+}
+
+
+
+
+Encryption and Decryption
+The Spring Cloud CLI comes with an "encrypt" and a "decrypt"
+command. Both accept arguments in the same form with a key specified
+as a mandatory "--key", e.g.
+$ spring encrypt mysecret --key foo
+682bc583f4641835fa2db009355293665d2647dade3375c0ee201de2a49f7bda
+$ spring decrypt --key foo 682bc583f4641835fa2db009355293665d2647dade3375c0ee201de2a49f7bda
+mysecret
+To use a key in a file (e.g. an RSA public key for encyption) prepend
+the key value with "@" and provide the file path, e.g.
+$ spring encrypt mysecret --key @${HOME}/.ssh/id_rsa.pub
+AQAjPgt3eFZQXwt8tsHAVv/QHiY5sI2dRcR+...
+
+
\ No newline at end of file
diff --git a/spring-cloud-cli/.gitignore b/spring-cloud-cli/.gitignore
deleted file mode 100644
index b83d2226..00000000
--- a/spring-cloud-cli/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/target/
diff --git a/spring-cloud-cli/README.md b/spring-cloud-cli/README.md
deleted file mode 100644
index 5e4c10c4..00000000
--- a/spring-cloud-cli/README.md
+++ /dev/null
@@ -1,9 +0,0 @@
-Spring Boot command line features for
-[Spring Cloud](https://github.com/spring-cloud). To install, make
-sure you have
-[Spring Boot CLI](https://github.com/spring-projects/spring-boot)
-(1.1.x with x>=5):
-
- $ spring version
- Spring CLI v1.1.5.RELEASE
-
diff --git a/spring-cloud-cli/pom.xml b/spring-cloud-cli/pom.xml
deleted file mode 100644
index 08ea6378..00000000
--- a/spring-cloud-cli/pom.xml
+++ /dev/null
@@ -1,91 +0,0 @@
-
-
- 4.0.0
-
- spring-cloud-cli
- jar
-
- spring-cloud-cli
- Spring Patform Cli integration project
-
-
- org.springframework.cloud
- spring-cloud-cli-parent
- 3.1.2-SNAPSHOT
-
-
-
-
-
- src/main/resources
- true
-
-
-
-
-
-
- org.springframework.cloud.launcher
- spring-cloud-launcher-cli
- ${project.version}
-
-
- org.springframework.cloud
- spring-cloud-stream
- provided
-
-
- net.sf.jopt-simple
- jopt-simple
- provided
-
-
- org.springframework.security
- spring-security-rsa
-
-
- org.springframework
- spring-core
-
-
-
-
- org.springframework.security
- spring-security-crypto
-
-
- org.springframework.boot
- spring-boot-cli
- ${spring-boot.version}
- provided
-
-
- org.codehaus.groovy
- groovy
- provided
-
-
- org.springframework.boot
- spring-boot-starter-test
- test
-
-
- org.junit.vintage
- junit-vintage-engine
- test
-
-
-
-
-
- org.springframework.boot
- spring-boot-parent
- ${spring-boot.version}
- pom
- import
-
-
-
-
-
diff --git a/spring-cloud-cli/src/main/java/org/springframework/boot/groovy/cloud/EnableBinding.java b/spring-cloud-cli/src/main/java/org/springframework/boot/groovy/cloud/EnableBinding.java
deleted file mode 100644
index 1b2f870b..00000000
--- a/spring-cloud-cli/src/main/java/org/springframework/boot/groovy/cloud/EnableBinding.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.boot.groovy.cloud;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-import org.springframework.cloud.cli.compiler.StreamRabbitCompilerAutoConfiguration;
-import org.springframework.core.annotation.AliasFor;
-
-/**
- * Pseudo annotation used to trigger {@link StreamRabbitCompilerAutoConfiguration} and
- * Redis.
- */
-@Target(ElementType.TYPE)
-@Documented
-@Retention(RetentionPolicy.RUNTIME)
-@org.springframework.cloud.stream.annotation.EnableBinding
-public @interface EnableBinding {
-
- @AliasFor(annotation = org.springframework.cloud.stream.annotation.EnableBinding.class, attribute = "value")
- Class>[] value() default {};
-
- String transport() default "rabbit";
-}
diff --git a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/command/CloudCommandFactory.java b/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/command/CloudCommandFactory.java
deleted file mode 100644
index dd154166..00000000
--- a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/command/CloudCommandFactory.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2013-2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.cloud.cli.command;
-
-import java.util.Arrays;
-import java.util.Collection;
-
-import org.springframework.boot.cli.command.Command;
-import org.springframework.boot.cli.command.CommandFactory;
-import org.springframework.cloud.cli.command.encrypt.DecryptCommand;
-import org.springframework.cloud.cli.command.encrypt.EncryptCommand;
-import org.springframework.cloud.cli.command.url.UrlDecodeCommand;
-import org.springframework.cloud.cli.command.url.UrlEncodeCommand;
-import org.springframework.cloud.launcher.cli.LauncherCommand;
-
-/**
- * @author Dave Syer
- *
- */
-public class CloudCommandFactory implements CommandFactory {
-
- @Override
- public Collection getCommands() {
- return Arrays.asList(new EncryptCommand(), new DecryptCommand(), new UrlEncodeCommand(), new UrlDecodeCommand(), new LauncherCommand());
- }
-
-}
diff --git a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/command/encrypt/BaseEncryptOptionHandler.java b/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/command/encrypt/BaseEncryptOptionHandler.java
deleted file mode 100644
index ec3fc9c7..00000000
--- a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/command/encrypt/BaseEncryptOptionHandler.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright 2013-2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.cloud.cli.command.encrypt;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.nio.charset.Charset;
-
-import org.springframework.boot.cli.command.options.OptionHandler;
-import org.springframework.boot.cli.util.Log;
-import org.springframework.core.io.FileSystemResource;
-import org.springframework.security.crypto.encrypt.TextEncryptor;
-import org.springframework.security.rsa.crypto.KeyStoreKeyFactory;
-import org.springframework.security.rsa.crypto.RsaSecretEncryptor;
-import org.springframework.util.StreamUtils;
-
-import static java.util.Arrays.asList;
-
-import joptsimple.OptionSet;
-import joptsimple.OptionSpec;
-
-class BaseEncryptOptionHandler extends OptionHandler {
-
- private OptionSpec keyOption;
-
- private OptionSpec aliasOption;
-
- private OptionSpec passwordOption;
-
- private OptionSpec keyPassOption;
-
- private Charset charset;
-
- {
- charset = Charset.forName("UTF-8");
- }
-
- @Override
- protected final void options() {
- this.keyOption = option(asList("key", "k"),
- "Specify key (symmetric secret, or pem-encoded key). If the value starts with @ it is interpreted as a file location.")
- .withRequiredArg();
- this.passwordOption = option("password",
- "A password for the keyfile (assuming the --key option is a KeyStore file).")
- .withRequiredArg();
- this.keyPassOption = option("keypass",
- "A password for the key, defaults to the same as the store password (assuming the --key option is a KeyStore file).")
- .withRequiredArg();
- this.aliasOption = option("alias",
- "An alias for the the key in a keyfile (assuming the --key option is a KeyStore file).")
- .withRequiredArg();
- doOptions();
- }
-
- protected void doOptions() {
- }
-
- protected TextEncryptor createEncryptor(OptionSet options) {
- String value = keyOption.value(options);
- if (value == null) {
- throw new MissingKeyException();
- }
- if (options.has(passwordOption)) { // it's a keystore
- String password = options.valueOf(passwordOption);
- String alias = options.valueOf(aliasOption);
- KeyStoreKeyFactory factory = new KeyStoreKeyFactory(
- new FileSystemResource(value), password.toCharArray());
- if (options.has(keyPassOption)) {
- String keypass = options.valueOf(keyPassOption);
- RsaSecretEncryptor encryptor = new RsaSecretEncryptor(
- factory.getKeyPair(alias, keypass.toCharArray()));
- return encryptor;
- }
- else {
- RsaSecretEncryptor encryptor = new RsaSecretEncryptor(
- factory.getKeyPair(alias));
- return encryptor;
- }
- }
- boolean verbose = Boolean.getBoolean("debug");
- if (value.startsWith("@")) {
- value = readFile(value.substring(1));
- }
- try {
- value = readFile(value);
- if (verbose) {
- int len = Math.min(100, Math.max(value.length(), value.indexOf("\n")));
- Log.info("File contents:\n" + value.substring(0, len) + "...");
- }
- }
- catch (Exception e) {
- // not a file
- }
- return new EncryptorFactory(verbose).create(value.trim().replaceAll("\n", ""));
- }
-
- private String readFile(String filename) {
- try {
- return StreamUtils.copyToString(new FileInputStream(new File(filename)),
- charset);
- }
- catch (RuntimeException e) {
- throw e;
- }
- catch (Exception e) {
- throw new IllegalStateException(e);
- }
- }
-
-}
\ No newline at end of file
diff --git a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/command/encrypt/DecryptCommand.java b/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/command/encrypt/DecryptCommand.java
deleted file mode 100644
index 427c60ee..00000000
--- a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/command/encrypt/DecryptCommand.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2013-2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.cloud.cli.command.encrypt;
-
-import joptsimple.OptionSet;
-
-import org.springframework.boot.cli.command.OptionParsingCommand;
-import org.springframework.boot.cli.command.status.ExitStatus;
-import org.springframework.security.crypto.encrypt.TextEncryptor;
-import org.springframework.util.StringUtils;
-
-/**
- * @author Dave Syer
- *
- */
-public class DecryptCommand extends OptionParsingCommand {
-
- public DecryptCommand() {
- super("decrypt", "Decrypt a string previsouly encrypted with the same key (or key pair)",
- new DecryptOptionHandler());
- }
-
- @Override
- public String getUsageHelp() {
- return "[options] ";
- }
-
- private static class DecryptOptionHandler extends BaseEncryptOptionHandler {
-
- @Override
- protected synchronized ExitStatus run(OptionSet options) throws Exception {
- TextEncryptor encryptor = createEncryptor(options);
- String text = StringUtils.collectionToDelimitedString(
- options.nonOptionArguments(), " ");
- if (text.startsWith("{cipher}")) {
- text = text.substring("{cipher}".length());
- }
- System.out.println(encryptor.decrypt(text));
- return ExitStatus.OK;
- }
-
- }
-
-}
diff --git a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/command/encrypt/EncryptCommand.java b/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/command/encrypt/EncryptCommand.java
deleted file mode 100644
index 428efdeb..00000000
--- a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/command/encrypt/EncryptCommand.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright 2013-2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.cloud.cli.command.encrypt;
-
-import static java.util.Arrays.asList;
-import joptsimple.OptionSet;
-import joptsimple.OptionSpec;
-
-import org.springframework.boot.cli.command.OptionParsingCommand;
-import org.springframework.boot.cli.command.status.ExitStatus;
-import org.springframework.security.crypto.encrypt.TextEncryptor;
-import org.springframework.util.StringUtils;
-
-/**
- * @author Dave Syer
- *
- */
-public class EncryptCommand extends OptionParsingCommand {
-
- public EncryptCommand() {
- super("encrypt",
- "Encrypt a string so, for instance, it can be added to source control",
- new EncryptOptionHandler());
- }
-
- @Override
- public String getUsageHelp() {
- return "[options] ";
- }
-
- private static class EncryptOptionHandler extends BaseEncryptOptionHandler {
-
- private OptionSpec propertyOption;
-
- @Override
- protected void doOptions() {
- this.propertyOption = option(
- asList("property", "p"),
- "A name for the encrypted value. Output will be in a form that can be pasted in to a properties file.")
- .withRequiredArg();
- }
-
- @Override
- protected synchronized ExitStatus run(OptionSet options) throws Exception {
- TextEncryptor encryptor = createEncryptor(options);
- String text = StringUtils.collectionToDelimitedString(
- options.nonOptionArguments(), " ");
- System.out.println(formatCipher(options, encryptor.encrypt(text)));
- return ExitStatus.OK;
- }
-
- protected String formatCipher(OptionSet options, String output) {
- if (options.has(propertyOption)) {
- output = options.valueOf(propertyOption).replace(":", "\\:")
- .replace("=", "\\=").replace(" ", "\\ ")
- + "={cipher}" + output;
- }
- return output;
- }
-
- }
-
-}
diff --git a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/command/encrypt/EncryptorFactory.java b/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/command/encrypt/EncryptorFactory.java
deleted file mode 100644
index 5bfbfc50..00000000
--- a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/command/encrypt/EncryptorFactory.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2013-2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.cloud.cli.command.encrypt;
-
-import org.springframework.boot.cli.util.Log;
-import org.springframework.security.crypto.encrypt.Encryptors;
-import org.springframework.security.crypto.encrypt.TextEncryptor;
-import org.springframework.security.rsa.crypto.RsaSecretEncryptor;
-
-/**
- * @author Dave Syer
- *
- */
-public class EncryptorFactory {
-
- // TODO: expose as config property
- private static final String SALT = "deadbeef";
-
- private final boolean verbose;
-
- public EncryptorFactory() {
- this(false);
- }
-
- public EncryptorFactory(boolean verbose) {
- this.verbose = verbose;
- }
-
- public TextEncryptor create(String data) {
-
- TextEncryptor encryptor = null;
- try {
- encryptor = new RsaSecretEncryptor(data);
- }
- catch (IllegalArgumentException e) {
- if (verbose) {
- Log.info("Could not create RSA Encryptor (" + e.getMessage() + ")");
- }
- }
- if (encryptor == null) {
- if (verbose) {
- Log.info("Trying public key");
- }
- try {
- encryptor = new RsaSecretEncryptor(data);
- }
- catch (IllegalArgumentException e) {
- if (verbose) {
- Log.info("Could not create public key RSA Encryptor ("
- + e.getMessage() + ")");
- }
- }
- }
- if (encryptor == null) {
- if (verbose) {
- Log.info("Trying symmetric key");
- }
- encryptor = Encryptors.text(data, SALT);
- }
- if (encryptor == null) {
- if (verbose) {
- Log.error("Could not create any Encryptor");
- }
- throw new KeyFormatException();
- }
-
- return encryptor;
- }
-
-}
diff --git a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/command/encrypt/KeyFormatException.java b/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/command/encrypt/KeyFormatException.java
deleted file mode 100644
index 9c511c7d..00000000
--- a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/command/encrypt/KeyFormatException.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright 2013-2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.cloud.cli.command.encrypt;
-
-@SuppressWarnings("serial")
-public class KeyFormatException extends RuntimeException {
-}
\ No newline at end of file
diff --git a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/command/encrypt/MissingKeyException.java b/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/command/encrypt/MissingKeyException.java
deleted file mode 100644
index b970b633..00000000
--- a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/command/encrypt/MissingKeyException.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright 2012-2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.cloud.cli.command.encrypt;
-
-import org.springframework.boot.cli.command.CommandException;
-
-@SuppressWarnings("serial")
-public class MissingKeyException extends CommandException {
-
- public MissingKeyException() {
- super("Error: missing key (please use --key)");
- }
-}
diff --git a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/command/url/BaseEncodeOptionHandler.java b/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/command/url/BaseEncodeOptionHandler.java
deleted file mode 100644
index 32baf06f..00000000
--- a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/command/url/BaseEncodeOptionHandler.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package org.springframework.cloud.cli.command.url;
-
-import static java.util.Arrays.asList;
-
-import joptsimple.OptionSpec;
-import org.springframework.boot.cli.command.options.OptionHandler;
-
-
-public class BaseEncodeOptionHandler extends OptionHandler {
- OptionSpec charsetOption;
-
- @Override
- protected final void options() {
- this.charsetOption = option(asList("charset", "c"),
- "Character set (defaults to UTF-8)").withRequiredArg();
- doOptions();
- }
-
- protected void doOptions(){
-
- }
-}
diff --git a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/command/url/UrlDecodeCommand.java b/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/command/url/UrlDecodeCommand.java
deleted file mode 100644
index 5c51c5cd..00000000
--- a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/command/url/UrlDecodeCommand.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2013-2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.cloud.cli.command.url;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URLDecoder;
-import java.net.URLEncoder;
-import java.nio.charset.Charset;
-import java.nio.charset.UnsupportedCharsetException;
-
-import org.springframework.boot.cli.command.OptionParsingCommand;
-import org.springframework.boot.cli.command.options.OptionHandler;
-import org.springframework.boot.cli.command.status.ExitStatus;
-import org.springframework.util.StringUtils;
-
-import joptsimple.OptionSet;
-
-/**
- * @author William Witt
- */
-public class UrlDecodeCommand extends OptionParsingCommand {
-
- public UrlDecodeCommand() {
- super("urlDecode", "URL decodes the subsequent string",
- new UrlDecodeOptionHandler());
- }
-
- @Override
- public String getUsageHelp() {
- return "";
- }
-
- private static class UrlDecodeOptionHandler extends BaseEncodeOptionHandler {
-
- @Override
- protected synchronized ExitStatus run(OptionSet options) throws Exception {
- String charset = "UTF-8";
- if(options.has(charsetOption)){
- charset = options.valueOf(charsetOption);
- }
- String text = StringUtils
- .collectionToDelimitedString(options.nonOptionArguments(), " ");
- try {
- Charset.forName(charset);
- String outText = URLDecoder.decode(text, charset);
- System.out.println(outText);
- return ExitStatus.OK;
- } catch (UnsupportedCharsetException e){
- System.out.println("Unsupported Character Set");
- return ExitStatus.ERROR;
- }
- }
- }
-}
diff --git a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/command/url/UrlEncodeCommand.java b/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/command/url/UrlEncodeCommand.java
deleted file mode 100644
index 836b2fc2..00000000
--- a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/command/url/UrlEncodeCommand.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2013-2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.cloud.cli.command.url;
-
-import joptsimple.OptionSet;
-import org.springframework.boot.cli.command.OptionParsingCommand;
-import org.springframework.boot.cli.command.status.ExitStatus;
-import org.springframework.util.StringUtils;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-import java.nio.charset.Charset;
-import java.nio.charset.UnsupportedCharsetException;
-
-/**
- * @author William Witt
- */
-public class UrlEncodeCommand extends OptionParsingCommand {
-
- public UrlEncodeCommand() {
- super("urlEncode", "URL encodes the subsequent string",
- new UrlEncodeOptionHandler());
- }
-
- @Override
- public String getUsageHelp() {
- return "[options] ";
- }
-
- private static class UrlEncodeOptionHandler extends BaseEncodeOptionHandler{
-
- @Override
- protected synchronized ExitStatus run(OptionSet options) throws Exception {
- String charset = "UTF-8";
- if(options.has(charsetOption)){
- charset = options.valueOf(charsetOption);
- }
- String text = StringUtils
- .collectionToDelimitedString(options.nonOptionArguments(), " ");
- try {
- Charset.forName(charset);
- String outText = URLEncoder.encode(text, charset);
- System.out.println(outText);
- return ExitStatus.OK;
- } catch (UnsupportedCharsetException e){
- System.out.println("Unsupported Character Set");
- return ExitStatus.ERROR;
- }
- }
- }
-}
-
diff --git a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/compiler/BaseStreamCompilerAutoConfiguration.java b/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/compiler/BaseStreamCompilerAutoConfiguration.java
deleted file mode 100644
index 25e08b27..00000000
--- a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/compiler/BaseStreamCompilerAutoConfiguration.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2013-2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.cloud.cli.compiler;
-
-import org.codehaus.groovy.ast.AnnotationNode;
-import org.codehaus.groovy.ast.ClassNode;
-import org.codehaus.groovy.ast.expr.Expression;
-import org.codehaus.groovy.control.CompilationFailedException;
-import org.codehaus.groovy.control.customizers.ImportCustomizer;
-import org.springframework.boot.cli.compiler.AstUtils;
-import org.springframework.boot.cli.compiler.CompilerAutoConfiguration;
-import org.springframework.boot.cli.compiler.autoconfigure.SpringIntegrationCompilerAutoConfiguration;
-import org.springframework.util.PatternMatchUtils;
-import org.springframework.util.SystemPropertyUtils;
-
-/**
- * @author Dave Syer
- *
- */
-public abstract class BaseStreamCompilerAutoConfiguration
- extends CompilerAutoConfiguration {
-
- private SpringIntegrationCompilerAutoConfiguration integration = new SpringIntegrationCompilerAutoConfiguration();
-
- @Override
- public boolean matches(ClassNode classNode) {
- boolean annotated = AstUtils.hasAtLeastOneAnnotation(classNode, "EnableBinding");
- return annotated && isTransport(classNode, getTransport());
- }
-
- protected abstract String getTransport();
-
- static boolean isTransport(ClassNode node, String type) {
- for (AnnotationNode annotationNode : node.getAnnotations()) {
- String annotation = "EnableBinding";
- if (PatternMatchUtils.simpleMatch(annotation,
- annotationNode.getClassNode().getName())) {
- Expression expression = annotationNode.getMembers().get("transport");
- String transport = expression == null ? "rabbit" : expression.getText();
- if (transport != null) {
- transport = SystemPropertyUtils.resolvePlaceholders(transport);
- }
- return transport.equals(type);
- }
- }
- return false;
- }
-
- @Override
- public void applyImports(ImportCustomizer imports) throws CompilationFailedException {
- this.integration.applyImports(imports);
- imports.addImports("org.springframework.boot.groovy.cloud.EnableBinding");
- imports.addImport("IntegrationMessageSource",
- "org.springframework.integration.core.MessageSource");
- imports.addStarImports("org.springframework.cloud.stream.annotation",
- "org.springframework.cloud.stream.messaging");
- }
-
-}
diff --git a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/compiler/ConfigServerCompilerAutoConfiguration.java b/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/compiler/ConfigServerCompilerAutoConfiguration.java
deleted file mode 100644
index acd0d3ff..00000000
--- a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/compiler/ConfigServerCompilerAutoConfiguration.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2013-2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.cloud.cli.compiler;
-
-import org.codehaus.groovy.ast.ClassNode;
-import org.codehaus.groovy.control.CompilationFailedException;
-import org.codehaus.groovy.control.customizers.ImportCustomizer;
-import org.springframework.boot.cli.compiler.AstUtils;
-import org.springframework.boot.cli.compiler.CompilerAutoConfiguration;
-import org.springframework.boot.cli.compiler.DependencyCustomizer;
-
-/**
- * @author Dave Syer
- *
- */
-public class ConfigServerCompilerAutoConfiguration extends CompilerAutoConfiguration {
-
- @Override
- public boolean matches(ClassNode classNode) {
- return AstUtils.hasAtLeastOneAnnotation(classNode, "EnableConfigServer");
- }
-
- @Override
- public void applyDependencies(DependencyCustomizer dependencies) {
- dependencies
- .ifAnyMissingClasses("org.springframework.cloud.config.server.EnableConfigServer")
- .add("spring-cloud-config-server");
- }
-
- @Override
- public void applyImports(ImportCustomizer imports) throws CompilationFailedException {
- imports.addImports("org.springframework.cloud.config.server.EnableConfigServer");
- }
-
-}
diff --git a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/compiler/EurekaClientCompilerAutoConfiguration.java b/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/compiler/EurekaClientCompilerAutoConfiguration.java
deleted file mode 100644
index 0f9b5127..00000000
--- a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/compiler/EurekaClientCompilerAutoConfiguration.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2013-2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.cloud.cli.compiler;
-
-import org.codehaus.groovy.ast.ClassNode;
-import org.codehaus.groovy.control.CompilationFailedException;
-import org.codehaus.groovy.control.customizers.ImportCustomizer;
-import org.springframework.boot.cli.compiler.AstUtils;
-import org.springframework.boot.cli.compiler.CompilerAutoConfiguration;
-import org.springframework.boot.cli.compiler.DependencyCustomizer;
-
-/**
- * @author Dave Syer
- *
- */
-public class EurekaClientCompilerAutoConfiguration extends CompilerAutoConfiguration {
-
- @Override
- public boolean matches(ClassNode classNode) {
- return AstUtils.hasAtLeastOneAnnotation(classNode, "EnableDiscoveryClient");
- }
-
- @Override
- public void applyDependencies(DependencyCustomizer dependencies) {
- dependencies.ifAnyMissingClasses(
- "org.springframework.cloud.client.discovery.EnableDiscoveryClient").add(
- "spring-cloud-starter-netflix-eureka-client");
- }
-
- @Override
- public void applyImports(ImportCustomizer imports) throws CompilationFailedException {
- imports.addImports(
- "org.springframework.cloud.client.discovery.EnableDiscoveryClient",
- "org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean",
- "org.springframework.cloud.netflix.eureka.EurekaClientConfigBean",
- "org.springframework.cloud.client.discovery.DiscoveryClient",
- "org.springframework.cloud.client.ServiceInstance");
- }
-
-}
diff --git a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/compiler/EurekaServerCompilerAutoConfiguration.java b/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/compiler/EurekaServerCompilerAutoConfiguration.java
deleted file mode 100644
index 7beb7d72..00000000
--- a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/compiler/EurekaServerCompilerAutoConfiguration.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2013-2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.cloud.cli.compiler;
-
-import org.codehaus.groovy.ast.ClassNode;
-import org.codehaus.groovy.control.CompilationFailedException;
-import org.codehaus.groovy.control.customizers.ImportCustomizer;
-import org.springframework.boot.cli.compiler.AstUtils;
-import org.springframework.boot.cli.compiler.CompilerAutoConfiguration;
-import org.springframework.boot.cli.compiler.DependencyCustomizer;
-
-/**
- * @author Dave Syer
- *
- */
-public class EurekaServerCompilerAutoConfiguration extends CompilerAutoConfiguration {
-
- @Override
- public boolean matches(ClassNode classNode) {
- return AstUtils.hasAtLeastOneAnnotation(classNode, "EnableEurekaServer");
- }
-
- @Override
- public void applyDependencies(DependencyCustomizer dependencies) {
- dependencies.ifAnyMissingClasses(
- "org.springframework.cloud.netflix.eureka.server.EnableEurekaServer")
- .add("spring-cloud-starter-netflix-eureka-server");
- if (JavaVersion.current().isJava11Compatible()) {
- dependencies.add("jaxb-api")
- .add("javax.activation-api")
- .add("jaxb-runtime");
- }
- }
-
- @Override
- public void applyImports(ImportCustomizer imports) throws CompilationFailedException {
- imports.addImports("org.springframework.cloud.netflix.eureka.server.EnableEurekaServer",
- "org.springframework.cloud.client.discovery.EnableDiscoveryClient",
- "org.springframework.cloud.netflix.eureka.server.EurekaServerConfigBean",
- "org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean",
- "org.springframework.cloud.netflix.eureka.EurekaClientConfigBean",
- "com.netflix.discovery.DiscoveryClient",
- "com.netflix.appinfo.InstanceInfo");
- }
-
-}
diff --git a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/compiler/JavaVersion.java b/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/compiler/JavaVersion.java
deleted file mode 100644
index c63d9f38..00000000
--- a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/compiler/JavaVersion.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright 2013-2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.cloud.cli.compiler;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * TAKEN FROM GRADLE (https://github.com/gradle/gradle/blob/master/subprojects/base-services/src/main/java/org/gradle/api/JavaVersion.java)
- *
- * An enumeration of Java versions.
- * Before 9: https://www.oracle.com/technetwork/java/javase/versioning-naming-139433.html
- * 9+: https://openjdk.java.net/jeps/223
- */
-enum JavaVersion {
- VERSION_1_1, VERSION_1_2, VERSION_1_3, VERSION_1_4,
- VERSION_1_5, VERSION_1_6, VERSION_1_7, VERSION_1_8,
- VERSION_1_9, VERSION_1_10,
- /**
- * Java 11 major version.
- *
- * @since 4.7
- */
- VERSION_11,
-
- /**
- * Java 12 major version.
- *
- * @since 5.0
- */
- VERSION_12,
-
- /**
- * Higher version of Java.
- * @since 4.7
- */
- VERSION_HIGHER;
- // Since Java 9, version should be X instead of 1.X
- // However, to keep backward compatibility, we change from 11
- private static final int FIRST_MAJOR_VERSION_ORDINAL = 10;
- private static JavaVersion currentJavaVersion;
- private final String versionName;
-
- JavaVersion() {
- this.versionName = ordinal() >= FIRST_MAJOR_VERSION_ORDINAL ? getMajorVersion() : "1." + getMajorVersion();
- }
-
- /**
- * Converts the given object into a {@code JavaVersion}.
- *
- * @param value An object whose toString() value is to be converted. May be null.
- * @return The version, or null if the provided value is null.
- * @throws IllegalArgumentException when the provided value cannot be converted.
- */
- public static JavaVersion toVersion(Object value) throws IllegalArgumentException {
- if (value == null) {
- return null;
- }
- if (value instanceof JavaVersion) {
- return (JavaVersion) value;
- }
- String name = value.toString();
- int firstNonVersionCharIndex = findFirstNonVersionCharIndex(name);
- String[] versionStrings = name.substring(0, firstNonVersionCharIndex)
- .split("\\.");
- List versions = convertToNumber(name, versionStrings);
- if (isLegacyVersion(versions)) {
- assertTrue(name, versions.get(1) > 0);
- return getVersionForMajor(versions.get(1));
- }
- else {
- return getVersionForMajor(versions.get(0));
- }
- }
-
- /**
- * Returns the version of the current JVM.
- *
- * @return The version of the current JVM.
- */
- public static JavaVersion current() {
- if (currentJavaVersion == null) {
- currentJavaVersion = toVersion(System.getProperty("java.version"));
- }
- return currentJavaVersion;
- }
-
- private static JavaVersion getVersionForMajor(int major) {
- return major >= values().length ? JavaVersion.VERSION_HIGHER : values()[major - 1];
- }
-
- private static void assertTrue(String value, boolean condition) {
- if (!condition) {
- throw new IllegalArgumentException("Could not determine java version from '" + value + "'.");
- }
- }
-
- private static boolean isLegacyVersion(List versions) {
- return 1 == versions.get(0) && versions.size() > 1;
- }
-
- private static List convertToNumber(String value, String[] versionStrs) {
- List result = new ArrayList();
- for (String s : versionStrs) {
- assertTrue(value, !isNumberStartingWithZero(s));
- try {
- result.add(Integer.parseInt(s));
- }
- catch (NumberFormatException e) {
- assertTrue(value, false);
- }
- }
- assertTrue(value, !result.isEmpty() && result.get(0) > 0);
- return result;
- }
-
- private static boolean isNumberStartingWithZero(String number) {
- return number.length() > 1 && number.startsWith("0");
- }
-
- private static int findFirstNonVersionCharIndex(String s) {
- assertTrue(s, s.length() != 0);
-
- for (int i = 0; i < s.length(); ++i) {
- if (!isDigitOrPeriod(s.charAt(i))) {
- assertTrue(s, i != 0);
- return i;
- }
- }
-
- return s.length();
- }
-
- private static boolean isDigitOrPeriod(char c) {
- return (c >= '0' && c <= '9') || c == '.';
- }
-
- /**
- * Returns if the version is Java 11 compatible.
- *
- * @since 4.7
- */
- public boolean isJava11Compatible() {
- return this.compareTo(VERSION_11) >= 0;
- }
-
- @Override
- public String toString() {
- return this.versionName;
- }
-
-
- public String getMajorVersion() {
- return String.valueOf(ordinal() + 1);
- }
-}
\ No newline at end of file
diff --git a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/compiler/OAuth2LoadBalancedCompilerAutoConfiguration.java b/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/compiler/OAuth2LoadBalancedCompilerAutoConfiguration.java
deleted file mode 100644
index 7ab828cb..00000000
--- a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/compiler/OAuth2LoadBalancedCompilerAutoConfiguration.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2013-2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.cloud.cli.compiler;
-
-import org.codehaus.groovy.ast.ClassNode;
-import org.springframework.boot.cli.compiler.AstUtils;
-import org.springframework.boot.cli.compiler.CompilerAutoConfiguration;
-import org.springframework.boot.cli.compiler.DependencyCustomizer;
-
-/**
- * @author Dave Syer
- *
- */
-public class OAuth2LoadBalancedCompilerAutoConfiguration extends CompilerAutoConfiguration {
-
- @Override
- public boolean matches(ClassNode classNode) {
- return AstUtils.hasAtLeastOneAnnotation(classNode, "EnableOAuth2Sso");
- }
-
- @Override
- public void applyDependencies(DependencyCustomizer dependencies) {
- dependencies
- .ifAnyMissingClasses(
- "org.springframework.cloud.security.oauth2.client.OAuth2LoadBalancerClientAutoConfiguration")
- .add("spring-cloud-starter-oauth2");
- }
-
-}
diff --git a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/compiler/SpringCloudBomAstTransformation.java b/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/compiler/SpringCloudBomAstTransformation.java
deleted file mode 100644
index 0cb3c914..00000000
--- a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/compiler/SpringCloudBomAstTransformation.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.cli.compiler;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
-
-import org.codehaus.groovy.control.CompilePhase;
-import org.codehaus.groovy.transform.GroovyASTTransformation;
-import org.springframework.boot.cli.compiler.DependencyManagementBomTransformation;
-import org.springframework.boot.cli.compiler.GenericBomAstTransformation;
-import org.springframework.core.io.ClassPathResource;
-import org.springframework.util.ReflectionUtils;
-import org.springframework.util.StreamUtils;
-import org.springframework.util.StringUtils;
-
-/**
- * @author Dave Syer
- *
- */
-@GroovyASTTransformation(phase = CompilePhase.CONVERSION)
-public class SpringCloudBomAstTransformation extends GenericBomAstTransformation {
-
- @Override
- protected String getBomModule() {
- return "org.springframework.cloud:spring-cloud-starter-parent:" + getBomVersion();
- }
-
- @Override
- public int getOrder() {
- return DependencyManagementBomTransformation.ORDER - 50;
- }
-
- String getBomVersion() {
- try (InputStream in = new ClassPathResource("META-INF/springcloudbom-version.txt").getInputStream()) {
- String version = StreamUtils.copyToString(in, StandardCharsets.UTF_8);
- if (StringUtils.hasText(version)) {
- version = version.trim();
- }
- return version;
- }
- catch (IOException e) {
- ReflectionUtils.rethrowRuntimeException(e);
- }
- // not reachable since exception rethrown at runtime
- return null;
- }
-
-}
diff --git a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/compiler/SpringCloudCompilerAutoConfiguration.java b/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/compiler/SpringCloudCompilerAutoConfiguration.java
deleted file mode 100644
index 0fb1486f..00000000
--- a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/compiler/SpringCloudCompilerAutoConfiguration.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2013-2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.cloud.cli.compiler;
-
-import org.codehaus.groovy.control.CompilationFailedException;
-import org.codehaus.groovy.control.customizers.ImportCustomizer;
-import org.springframework.boot.cli.compiler.CompilerAutoConfiguration;
-import org.springframework.boot.cli.compiler.DependencyCustomizer;
-
-/**
- * @author Dave Syer
- *
- */
-public class SpringCloudCompilerAutoConfiguration extends
- CompilerAutoConfiguration {
-
- @Override
- public void applyDependencies(DependencyCustomizer dependencies) {
- dependencies
- .ifAnyMissingClasses(
- "org.springframework.boot.actuate.endpoint.EnvironmentEndpoint")
- .add("spring-boot-starter-actuator");
- dependencies.ifAnyMissingClasses(
- "org.springframework.cloud.config.Environment").add(
- "spring-cloud-starter-config");
- }
-
- @Override
- public void applyImports(ImportCustomizer imports)
- throws CompilationFailedException {
- imports.addImports("org.springframework.cloud.context.config.annotation.RefreshScope");
- }
-
-}
diff --git a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/compiler/StreamKafkaCompilerAutoConfiguration.java b/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/compiler/StreamKafkaCompilerAutoConfiguration.java
deleted file mode 100644
index 056661db..00000000
--- a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/compiler/StreamKafkaCompilerAutoConfiguration.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2013-2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.cloud.cli.compiler;
-
-import org.springframework.boot.cli.compiler.DependencyCustomizer;
-
-/**
- * @author Dave Syer
- *
- */
-public class StreamKafkaCompilerAutoConfiguration
- extends BaseStreamCompilerAutoConfiguration {
-
- @Override
- protected String getTransport() {
- return "kafka";
- }
-
- @Override
- public void applyDependencies(DependencyCustomizer dependencies) {
- dependencies
- .ifAnyMissingClasses(
- "org.springframework.cloud.stream.binder.kafka.config.KafkaServiceAutoConfiguration")
- .add("spring-cloud-starter-stream-kafka");
- }
-
-}
diff --git a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/compiler/StreamRabbitCompilerAutoConfiguration.java b/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/compiler/StreamRabbitCompilerAutoConfiguration.java
deleted file mode 100644
index 7bb8220a..00000000
--- a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/compiler/StreamRabbitCompilerAutoConfiguration.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2013-2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.cloud.cli.compiler;
-
-import org.springframework.boot.cli.compiler.DependencyCustomizer;
-
-/**
- * @author Dave Syer
- *
- */
-public class StreamRabbitCompilerAutoConfiguration
- extends BaseStreamCompilerAutoConfiguration {
-
- @Override
- protected String getTransport() {
- return "rabbit";
- }
-
- @Override
- public void applyDependencies(DependencyCustomizer dependencies) {
- dependencies
- .ifAnyMissingClasses(
- "org.springframework.cloud.stream.binder.rabbit.config.RabbitServiceAutoConfiguration")
- .add("spring-cloud-starter-stream-rabbit");
- }
-
-}
diff --git a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/compiler/StubRunnerCompilerAutoConfiguration.java b/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/compiler/StubRunnerCompilerAutoConfiguration.java
deleted file mode 100644
index 2b45111f..00000000
--- a/spring-cloud-cli/src/main/java/org/springframework/cloud/cli/compiler/StubRunnerCompilerAutoConfiguration.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2013-2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.cloud.cli.compiler;
-
-import org.codehaus.groovy.ast.ClassNode;
-import org.codehaus.groovy.control.CompilationFailedException;
-import org.codehaus.groovy.control.customizers.ImportCustomizer;
-import org.springframework.boot.cli.compiler.AstUtils;
-import org.springframework.boot.cli.compiler.CompilerAutoConfiguration;
-import org.springframework.boot.cli.compiler.DependencyCustomizer;
-
-/**
- * @author Marcin Grzejszczak
- *
- */
-public class StubRunnerCompilerAutoConfiguration extends CompilerAutoConfiguration {
-
- @Override
- public boolean matches(ClassNode classNode) {
- return AstUtils.hasAtLeastOneAnnotation(classNode, "EnableStubRunnerServer");
- }
-
- @Override
- public void applyDependencies(DependencyCustomizer dependencies) {
- dependencies
- .ifAnyMissingClasses("org.springframework.cloud.contract.stubrunner.server.EnableStubRunnerServer")
- .add("spring-cloud-contract-stub-runner-boot");
- }
-
- @Override
- public void applyImports(ImportCustomizer imports) throws CompilationFailedException {
- imports.addImports("org.springframework.cloud.contract.stubrunner.server.EnableStubRunnerServer");
- }
-
-}
diff --git a/spring-cloud-cli/src/main/resources/META-INF/services/org.springframework.boot.cli.command.CommandFactory b/spring-cloud-cli/src/main/resources/META-INF/services/org.springframework.boot.cli.command.CommandFactory
deleted file mode 100644
index d7b5678a..00000000
--- a/spring-cloud-cli/src/main/resources/META-INF/services/org.springframework.boot.cli.command.CommandFactory
+++ /dev/null
@@ -1 +0,0 @@
-org.springframework.cloud.cli.command.CloudCommandFactory
diff --git a/spring-cloud-cli/src/main/resources/META-INF/services/org.springframework.boot.cli.compiler.CompilerAutoConfiguration b/spring-cloud-cli/src/main/resources/META-INF/services/org.springframework.boot.cli.compiler.CompilerAutoConfiguration
deleted file mode 100644
index 523c8347..00000000
--- a/spring-cloud-cli/src/main/resources/META-INF/services/org.springframework.boot.cli.compiler.CompilerAutoConfiguration
+++ /dev/null
@@ -1,8 +0,0 @@
-org.springframework.cloud.cli.compiler.SpringCloudCompilerAutoConfiguration
-org.springframework.cloud.cli.compiler.ConfigServerCompilerAutoConfiguration
-org.springframework.cloud.cli.compiler.EurekaClientCompilerAutoConfiguration
-org.springframework.cloud.cli.compiler.EurekaServerCompilerAutoConfiguration
-org.springframework.cloud.cli.compiler.OAuth2LoadBalancedCompilerAutoConfiguration
-org.springframework.cloud.cli.compiler.StreamKafkaCompilerAutoConfiguration
-org.springframework.cloud.cli.compiler.StreamRabbitCompilerAutoConfiguration
-org.springframework.cloud.cli.compiler.StubRunnerCompilerAutoConfiguration
diff --git a/spring-cloud-cli/src/main/resources/META-INF/services/org.springframework.boot.cli.compiler.SpringBootAstTransformation b/spring-cloud-cli/src/main/resources/META-INF/services/org.springframework.boot.cli.compiler.SpringBootAstTransformation
deleted file mode 100644
index accdfbad..00000000
--- a/spring-cloud-cli/src/main/resources/META-INF/services/org.springframework.boot.cli.compiler.SpringBootAstTransformation
+++ /dev/null
@@ -1 +0,0 @@
-org.springframework.cloud.cli.compiler.SpringCloudBomAstTransformation
\ No newline at end of file
diff --git a/spring-cloud-cli/src/main/resources/META-INF/springcloudbom-version.txt b/spring-cloud-cli/src/main/resources/META-INF/springcloudbom-version.txt
deleted file mode 100644
index dcbc4223..00000000
--- a/spring-cloud-cli/src/main/resources/META-INF/springcloudbom-version.txt
+++ /dev/null
@@ -1 +0,0 @@
-@spring-cloud.version@
diff --git a/spring-cloud-cli/src/test/java/org/springframework/cloud/cli/command/encrypt/DecryptCommandTests.java b/spring-cloud-cli/src/test/java/org/springframework/cloud/cli/command/encrypt/DecryptCommandTests.java
deleted file mode 100644
index f914dbab..00000000
--- a/spring-cloud-cli/src/test/java/org/springframework/cloud/cli/command/encrypt/DecryptCommandTests.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright 2013-2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.cloud.cli.command.encrypt;
-
-import java.nio.charset.Charset;
-
-import org.junit.Test;
-
-import org.springframework.boot.cli.command.status.ExitStatus;
-import org.springframework.core.io.ClassPathResource;
-import org.springframework.security.rsa.crypto.KeyStoreKeyFactory;
-import org.springframework.security.rsa.crypto.RsaSecretEncryptor;
-import org.springframework.util.StreamUtils;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * @author Dave Syer
- *
- */
-public class DecryptCommandTests {
-
- private DecryptCommand command = new DecryptCommand();
-
- @Test
- public void decryptsFromSymmetricKey() throws Exception {
- assertEquals(ExitStatus.OK, command.run("-k", "deadbeef",
- "68b7f624de187e79cebfdc9e2e869189b981d7e976385839506de265bb892a5d"));
- }
-
- @Test
- public void decryptsFromRsaKey() throws Exception {
- RsaSecretEncryptor encryptor = new RsaSecretEncryptor(StreamUtils
- .copyToString(new ClassPathResource("private.pem").getInputStream(),
- Charset.forName("UTF-8"))
- .replaceAll("\n", ""));
- String cipher = encryptor.encrypt("foo");
- assertEquals(ExitStatus.OK,
- command.run("-k", "@src/test/resources/private.pem", cipher));
- }
-
- @Test
- public void decryptsFromRsaKeyWithKeyStore() throws Exception {
- KeyStoreKeyFactory factory = new KeyStoreKeyFactory(
- new ClassPathResource("keystore.jks"), "letmein".toCharArray());
- RsaSecretEncryptor encryptor = new RsaSecretEncryptor(
- factory.getKeyPair("mytestkey", "changeme".toCharArray()));
- String cipher = encryptor.encrypt("foo");
- assertEquals(ExitStatus.OK,
- command.run("-k", "src/test/resources/keystore.jks", "--password",
- "letmein", "--keypass", "changeme", "--alias", "mytestkey",
- cipher));
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void failsWithPlainText() throws Exception {
- assertEquals(ExitStatus.OK, command.run("-k", "deadbeef", "foo"));
- }
-
- @Test(expected = IllegalStateException.class)
- public void failsWithBadFile() throws Exception {
- assertEquals(ExitStatus.OK, command.run("-k", "@nosuchfile", "foo"));
- }
-
-}
diff --git a/spring-cloud-cli/src/test/java/org/springframework/cloud/cli/command/encrypt/EncryptCommandTests.java b/spring-cloud-cli/src/test/java/org/springframework/cloud/cli/command/encrypt/EncryptCommandTests.java
deleted file mode 100644
index dae95ac8..00000000
--- a/spring-cloud-cli/src/test/java/org/springframework/cloud/cli/command/encrypt/EncryptCommandTests.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2013-2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.cloud.cli.command.encrypt;
-
-import static org.junit.Assert.*;
-
-import org.junit.Test;
-import org.springframework.boot.cli.command.status.ExitStatus;
-
-
-/**
- * @author Dave Syer
- *
- */
-public class EncryptCommandTests {
-
- private EncryptCommand command = new EncryptCommand();
-
- @Test
- public void encryptsFromSymmetricKey() throws Exception {
- assertEquals(ExitStatus.OK, command.run("-k", "deadbeef", "foo"));
- }
-
- @Test(expected=MissingKeyException.class)
- public void errorOnNoKey() throws Exception {
- assertEquals(ExitStatus.ERROR, command.run("foo"));
- }
-
- @Test(expected=IllegalStateException.class)
- public void failsWithBadFile() throws Exception {
- assertEquals(ExitStatus.OK, command.run("-k", "@nosuchfile", "foo"));
- }
-
-}
diff --git a/spring-cloud-cli/src/test/java/org/springframework/cloud/cli/command/url/OutputCapture.java b/spring-cloud-cli/src/test/java/org/springframework/cloud/cli/command/url/OutputCapture.java
deleted file mode 100644
index fcb141ee..00000000
--- a/spring-cloud-cli/src/test/java/org/springframework/cloud/cli/command/url/OutputCapture.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright 2012-2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.cli.command.url;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.PrintStream;
-
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-/**
- * Capture output from System.out and System.err.
- *
- * @author Phillip Webb
- */
-public class OutputCapture implements TestRule {
-
- private CaptureOutputStream captureOut;
-
- private CaptureOutputStream captureErr;
-
- private ByteArrayOutputStream copy;
-
- @Override
- public Statement apply(final Statement base, Description description) {
- return new Statement() {
- @Override
- public void evaluate() throws Throwable {
- captureOutput();
- try {
- base.evaluate();
- }
- finally {
- releaseOutput();
- }
- }
- };
- }
-
- protected void captureOutput() {
- this.copy = new ByteArrayOutputStream();
- this.captureOut = new CaptureOutputStream(System.out, this.copy);
- this.captureErr = new CaptureOutputStream(System.err, this.copy);
- System.setOut(new PrintStream(this.captureOut));
- System.setErr(new PrintStream(this.captureErr));
- }
-
- protected void releaseOutput() {
- System.setOut(this.captureOut.getOriginal());
- System.setErr(this.captureErr.getOriginal());
- this.copy = null;
- }
-
- public void flush() {
- try {
- this.captureOut.flush();
- this.captureErr.flush();
- }
- catch (IOException ex) {
- // ignore
- }
- }
-
- @Override
- public String toString() {
- flush();
- return this.copy.toString();
- }
-
- private static class CaptureOutputStream extends OutputStream {
-
- private final PrintStream original;
-
- private final OutputStream copy;
-
- CaptureOutputStream(PrintStream original, OutputStream copy) {
- this.original = original;
- this.copy = copy;
- }
-
- @Override
- public void write(int b) throws IOException {
- this.copy.write(b);
- this.original.write(b);
- this.original.flush();
- }
-
- @Override
- public void write(byte[] b) throws IOException {
- write(b, 0, b.length);
- }
-
- @Override
- public void write(byte[] b, int off, int len) throws IOException {
- this.copy.write(b, off, len);
- this.original.write(b, off, len);
- }
-
- public PrintStream getOriginal() {
- return this.original;
- }
-
- @Override
- public void flush() throws IOException {
- this.copy.flush();
- this.original.flush();
- }
- }
-
-}
diff --git a/spring-cloud-cli/src/test/java/org/springframework/cloud/cli/command/url/UrlDecodeCommandTest.java b/spring-cloud-cli/src/test/java/org/springframework/cloud/cli/command/url/UrlDecodeCommandTest.java
deleted file mode 100644
index 3cdb7498..00000000
--- a/spring-cloud-cli/src/test/java/org/springframework/cloud/cli/command/url/UrlDecodeCommandTest.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2013-2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.cloud.cli.command.url;
-
-import org.junit.Rule;
-import org.junit.Test;
-
-import org.springframework.boot.cli.command.Command;
-import org.springframework.boot.cli.command.status.ExitStatus;
-import org.springframework.boot.test.system.OutputCaptureRule;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * @author William Witt
- */
-public class UrlDecodeCommandTest {
- Command command = new UrlDecodeCommand();
-
- @Rule
- public OutputCaptureRule capture = new OutputCaptureRule();
-
- @Test
- public void urlDecodeNoSpecialChars() throws Exception {
- command.run("abcdefg");
- assertEquals("abcdefg\n", capture.toString());
- }
-
- @Test
- public void urlDecodeSpecialChars() throws Exception {
- command.run("a+b+c%26d%25efg%2B");
- assertEquals("a b c&d%efg+\n", capture.toString());
- }
-
- @Test
- public void urlDecodeNoSpecialCharsWithCharset() throws Exception {
- command.run("-c", "UTF-8", "abcdefg");
- assertEquals("abcdefg\n", capture.toString());
- }
-
- @Test
- public void urlDecodeSpecialCharsWithCharset() throws Exception {
- command.run("-c", "UTF-8", "a+b+c%26d%25efg%2B");
- assertEquals("a b c&d%efg+\n", capture.toString());
- }
-
- @Test
- public void urlDecodeNoSpecialCharsWithUnsupportedCharset() throws Exception {
- assertEquals(ExitStatus.ERROR, command.run("-c", "UTF-9", "abcdefg"));
- }
-
- @Test
- public void urlDecodeSpecialCharsWithUnsupportedCharset() throws Exception {
- assertEquals(ExitStatus.ERROR, command.run("-c", "UTF-9", "a b c&d%efg+"));
- }
-}
\ No newline at end of file
diff --git a/spring-cloud-cli/src/test/java/org/springframework/cloud/cli/command/url/UrlEncodeCommandTest.java b/spring-cloud-cli/src/test/java/org/springframework/cloud/cli/command/url/UrlEncodeCommandTest.java
deleted file mode 100644
index 0adeefae..00000000
--- a/spring-cloud-cli/src/test/java/org/springframework/cloud/cli/command/url/UrlEncodeCommandTest.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2013-2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.cloud.cli.command.url;
-
-import org.junit.Rule;
-import org.junit.Test;
-
-import org.springframework.boot.cli.command.Command;
-import org.springframework.boot.cli.command.status.ExitStatus;
-import org.springframework.boot.test.system.OutputCaptureRule;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * @author William Witt
- */
-public class UrlEncodeCommandTest {
- Command command = new UrlEncodeCommand();
-
- @Rule
- public OutputCaptureRule capture = new OutputCaptureRule();
-
- @Test
- public void urlEncodeNoSpecialChars() throws Exception {
- command.run("abcdefg");
- assertEquals("abcdefg\n", capture.toString());
- }
-
- @Test
- public void urlEncodeSpecialChars() throws Exception {
- command.run("a b c&d%efg+");
- assertEquals("a+b+c%26d%25efg%2B\n", capture.toString());
- }
-
- @Test
- public void urlEncodeNoSpecialCharsWithCharset() throws Exception {
- command.run("-c", "UTF-8", "abcdefg");
- assertEquals("abcdefg\n", capture.toString());
- }
-
- @Test
- public void urlEncodeSpecialCharsWithCharset() throws Exception {
- command.run("-c", "UTF-8", "a b c&d%efg+");
- assertEquals("a+b+c%26d%25efg%2B\n", capture.toString());
- }
-
- @Test
- public void urlEncodeNoSpecialCharsWithUnsupportedCharset() throws Exception {
- assertEquals(ExitStatus.ERROR, command.run("-c", "UTF-9", "abcdefg"));
- }
-
- @Test
- public void urlEncodeSpecialCharsWithUnsupportedCharset() throws Exception {
- assertEquals(ExitStatus.ERROR, command.run("-c", "UTF-9", "a b c&d%efg+"));
- }
-}
\ No newline at end of file
diff --git a/spring-cloud-cli/src/test/java/org/springframework/cloud/cli/compiler/SpringCloudBomAstTransformationTests.java b/spring-cloud-cli/src/test/java/org/springframework/cloud/cli/compiler/SpringCloudBomAstTransformationTests.java
deleted file mode 100644
index 69e8863e..00000000
--- a/spring-cloud-cli/src/test/java/org/springframework/cloud/cli/compiler/SpringCloudBomAstTransformationTests.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package org.springframework.cloud.cli.compiler;
-
-import org.junit.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class SpringCloudBomAstTransformationTests {
-
- @Test
- public void defaultVersionReadFromFile() {
- String version = new SpringCloudBomAstTransformation().getBomVersion();
- // starts with one or more digits then a .
- assertThat(version).isNotBlank().doesNotContainAnyWhitespaces().containsPattern("^\\d+\\..*");
- }
-}
diff --git a/spring-cloud-cli/src/test/resources/application.yml b/spring-cloud-cli/src/test/resources/application.yml
deleted file mode 100644
index e2fc82cb..00000000
--- a/spring-cloud-cli/src/test/resources/application.yml
+++ /dev/null
@@ -1,15 +0,0 @@
-debug: true
-spring:
- application:
- name: eureka
-management:
- context-path: /admin
-eureka:
- server:
- waitTimeInMsWhenSyncEmpty: 1000
- client:
- serviceUrl:
- defaultZone: http://localhost:8080/eureka/
- default.defaultZone: http://localhost:8080/eureka/
- registerWithEureka: false
- fetchRegistry: false
\ No newline at end of file
diff --git a/spring-cloud-cli/src/test/resources/keystore.jks b/spring-cloud-cli/src/test/resources/keystore.jks
deleted file mode 100644
index 8cd9b5a1..00000000
Binary files a/spring-cloud-cli/src/test/resources/keystore.jks and /dev/null differ
diff --git a/spring-cloud-cli/src/test/resources/private.pem b/spring-cloud-cli/src/test/resources/private.pem
deleted file mode 100644
index 16f1630f..00000000
--- a/spring-cloud-cli/src/test/resources/private.pem
+++ /dev/null
@@ -1,15 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIICXAIBAAKBgQDQ835BXnZ7WU6SJd39rpl/qjm97W+i2K2fSMBzbCtbC3Z733tc
-TJH20nb0n97V6/ItKx0YcI3McHVH0PcqlxVRMO78RtvBuSOJZfddNaafKAEm7YFW
-FWs2OVGRj497T+/QpSlV9zAbtHUusJWHdu6mSaPMhJwY5Gm0kMUBQnMZuQIDAQAB
-AoGAEkTXyxtZPJuoVPrel+mGHjVh6wsxcYmEVKLlwLG6cLFl4Jq/jGhdcrkgEW9Q
-6l9Aw1Y7qwFcRH2oo2jP03d2M4SMcJeAf5nC9lnNmXnEXurJvjNDuP6GihTQBMFZ
-R35IXKRjwPDobG76INySu3dbpdCj3HZIozdgpGIS4uKL/WkCQQD3gsmdvfOcsXtz
-t/BswnuZoeqOJjoHr+6Sr5AWI1FXitTeAWvupKBbLscpGdk8/AsfK9E96xCPk1N3
-ws+AG/NvAkEA2B4kAlUnz6pA2BG1MKNqc6Am+MfXmOCDdTcoSEav17KAb3tPx0FY
-4n+CTd4lsGG13rXxtXETxKA9xVD2RkcRVwJABIofjIcZWrxemUa8YCJJBg5UMPs+
-gTmW1JXnvKA1M7fWI6Q/CId4cXOwL27L7zRoN9Aj7FDNYvS+ySmHiL/6fQJBANZN
-1RFHFeoz/ocD0DNB6L5tchfCO0VKZLDoGBbLmXT/eaKSmcKRRy2amUDT53Wm/qyw
-qNVuItcYuwgdx4ha0pMCQDZfzYIH//t0K+jW5N7+pdLP1KsnSuHZOPn3uQaSXhWr
-5JupxP9s5r6DMztLpcFHN/fQRCYVg+5KOCWDgZYTamE=
------END RSA PRIVATE KEY-----
diff --git a/spring-cloud-launcher/README.md b/spring-cloud-launcher/README.md
deleted file mode 100644
index 2a90e586..00000000
--- a/spring-cloud-launcher/README.md
+++ /dev/null
@@ -1,74 +0,0 @@
-## Spring Cloud Launcher
-
-### Building
-
-`./mvnw clean install` from parent directory
-
-### Installing
-
-[Install Spring CLI first](../docs/src/main/asciidoc/install.adoc)
-
-### Running
-
-```
-$ spring cloud
-```
-
-Currently starts configserver, dataflow, eureka, h2 (db server) and kafka. [Here](spring-cloud-launcher-deployer/src/main/resources/cloud.yml) is the full configuration.
-
-### Configuring
-
-Spring Cloud Launcher uses normal Spring Boot configuration mechanisms. The config name is `cloud`, so configuration can go in `cloud.yml` or `cloud.properties`.
-
-For example, to run configserver and eureka, create a `cloud.yml` that looks like:
-```yaml
-spring:
- cloud:
- launcher:
- deployables:
- - name: configserver
- coordinates: maven://org.springframework.cloud.launcher:spring-cloud-launcher-configserver:1.2.1.RELEASE
- port: 8888
- waitUntilStarted: true
- order: -10
- - name: eureka
- coordinates: maven://org.springframework.cloud.launcher:spring-cloud-launcher-eureka:1.2.1.RELEASE
- port: 8761
-```
-
-The `name` attribute is required. If `waitUntilStarted` is true, Launcher will block until the application has reached the `deployed` state. Before commands are deployed, the list is sorted using Spring's `OrderComparator`. In the above case, `configserver` is deployed before any other app is deployed. Currently only `maven:` coordinates and standard Spring Resources (`file:`, etc...) are supported.
-
-You can also select from the [predefined deployables](spring-cloud-launcher-deployer/src/main/resources/cloud.yml). For example to run Spring Cloud Data Flow execute:
-```
-spring cloud dataflow
-```
-
-### Config Server git uri
-
-To run configserver with a git repo set the following in `./configserver.yml`:
-```yaml
-spring:
- profiles.active: git
- cloud.config.server.git.uri: https://mygitserver/myrepo.git
-```
-
-### Stopping
-
-`Ctrl-C` in the same terminal `spring cloud` was run.
-
-### TODO
-
-- [X] Eureka
-- [X] Configserver
-- [X] Kafka Broker
-- [X] Kafka Bus
-- [X] Easy inclusion of default deployables
-- [X] H2 Database
-- [X] Spring Cloud Dataflow server
-- [X] Launcher landing page (Eureka Dashboard works for now)
-- [X] Sleuth/Zipkin
-- [ ] Support external rabbit
-- [ ] Speedup startup (parallel start?, retry for config server, db and kafka?)
-- [ ] Cassandra Database
-- [ ] Client Side Library
-- [ ] Spring Boot Admin (Not compatible with Brixton)
diff --git a/spring-cloud-launcher/pom.xml b/spring-cloud-launcher/pom.xml
deleted file mode 100644
index 988bc5ec..00000000
--- a/spring-cloud-launcher/pom.xml
+++ /dev/null
@@ -1,63 +0,0 @@
-
-
- 4.0.0
-
- org.springframework.cloud
- spring-cloud-launcher
- 3.1.2-SNAPSHOT
- pom
-
- spring-cloud-launcher
- Spring Cloud Launcher
-
-
- org.springframework.cloud
- spring-cloud-cli-parent
- 3.1.2-SNAPSHOT
-
-
-
- 1.0.27.RELEASE
-
-
-
- spring-cloud-launcher-deployer
- spring-cloud-launcher-cli
- spring-cloud-launcher-configserver
-
-
- spring-cloud-launcher-eureka
- spring-cloud-launcher-h2
-
- spring-cloud-launcher-stubrunner
-
-
-
-
- org.springframework.boot
- spring-boot-configuration-processor
- true
- provided
-
-
-
-
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
- org.springframework.boot.experimental
- spring-boot-thin-layout
- ${thin-jar.version}
-
-
-
-
-
-
-
-
diff --git a/spring-cloud-launcher/spring-cloud-launcher-cli/pom.xml b/spring-cloud-launcher/spring-cloud-launcher-cli/pom.xml
deleted file mode 100644
index 865aa5ae..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-cli/pom.xml
+++ /dev/null
@@ -1,99 +0,0 @@
-
-
- 4.0.0
-
- org.springframework.cloud.launcher
- spring-cloud-launcher-cli
- jar
-
- spring-cloud-launcher-cli
- Spring Cloud Launcher CLI
-
-
- org.springframework.cloud
- spring-cloud-launcher
- 3.1.2-SNAPSHOT
-
-
-
- 3.6.3
-
-
-
-
-
- org.apache.maven
- maven-settings-builder
- ${maven.version}
-
-
-
-
-
-
- org.springframework
- spring-core
- provided
-
-
- org.springframework.boot
- spring-boot-cli
- ${spring-boot.version}
- provided
-
-
- org.codehaus.groovy
- groovy
- provided
-
-
- net.sf.jopt-simple
- jopt-simple
-
-
-
- org.codehaus.plexus
- plexus-utils
-
- 3.2.1
-
-
-
-
- commons-logging
- commons-logging
- 1.2
- provided
-
-
- org.springframework.boot
- spring-boot-starter-test
- test
-
-
- junit
- junit
- test
-
-
-
-
diff --git a/spring-cloud-launcher/spring-cloud-launcher-cli/src/main/java/org/springframework/cloud/launcher/cli/LauncherCommand.java b/spring-cloud-launcher/spring-cloud-launcher-cli/src/main/java/org/springframework/cloud/launcher/cli/LauncherCommand.java
deleted file mode 100644
index 8514dec8..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-cli/src/main/java/org/springframework/cloud/launcher/cli/LauncherCommand.java
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright 2013-2016 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.launcher.cli;
-
-import java.io.File;
-import java.net.MalformedURLException;
-import java.net.URI;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import org.springframework.boot.cli.command.HelpExample;
-import org.springframework.boot.cli.command.OptionParsingCommand;
-import org.springframework.boot.cli.command.options.OptionHandler;
-import org.springframework.boot.cli.command.status.ExitStatus;
-import org.springframework.boot.cli.compiler.RepositoryConfigurationFactory;
-import org.springframework.boot.cli.compiler.grape.AetherGrapeEngine;
-import org.springframework.boot.cli.compiler.grape.AetherGrapeEngineFactory;
-import org.springframework.boot.cli.compiler.grape.DependencyResolutionContext;
-import org.springframework.boot.cli.compiler.grape.RepositoryConfiguration;
-import org.springframework.util.StringUtils;
-
-import joptsimple.OptionSet;
-import joptsimple.OptionSpec;
-
-/**
- * @author Spencer Gibb
- */
-public class LauncherCommand extends OptionParsingCommand {
-
- public static final Log log = LogFactory.getLog(LauncherCommand.class);
-
- private static final String DEFAULT_VERSION = "2.2.0.RELEASE";
-
- private static final Collection EXAMPLES = new ArrayList<>();
-
- static {
- EXAMPLES.add(new HelpExample("Launch Eureka", "spring cloud eureka"));
- EXAMPLES.add(new HelpExample("Launch Config Server and Eureka",
- "spring cloud configserver eureka"));
- EXAMPLES.add(new HelpExample("List deployable apps", "spring cloud --list"));
- EXAMPLES.add(new HelpExample("Show version", "spring cloud --version"));
- }
-
- public LauncherCommand() {
- super("cloud", "Start Spring Cloud services, like Eureka, Config Server, etc.",
- new LauncherOptionHandler());
- }
-
- @Override
- public Collection getExamples() {
- return EXAMPLES;
- }
-
- private static class LauncherOptionHandler extends OptionHandler {
-
- private OptionSpec debugOption;
- private OptionSpec listOption;
- private OptionSpec deployerOption;
- private OptionSpec profileOption;
- private OptionSpec versionOption;
-
- @Override
- protected void options() {
- // if the classloader is loaded here, we could load a collection of
- // interfaces that can create options and then populate the args[]
- // that is sent to the DeployerThread
- this.debugOption = option(Arrays.asList("debug", "d"),
- "Debug logging for the deployer");
- this.listOption = option(Arrays.asList("list", "l"),
- "List the deployables (don't launch anything)");
- this.deployerOption = option(Arrays.asList("deployer"),
- "Use a different deployer instead of the default local one (either 'local' or 'thin')")
- .withRequiredArg().defaultsTo("local");
- this.profileOption = option(Arrays.asList("profile", "p"),
- "Use a different Spring profile (or profiles) for the deployer app, e.g. 'rabbit' for a Spring Cloud Bus with RabbitMQ")
- .withOptionalArg();
- this.versionOption = option(Arrays.asList("version", "v"),
- "Show the version (don't launch anything)");
- }
-
- @Override
- protected synchronized ExitStatus run(OptionSet options) throws Exception {
- if (options.has(this.versionOption)) {
- System.out.println("Spring Cloud CLI v" + getVersion());
- return ExitStatus.OK;
- }
- try {
- URLClassLoader classLoader = populateClassloader(options);
- // This is the main class in the deployer archive:
- String name = "org.springframework.boot.loader.wrapper.ThinJarWrapper";
- Class> threadClass = classLoader.loadClass(name);
- URL url = classLoader.getURLs()[0];
- threadClass.getMethod("main", String[].class).invoke(null,
- new Object[] { getArgs(options, url) });
- }
- catch (Exception e) {
- log.error("Error running spring cloud", e);
- return ExitStatus.ERROR;
- }
-
- return ExitStatus.OK;
- }
-
- private String[] getArgs(OptionSet options, URL url) {
- List args = new ArrayList<>();
- List apps = new ArrayList<>();
- args.add("--thin.archive=" + url.toString());
- int sourceArgCount = 0;
- for (Object option : options.nonOptionArguments()) {
- if (option instanceof String) {
- sourceArgCount++;
- if (option.toString().startsWith("--")) {
- // jopts makes all args after "--" non-options
- args.add(option.toString());
- }
- else {
- apps.add(option.toString());
- }
- }
- }
- if (options.has(this.debugOption)) {
- args.add("--debug=true");
- }
- if (options.has(this.profileOption)) {
- args.add("--spring.profiles.active=" + profileOption.value(options));
- }
- if (options.has(this.deployerOption)) {
- args.add("--thin.profile=" + deployerOption.value(options));
- }
- if (options.has(this.listOption)) {
- args.add("--launcher.list=true");
- }
- else {
- if (!apps.isEmpty()) {
- args.add("--launcher.deploy="
- + StringUtils.collectionToCommaDelimitedString(apps));
- }
- }
- args.addAll(options.nonOptionArguments().subList(sourceArgCount,
- options.nonOptionArguments().size()));
- return args.toArray(new String[args.size()]);
- }
-
- private URLClassLoader populateClassloader(OptionSet options)
- throws MalformedURLException {
- DependencyResolutionContext resolutionContext = new DependencyResolutionContext();
-
- List repositoryConfiguration = RepositoryConfigurationFactory
- .createDefaultRepositoryConfiguration();
- repositoryConfiguration.add(0, new RepositoryConfiguration("local",
- new File("repository").toURI(), true));
-
- boolean quiet = true;
- if (options.has(debugOption)) {
- System.setProperty("groovy.grape.report.downloads", "true");
- quiet = false;
- }
-
- AetherGrapeEngine grapeEngine = AetherGrapeEngineFactory.create(null,
- repositoryConfiguration, resolutionContext, quiet);
-
- HashMap dependency = new HashMap<>();
- dependency.put("group", "org.springframework.cloud.launcher");
- dependency.put("module", "spring-cloud-launcher-deployer");
- dependency.put("version", getVersion());
- dependency.put("transitive", false);
- URI[] uris = grapeEngine.resolve(null, dependency);
- URLClassLoader loader = new URLClassLoader(new URL[] { uris[0].toURL() },
- systemClassLoader(getClass().getClassLoader()));
- log.debug("resolved URIs " + Arrays.asList(loader.getURLs()));
- return loader;
- }
-
- private ClassLoader systemClassLoader(ClassLoader classLoader) {
- if (classLoader.getParent().getParent()!=null) {
- if (classLoader.getParent().getParent().getParent()!=null) {
- return classLoader.getParent().getParent().getParent();
- }
- return classLoader.getParent().getParent();
- }
- return classLoader.getParent();
- }
-
- private String getVersion() {
- Package pkg = LauncherCommand.class.getPackage();
- String version = (pkg != null ? pkg.getImplementationVersion()
- : DEFAULT_VERSION);
- return version != null ? version : DEFAULT_VERSION;
- }
-
- }
-
-}
diff --git a/spring-cloud-launcher/spring-cloud-launcher-cli/src/test/java/org/springframework/cloud/launcher/cli/LauncherCommandTests.java b/spring-cloud-launcher/spring-cloud-launcher-cli/src/test/java/org/springframework/cloud/launcher/cli/LauncherCommandTests.java
deleted file mode 100644
index c1ad3d89..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-cli/src/test/java/org/springframework/cloud/launcher/cli/LauncherCommandTests.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2013-2016 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.launcher.cli;
-
-import org.junit.Ignore;
-import org.junit.Rule;
-import org.junit.Test;
-
-import org.springframework.boot.test.system.OutputCaptureRule;
-
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.hamcrest.CoreMatchers.startsWith;
-import static org.junit.Assert.assertThat;
-
-/**
- * @author Spencer Gibb
- */
-public class LauncherCommandTests {
-
- @Rule
- public OutputCaptureRule output = new OutputCaptureRule();
-
- @Test
- @Ignore // FIXME: 3.0.0
- public void testCreateClassLoaderAndListDeployables() throws Exception {
- new LauncherCommand().run("--list");
- assertThat(output.toString(), containsString("configserver"));
- }
-
- @Test
- @Ignore // FIXME: 3.0.0
- public void testNonOptionArgsPassedDown() throws Exception {
- new LauncherCommand().run("--list", "--", "--spring.profiles.active=test",
- "--spring.config.location=file:./src/test/resources/");
- assertThat(output.toString(), containsString("foo"));
- }
-
- @Test
- @Ignore // FIXME: 3.0.0
- public void testVersion() throws Exception {
- new LauncherCommand().run("--version");
- assertThat(output.toString(), startsWith("Spring Cloud CLI v"));
- }
-}
diff --git a/spring-cloud-launcher/spring-cloud-launcher-cli/src/test/java/org/springframework/cloud/launcher/cli/OutputCapture.java b/spring-cloud-launcher/spring-cloud-launcher-cli/src/test/java/org/springframework/cloud/launcher/cli/OutputCapture.java
deleted file mode 100644
index a606a86f..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-cli/src/test/java/org/springframework/cloud/launcher/cli/OutputCapture.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright 2012-2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.launcher.cli;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.PrintStream;
-
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-/**
- * Capture output from System.out and System.err.
- *
- * @author Phillip Webb
- */
-public class OutputCapture implements TestRule {
-
- private CaptureOutputStream captureOut;
-
- private CaptureOutputStream captureErr;
-
- private ByteArrayOutputStream copy;
-
- @Override
- public Statement apply(final Statement base, Description description) {
- return new Statement() {
- @Override
- public void evaluate() throws Throwable {
- captureOutput();
- try {
- base.evaluate();
- }
- finally {
- releaseOutput();
- }
- }
- };
- }
-
- protected void captureOutput() {
- this.copy = new ByteArrayOutputStream();
- this.captureOut = new CaptureOutputStream(System.out, this.copy);
- this.captureErr = new CaptureOutputStream(System.err, this.copy);
- System.setOut(new PrintStream(this.captureOut));
- System.setErr(new PrintStream(this.captureErr));
- }
-
- protected void releaseOutput() {
- System.setOut(this.captureOut.getOriginal());
- System.setErr(this.captureErr.getOriginal());
- this.copy = null;
- }
-
- public void flush() {
- try {
- this.captureOut.flush();
- this.captureErr.flush();
- }
- catch (IOException ex) {
- // ignore
- }
- }
-
- @Override
- public String toString() {
- flush();
- return this.copy.toString();
- }
-
- private static class CaptureOutputStream extends OutputStream {
-
- private final PrintStream original;
-
- private final OutputStream copy;
-
- CaptureOutputStream(PrintStream original, OutputStream copy) {
- this.original = original;
- this.copy = copy;
- }
-
- @Override
- public void write(int b) throws IOException {
- this.copy.write(b);
- this.original.write(b);
- this.original.flush();
- }
-
- @Override
- public void write(byte[] b) throws IOException {
- write(b, 0, b.length);
- }
-
- @Override
- public void write(byte[] b, int off, int len) throws IOException {
- this.copy.write(b, off, len);
- this.original.write(b, off, len);
- }
-
- public PrintStream getOriginal() {
- return this.original;
- }
-
- @Override
- public void flush() throws IOException {
- this.copy.flush();
- this.original.flush();
- }
- }
-
-}
diff --git a/spring-cloud-launcher/spring-cloud-launcher-cli/src/test/resources/cloud-test.yml b/spring-cloud-launcher/spring-cloud-launcher-cli/src/test/resources/cloud-test.yml
deleted file mode 100644
index 4027b8e8..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-cli/src/test/resources/cloud-test.yml
+++ /dev/null
@@ -1,10 +0,0 @@
-debug: true
-spring:
- cloud:
- launcher:
- deployables:
- foo:
- coordinates: com.example:foo:0.0.1-SNAPSHOT
- port: 8000
- waitUntilStarted: true
- order: -200
diff --git a/spring-cloud-launcher/spring-cloud-launcher-configserver/pom.xml b/spring-cloud-launcher/spring-cloud-launcher-configserver/pom.xml
deleted file mode 100644
index 86b5210f..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-configserver/pom.xml
+++ /dev/null
@@ -1,60 +0,0 @@
-
-
- 4.0.0
-
- org.springframework.cloud.launcher
- spring-cloud-launcher-configserver
- jar
-
- spring-cloud-launcher-configserver
- Spring Cloud Launcher ConfigServer
-
-
- org.springframework.cloud
- spring-cloud-launcher
- 3.1.2-SNAPSHOT
-
-
-
-
- org.springframework.boot
- spring-boot-starter-actuator
-
-
- org.springframework.cloud
- spring-cloud-starter-netflix-eureka-client
-
-
- org.springframework.cloud
- spring-cloud-starter-bus-kafka
-
-
- org.springframework.cloud
- spring-cloud-config-server
-
-
- org.springframework.cloud
- spring-cloud-config-monitor
-
-
- org.springframework.boot
- spring-boot-starter-test
- test
-
-
- org.junit.vintage
- junit-vintage-engine
- test
-
-
-
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
-
-
diff --git a/spring-cloud-launcher/spring-cloud-launcher-configserver/src/main/java/org/springframework/cloud/launcher/configserver/ConfigServerApplication.java b/spring-cloud-launcher/spring-cloud-launcher-configserver/src/main/java/org/springframework/cloud/launcher/configserver/ConfigServerApplication.java
deleted file mode 100644
index 4b62388e..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-configserver/src/main/java/org/springframework/cloud/launcher/configserver/ConfigServerApplication.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2013-2016 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.launcher.configserver;
-
-import java.io.IOException;
-
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
-import org.springframework.cloud.config.server.EnableConfigServer;
-
-/**
- * @author Spencer Gibb
- */
-@EnableConfigServer
-@EnableDiscoveryClient
-@SpringBootApplication
-public class ConfigServerApplication {
-
- public static void main(String[] args) throws IOException {
- SpringApplication.run(ConfigServerApplication.class, args);
- }
-}
diff --git a/spring-cloud-launcher/spring-cloud-launcher-configserver/src/main/resources/META-INF/thin-rabbit.properties b/spring-cloud-launcher/spring-cloud-launcher-configserver/src/main/resources/META-INF/thin-rabbit.properties
deleted file mode 100644
index ea8fc55b..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-configserver/src/main/resources/META-INF/thin-rabbit.properties
+++ /dev/null
@@ -1,3 +0,0 @@
-exclusions.spring-cloud-starter-bus-kafka: org.springframework.cloud:spring-cloud-starter-bus-kafka
-exclusions.servlet-api: javax.servlet:servlet-api
-dependencies.spring-cloud-starter-bus-amqp: org.springframework.cloud:spring-cloud-starter-bus-amqp
diff --git a/spring-cloud-launcher/spring-cloud-launcher-configserver/src/main/resources/META-INF/thin.properties b/spring-cloud-launcher/spring-cloud-launcher-configserver/src/main/resources/META-INF/thin.properties
deleted file mode 100644
index f5e6295a..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-configserver/src/main/resources/META-INF/thin.properties
+++ /dev/null
@@ -1 +0,0 @@
-exclusions.servlet-api: javax.servlet:servlet-api
diff --git a/spring-cloud-launcher/spring-cloud-launcher-configserver/src/main/resources/application.yml b/spring-cloud-launcher/spring-cloud-launcher-configserver/src/main/resources/application.yml
deleted file mode 100644
index cedd11f3..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-configserver/src/main/resources/application.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-spring:
- application:
- name: configserver
- profiles:
- active: native
- cloud:
- config:
- server:
- bootstrap: true
- native:
- search-locations: classpath:/launcher/, file:./launcher/
-
-server:
- port: 8888
-
-info:
- artifactId: "@project.artifactId@"
- description: "@project.description@"
- version: "@project.version@"
\ No newline at end of file
diff --git a/spring-cloud-launcher/spring-cloud-launcher-configserver/src/main/resources/launcher/application.yml b/spring-cloud-launcher/spring-cloud-launcher-configserver/src/main/resources/launcher/application.yml
deleted file mode 100644
index 2fcfda4b..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-configserver/src/main/resources/launcher/application.yml
+++ /dev/null
@@ -1,30 +0,0 @@
-info:
- description: Spring Cloud Launcher
-
-eureka:
- client:
- instance-info-replication-interval-seconds: 5
- initial-instance-info-replication-interval-seconds: 5
- serviceUrl:
- defaultZone: http://localhost:8761/eureka/
-
-endpoints:
- restart:
- enabled: true
-
-ribbon:
- ConnectTimeout: 3000
- ReadTimeout: 60000
-
-h2.datasource.url: jdbc:h2:tcp://localhost:9096/./target/test
-#spring:
-# datasource:
-# url: ${h2.datasource.url}
-
-logging:
- level:
- kafka: WARN
- org.apache.zookeeper: WARN
- org.apache.zookeeper.ClientCnxn: ERROR
- org.apache.kafka: WARN
- org.I0Itec: WARN
diff --git a/spring-cloud-launcher/spring-cloud-launcher-configserver/src/test/java/org/springframework/cloud/launcher/configserver/DeployerApplicationTests.java b/spring-cloud-launcher/spring-cloud-launcher-configserver/src/test/java/org/springframework/cloud/launcher/configserver/DeployerApplicationTests.java
deleted file mode 100644
index ae43f51f..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-configserver/src/test/java/org/springframework/cloud/launcher/configserver/DeployerApplicationTests.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package org.springframework.cloud.launcher.configserver;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit4.SpringRunner;
-
-@RunWith(SpringRunner.class)
-@SpringBootTest({ "spring.cloud.config.server.git.uri=file:./target",
- "spring.cloud.bus.enabled=false" })
-public class DeployerApplicationTests {
-
- @Test
- public void contextLoads() {
- }
-
-}
diff --git a/spring-cloud-launcher/spring-cloud-launcher-dataflow/pom.xml b/spring-cloud-launcher/spring-cloud-launcher-dataflow/pom.xml
deleted file mode 100644
index 939e615e..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-dataflow/pom.xml
+++ /dev/null
@@ -1,67 +0,0 @@
-
-
- 4.0.0
-
- org.springframework.cloud.launcher
- spring-cloud-launcher-dataflow
- jar
-
- spring-cloud-launcher-dataflow
- Spring Cloud Launcher Data Flow
-
-
- org.springframework.cloud
- spring-cloud-launcher
- 3.1.2-SNAPSHOT
-
-
-
- 1.2.3.RELEASE
-
-
-
-
-
- org.springframework.cloud
- spring-cloud-dataflow-dependencies
- ${spring-cloud-dataflow.version}
- pom
- import
-
-
-
-
-
-
- org.springframework.boot
- spring-boot-starter-actuator
-
-
- org.springframework.cloud
- spring-cloud-starter-config
-
-
- org.springframework.cloud
- spring-cloud-starter-netflix-eureka-client
-
-
- org.springframework.cloud
- spring-cloud-starter-dataflow-server-local
-
-
- org.springframework.boot
- spring-boot-starter-test
- test
-
-
-
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
-
-
diff --git a/spring-cloud-launcher/spring-cloud-launcher-dataflow/src/main/java/org/springframework/cloud/launcher/dataflow/DataFlowApplication.java b/spring-cloud-launcher/spring-cloud-launcher-dataflow/src/main/java/org/springframework/cloud/launcher/dataflow/DataFlowApplication.java
deleted file mode 100644
index 0919b1c4..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-dataflow/src/main/java/org/springframework/cloud/launcher/dataflow/DataFlowApplication.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2013-2016 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.launcher.dataflow;
-
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
-import org.springframework.cloud.dataflow.server.EnableDataFlowServer;
-
-/**
- * @author Spencer Gibb
- */
-@EnableDataFlowServer
-@EnableDiscoveryClient
-@SpringBootApplication
-public class DataFlowApplication {
-
- public static void main(String[] args) {
- SpringApplication.run(DataFlowApplication.class, args);
- }
-
-}
diff --git a/spring-cloud-launcher/spring-cloud-launcher-dataflow/src/main/resources/META-INF/thin-rabbit.properties b/spring-cloud-launcher/spring-cloud-launcher-dataflow/src/main/resources/META-INF/thin-rabbit.properties
deleted file mode 100644
index 0343528f..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-dataflow/src/main/resources/META-INF/thin-rabbit.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-exclusions.spring-cloud-starter-bus-kafka: org.springframework.cloud:spring-cloud-starter-bus-kafka
-dependencies.spring-cloud-starter-bus-amqp: org.springframework.cloud:spring-cloud-starter-bus-amqp
diff --git a/spring-cloud-launcher/spring-cloud-launcher-dataflow/src/main/resources/application.yml b/spring-cloud-launcher/spring-cloud-launcher-dataflow/src/main/resources/application.yml
deleted file mode 100644
index f84eac65..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-dataflow/src/main/resources/application.yml
+++ /dev/null
@@ -1,25 +0,0 @@
-server:
- port: 9393
-
-# debug: true
-
-eureka:
- instance:
- status-page-url-path: /dashboard #allows you to click on the link in eureka dashboard
-
-info:
- artifactId: "@project.artifactId@"
- description: "@project.description@"
- version: "@project.version@"
-
-security:
- basic:
- enabled: false
-
-management:
- security:
- enabled: false
-
-spring.cloud.dataflow.applicationProperties.stream.spring.cloud.deployer.JAVA_OPTS: -Xmx128m
-# app.time.spring.cloud.deployer.JAVA_OPTS: -Xmx128m
-# app.log.spring.cloud.deployer.JAVA_OPTS: -Xmx128m
\ No newline at end of file
diff --git a/spring-cloud-launcher/spring-cloud-launcher-dataflow/src/main/resources/bootstrap.yml b/spring-cloud-launcher/spring-cloud-launcher-dataflow/src/main/resources/bootstrap.yml
deleted file mode 100644
index 6ef41f92..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-dataflow/src/main/resources/bootstrap.yml
+++ /dev/null
@@ -1,3 +0,0 @@
-spring:
- application:
- name: dataflow
diff --git a/spring-cloud-launcher/spring-cloud-launcher-dataflow/src/test/java/org/springframework/cloud/launcher/dataflow/DeployerApplicationTests.java b/spring-cloud-launcher/spring-cloud-launcher-dataflow/src/test/java/org/springframework/cloud/launcher/dataflow/DeployerApplicationTests.java
deleted file mode 100644
index e114ac08..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-dataflow/src/test/java/org/springframework/cloud/launcher/dataflow/DeployerApplicationTests.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package org.springframework.cloud.launcher.dataflow;
-
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit4.SpringRunner;
-
-@RunWith(SpringRunner.class)
-@SpringBootTest({ "spring.cloud.bus.enabled=false", "eureka.client.enabled=false" })
-public class DeployerApplicationTests {
-
- @Test
- public void contextLoads() {
- }
-
-}
diff --git a/spring-cloud-launcher/spring-cloud-launcher-deployer/pom.xml b/spring-cloud-launcher/spring-cloud-launcher-deployer/pom.xml
deleted file mode 100644
index 73145a02..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-deployer/pom.xml
+++ /dev/null
@@ -1,117 +0,0 @@
-
-
- 4.0.0
-
- org.springframework.cloud.launcher
- spring-cloud-launcher-deployer
- jar
-
- spring-cloud-launcher-deployer
- Spring Cloud Launcher Deployer
-
-
- org.springframework.cloud
- spring-cloud-launcher
- 3.1.2-SNAPSHOT
-
-
-
- 2.0.6.RELEASE
- 2.0.3.RELEASE
- 1.0.24.RELEASE
- 3.3.9
-
-
-
-
-
- org.springframework.cloud
- spring-cloud-deployer-local
- ${spring-cloud-deployer.version}
-
-
- org.springframework.cloud
- spring-cloud-deployer-thin
- ${spring-cloud-deployer-thin.version}
-
-
- org.springframework.boot
- spring-boot-test-support
-
-
-
-
- org.springframework.cloud
- spring-cloud-deployer-resource-support
- ${spring-cloud-deployer-resource-support.version}
-
-
- org.apache.maven
- maven-aether-provider
- ${maven.version}
-
-
- org.apache.maven
- maven-settings-builder
- ${maven.version}
-
-
-
-
-
-
-
- org.springframework.boot
- spring-boot-loader
- 2.1.9.RELEASE
-
-
- org.springframework.cloud
- spring-cloud-deployer-thin
-
-
- org.springframework.cloud
- spring-cloud-deployer-resource-support
-
-
- org.springframework.boot
- spring-boot-starter-validation
-
-
- org.springframework.boot
- spring-boot-starter-test
- test
-
-
- org.junit.vintage
- junit-vintage-engine
- test
-
-
-
-
-
-
- src/main/resources
- true
-
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
- org.apache.maven.plugins
- maven-surefire-plugin
-
-
- ${project.version}
-
-
-
-
-
-
diff --git a/spring-cloud-launcher/spring-cloud-launcher-deployer/src/main/java/org/springframework/cloud/launcher/deployer/Deployer.java b/spring-cloud-launcher/spring-cloud-launcher-deployer/src/main/java/org/springframework/cloud/launcher/deployer/Deployer.java
deleted file mode 100644
index 45880843..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-deployer/src/main/java/org/springframework/cloud/launcher/deployer/Deployer.java
+++ /dev/null
@@ -1,338 +0,0 @@
-/*
- * Copyright 2012-2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.launcher.deployer;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.springframework.boot.env.YamlPropertySourceLoader;
-import org.springframework.cloud.deployer.spi.app.AppDeployer;
-import org.springframework.cloud.deployer.spi.app.AppStatus;
-import org.springframework.cloud.deployer.spi.app.DeploymentState;
-import org.springframework.cloud.deployer.spi.core.AppDefinition;
-import org.springframework.cloud.deployer.spi.core.AppDeploymentRequest;
-import org.springframework.cloud.launcher.deployer.DeployerProperties.Deployable;
-import org.springframework.context.event.ContextClosedEvent;
-import org.springframework.context.event.EventListener;
-import org.springframework.core.OrderComparator;
-import org.springframework.core.env.CompositePropertySource;
-import org.springframework.core.env.ConfigurableEnvironment;
-import org.springframework.core.env.EnumerablePropertySource;
-import org.springframework.core.env.PropertySource;
-import org.springframework.core.io.ClassPathResource;
-import org.springframework.core.io.FileSystemResource;
-import org.springframework.core.io.Resource;
-import org.springframework.core.io.ResourceLoader;
-import org.springframework.util.StringUtils;
-
-import static org.springframework.util.StringUtils.collectionToCommaDelimitedString;
-
-/**
- * @author Dave Syer
- *
- */
-public class Deployer {
-
- private static final Logger logger = LoggerFactory.getLogger(Deployer.class);
-
- public static final String DIRECTORY_NAME = ".spring-cloud";
-
- final AppDeployer deployer;
-
- final ResourceLoader resourceLoader;
-
- final DeployerProperties properties;
-
- final ConfigurableEnvironment environment;
-
- private Map deployed = new ConcurrentHashMap<>();
-
- public Deployer(AppDeployer deployer, ResourceLoader resourceLoader,
- DeployerProperties properties, ConfigurableEnvironment environment) {
- this.deployer = deployer;
- this.resourceLoader = resourceLoader;
- this.properties = properties;
- this.environment = environment;
- }
-
- public void deploy() {
- ArrayList invalid = new ArrayList<>();
- // validate that items in deploy, are valid deployables
- for (String toDeploy : properties.getDeploy()) {
- if (!properties.getDeployables().containsKey(toDeploy)) {
- invalid.add(toDeploy);
- }
- }
-
- if (!invalid.isEmpty()) {
- logger.error("Error starting 'spring cloud'."
- + "\n\nThe following are not valid: '"
- + collectionToCommaDelimitedString(invalid)
- + "'. Please check the name(s) and try again.\n"
- + "Valid choices are: " + collectionToCommaDelimitedString(
- properties.getDeployables().keySet())
- + ".\n");
- return;
- }
-
- ArrayList deployables = new ArrayList<>(
- properties.getDeployables().values());
- OrderComparator.sort(deployables);
-
- logger.debug("Deployables {}", properties.getDeployables());
-
- for (Deployable deployable : deployables) {
- deployInternal(deployer, resourceLoader, deployable, properties, environment);
- }
-
- for (Deployable deployable : deployables) {
- if (shouldDeploy(deployable, properties)
- && StringUtils.hasText(deployable.getMessage())) {
- System.out.println("\n\n" + deployable.getName() + ": "
- + deployable.getMessage() + "\n");
- }
- }
-
- if (this.deployed.isEmpty()) {
- System.out.println(
- "\n\nNothing to deploy (see spring.cloud.launcher.deploy).\n");
- return;
- }
-
- System.out.println("\n\nType Ctrl-C to quit.\n");
- while (true) {
- for (Map.Entry entry : this.deployed.entrySet()) {
- String id = entry.getKey();
- DeploymentState state = entry.getValue();
- AppStatus status = deployer.status(id);
- DeploymentState newState = status.getState();
- if (state != newState) {
- logger.info("{} change status from {} to {}", id, state, newState);
- this.deployed.put(id, newState);
- }
- }
- try {
- Thread.sleep(properties.getStatusSleepMillis());
- }
- catch (InterruptedException e) {
- logger.error("error sleeping", e);
- Thread.currentThread().interrupt();
- }
- }
-
- }
-
- @EventListener
- public void shutdown(ContextClosedEvent event) {
- logger.info("\n\nShutting down ...\n");
- for (String id : Deployer.this.deployed.keySet()) {
- logger.info("Undeploying {}", id);
- deployer.undeploy(id);
- }
- }
-
- private String deployInternal(AppDeployer deployer, ResourceLoader resourceLoader,
- Deployable deployable, DeployerProperties properties,
- ConfigurableEnvironment environment) {
- if (!shouldDeploy(deployable, properties)) {
- return null;
- }
-
- logger.debug("getting resource {} = {}", deployable.getName(),
- deployable.getCoordinates());
- Resource resource = resourceLoader.getResource(deployable.getCoordinates());
-
- Map appDefProps = new HashMap<>();
- appDefProps.put("server.port", String.valueOf(deployable.getPort()));
-
- // For each of the other deployables, add "negative" properties that apply to all
- // apps when it is disabled
- for (Deployable other : properties.getDeployables().values()) {
- if (!shouldDeploy(other.getName(), properties)) {
- appDefProps.putAll(other.getDisabled());
- }
- }
- for (Deployable other : properties.getDeployables().values()) {
- if (shouldDeploy(other.getName(), properties)) {
- appDefProps.putAll(other.getEnabled());
- }
- }
- appDefProps.putAll(deployable.getApplicationProperties());
- appDefProps.putAll(getThinProperties(deployable.getProperties()));
- Map map = extractProperties("/" + deployable.getName() + ".yml");
- for (String key : map.keySet()) {
- appDefProps.put(key, map.get(key));
- }
-
- AppDefinition definition = new AppDefinition(deployable.getName(), appDefProps);
-
- Map deploymentProperties = new LinkedHashMap<>();
- deploymentProperties.put(AppDeployer.GROUP_PROPERTY_KEY, "launcher");
- deploymentProperties.putAll(deployable.getProperties());
-
- AppDeploymentRequest request = new AppDeploymentRequest(definition, resource,
- deploymentProperties);
-
- logger.debug("Deploying resource {} = {}", deployable.getName(),
- deployable.getCoordinates());
- logger.debug("AppDefinition Properties: {}", appDefProps);
- logger.debug("Deployment Properties: {}", deploymentProperties);
- String id = deployer.deploy(request);
- AppStatus appStatus = getAppStatus(deployer, id);
- // TODO: stream stdout/stderr like docker-compose (with colors and prefix) - the
- // colors work with the "thin" deployer, but there is no prefix in the logs yet
-
- if (deployable.isWaitUntilStarted()) {
- try {
- logger.info("\n\nWaiting for {} to start.\n", deployable.getName());
-
- while (appStatus.getState() != DeploymentState.deployed
- && appStatus.getState() != DeploymentState.failed) {
- Thread.sleep(properties.getStatusSleepMillis());
- appStatus = getAppStatus(deployer, id);
- logger.trace("State of {} = {}", id, appStatus.getState());
- }
- }
- catch (Exception e) {
- logger.error("error updating status of " + id, e);
- }
- }
- logger.info("Status of {}: {}", id, appStatus);
-
- return id;
- }
-
- private Map getThinProperties(
- Map properties) {
- Map map = new HashMap<>();
- for (String key : properties.keySet()) {
- if (key.startsWith(AppDeployer.PREFIX + "thin.")) {
- map.put(key, properties.get(key));
- }
- }
- return map ;
- }
-
- private boolean shouldDeploy(Deployable deployable, DeployerProperties properties) {
- return shouldDeploy(deployable.getName(), properties);
- }
-
- private boolean shouldDeploy(String name, DeployerProperties properties) {
- boolean deploy = properties.getDeploy().contains(name);
- logger.trace("shouldDeploy {} = {}", name, deploy);
- return deploy;
- }
-
- private AppStatus getAppStatus(AppDeployer deployer, String id) {
- AppStatus appStatus = deployer.status(id);
- this.deployed.put(id, appStatus.getState());
- return appStatus;
- }
-
- private Map extractProperties(String path) {
- PropertySource> source = extractPropertySource(path);
- Map map = new LinkedHashMap();
- if (source instanceof EnumerablePropertySource) {
- EnumerablePropertySource> enumerable = (EnumerablePropertySource>) source;
- for (String name : enumerable.getPropertyNames()) {
- map.put(name, source.getProperty(name) == null ? null
- : source.getProperty(name).toString());
- }
- }
- return map;
- }
-
- private PropertySource> extractPropertySource(String path) {
- PropertySource> source = null;
- Resource resource = new ClassPathResource("config" + path,
- DeployerApplication.class);
- source = loadPropertySource(resource, path);
- if (source == null) {
- resource = new ClassPathResource(path, DeployerApplication.class);
- source = loadPropertySource(resource, path);
- }
- if (source == null) {
- resource = new FileSystemResource("config" + path);
- source = loadPropertySource(resource, path);
- }
- if (source == null) {
- resource = new FileSystemResource("." + path);
- source = loadPropertySource(resource, path);
- }
- if (source == null) {
- File home = getHomeFolder();
- File springCloudDir = (home == null ? null : new File(home, DIRECTORY_NAME));
- if (logger.isDebugEnabled() && springCloudDir != null) {
- logger.debug("~/.spring-cloud directory: {}, exists: {}, isDir: {}",
- springCloudDir, springCloudDir.exists(),
- springCloudDir.isDirectory());
- }
- else if (logger.isDebugEnabled()) {
- logger.debug("no ~/.spring-cloud directory");
- }
- if (springCloudDir != null && springCloudDir.exists()
- && springCloudDir.isDirectory()) {
- resource = new FileSystemResource(new File(springCloudDir, path));
- source = loadPropertySource(resource, path);
- }
- }
- return source;
- }
-
- protected File getHomeFolder() {
- String home = System.getProperty("user.home");
- if (StringUtils.hasLength(home)) {
- return new File(home);
- }
- return null;
- }
-
- private PropertySource> loadPropertySource(Resource resource, String path) {
- if (resource.exists()) {
- try {
- List> sources = new YamlPropertySourceLoader().load(path,
- resource);
- if (sources != null) {
- logger.info("Loaded YAML properties from: " + resource);
- } else if (sources == null || sources.isEmpty()){
- return null;
- }
-
- CompositePropertySource composite = new CompositePropertySource("cli-sources");
-
- for (PropertySource propertySource : sources) {
- composite.addPropertySource(propertySource);
- }
-
- return composite;
- }
- catch (IOException e) {
- }
- }
- return null;
- }
-
-}
diff --git a/spring-cloud-launcher/spring-cloud-launcher-deployer/src/main/java/org/springframework/cloud/launcher/deployer/DeployerApplication.java b/spring-cloud-launcher/spring-cloud-launcher-deployer/src/main/java/org/springframework/cloud/launcher/deployer/DeployerApplication.java
deleted file mode 100644
index e8f77dff..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-deployer/src/main/java/org/springframework/cloud/launcher/deployer/DeployerApplication.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright 2013-2016 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.launcher.deployer;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.springframework.boot.Banner.Mode;
-import org.springframework.boot.WebApplicationType;
-import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
-import org.springframework.boot.builder.SpringApplicationBuilder;
-import org.springframework.boot.logging.LogLevel;
-import org.springframework.boot.logging.logback.LogbackLoggingSystem;
-import org.springframework.context.ConfigurableApplicationContext;
-import org.springframework.core.io.ClassPathResource;
-import org.springframework.util.ClassUtils;
-import org.springframework.util.ReflectionUtils;
-import org.springframework.util.StreamUtils;
-import org.springframework.util.StringUtils;
-
-/**
- * @author Spencer Gibb
- */
-public class DeployerApplication {
-
- private static final Logger logger = LoggerFactory
- .getLogger(DeployerApplication.class);
-
- private String[] args;
-
- public DeployerApplication(String... args) {
- this.args = args;
- }
-
- public static void main(String[] args) {
- new DeployerApplication(args).run();
- }
-
- void run() {
- List list = Arrays.asList(this.args);
- if (list.contains("--launcher.list=true")) {
- quiet();
- list();
- }
- else {
- launch();
- }
- }
-
- private void quiet() {
- try {
- LogbackLoggingSystem.get(ClassUtils.getDefaultClassLoader())
- .setLogLevel("ROOT", LogLevel.OFF);
- }
- catch (Exception e) {
- logger.error("Unable to turn of ROOT logger for quiet()", e);
- }
- }
-
- private void list() {
- DeployerProperties properties = loadCloudProperties();
- if (!properties.getDeployables().isEmpty()) {
- Collection names = new ArrayList<>(
- properties.getDeployables().keySet());
- System.out.println(StringUtils.collectionToDelimitedString(names, " "));
- }
- }
-
- private DeployerProperties loadCloudProperties() {
-
- final ConfigurableApplicationContext context = new SpringApplicationBuilder(
- PropertyPlaceholderAutoConfiguration.class, DeployerConfiguration.class)
- .bannerMode(Mode.OFF).logStartupInfo(false).web(WebApplicationType.NONE)
- .properties("spring.config.name=cloud", "logging.level.ROOT=OFF",
- "spring.cloud.launcher.list=true",
- "launcher.version=" + getVersion())
- .run(this.args);
- try {
- return context.getBean(DeployerProperties.class);
- }
- finally {
- context.close();
- }
- }
-
- String getVersion() {
- Package pkg = DeployerApplication.class.getPackage();
- return (pkg != null ? pkg.getImplementationVersion() == null ? getDefaultVersion()
- : pkg.getImplementationVersion() : getDefaultVersion());
- }
-
- String getDefaultVersion() {
- try (InputStream in = new ClassPathResource("META-INF/cli-version.txt").getInputStream()) {
- String version = StreamUtils.copyToString(in, StandardCharsets.UTF_8);
- if (StringUtils.hasText(version)) {
- version = version.trim();
- }
- return version;
- }
- catch (IOException e) {
- ReflectionUtils.rethrowRuntimeException(e);
- }
- // not reachable since exception rethrown at runtime
- return null;
- }
-
- private void launch() {
-
- final ConfigurableApplicationContext context = new SpringApplicationBuilder(
- PropertyPlaceholderAutoConfiguration.class, DeployerConfiguration.class)
- .web(WebApplicationType.NONE)
- .properties("spring.config.name=cloud",
- "banner.location=launcher-banner.txt",
- "launcher.version=" + getVersion())
- .run(this.args);
-
- final Deployer deployer = context.getBean(Deployer.class);
- deployer.deploy();
-
- }
-
-}
diff --git a/spring-cloud-launcher/spring-cloud-launcher-deployer/src/main/java/org/springframework/cloud/launcher/deployer/DeployerConfiguration.java b/spring-cloud-launcher/spring-cloud-launcher-deployer/src/main/java/org/springframework/cloud/launcher/deployer/DeployerConfiguration.java
deleted file mode 100644
index e92f793c..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-deployer/src/main/java/org/springframework/cloud/launcher/deployer/DeployerConfiguration.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2013-2016 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.launcher.deployer;
-
-import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.cloud.deployer.resource.maven.MavenProperties;
-import org.springframework.cloud.deployer.resource.maven.MavenResourceLoader;
-import org.springframework.cloud.deployer.resource.support.DelegatingResourceLoader;
-import org.springframework.cloud.deployer.spi.app.AppDeployer;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.core.env.ConfigurableEnvironment;
-import org.springframework.core.io.ResourceLoader;
-
-import java.util.HashMap;
-
-/**
- * @author Spencer Gibb
- */
-@Configuration
-@EnableAutoConfiguration
-@EnableConfigurationProperties({ DeployerProperties.class })
-public class DeployerConfiguration {
-
- @Bean
- public Deployer deployer(AppDeployer deployer, MavenResourceLoader resourceLoader,
- DeployerProperties properties, ConfigurableEnvironment environment) {
- return new Deployer(deployer, resourceLoader, properties, environment);
- }
-
- @ConfigurationProperties(prefix = "spring.cloud.maven")
- @Bean
- public MavenProperties mavenProperties() {
- return new MavenProperties();
- }
-
- @Bean
- public MavenResourceLoader mavenResourceLoader(MavenProperties mavenProperties) {
- return new MavenResourceLoader(mavenProperties);
- }
-
- @Bean
- public DelegatingResourceLoader delegatingResourceLoader(MavenResourceLoader mavenResourceLoader) {
- HashMap map = new HashMap<>();
- map.put("maven", mavenResourceLoader);
- return new DelegatingResourceLoader(map);
- }
-}
diff --git a/spring-cloud-launcher/spring-cloud-launcher-deployer/src/main/java/org/springframework/cloud/launcher/deployer/DeployerProperties.java b/spring-cloud-launcher/spring-cloud-launcher-deployer/src/main/java/org/springframework/cloud/launcher/deployer/DeployerProperties.java
deleted file mode 100644
index 5ed7c0db..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-deployer/src/main/java/org/springframework/cloud/launcher/deployer/DeployerProperties.java
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * Copyright 2013-2016 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.launcher.deployer;
-
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.annotation.PostConstruct;
-import javax.validation.constraints.NotNull;
-
-import org.hibernate.validator.constraints.NotEmpty;
-
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.core.Ordered;
-
-/**
- * @author Spencer Gibb
- */
-@ConfigurationProperties(prefix = "spring.cloud.launcher")
-public class DeployerProperties {
-
- /**
- * A set of deployable applications.
- */
- @NotNull
- private Map deployables = new LinkedHashMap<>();
-
- /**
- * The names of the deployable applications to actually deploy.
- */
- @NotNull
- private List deploy = new ArrayList<>();
-
- /**
- * Flag to say that user only requests a list of deployables.
- */
- private boolean list = false;
-
- /**
- * Time to sleep in a tight loop while waiting for an app to start.
- */
- private int statusSleepMillis = 300;
-
- public boolean isList() {
- return this.list;
- }
-
- public void setList(boolean list) {
- this.list = list;
- }
-
- public Map getDeployables() {
- return this.deployables;
- }
-
- public void setDeployables(Map deployables) {
- this.deployables = deployables;
- }
-
- public List getDeploy() {
- return this.deploy;
- }
-
- public void setDeploy(List deploy) {
- this.deploy = deploy;
- }
-
- public int getStatusSleepMillis() {
- return this.statusSleepMillis;
- }
-
- public void setStatusSleepMillis(int statusSleepMillis) {
- this.statusSleepMillis = statusSleepMillis;
- }
-
- @PostConstruct
- public void init() {
- for (String name : deployables.keySet()) {
- Deployable deployable = deployables.get(name);
- if (deployable.getName() == null) {
- deployable.setName(name);
- }
- }
- }
-
- @Override
- public String toString() {
- final StringBuffer sb = new StringBuffer("DeployerProperties{");
- sb.append("deployables=").append(this.deployables);
- sb.append(", deploy=").append(this.deploy);
- sb.append(", statusSleepMillis=").append(this.statusSleepMillis);
- sb.append('}');
- return sb.toString();
- }
-
- public static class Deployable implements Ordered {
- /**
- * Maven (grab-style) co-ordinates of the deployable application artifact in the
- * form "group:artifact[:classifer]:version" (classifer defaults to "jar").
- */
- @NotEmpty
- private String coordinates;
- /**
- * Name of the deployable application.
- */
- @NotEmpty
- private String name;
- /**
- * Port to listen on.
- */
- private int port = 0;
- /**
- * Flag to say that this application must be running before any with higher order
- * are launched.
- */
- private boolean waitUntilStarted;
- /**
- * The order to deploy this application. Default is unordered (so last).
- */
- private int order = 0;
- /**
- * A message to print when the application starts.
- */
- private String message;
- /**
- * A map of "negative" properties that apply to all apps when this one is
- * disabled. E.g. when eureka is disabled you might want
- * "eureka.client.enabled=false".
- */
- private Map disabled = new LinkedHashMap<>();
- /**
- * A map of "positive" properties that apply to all apps when this one is enabled.
- * E.g. when h2 is disabled you might want the JDBC URL to be used everywhere.
- */
- private Map enabled = new LinkedHashMap<>();
- /**
- * A map of "deployment" properties passed to the deployer (not the app) when an
- * app is launched. E.g. you can use
- * spring.cloud.deployer.local.javaOpts here to pass JVM args to a
- * local deployer.
- */
- private Map properties = new LinkedHashMap<>();
-
- /**
- * A map of properties passed to the app (not the deployer) when an app is
- * launched.
- */
- private Map applicationProperties;
-
- public String getCoordinates() {
- return this.coordinates;
- }
-
- public void setCoordinates(String coordinates) {
- this.coordinates = coordinates;
- }
-
- public String getName() {
- return this.name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public int getPort() {
- return this.port;
- }
-
- public void setPort(int port) {
- this.port = port;
- }
-
- public boolean isWaitUntilStarted() {
- return this.waitUntilStarted;
- }
-
- public void setWaitUntilStarted(boolean waitUntilStarted) {
- this.waitUntilStarted = waitUntilStarted;
- }
-
- @Override
- public int getOrder() {
- return this.order;
- }
-
- public void setOrder(int order) {
- this.order = order;
- }
-
- public String getMessage() {
- return this.message;
- }
-
- public void setMessage(String message) {
- this.message = message;
- }
-
- public void setDisabled(Map disabled) {
- this.disabled = disabled;
- }
-
- public Map getDisabled() {
- return disabled;
- }
-
- public Map getEnabled() {
- return enabled;
- }
-
- public void setEnabled(Map enabled) {
- this.enabled = enabled;
- }
-
- public Map getProperties() {
- return properties;
- }
-
- public void setProperties(Map properties) {
- this.properties = properties;
- }
-
- public Map getApplicationProperties() {
- return applicationProperties;
- }
-
- public void setApplicationProperties(Map applicationProperties) {
- this.applicationProperties = applicationProperties;
- }
-
- @Override
- public String toString() {
- final StringBuffer sb = new StringBuffer("Deployable{");
- sb.append("coordinates='").append(this.coordinates).append('\'');
- sb.append(", name='").append(this.name).append('\'');
- sb.append(", port=").append(this.port);
- sb.append(", waitUntilStarted=").append(this.waitUntilStarted);
- sb.append(", order=").append(this.order);
- sb.append(", disabled=").append(this.disabled);
- sb.append(", enabled=").append(this.disabled);
- sb.append(", properties=").append(this.properties);
- sb.append(", message=").append(this.message);
- sb.append('}');
- return sb.toString();
- }
-
- }
-}
diff --git a/spring-cloud-launcher/spring-cloud-launcher-deployer/src/main/resources/META-INF/cli-version.txt b/spring-cloud-launcher/spring-cloud-launcher-deployer/src/main/resources/META-INF/cli-version.txt
deleted file mode 100644
index 73f30eb1..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-deployer/src/main/resources/META-INF/cli-version.txt
+++ /dev/null
@@ -1 +0,0 @@
-@project.version@
diff --git a/spring-cloud-launcher/spring-cloud-launcher-deployer/src/main/resources/META-INF/thin-local.properties b/spring-cloud-launcher/spring-cloud-launcher-deployer/src/main/resources/META-INF/thin-local.properties
deleted file mode 100644
index b288e13b..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-deployer/src/main/resources/META-INF/thin-local.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-exclusions.spring-cloud-deployer-local: org.springframework.cloud:spring-cloud-deployer-thin
-dependencies.spring-cloud-deplyer-thin: org.springframework.cloud:spring-cloud-deployer-local
diff --git a/spring-cloud-launcher/spring-cloud-launcher-deployer/src/main/resources/META-INF/thin-rabbit.properties b/spring-cloud-launcher/spring-cloud-launcher-deployer/src/main/resources/META-INF/thin-rabbit.properties
deleted file mode 100644
index 0343528f..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-deployer/src/main/resources/META-INF/thin-rabbit.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-exclusions.spring-cloud-starter-bus-kafka: org.springframework.cloud:spring-cloud-starter-bus-kafka
-dependencies.spring-cloud-starter-bus-amqp: org.springframework.cloud:spring-cloud-starter-bus-amqp
diff --git a/spring-cloud-launcher/spring-cloud-launcher-deployer/src/main/resources/META-INF/thin-thin.properties b/spring-cloud-launcher/spring-cloud-launcher-deployer/src/main/resources/META-INF/thin-thin.properties
deleted file mode 100644
index 9490409b..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-deployer/src/main/resources/META-INF/thin-thin.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-exclusions.spring-cloud-deployer-local: org.springframework.cloud:spring-cloud-deployer-local
-dependencies.spring-cloud-deplyer-thin: org.springframework.cloud:spring-cloud-deployer-thin
diff --git a/spring-cloud-launcher/spring-cloud-launcher-deployer/src/main/resources/cloud.yml b/spring-cloud-launcher/spring-cloud-launcher-deployer/src/main/resources/cloud.yml
deleted file mode 100644
index d28bbae5..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-deployer/src/main/resources/cloud.yml
+++ /dev/null
@@ -1,130 +0,0 @@
-dt:
- pre: maven://org.springframework.cloud.launcher:spring-cloud-launcher-
- ver: ${launcher.version}
- mem: 128m
- opts: -XX:TieredStopAtLevel=1 -noverify
-
-spring:
- cloud:
- maven:
- remote-repositories:
- central:
- url: https://repo1.maven.org/maven2
- spring-milestone:
- url: https://repo.spring.io/milestone
- spring-snapshot:
- url: https://repo.spring.io/snapshot
- launcher:
- deployables:
- configserver:
- coordinates: ${dt.pre}configserver:${dt.ver}
- port: 8888
- waitUntilStarted: true
- order: -100
- properties:
- spring.cloud.deployer.memory: ${dt.mem}
- spring.cloud.deployer.local.javaOpts: ${dt.opts}
- application-properties:
- management.security.enabled: false
- dataflow:
- coordinates: ${dt.pre}dataflow:${dt.ver}
- port: 9393
- properties:
- spring.cloud.deployer.memory: ${dt.mem}
- spring.cloud.deployer.local.javaOpts: ${dt.opts}
- application-properties:
- management.security.enabled: false
- eureka:
- coordinates: ${dt.pre}eureka:${dt.ver}
- port: 8761
- message: To see the dashboard open http://localhost:8761
- disabled:
- eureka.client.enabled: false
- properties:
- spring.cloud.deployer.memory: ${dt.mem}
- spring.cloud.deployer.local.javaOpts: ${dt.opts}
- application-properties:
- management.security.enabled: false
- h2:
- coordinates: ${dt.pre}h2:${dt.ver}
- port: 9095
- message: Connect on jdbc:h2:tcp://localhost:9096/mem:test, web console at http://localhost:9095
- waitUntilStarted: true
- order: -50
- enabled:
- spring.datasource.url: jdbc:h2:tcp://localhost:9096/mem:test
- spring.dataflow.embedded.database.enabled: false
- properties:
- spring.cloud.deployer.memory: ${dt.mem}
- spring.cloud.deployer.local.javaOpts: ${dt.opts}
- application-properties:
- management.security.enabled: false
- kafka:
- coordinates: ${dt.pre}kafka:${dt.ver}
- port: 9091
- waitUntilStarted: true
- order: -200
- disabled:
- spring.cloud.bus.enabled: false
- properties:
- spring.cloud.deployer.memory: ${dt.mem}
- spring.cloud.deployer.local.javaOpts: ${dt.opts}
- application-properties:
- management.security.enabled: false
- stubrunner:
- coordinates: ${dt.pre}stubrunner:${dt.ver}
- port: 8750
- message: To see the registered stubs open http://localhost:8750/stubs
- order: 0
- properties:
- spring.cloud.deployer.memory: ${dt.mem}
- spring.cloud.deployer.local.javaOpts: ${dt.opts}
- application-properties:
- management.security.enabled: false
- zipkin:
- coordinates: io.zipkin.java:zipkin-server:jar:exec:2.8.2
- port: 9411
- order: 0
- properties:
- spring.cloud.deployer.memory: ${dt.mem}
- spring.cloud.deployer.local.javaOpts: ${dt.opts}
- application-properties:
- management.security.enabled: false
- deploy: ${launcher.deploy:configserver,eureka}
-
----
-spring:
- profiles: rabbit
- cloud:
- launcher:
- deployables:
- configserver:
- properties:
- spring.cloud.deployer.thin.profile: rabbit
- application-properties:
- spring.cloud.bus.enabled: true
- eureka:
- properties:
- spring.cloud.deployer.thin.profile: rabbit
- application-properties:
- spring.cloud.bus.enabled: true
- h2:
- properties:
- spring.cloud.deployer.thin.profile: rabbit
- application-properties:
- spring.cloud.bus.enabled: true
- dataflow:
- properties:
- spring.cloud.deployer.thin.profile: rabbit
- application-properties:
- spring.cloud.bus.enabled: true
- stubrunner:
- properties:
- spring.cloud.deployer.thin.profile: rabbit
- application-properties:
- spring.cloud.bus.enabled: true
- zipkin:
- properties:
- spring.cloud.deployer.thin.profile: rabbit
- application-properties:
- spring.cloud.bus.enabled: true
diff --git a/spring-cloud-launcher/spring-cloud-launcher-deployer/src/main/resources/launcher-banner.txt b/spring-cloud-launcher/spring-cloud-launcher-deployer/src/main/resources/launcher-banner.txt
deleted file mode 100644
index d8d36467..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-deployer/src/main/resources/launcher-banner.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-${Ansi.GREEN}
-███████╗██████╗ ██████╗ ██╗███╗ ██╗ ██████╗ ██████╗██╗ ██████╗ ██╗ ██╗██████╗
-██╔════╝██╔══██╗██╔══██╗██║████╗ ██║██╔════╝ ██╔════╝██║ ██╔═══██╗██║ ██║██╔══██╗
-███████╗██████╔╝██████╔╝██║██╔██╗ ██║██║ ███╗ ██║ ██║ ██║ ██║██║ ██║██║ ██║
-╚════██║██╔═══╝ ██╔══██╗██║██║╚██╗██║██║ ██║ ██║ ██║ ██║ ██║██║ ██║██║ ██║
-███████║██║ ██║ ██║██║██║ ╚████║╚██████╔╝ ╚██████╗███████╗╚██████╔╝╚██████╔╝██████╔╝
-╚══════╝╚═╝ ╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝ ╚═════╝ ╚═════╝╚══════╝ ╚═════╝ ╚═════╝ ╚═════╝
-${Ansi.WHITE}
--- Spring Cloud Launcher --
diff --git a/spring-cloud-launcher/spring-cloud-launcher-deployer/src/test/java/org/springframework/cloud/launcher/deployer/DeployerApplicationTests.java b/spring-cloud-launcher/spring-cloud-launcher-deployer/src/test/java/org/springframework/cloud/launcher/deployer/DeployerApplicationTests.java
deleted file mode 100644
index 2899f006..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-deployer/src/test/java/org/springframework/cloud/launcher/deployer/DeployerApplicationTests.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2013-2016 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.launcher.deployer;
-
-import org.junit.Ignore;
-import org.junit.Rule;
-import org.junit.Test;
-
-import org.springframework.boot.test.system.OutputCaptureRule;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-/**
- * @author Spencer Gibb
- */
-public class DeployerApplicationTests {
-
- @Rule
- public OutputCaptureRule output = new OutputCaptureRule();
-
- @Test
- @Ignore("I don't know how to change the stored deployer version")
- public void testDefaultLibrary() throws Exception {
- DeployerApplication wrapper = new DeployerApplication();
- if (System.getProperty("project.version") != null) {
- assertThat(wrapper.getVersion())
- .contains(System.getProperty("project.version"));
- }
- }
-
- @Test
- public void testCreateClassLoaderAndListDeployables() throws Exception {
- new DeployerApplication("--launcher.list=true").run();
- assertThat(output.toString()).contains("configserver");
- }
-
- @Test
- public void testNonOptionArgsPassedDown() throws Exception {
- new DeployerApplication("--launcher.list=true", "--spring.profiles.active=test")
- .run();
- assertThat(output.toString()).contains("foo");
- }
-
- @Test
- public void testInvalidDeployableFails() throws Exception {
- new DeployerApplication("--launcher.deploy=foo,bar").run();
- assertThat(output.toString())
- .contains("The following are not valid: 'foo,bar'");
- }
-
- @Test
- public void defaultVersionReadFromFile() {
- String defaultVersion = new DeployerApplication("--launcher.deploy=foo,bar").getDefaultVersion();
- // starts with one or more digits then a .
- assertThat(defaultVersion).isNotBlank().doesNotContainAnyWhitespaces().containsPattern("^\\d+\\..*");
- }
-}
diff --git a/spring-cloud-launcher/spring-cloud-launcher-deployer/src/test/java/org/springframework/cloud/launcher/deployer/LauncherAppDeployerTests.java b/spring-cloud-launcher/spring-cloud-launcher-deployer/src/test/java/org/springframework/cloud/launcher/deployer/LauncherAppDeployerTests.java
deleted file mode 100644
index e452ec1f..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-deployer/src/test/java/org/springframework/cloud/launcher/deployer/LauncherAppDeployerTests.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2012-2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.launcher.deployer;
-
-import java.util.Arrays;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-
-import org.junit.Assume;
-import org.junit.BeforeClass;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.springframework.boot.loader.thin.ArchiveUtils;
-import org.springframework.boot.loader.tools.LogbackInitializer;
-import org.springframework.cloud.deployer.spi.app.DeploymentState;
-import org.springframework.cloud.deployer.spi.core.AppDefinition;
-import org.springframework.cloud.deployer.spi.core.AppDeploymentRequest;
-import org.springframework.cloud.deployer.thin.ThinJarAppDeployer;
-import org.springframework.core.io.FileSystemResource;
-import org.springframework.core.io.Resource;
-import org.springframework.util.StringUtils;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-/**
- * @author Dave Syer
- */
-@RunWith(Parameterized.class)
-public class LauncherAppDeployerTests {
-
- static {
- LogbackInitializer.initialize();
- }
-
- private static ThinJarAppDeployer deployer = new ThinJarAppDeployer();
- private static String resource;
-
- @BeforeClass
- public static void skip() {
- try {
- resource = "maven://org.springframework.cloud.launcher:spring-cloud-launcher-configserver:"
- + new DeployerApplication().getVersion();
- ArchiveUtils.getArchiveRoot(ArchiveUtils.getArchive(resource));
- }
- catch (Exception e) {
- Assume.assumeNoException(
- "Could not locate jar for tests. Please build spring-cloud-cli locally first.",
- e);
- }
- }
-
- @Parameterized.Parameters
- public static List data() {
- // Repeat a couple of times to ensure it's consistent
- return Arrays.asList(new Object[2][0]);
- }
-
- @Test
- @Ignore //FIXME: 2.0.x
- public void rabbit() throws Exception {
- String first = deploy(resource, "spring.cloud.deployer.thin.profile=rabbit", "");
- // Deployment is blocking so it either failed or succeeded.
- assertThat(deployer.status(first).getState()).isEqualTo(DeploymentState.deployed);
- deployer.undeploy(first);
- }
-
- private String deploy(String jarName, String deployment, String application, String... args)
- throws Exception {
- Resource resource = new FileSystemResource(
- ArchiveUtils.getArchiveRoot(ArchiveUtils.getArchive(jarName)));
- AppDefinition definition = new AppDefinition(resource.getFilename(),
- properties(application));
- AppDeploymentRequest request = new AppDeploymentRequest(definition, resource,
- properties(deployment), Arrays.asList(args));
- String deployed = deployer.deploy(request);
- return deployed;
- }
-
- private Map properties(String properties) {
- Map map = new LinkedHashMap<>();
- Properties props = StringUtils.splitArrayElementsIntoProperties(
- StringUtils.commaDelimitedListToStringArray(properties), "=");
- if (props != null) {
- for (Object name : props.keySet()) {
- String key = (String) name;
- map.put(key, props.getProperty(key));
- }
- }
- return map;
- }
-
-}
diff --git a/spring-cloud-launcher/spring-cloud-launcher-deployer/src/test/resources/cloud-test.yml b/spring-cloud-launcher/spring-cloud-launcher-deployer/src/test/resources/cloud-test.yml
deleted file mode 100644
index b9e89461..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-deployer/src/test/resources/cloud-test.yml
+++ /dev/null
@@ -1,11 +0,0 @@
-spring:
- cloud:
- launcher:
- deployables:
- foo:
- coordinates: com.example:foo:0.0.1-SNAPSHOT
- port: 8000
- waitUntilStarted: true
- order: -200
- properties:
- JAVA_OPTS: -Xmx64m
diff --git a/spring-cloud-launcher/spring-cloud-launcher-eureka/pom.xml b/spring-cloud-launcher/spring-cloud-launcher-eureka/pom.xml
deleted file mode 100644
index 3a76992f..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-eureka/pom.xml
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
- 4.0.0
-
- org.springframework.cloud.launcher
- spring-cloud-launcher-eureka
- jar
-
- spring-cloud-launcher-eureka
- Spring Cloud Launcher Eureka
-
-
- org.springframework.cloud
- spring-cloud-launcher
- 3.1.2-SNAPSHOT
-
-
-
-
- org.springframework.boot
- spring-boot-starter-actuator
-
-
- org.springframework.cloud
- spring-cloud-starter-config
-
-
- org.springframework.cloud
- spring-cloud-starter-bus-kafka
-
-
- org.springframework.cloud
- spring-cloud-netflix-eureka-server
-
-
- javax.xml.bind
- jaxb-api
-
-
- org.glassfish.jaxb
- jaxb-runtime
-
-
- javax.activation
- javax.activation-api
-
-
- org.springframework.boot
- spring-boot-starter-test
- test
-
-
- org.junit.vintage
- junit-vintage-engine
- test
-
-
-
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
-
-
diff --git a/spring-cloud-launcher/spring-cloud-launcher-eureka/src/main/java/org/springframework/cloud/launcher/eureka/EurekaApplication.java b/spring-cloud-launcher/spring-cloud-launcher-eureka/src/main/java/org/springframework/cloud/launcher/eureka/EurekaApplication.java
deleted file mode 100644
index c6624cf7..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-eureka/src/main/java/org/springframework/cloud/launcher/eureka/EurekaApplication.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2013-2016 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.launcher.eureka;
-
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
-
-/**
- * @author Spencer Gibb
- */
-@EnableEurekaServer
-@SpringBootApplication
-public class EurekaApplication {
- public static void main(String[] args) {
- SpringApplication.run(EurekaApplication.class, args);
- }
-}
diff --git a/spring-cloud-launcher/spring-cloud-launcher-eureka/src/main/resources/META-INF/thin-rabbit.properties b/spring-cloud-launcher/spring-cloud-launcher-eureka/src/main/resources/META-INF/thin-rabbit.properties
deleted file mode 100644
index 0343528f..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-eureka/src/main/resources/META-INF/thin-rabbit.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-exclusions.spring-cloud-starter-bus-kafka: org.springframework.cloud:spring-cloud-starter-bus-kafka
-dependencies.spring-cloud-starter-bus-amqp: org.springframework.cloud:spring-cloud-starter-bus-amqp
diff --git a/spring-cloud-launcher/spring-cloud-launcher-eureka/src/main/resources/application.yml b/spring-cloud-launcher/spring-cloud-launcher-eureka/src/main/resources/application.yml
deleted file mode 100644
index 71e0bab6..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-eureka/src/main/resources/application.yml
+++ /dev/null
@@ -1,15 +0,0 @@
-server:
- port: 8761
-
-eureka:
- client:
- registerWithEureka: false
- fetchRegistry: false
- server:
- renewal-percent-threshold: 0.01
- waitTimeInMsWhenSyncEmpty: 0
-
-info:
- artifactId: "@project.artifactId@"
- description: "@project.description@"
- version: "@project.version@"
\ No newline at end of file
diff --git a/spring-cloud-launcher/spring-cloud-launcher-eureka/src/main/resources/bootstrap.yml b/spring-cloud-launcher/spring-cloud-launcher-eureka/src/main/resources/bootstrap.yml
deleted file mode 100644
index 076a289b..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-eureka/src/main/resources/bootstrap.yml
+++ /dev/null
@@ -1,3 +0,0 @@
-spring:
- application:
- name: eurekaserver
diff --git a/spring-cloud-launcher/spring-cloud-launcher-eureka/src/test/java/org/springframework/cloud/launcher/eureka/DeployerApplicationTests.java b/spring-cloud-launcher/spring-cloud-launcher-eureka/src/test/java/org/springframework/cloud/launcher/eureka/DeployerApplicationTests.java
deleted file mode 100644
index 3729d109..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-eureka/src/test/java/org/springframework/cloud/launcher/eureka/DeployerApplicationTests.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package org.springframework.cloud.launcher.eureka;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit4.SpringRunner;
-
-@RunWith(SpringRunner.class)
-@SpringBootTest({"spring.cloud.bus.enabled=false", "spring.cloud.config.enabled=false"})
-public class DeployerApplicationTests {
-
- @Test
- public void contextLoads() {
- }
-
-}
diff --git a/spring-cloud-launcher/spring-cloud-launcher-h2/pom.xml b/spring-cloud-launcher/spring-cloud-launcher-h2/pom.xml
deleted file mode 100644
index ddefb188..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-h2/pom.xml
+++ /dev/null
@@ -1,87 +0,0 @@
-
-
- 4.0.0
-
- org.springframework.cloud.launcher
- spring-cloud-launcher-h2
- jar
-
- spring-cloud-launcher-h2
- Spring Cloud Launcher H2
-
-
- org.springframework.cloud
- spring-cloud-launcher
- 3.1.2-SNAPSHOT
-
-
-
-
- com.h2database
- h2
-
-
- org.springframework.boot
- spring-boot-starter-web
-
-
- org.springframework.boot
- spring-boot-starter-actuator
-
-
- org.springframework.cloud
- spring-cloud-starter-config
-
-
- org.springframework.cloud
- spring-cloud-starter-bus-kafka
-
-
- org.springframework.cloud
- spring-cloud-netflix-eureka-client
-
-
- com.netflix.eureka
- eureka-client
-
-
- com.sun.jersey
- jersey-client
-
-
- com.sun.jersey
- jersey-core
-
-
- com.sun.jersey.contribs
- jersey-apache-client4
-
-
- com.netflix.archaius
- archaius-core
-
-
-
-
- org.springframework.boot
- spring-boot-starter-test
- test
-
-
- org.junit.vintage
- junit-vintage-engine
- test
-
-
-
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
-
-
diff --git a/spring-cloud-launcher/spring-cloud-launcher-h2/src/main/java/org/springframework/cloud/launcher/h2/H2Application.java b/spring-cloud-launcher/spring-cloud-launcher-h2/src/main/java/org/springframework/cloud/launcher/h2/H2Application.java
deleted file mode 100644
index 2ac88e7a..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-h2/src/main/java/org/springframework/cloud/launcher/h2/H2Application.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright 2013-2016 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.launcher.h2;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.h2.server.web.WebServlet;
-import org.h2.tools.Console;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.boot.web.servlet.ServletRegistrationBean;
-import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
-import org.springframework.context.SmartLifecycle;
-import org.springframework.context.annotation.Bean;
-import org.springframework.stereotype.Controller;
-import org.springframework.stereotype.Service;
-import org.springframework.util.Assert;
-import org.springframework.util.ReflectionUtils;
-import org.springframework.util.StringUtils;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * @author Spencer Gibb
- */
-@EnableDiscoveryClient
-@SpringBootApplication
-@Controller
-public class H2Application {
-
- private static final Log log = LogFactory.getLog(H2Application.class);
-
- public static void main(String[] args) {
- SpringApplication.run(H2Application.class, args);
- }
-
- @Bean
- public ServletRegistrationBean h2Console() {
- String urlMapping = "/*";
- ServletRegistrationBean registration = new ServletRegistrationBean(new WebServlet(), urlMapping);
- registration.addInitParameter("-webAllowOthers", "");
- return registration;
- }
- @Service
- static class H2Server implements SmartLifecycle {
- private AtomicBoolean running = new AtomicBoolean(false);
-
- private Console console;
-
- @Value("${spring.datasource.url:jdbc:h2:tcp://localhost:9096/./target/test}")
- private String dataSourceUrl;
-
- @Override
- public boolean isAutoStartup() {
- return true;
- }
-
- @Override
- public void stop(Runnable callback) {
- stop();
- callback.run();
- }
-
- @Override
- public void start() {
- if (this.running.compareAndSet(false, true)) {
- try {
- log.info("Starting H2 Server");
- this.console = new Console();
- this.console.runTool("-tcp", "-tcpAllowOthers", "-tcpPort", getH2Port(this.dataSourceUrl));
- } catch (Exception e) {
- ReflectionUtils.rethrowRuntimeException(e);
- }
- }
- }
-
- private String getH2Port(String url) {
- String[] tokens = StringUtils.tokenizeToStringArray(url, ":");
- Assert.isTrue(tokens.length >= 5, "URL not properly formatted");
- return tokens[4].substring(0, tokens[4].indexOf("/"));
- }
-
- @Override
- public void stop() {
- if (this.running.compareAndSet(true, false)) {
- log.info("Stopping H2 Server");
- this.console.shutdown();
- }
- }
-
- @Override
- public boolean isRunning() {
- return this.running.get();
- }
-
- @Override
- public int getPhase() {
- return 0;
- }
- }
-}
diff --git a/spring-cloud-launcher/spring-cloud-launcher-h2/src/main/resources/META-INF/thin-rabbit.properties b/spring-cloud-launcher/spring-cloud-launcher-h2/src/main/resources/META-INF/thin-rabbit.properties
deleted file mode 100644
index 0343528f..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-h2/src/main/resources/META-INF/thin-rabbit.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-exclusions.spring-cloud-starter-bus-kafka: org.springframework.cloud:spring-cloud-starter-bus-kafka
-dependencies.spring-cloud-starter-bus-amqp: org.springframework.cloud:spring-cloud-starter-bus-amqp
diff --git a/spring-cloud-launcher/spring-cloud-launcher-h2/src/main/resources/application.yml b/spring-cloud-launcher/spring-cloud-launcher-h2/src/main/resources/application.yml
deleted file mode 100644
index 52467522..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-h2/src/main/resources/application.yml
+++ /dev/null
@@ -1,14 +0,0 @@
-server:
- port: 9095
-
-info:
- artifactId: "@project.artifactId@"
- description: "@project.description@"
- version: "@project.version@"
-
-eureka:
- instance:
- # port of the h2 console
- non-secure-port: 9095
- status-page-url-path: / #allows you to click on the link in eureka dashboard
-
diff --git a/spring-cloud-launcher/spring-cloud-launcher-h2/src/main/resources/bootstrap.yml b/spring-cloud-launcher/spring-cloud-launcher-h2/src/main/resources/bootstrap.yml
deleted file mode 100644
index 52cbd0fc..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-h2/src/main/resources/bootstrap.yml
+++ /dev/null
@@ -1,3 +0,0 @@
-spring:
- application:
- name: h2server
diff --git a/spring-cloud-launcher/spring-cloud-launcher-h2/src/test/java/org/springframework/cloud/launcher/h2/DeployerApplicationTests.java b/spring-cloud-launcher/spring-cloud-launcher-h2/src/test/java/org/springframework/cloud/launcher/h2/DeployerApplicationTests.java
deleted file mode 100644
index 6a5be8f0..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-h2/src/test/java/org/springframework/cloud/launcher/h2/DeployerApplicationTests.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package org.springframework.cloud.launcher.h2;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit4.SpringRunner;
-
-@RunWith(SpringRunner.class)
-@SpringBootTest({"spring.cloud.bus.enabled=false", "spring.cloud.config.enabled=false"})
-public class DeployerApplicationTests {
-
- @Test
- public void contextLoads() {
- }
-
-}
diff --git a/spring-cloud-launcher/spring-cloud-launcher-kafka/pom.xml b/spring-cloud-launcher/spring-cloud-launcher-kafka/pom.xml
deleted file mode 100644
index 85dd2dd4..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-kafka/pom.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-
-
- 4.0.0
-
- org.springframework.cloud.launcher
- spring-cloud-launcher-kafka
- jar
-
- spring-cloud-launcher-kafka
- Spring Cloud Launcher Kafka
-
-
- org.springframework.cloud
- spring-cloud-launcher
- 3.1.2-SNAPSHOT
-
-
-
-
- org.springframework.boot
- spring-boot-starter-web
-
-
- org.springframework.boot
- spring-boot-starter-actuator
-
-
- org.springframework.cloud
- spring-cloud-starter-config
-
-
- org.springframework.kafka
- spring-kafka-test
-
-
- org.springframework.boot
- spring-boot-starter-test
- test
-
-
-
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
-
-
diff --git a/spring-cloud-launcher/spring-cloud-launcher-kafka/src/main/java/org/springframework/cloud/launcher/kafka/KafkaApplication.java b/spring-cloud-launcher/spring-cloud-launcher-kafka/src/main/java/org/springframework/cloud/launcher/kafka/KafkaApplication.java
deleted file mode 100644
index dfa26eec..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-kafka/src/main/java/org/springframework/cloud/launcher/kafka/KafkaApplication.java
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright 2013-2016 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.launcher.kafka;
-
-import java.io.File;
-import java.net.InetSocketAddress;
-import java.util.Properties;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import org.I0Itec.zkclient.ZkClient;
-import org.I0Itec.zkclient.exception.ZkInterruptedException;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.kafka.common.utils.Time;
-import org.apache.kafka.common.utils.Utils;
-import org.apache.zookeeper.server.NIOServerCnxnFactory;
-import org.apache.zookeeper.server.ZooKeeperServer;
-
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.boot.builder.SpringApplicationBuilder;
-import org.springframework.context.SmartLifecycle;
-import org.springframework.stereotype.Service;
-import org.springframework.util.ReflectionUtils;
-
-import kafka.server.KafkaConfig;
-import kafka.server.KafkaServer;
-import kafka.server.NotRunning;
-import kafka.utils.CoreUtils;
-import kafka.utils.TestUtils;
-import kafka.utils.ZKStringSerializer$;
-
-/**
- * @author Spencer Gibb
- *
- * see https://github.com/spring-projects/spring-kafka/blob/2.0.x/spring-kafka-test/src/main/java/org/springframework/kafka/test/rule/KafkaEmbedded.java
- */
-@SpringBootApplication
-public class KafkaApplication {
-
- private static final Log log = LogFactory.getLog(KafkaApplication.class);
-
- public static void main(String[] args) {
- new SpringApplicationBuilder(KafkaApplication.class).run(args);
- }
-
- @Service
- static class KafkaDevServer implements SmartLifecycle {
- private AtomicBoolean running = new AtomicBoolean(false);
- private ZkClient zkClient;
-
- private EmbeddedZookeeper zookeeper;
-
- private KafkaServer kafkaServer;
-
- @Value("${kafka.port:${KAFKA_PORT:9092}}")
- private int port;
-
- @Value("${zk.port:${ZK_PORT:2181}}")
- private int zkPort;
-
- @Override
- public boolean isAutoStartup() {
- return true;
- }
-
- @Override
- public void stop(Runnable callback) {
- stop();
- callback.run();
- }
-
- @Override
- public void start() {
- if (this.running.compareAndSet(false, true)) {
- try {
- log.info("Starting Zookeeper");
- this.zookeeper = new EmbeddedZookeeper(this.zkPort);
- String zkConnectString = "127.0.0.1:" + this.zookeeper.getPort();
- log.info("Started Zookeeper at " + zkConnectString);
- try {
- int zkConnectionTimeout = 10000;
- int zkSessionTimeout = 10000;
- zkClient = new ZkClient(zkConnectString, zkSessionTimeout,
- zkConnectionTimeout, ZKStringSerializer$.MODULE$);
- }
- catch (Exception e) {
- zookeeper.shutdown();
- throw e;
- }
- try {
- log.info("Creating Kafka server");
- // TODO: move to properties?
- int nodeId = 0;
- boolean enableControlledShutdown = true;
- Properties brokerConfigProperties = TestUtils.createBrokerConfig(
- nodeId, zkConnectString, enableControlledShutdown, true,
- port, scala.Option.apply(null),
- scala.Option.apply(null),
- scala.Option.apply(null), true, false, 0,
- false, 0, false, 0, scala.Option.apply(null), 1, false);
- brokerConfigProperties.setProperty("replica.socket.timeout.ms",
- "1000");
- brokerConfigProperties.setProperty("controller.socket.timeout.ms",
- "1000");
- brokerConfigProperties
- .setProperty("offsets.topic.replication.factor", "1");
- brokerConfigProperties.put("zookeeper.connect", zkConnectString);
- kafkaServer = TestUtils.createServer(
- new KafkaConfig(brokerConfigProperties),
- Time.SYSTEM);
- log.info("Created Kafka server at "
- + kafkaServer.config().hostName() + ":"
- + kafkaServer.config().port());
- }
- catch (Exception e) {
- zookeeper.shutdown();
- zkClient.close();
- throw e;
- }
- }
- catch (Exception e) {
- ReflectionUtils.rethrowRuntimeException(e);
- }
- }
- }
-
- @Override
- public void stop() {
- if (this.running.compareAndSet(true, false)) {
- log.info("Stopping Kafka");
- try {
- if (kafkaServer.brokerState()
- .currentState() != (NotRunning.state())) {
- kafkaServer.shutdown();
- kafkaServer.awaitShutdown();
- }
- }
- catch (Exception e) {
- // do nothing
- }
- try {
- CoreUtils.delete(kafkaServer.config().logDirs());
- }
- catch (Exception e) {
- // do nothing
- }
- log.info("Stopping Zookeeper");
- try {
- this.zkClient.close();
- }
- catch (ZkInterruptedException e) {
- // do nothing
- }
- try {
- this.zookeeper.shutdown();
- }
- catch (Exception e) {
- // do nothing
- }
- }
- }
-
- @Override
- public boolean isRunning() {
- return this.running.get();
- }
-
- @Override
- public int getPhase() {
- return 0;
- }
- }
-
- static class EmbeddedZookeeper {
- private File snapshotDir = TestUtils.tempDir();
- private File logDir = TestUtils.tempDir();
- private int tickTime = 500;
- private NIOServerCnxnFactory factory = new NIOServerCnxnFactory();
- private ZooKeeperServer zookeeper;
- private InetSocketAddress addr;
- private int port;
-
- public EmbeddedZookeeper(int port) throws Exception {
- this.port = port;
- zookeeper = new ZooKeeperServer(snapshotDir, logDir, tickTime);
- addr = new InetSocketAddress("127.0.0.1", port);
- factory.configure(addr, 0);
- factory.startup(zookeeper);
- }
-
- public int getPort() {
- return port;
- }
-
- void shutdown() throws Exception {
- zookeeper.shutdown();
- factory.shutdown();
- Utils.delete(logDir);
- Utils.delete(snapshotDir);
- }
- }
-}
diff --git a/spring-cloud-launcher/spring-cloud-launcher-kafka/src/main/resources/application.yml b/spring-cloud-launcher/spring-cloud-launcher-kafka/src/main/resources/application.yml
deleted file mode 100644
index 528e2585..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-kafka/src/main/resources/application.yml
+++ /dev/null
@@ -1,13 +0,0 @@
-server:
- port: 9091
-
-kafka:
- port: 9092
-
-zk:
- port: 2181
-
-info:
- artifactId: "@project.artifactId@"
- description: "@project.description@"
- version: "@project.version@"
\ No newline at end of file
diff --git a/spring-cloud-launcher/spring-cloud-launcher-kafka/src/main/resources/bootstrap.yml b/spring-cloud-launcher/spring-cloud-launcher-kafka/src/main/resources/bootstrap.yml
deleted file mode 100644
index fccd3ad1..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-kafka/src/main/resources/bootstrap.yml
+++ /dev/null
@@ -1,3 +0,0 @@
-spring:
- application:
- name: kafka
diff --git a/spring-cloud-launcher/spring-cloud-launcher-kafka/src/test/java/org/springframework/cloud/launcher/kafka/DeployerApplicationTests.java b/spring-cloud-launcher/spring-cloud-launcher-kafka/src/test/java/org/springframework/cloud/launcher/kafka/DeployerApplicationTests.java
deleted file mode 100644
index 2b0c04ba..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-kafka/src/test/java/org/springframework/cloud/launcher/kafka/DeployerApplicationTests.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package org.springframework.cloud.launcher.kafka;
-
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit4.SpringRunner;
-import org.springframework.util.SocketUtils;
-
-@RunWith(SpringRunner.class)
-@SpringBootTest
-public class DeployerApplicationTests {
-
- @BeforeClass
- public static void before() {
- System.setProperty("kafka.port", String.valueOf(SocketUtils.findAvailableTcpPort()));
- System.setProperty("zk.port", String.valueOf(SocketUtils.findAvailableTcpPort()));
- }
-
- @AfterClass
- public static void after() {
- System.clearProperty("kafka.port");
- System.clearProperty("zk.port");
- }
-
- @Test
- public void contextLoads() {
- }
-
-}
diff --git a/spring-cloud-launcher/spring-cloud-launcher-stubrunner/pom.xml b/spring-cloud-launcher/spring-cloud-launcher-stubrunner/pom.xml
deleted file mode 100644
index f2c18f6b..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-stubrunner/pom.xml
+++ /dev/null
@@ -1,59 +0,0 @@
-
-
- 4.0.0
-
- org.springframework.cloud.launcher
- spring-cloud-launcher-stubrunner
- jar
-
- spring-cloud-launcher-stubrunner
- Spring Cloud Launcher Stub Runner
-
-
- org.springframework.cloud
- spring-cloud-launcher
- 3.1.2-SNAPSHOT
-
-
-
-
- org.springframework.boot
- spring-boot-starter-actuator
-
-
- org.springframework.boot
- spring-boot-starter-web
-
-
- org.springframework.cloud
- spring-cloud-starter-contract-stub-runner
-
-
- org.springframework.boot
- spring-boot-starter-test
-
-
-
-
- org.springframework.boot
- spring-boot-starter-test
- ${spring-boot.version}
- test
-
-
- org.junit.vintage
- junit-vintage-engine
- test
-
-
-
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
-
-
diff --git a/spring-cloud-launcher/spring-cloud-launcher-stubrunner/src/main/java/org/springframework/cloud/launcher/stubrunner/StubRunnerApplication.java b/spring-cloud-launcher/spring-cloud-launcher-stubrunner/src/main/java/org/springframework/cloud/launcher/stubrunner/StubRunnerApplication.java
deleted file mode 100644
index 112afe29..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-stubrunner/src/main/java/org/springframework/cloud/launcher/stubrunner/StubRunnerApplication.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2013-2016 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.launcher.stubrunner;
-
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.cloud.contract.stubrunner.server.EnableStubRunnerServer;
-
-/**
- * @author Marcin Grzejszczak
- */
-@EnableStubRunnerServer
-@SpringBootApplication
-public class StubRunnerApplication {
- public static void main(String[] args) {
- SpringApplication.run(StubRunnerApplication.class, args);
- }
-}
diff --git a/spring-cloud-launcher/spring-cloud-launcher-stubrunner/src/main/resources/META-INF/thin-rabbit.properties b/spring-cloud-launcher/spring-cloud-launcher-stubrunner/src/main/resources/META-INF/thin-rabbit.properties
deleted file mode 100644
index 0343528f..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-stubrunner/src/main/resources/META-INF/thin-rabbit.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-exclusions.spring-cloud-starter-bus-kafka: org.springframework.cloud:spring-cloud-starter-bus-kafka
-dependencies.spring-cloud-starter-bus-amqp: org.springframework.cloud:spring-cloud-starter-bus-amqp
diff --git a/spring-cloud-launcher/spring-cloud-launcher-stubrunner/src/main/resources/application.yml b/spring-cloud-launcher/spring-cloud-launcher-stubrunner/src/main/resources/application.yml
deleted file mode 100644
index d65102df..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-stubrunner/src/main/resources/application.yml
+++ /dev/null
@@ -1,11 +0,0 @@
-spring:
- application:
- name: stubrunner
-
-server:
- port: 8750
-
-info:
- artifactId: "@project.artifactId@"
- description: "@project.description@"
- version: "@project.version@"
\ No newline at end of file
diff --git a/spring-cloud-launcher/spring-cloud-launcher-stubrunner/src/main/resources/launcher/application.yml b/spring-cloud-launcher/spring-cloud-launcher-stubrunner/src/main/resources/launcher/application.yml
deleted file mode 100644
index 2fcfda4b..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-stubrunner/src/main/resources/launcher/application.yml
+++ /dev/null
@@ -1,30 +0,0 @@
-info:
- description: Spring Cloud Launcher
-
-eureka:
- client:
- instance-info-replication-interval-seconds: 5
- initial-instance-info-replication-interval-seconds: 5
- serviceUrl:
- defaultZone: http://localhost:8761/eureka/
-
-endpoints:
- restart:
- enabled: true
-
-ribbon:
- ConnectTimeout: 3000
- ReadTimeout: 60000
-
-h2.datasource.url: jdbc:h2:tcp://localhost:9096/./target/test
-#spring:
-# datasource:
-# url: ${h2.datasource.url}
-
-logging:
- level:
- kafka: WARN
- org.apache.zookeeper: WARN
- org.apache.zookeeper.ClientCnxn: ERROR
- org.apache.kafka: WARN
- org.I0Itec: WARN
diff --git a/spring-cloud-launcher/spring-cloud-launcher-stubrunner/src/test/java/org/springframework/cloud/launcher/stubrunner/DeployerApplicationTests.java b/spring-cloud-launcher/spring-cloud-launcher-stubrunner/src/test/java/org/springframework/cloud/launcher/stubrunner/DeployerApplicationTests.java
deleted file mode 100644
index 96f9c04a..00000000
--- a/spring-cloud-launcher/spring-cloud-launcher-stubrunner/src/test/java/org/springframework/cloud/launcher/stubrunner/DeployerApplicationTests.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package org.springframework.cloud.launcher.stubrunner;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit4.SpringRunner;
-
-@RunWith(SpringRunner.class)
-@SpringBootTest
-public class DeployerApplicationTests {
-
- @Test
- public void contextLoads() {
- }
-
-}