You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by zr...@apache.org on 2019/09/04 21:02:00 UTC

[camel] 06/16: CAMEL-13588: additional escapes for URLs

This is an automated email from the ASF dual-hosted git repository.

zregvart pushed a commit to branch camel-2.x
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 4a269a129f4e8b796d0e090c80b1fcc4ec978192
Author: Zoran Regvart <zr...@apache.org>
AuthorDate: Tue Sep 3 11:35:41 2019 +0200

    CAMEL-13588: additional escapes for URLs
    
    (cherry picked from commit 9a9dd2a5a56628f2a367bf95b83279c07f31b9c7)
    
    # Conflicts:
    #	components/camel-drill/src/main/docs/drill-component.adoc
    #	components/camel-file/src/main/docs/file-component.adoc
    #	components/camel-ftp/src/main/docs/ftp-component.adoc
    #	components/camel-ftp/src/main/docs/ftps-component.adoc
    #	components/camel-ftp/src/main/docs/sftp-component.adoc
    #	components/camel-http4/src/main/docs/http4-component.adoc
    #	components/camel-jira/src/main/docs/jira-component.adoc
    #	components/camel-kafka/src/main/docs/kafka-component.adoc
    #	components/camel-linkedin/camel-linkedin-component/src/main/docs/linkedin-component.adoc
    #	components/camel-rabbitmq/src/main/docs/rabbitmq-component.adoc
    #	components/camel-rest-swagger/src/main/docs/rest-swagger-component.adoc
    #	components/camel-rest-swagger/src/main/java/org/apache/camel/component/rest/swagger/RestSwaggerComponent.java
    #	components/camel-salesforce/camel-salesforce-component/src/main/docs/salesforce-component.adoc
    #	components/camel-wordpress/src/main/docs/wordpress-component.adoc
    #	components/camel-xmlsecurity/src/main/docs/xmlsecurity-component.adoc
    #	components/readme.adoc
    #	docs/components/modules/ROOT/pages/ahc-component.adoc
    #	docs/components/modules/ROOT/pages/ahc-ws-component.adoc
    #	docs/components/modules/ROOT/pages/crypto-cms-component.adoc
    #	docs/components/modules/ROOT/pages/drill-component.adoc
    #	docs/components/modules/ROOT/pages/facebook-component.adoc
    #	docs/components/modules/ROOT/pages/file-component.adoc
    #	docs/components/modules/ROOT/pages/ftp-component.adoc
    #	docs/components/modules/ROOT/pages/ftps-component.adoc
    #	docs/components/modules/ROOT/pages/google-calendar-component.adoc
    #	docs/components/modules/ROOT/pages/google-calendar-stream-component.adoc
    #	docs/components/modules/ROOT/pages/google-drive-component.adoc
    #	docs/components/modules/ROOT/pages/google-sheets-stream-component.adoc
    #	docs/components/modules/ROOT/pages/http4-component.adoc
    #	docs/components/modules/ROOT/pages/ironmq-component.adoc
    #	docs/components/modules/ROOT/pages/jira-component.adoc
    #	docs/components/modules/ROOT/pages/kafka-component.adoc
    #	docs/components/modules/ROOT/pages/linkedin-component.adoc
    #	docs/components/modules/ROOT/pages/lra.adoc
    #	docs/components/modules/ROOT/pages/netty4-component.adoc
    #	docs/components/modules/ROOT/pages/netty4-http-component.adoc
    #	docs/components/modules/ROOT/pages/olingo2-component.adoc
    #	docs/components/modules/ROOT/pages/olingo4-component.adoc
    #	docs/components/modules/ROOT/pages/rabbitmq-component.adoc
    #	docs/components/modules/ROOT/pages/rest-swagger-component.adoc
    #	docs/components/modules/ROOT/pages/salesforce-component.adoc
    #	docs/components/modules/ROOT/pages/servicenow-component.adoc
    #	docs/components/modules/ROOT/pages/sftp-component.adoc
    #	docs/components/modules/ROOT/pages/wordpress-component.adoc
    #	docs/components/modules/ROOT/pages/xmlsecurity-component.adoc
    #	docs/components/modules/ROOT/pages/zipkin.adoc
    #	tooling/maven/camel-package-maven-plugin/pom.xml
    #	tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/UpdateSpringBootAutoConfigurationReadmeMojo.java
    #	tooling/maven/camel-package-maven-plugin/src/main/resources/spring-boot-auto-configure-options.mvel
---
 .../src/main/docs/ahc-ws-component.adoc            |  2 +-
 .../camel-ahc/src/main/docs/ahc-component.adoc     |  2 +-
 .../src/main/docs/crypto-cms-component.adoc        |  4 +-
 .../src/main/docs/facebook-component.adoc          |  4 +-
 .../src/main/docs/google-calendar-component.adoc   |  4 +-
 .../docs/google-calendar-stream-component.adoc     |  4 +-
 .../src/main/docs/google-drive-component.adoc      |  4 +-
 .../main/docs/google-sheets-stream-component.adoc  |  4 +-
 .../src/main/docs/ironmq-component.adoc            |  2 +-
 components/camel-lra/src/main/docs/lra.adoc        |  4 +-
 .../src/main/docs/netty4-http-component.adoc       |  2 +-
 .../src/main/docs/netty4-component.adoc            |  4 +-
 .../src/main/docs/olingo2-component.adoc           |  4 +-
 .../src/main/docs/olingo4-component.adoc           |  4 +-
 .../src/main/docs/servicenow-component.adoc        |  8 +--
 components/camel-zipkin/src/main/docs/zipkin.adoc  |  2 +-
 tooling/maven/camel-package-maven-plugin/pom.xml   |  5 ++
 .../apache/camel/maven/packaging/MvelHelper.java   | 43 ++++++++++++++
 .../camel/maven/packaging/PrepareExampleMojo.java  |  2 +-
 .../camel/maven/packaging/PrepareReadmeMojo.java   | 10 ++--
 .../camel/maven/packaging/UpdateReadmeMojo.java    |  3 +-
 ...pdateSpringBootAutoConfigurationReadmeMojo.java | 17 +++++-
 .../src/main/resources/component-options.mvel      |  2 +-
 .../src/main/resources/dataformat-options.mvel     |  2 +-
 .../src/main/resources/eip-options.mvel            |  2 +-
 .../src/main/resources/endpoint-options.mvel       |  4 +-
 .../src/main/resources/language-options.mvel       |  2 +-
 .../src/main/resources/readme-components.mvel      |  2 +-
 .../src/main/resources/readme-dataformats.mvel     |  2 +-
 .../src/main/resources/readme-eips.mvel            |  2 +-
 .../src/main/resources/readme-examples.mvel        |  2 +-
 .../src/main/resources/readme-languages.mvel       |  2 +-
 .../src/main/resources/readme-others.mvel          |  2 +-
 .../spring-boot-auto-configure-options.mvel        |  2 +-
 .../camel/maven/packaging/MvelHelperTest.java      | 66 ++++++++++++++++++++++
 35 files changed, 180 insertions(+), 50 deletions(-)

diff --git a/components/camel-ahc-ws/src/main/docs/ahc-ws-component.adoc b/components/camel-ahc-ws/src/main/docs/ahc-ws-component.adoc
index 287f089..505e403 100644
--- a/components/camel-ahc-ws/src/main/docs/ahc-ws-component.adoc
+++ b/components/camel-ahc-ws/src/main/docs/ahc-ws-component.adoc
@@ -78,7 +78,7 @@ with the following path and query parameters:
 [width="100%",cols="2,5,^1,2",options="header"]
 |===
 | Name | Description | Default | Type
-| *httpUri* | *Required* The URI to use such as http://hostname:port/path |  | URI
+| *httpUri* | *Required* The URI to use such as \http://hostname:port/path |  | URI
 |===
 
 
diff --git a/components/camel-ahc/src/main/docs/ahc-component.adoc b/components/camel-ahc/src/main/docs/ahc-component.adoc
index 0f2759d..f3b162f 100644
--- a/components/camel-ahc/src/main/docs/ahc-component.adoc
+++ b/components/camel-ahc/src/main/docs/ahc-component.adoc
@@ -59,7 +59,7 @@ with the following path and query parameters:
 [width="100%",cols="2,5,^1,2",options="header"]
 |===
 | Name | Description | Default | Type
-| *httpUri* | *Required* The URI to use such as http://hostname:port/path |  | URI
+| *httpUri* | *Required* The URI to use such as \http://hostname:port/path |  | URI
 |===
 
 
diff --git a/components/camel-crypto-cms/src/main/docs/crypto-cms-component.adoc b/components/camel-crypto-cms/src/main/docs/crypto-cms-component.adoc
index df3bb6d..a9bd7ab 100644
--- a/components/camel-crypto-cms/src/main/docs/crypto-cms-component.adoc
+++ b/components/camel-crypto-cms/src/main/docs/crypto-cms-component.adoc
@@ -79,10 +79,10 @@ with the following path and query parameters:
 | *password* (decrypt) | Sets the password of the private keys. It is assumed that all private keys in the keystore have the same password. If not set then it is assumed that the password of the private keys is given by the keystore password given in the KeyStoreParameters. |  | Char[]
 | *fromBase64* (decrypt_verify) | If true then the CMS message is base 64 encoded and must be decoded during the processing. Default value is false. | false | Boolean
 | *contentEncryptionAlgorithm* (encrypt) | Encryption algorithm, for example DESede/CBC/PKCS5Padding. Further possible values: DESede/CBC/PKCS5Padding, AES/CBC/PKCS5Padding, Camellia/CBC/PKCS5Padding, CAST5/CBC/PKCS5Padding. |  | String
-| *originatorInformation Provider* (encrypt) | Provider for the originator info. See https://tools.ietf.org/html/rfc5652#section-6.1. The default value is null. |  | OriginatorInformation Provider
+| *originatorInformation Provider* (encrypt) | Provider for the originator info. See \https://tools.ietf.org/html/rfc5652#section-6.1. The default value is null. |  | OriginatorInformation Provider
 | *recipient* (encrypt) | Recipient Info: reference to a bean which implements the interface org.apache.camel.component.crypto.cms.api.TransRecipientInfo |  | List
 | *secretKeyLength* (encrypt) | Key length for the secret symmetric key used for the content encryption. Only used if the specified content-encryption algorithm allows keys of different sizes. If contentEncryptionAlgorithm=AES/CBC/PKCS5Padding or Camellia/CBC/PKCS5Padding then 128; if contentEncryptionAlgorithm=DESede/CBC/PKCS5Padding then 192, 128; if strong encryption is enabled then for AES/CBC/PKCS5Padding and Camellia/CBC/PKCS5Padding also the key lengths 192 and 256 are possible. |  | int
-| *unprotectedAttributes GeneratorProvider* (encrypt) | Provider of the generator for the unprotected attributes. The default value is null which means no unprotected attribute is added to the Enveloped Data object. See https://tools.ietf.org/html/rfc5652#section-6.1. |  | AttributesGenerator Provider
+| *unprotectedAttributes GeneratorProvider* (encrypt) | Provider of the generator for the unprotected attributes. The default value is null which means no unprotected attribute is added to the Enveloped Data object. See \https://tools.ietf.org/html/rfc5652#section-6.1. |  | AttributesGenerator Provider
 | *toBase64* (encrypt_sign) | Indicates whether the Signed Data or Enveloped Data instance shall be base 64 encoded. Default value is false. | false | Boolean
 | *includeContent* (sign) | Indicates whether the signed content should be included into the Signed Data instance. If false then a detached Signed Data instance is created in the header CamelCryptoCmsSignedData. | true | Boolean
 | *signer* (sign) | Signer information: reference to a bean which implements org.apache.camel.component.crypto.cms.api.SignerInfo |  | List
diff --git a/components/camel-facebook/src/main/docs/facebook-component.adoc b/components/camel-facebook/src/main/docs/facebook-component.adoc
index b821149..fd475bc 100644
--- a/components/camel-facebook/src/main/docs/facebook-component.adoc
+++ b/components/camel-facebook/src/main/docs/facebook-component.adoc
@@ -195,7 +195,7 @@ with the following path and query parameters:
 | *oAuthAppId* (security) | The application Id |  | String
 | *oAuthAppSecret* (security) | The application Secret |  | String
 | *oAuthAuthorizationURL* (security) | OAuth authorization URL | https://www.facebook.com/dialog/oauth | String
-| *oAuthPermissions* (security) | Default OAuth permissions. Comma separated permission names. See https://developers.facebook.com/docs/reference/login/#permissions for the detail |  | String
+| *oAuthPermissions* (security) | Default OAuth permissions. Comma separated permission names. See \https://developers.facebook.com/docs/reference/login/#permissions for the detail |  | String
 |===
 // endpoint options: END
 // spring-boot-auto-configure options: START
@@ -231,7 +231,7 @@ The component supports 29 options, which are listed below.
 | *camel.component.facebook.configuration.o-auth-app-id* | The application Id |  | String
 | *camel.component.facebook.configuration.o-auth-app-secret* | The application Secret |  | String
 | *camel.component.facebook.configuration.o-auth-authorization-u-r-l* | OAuth authorization URL | https://www.facebook.com/dialog/oauth | String
-| *camel.component.facebook.configuration.o-auth-permissions* | Default OAuth permissions. Comma separated permission names. See https://developers.facebook.com/docs/reference/login/#permissions for the detail |  | String
+| *camel.component.facebook.configuration.o-auth-permissions* | Default OAuth permissions. Comma separated permission names. See \https://developers.facebook.com/docs/reference/login/#permissions for the detail |  | String
 | *camel.component.facebook.configuration.pretty-debug-enabled* | Prettify JSON debug output if set to true | false | Boolean
 | *camel.component.facebook.configuration.rest-base-u-r-l* | API base URL | https://graph.facebook.com/ | String
 | *camel.component.facebook.configuration.use-s-s-l* | Use SSL | true | Boolean
diff --git a/components/camel-google-calendar/src/main/docs/google-calendar-component.adoc b/components/camel-google-calendar/src/main/docs/google-calendar-component.adoc
index f19ff27..53bfc5b 100644
--- a/components/camel-google-calendar/src/main/docs/google-calendar-component.adoc
+++ b/components/camel-google-calendar/src/main/docs/google-calendar-component.adoc
@@ -90,7 +90,7 @@ with the following path and query parameters:
 | *inBody* (common) | Sets the name of a parameter to be passed in the exchange In Body |  | String
 | *p12FileName* (common) | The name of the p12 file which has the private key to use with the Google Service Account. |  | String
 | *refreshToken* (common) | OAuth 2 refresh token. Using this, the Google Calendar component can obtain a new accessToken whenever the current one expires - a necessity if the application is long-lived. |  | String
-| *scopes* (common) | Specifies the level of permissions you want a calendar application to have to a user account. You can separate multiple scopes by comma. See https://developers.google.com/google-apps/calendar/auth for more info. | https://www.googleapis.com/auth/calendar | String
+| *scopes* (common) | Specifies the level of permissions you want a calendar application to have to a user account. You can separate multiple scopes by comma. See \https://developers.google.com/google-apps/calendar/auth for more info. | https://www.googleapis.com/auth/calendar | String
 | *user* (common) | The email address of the user the application is trying to impersonate in the service account flow |  | String
 | *bridgeErrorHandler* (consumer) | Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored. | false | boolean
 | *exceptionHandler* (consumer) | To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the consumer will deal with exceptions, that will be logged at WARN or ERROR level and ignored. |  | ExceptionHandler
@@ -119,7 +119,7 @@ The component supports 14 options, which are listed below.
 | *camel.component.google-calendar.configuration.method-name* | What sub operation to use for the selected operation |  | String
 | *camel.component.google-calendar.configuration.p12-file-name* | The name of the p12 file which has the private key to use with the Google Service Account. |  | String
 | *camel.component.google-calendar.configuration.refresh-token* | OAuth 2 refresh token. Using this, the Google Calendar component can obtain a new accessToken whenever the current one expires - a necessity if the application is long-lived. |  | String
-| *camel.component.google-calendar.configuration.scopes* | Specifies the level of permissions you want a calendar application to have to a user account. You can separate multiple scopes by comma. See https://developers.google.com/google-apps/calendar/auth for more info. | https://www.googleapis.com/auth/calendar | String
+| *camel.component.google-calendar.configuration.scopes* | Specifies the level of permissions you want a calendar application to have to a user account. You can separate multiple scopes by comma. See \https://developers.google.com/google-apps/calendar/auth for more info. | https://www.googleapis.com/auth/calendar | String
 | *camel.component.google-calendar.configuration.user* | The email address of the user the application is trying to impersonate in the service account flow |  | String
 | *camel.component.google-calendar.enabled* | Enable google-calendar component | true | Boolean
 | *camel.component.google-calendar.resolve-property-placeholders* | Whether the component should resolve property placeholders on itself when starting. Only properties which are of String type can use property placeholders. | true | Boolean
diff --git a/components/camel-google-calendar/src/main/docs/google-calendar-stream-component.adoc b/components/camel-google-calendar/src/main/docs/google-calendar-stream-component.adoc
index bcfe036..85abac3 100644
--- a/components/camel-google-calendar/src/main/docs/google-calendar-stream-component.adoc
+++ b/components/camel-google-calendar/src/main/docs/google-calendar-stream-component.adoc
@@ -95,7 +95,7 @@ with the following path and query parameters:
 | *maxResults* (consumer) | Max results to be returned | 10 | int
 | *query* (consumer) | The query to execute on calendar |  | String
 | *refreshToken* (consumer) | OAuth 2 refresh token. Using this, the Google Calendar component can obtain a new accessToken whenever the current one expires - a necessity if the application is long-lived. |  | String
-| *scopes* (consumer) | Specifies the level of permissions you want a calendar application to have to a user account. See https://developers.google.com/calendar/auth for more info. |  | List
+| *scopes* (consumer) | Specifies the level of permissions you want a calendar application to have to a user account. See \https://developers.google.com/calendar/auth for more info. |  | List
 | *sendEmptyMessageWhenIdle* (consumer) | If the polling consumer did not poll any files, you can enable this option to send an empty message (no body) instead. | false | boolean
 | *exceptionHandler* (consumer) | To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the consumer will deal with exceptions, that will be logged at WARN or ERROR level and ignored. |  | ExceptionHandler
 | *exchangePattern* (consumer) | Sets the exchange pattern when the consumer creates an exchange. |  | ExchangePattern
@@ -139,7 +139,7 @@ The component supports 15 options, which are listed below.
 | *camel.component.google-calendar-stream.configuration.max-results* | Max results to be returned | 10 | Integer
 | *camel.component.google-calendar-stream.configuration.query* | The query to execute on calendar |  | String
 | *camel.component.google-calendar-stream.configuration.refresh-token* | OAuth 2 refresh token. Using this, the Google Calendar component can obtain a new accessToken whenever the current one expires - a necessity if the application is long-lived. |  | String
-| *camel.component.google-calendar-stream.configuration.scopes* | Specifies the level of permissions you want a calendar application to have to a user account. See https://developers.google.com/calendar/auth for more info. |  | List
+| *camel.component.google-calendar-stream.configuration.scopes* | Specifies the level of permissions you want a calendar application to have to a user account. See \https://developers.google.com/calendar/auth for more info. |  | List
 | *camel.component.google-calendar-stream.enabled* | Whether to enable auto configuration of the google-calendar-stream component. This is enabled by default. |  | Boolean
 | *camel.component.google-calendar-stream.resolve-property-placeholders* | Whether the component should resolve property placeholders on itself when starting. Only properties which are of String type can use property placeholders. | true | Boolean
 |===
diff --git a/components/camel-google-drive/src/main/docs/google-drive-component.adoc b/components/camel-google-drive/src/main/docs/google-drive-component.adoc
index 197827b..457b857 100644
--- a/components/camel-google-drive/src/main/docs/google-drive-component.adoc
+++ b/components/camel-google-drive/src/main/docs/google-drive-component.adoc
@@ -116,7 +116,7 @@ with the following path and query parameters:
 | *clientSecret* (common) | Client secret of the drive application |  | String
 | *inBody* (common) | Sets the name of a parameter to be passed in the exchange In Body |  | String
 | *refreshToken* (common) | OAuth 2 refresh token. Using this, the Google Calendar component can obtain a new accessToken whenever the current one expires - a necessity if the application is long-lived. |  | String
-| *scopes* (common) | Specifies the level of permissions you want a drive application to have to a user account. See https://developers.google.com/drive/web/scopes for more info. |  | List
+| *scopes* (common) | Specifies the level of permissions you want a drive application to have to a user account. See \https://developers.google.com/drive/web/scopes for more info. |  | List
 | *bridgeErrorHandler* (consumer) | Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored. | false | boolean
 | *exceptionHandler* (consumer) | To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the consumer will deal with exceptions, that will be logged at WARN or ERROR level and ignored. |  | ExceptionHandler
 | *exchangePattern* (consumer) | Sets the exchange pattern when the consumer creates an exchange. |  | ExchangePattern
@@ -142,7 +142,7 @@ The component supports 11 options, which are listed below.
 | *camel.component.google-drive.configuration.client-secret* | Client secret of the drive application |  | String
 | *camel.component.google-drive.configuration.method-name* | What sub operation to use for the selected operation |  | String
 | *camel.component.google-drive.configuration.refresh-token* | OAuth 2 refresh token. Using this, the Google Calendar component can obtain a new accessToken whenever the current one expires - a necessity if the application is long-lived. |  | String
-| *camel.component.google-drive.configuration.scopes* | Specifies the level of permissions you want a drive application to have to a user account. See https://developers.google.com/drive/web/scopes for more info. |  | List
+| *camel.component.google-drive.configuration.scopes* | Specifies the level of permissions you want a drive application to have to a user account. See \https://developers.google.com/drive/web/scopes for more info. |  | List
 | *camel.component.google-drive.enabled* | Enable google-drive component | true | Boolean
 | *camel.component.google-drive.resolve-property-placeholders* | Whether the component should resolve property placeholders on itself when starting. Only properties which are of String type can use property placeholders. | true | Boolean
 |===
diff --git a/components/camel-google-sheets/src/main/docs/google-sheets-stream-component.adoc b/components/camel-google-sheets/src/main/docs/google-sheets-stream-component.adoc
index e3aed90..67a6f7d 100644
--- a/components/camel-google-sheets/src/main/docs/google-sheets-stream-component.adoc
+++ b/components/camel-google-sheets/src/main/docs/google-sheets-stream-component.adoc
@@ -94,7 +94,7 @@ with the following path and query parameters:
 | *maxResults* (consumer) | Specify the maximum number of returned results. This will limit the number of rows in a returned value range data set or the number of returned value ranges in a batch request. | 0 | int
 | *range* (consumer) | Specifies the range of rows and columns in a sheet to get data from. |  | String
 | *refreshToken* (consumer) | OAuth 2 refresh token. Using this, the Google Calendar component can obtain a new accessToken whenever the current one expires - a necessity if the application is long-lived. |  | String
-| *scopes* (consumer) | Specifies the level of permissions you want a sheets application to have to a user account. See https://developers.google.com/identity/protocols/googlescopes for more info. |  | List
+| *scopes* (consumer) | Specifies the level of permissions you want a sheets application to have to a user account. See \https://developers.google.com/identity/protocols/googlescopes for more info. |  | List
 | *sendEmptyMessageWhenIdle* (consumer) | If the polling consumer did not poll any files, you can enable this option to send an empty message (no body) instead. | false | boolean
 | *splitResults* (consumer) | True if value range result should be split into rows or columns to process each of them individually. When true each row or column is represented with a separate exchange in batch processing. Otherwise value range object is used as exchange junk size. | false | boolean
 | *spreadsheetId* (consumer) | Specifies the spreadsheet identifier that is used to identify the target to obtain. |  | String
@@ -140,7 +140,7 @@ The component supports 17 options, which are listed below.
 | *camel.component.google-sheets-stream.configuration.max-results* | Specify the maximum number of returned results. This will limit the number of rows in a returned value range data set or the number of returned value ranges in a batch request. | 0 | Integer
 | *camel.component.google-sheets-stream.configuration.range* | Specifies the range of rows and columns in a sheet to get data from. |  | String
 | *camel.component.google-sheets-stream.configuration.refresh-token* | OAuth 2 refresh token. Using this, the Google Calendar component can obtain a new accessToken whenever the current one expires - a necessity if the application is long-lived. |  | String
-| *camel.component.google-sheets-stream.configuration.scopes* | Specifies the level of permissions you want a sheets application to have to a user account. See https://developers.google.com/identity/protocols/googlescopes for more info. |  | List
+| *camel.component.google-sheets-stream.configuration.scopes* | Specifies the level of permissions you want a sheets application to have to a user account. See \https://developers.google.com/identity/protocols/googlescopes for more info. |  | List
 | *camel.component.google-sheets-stream.configuration.split-results* | True if value range result should be split into rows or columns to process each of them individually. When true each row or column is represented with a separate exchange in batch processing. Otherwise value range object is used as exchange junk size. | false | Boolean
 | *camel.component.google-sheets-stream.configuration.spreadsheet-id* | Specifies the spreadsheet identifier that is used to identify the target to obtain. |  | String
 | *camel.component.google-sheets-stream.configuration.value-render-option* | Determines how values should be rendered in the output. | FORMATTED_VALUE | String
diff --git a/components/camel-ironmq/src/main/docs/ironmq-component.adoc b/components/camel-ironmq/src/main/docs/ironmq-component.adoc
index e60324c..f185097 100644
--- a/components/camel-ironmq/src/main/docs/ironmq-component.adoc
+++ b/components/camel-ironmq/src/main/docs/ironmq-component.adoc
@@ -66,7 +66,7 @@ with the following path and query parameters:
 |===
 | Name | Description | Default | Type
 | *client* (common) | Reference to a io.iron.ironmq.Client in the Registry. |  | Client
-| *ironMQCloud* (common) | IronMq Cloud url. Urls for public clusters: https://mq-aws-us-east-1-1.iron.io (US) and https://mq-aws-eu-west-1-1.iron.io (EU) | https://mq-aws-us-east-1-1.iron.io | String
+| *ironMQCloud* (common) | IronMq Cloud url. Urls for public clusters: \https://mq-aws-us-east-1-1.iron.io (US) and \https://mq-aws-eu-west-1-1.iron.io (EU) | https://mq-aws-us-east-1-1.iron.io | String
 | *preserveHeaders* (common) | Should message headers be preserved when publishing messages. This will add the Camel headers to the Iron MQ message as a json payload with a header list, and a message body. Useful when Camel is both consumer and producer. | false | boolean
 | *projectId* (common) | IronMQ projectId |  | String
 | *token* (common) | IronMQ token |  | String
diff --git a/components/camel-lra/src/main/docs/lra.adoc b/components/camel-lra/src/main/docs/lra.adoc
index 852fef3..f8a69ea 100644
--- a/components/camel-lra/src/main/docs/lra.adoc
+++ b/components/camel-lra/src/main/docs/lra.adoc
@@ -29,9 +29,9 @@ The component supports 5 options, which are listed below.
 |===
 | Name | Description | Default | Type
 | *camel.service.lra.coordinator-context-path* | The context path of the LRA coordinator service |  | String
-| *camel.service.lra.coordinator-url* | The base URL of the LRA coordinator service (e.g. http://lra-host:8080) |  | String
+| *camel.service.lra.coordinator-url* | The base URL of the LRA coordinator service (e.g. \http://lra-host:8080) |  | String
 | *camel.service.lra.enabled* | Global option to enable/disable component auto-configuration, default is true. | true | Boolean
 | *camel.service.lra.local-participant-context-path* | The context path of the local participant callback services |  | String
-| *camel.service.lra.local-participant-url* | The local URL where the coordinator should send callbacks to (e.g. http://my-host-name:8080) |  | String
+| *camel.service.lra.local-participant-url* | The local URL where the coordinator should send callbacks to (e.g. \http://my-host-name:8080) |  | String
 |===
 // spring-boot-auto-configure options: END
diff --git a/components/camel-netty4-http/src/main/docs/netty4-http-component.adoc b/components/camel-netty4-http/src/main/docs/netty4-http-component.adoc
index 144a257..5d5c2ec 100644
--- a/components/camel-netty4-http/src/main/docs/netty4-http-component.adoc
+++ b/components/camel-netty4-http/src/main/docs/netty4-http-component.adoc
@@ -181,7 +181,7 @@ with the following path and query parameters:
 | *configuration* (advanced) | To use a custom configured NettyHttpConfiguration for configuring this endpoint. |  | NettyHttpConfiguration
 | *disableStreamCache* (advanced) | Determines whether or not the raw input stream from Netty HttpRequest#getContent() or HttpResponset#getContent() is cached or not (Camel will read the stream into a in light-weight memory based Stream caching) cache. By default Camel will cache the Netty input stream to support reading it multiple times to ensure it Camel can retrieve all data from the stream. However you can set this option to true when you for example need to access the raw stream, s [...]
 | *headerFilterStrategy* (advanced) | To use a custom org.apache.camel.spi.HeaderFilterStrategy to filter headers. |  | HeaderFilterStrategy
-| *nativeTransport* (advanced) | Whether to use native transport instead of NIO. Native transport takes advantage of the host operating system and is only supported on some platforms. You need to add the netty JAR for the host operating system you are using. See more details at: http://netty.io/wiki/native-transports.html | false | boolean
+| *nativeTransport* (advanced) | Whether to use native transport instead of NIO. Native transport takes advantage of the host operating system and is only supported on some platforms. You need to add the netty JAR for the host operating system you are using. See more details at: \http://netty.io/wiki/native-transports.html | false | boolean
 | *nettyHttpBinding* (advanced) | To use a custom org.apache.camel.component.netty4.http.NettyHttpBinding for binding to/from Netty and Camel Message API. |  | NettyHttpBinding
 | *options* (advanced) | Allows to configure additional netty options using option. as prefix. For example option.child.keepAlive=false to set the netty option child.keepAlive=false. See the Netty documentation for possible options that can be used. |  | Map
 | *receiveBufferSize* (advanced) | The TCP/UDP buffer sizes to be used during inbound communication. Size is bytes. | 65536 | int
diff --git a/components/camel-netty4/src/main/docs/netty4-component.adoc b/components/camel-netty4/src/main/docs/netty4-component.adoc
index 0fce4ab..e7d666d 100644
--- a/components/camel-netty4/src/main/docs/netty4-component.adoc
+++ b/components/camel-netty4/src/main/docs/netty4-component.adoc
@@ -133,7 +133,7 @@ with the following path and query parameters:
 | *allowSerializedHeaders* (advanced) | Only used for TCP when transferExchange is true. When set to true, serializable objects in headers and properties will be added to the exchange. Otherwise Camel will exclude any non-serializable objects and log it at WARN level. | false | boolean
 | *bootstrapConfiguration* (advanced) | To use a custom configured NettyServerBootstrapConfiguration for configuring this endpoint. |  | NettyServerBootstrap Configuration
 | *channelGroup* (advanced) | To use a explicit ChannelGroup. |  | ChannelGroup
-| *nativeTransport* (advanced) | Whether to use native transport instead of NIO. Native transport takes advantage of the host operating system and is only supported on some platforms. You need to add the netty JAR for the host operating system you are using. See more details at: http://netty.io/wiki/native-transports.html | false | boolean
+| *nativeTransport* (advanced) | Whether to use native transport instead of NIO. Native transport takes advantage of the host operating system and is only supported on some platforms. You need to add the netty JAR for the host operating system you are using. See more details at: \http://netty.io/wiki/native-transports.html | false | boolean
 | *options* (advanced) | Allows to configure additional netty options using option. as prefix. For example option.child.keepAlive=false to set the netty option child.keepAlive=false. See the Netty documentation for possible options that can be used. |  | Map
 | *receiveBufferSize* (advanced) | The TCP/UDP buffer sizes to be used during inbound communication. Size is bytes. | 65536 | int
 | *receiveBufferSizePredictor* (advanced) | Configures the buffer size predictor. See details at Jetty documentation and this mail thread. |  | int
@@ -204,7 +204,7 @@ The component supports 78 options, which are listed below.
 | *camel.component.netty4.configuration.key-store-format* | Keystore format to be used for payload encryption. Defaults to JKS if not set |  | String
 | *camel.component.netty4.configuration.key-store-resource* | Client side certificate keystore to be used for encryption. Is loaded by default from classpath, but you can prefix with classpath:, file:, or http: to load the resource from different systems. |  | String
 | *camel.component.netty4.configuration.lazy-channel-creation* | Channels can be lazily created to avoid exceptions, if the remote server is not up and running when the Camel producer is started. | true | Boolean
-| *camel.component.netty4.configuration.native-transport* | Whether to use native transport instead of NIO. Native transport takes advantage of the host operating system and is only supported on some platforms. You need to add the netty JAR for the host operating system you are using. See more details at: http://netty.io/wiki/native-transports.html | false | Boolean
+| *camel.component.netty4.configuration.native-transport* | Whether to use native transport instead of NIO. Native transport takes advantage of the host operating system and is only supported on some platforms. You need to add the netty JAR for the host operating system you are using. See more details at: \http://netty.io/wiki/native-transports.html | false | Boolean
 | *camel.component.netty4.configuration.need-client-auth* | Configures whether the server needs client authentication when using SSL. | false | Boolean
 | *camel.component.netty4.configuration.netty-server-bootstrap-factory* | To use a custom NettyServerBootstrapFactory |  | NettyServerBootstrap Factory
 | *camel.component.netty4.configuration.network-interface* | When using UDP then this option can be used to specify a network interface by its name, such as eth0 to join a multicast group. |  | String
diff --git a/components/camel-olingo2/camel-olingo2-component/src/main/docs/olingo2-component.adoc b/components/camel-olingo2/camel-olingo2-component/src/main/docs/olingo2-component.adoc
index 68afdbc..43fdc9a 100644
--- a/components/camel-olingo2/camel-olingo2-component/src/main/docs/olingo2-component.adoc
+++ b/components/camel-olingo2/camel-olingo2-component/src/main/docs/olingo2-component.adoc
@@ -96,7 +96,7 @@ with the following path and query parameters:
 | *httpHeaders* (common) | Custom HTTP headers to inject into every request, this could include OAuth tokens, etc. |  | Map
 | *inBody* (common) | Sets the name of a parameter to be passed in the exchange In Body |  | String
 | *proxy* (common) | HTTP proxy server configuration |  | HttpHost
-| *serviceUri* (common) | Target OData service base URI, e.g. http://services.odata.org/OData/OData.svc |  | String
+| *serviceUri* (common) | Target OData service base URI, e.g. \http://services.odata.org/OData/OData.svc |  | String
 | *socketTimeout* (common) | HTTP request timeout in milliseconds, defaults to 30,000 (30 seconds) | 30000 | int
 | *sslContextParameters* (common) | To configure security using SSLContextParameters |  | SSLContextParameters
 | *bridgeErrorHandler* (consumer) | Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored. | false | boolean
@@ -125,7 +125,7 @@ The component supports 15 options, which are listed below.
 | *camel.component.olingo2.configuration.http-headers* | Custom HTTP headers to inject into every request, this could include OAuth tokens, etc. |  | Map
 | *camel.component.olingo2.configuration.method-name* | What sub operation to use for the selected operation |  | String
 | *camel.component.olingo2.configuration.proxy* | HTTP proxy server configuration |  | HttpHost
-| *camel.component.olingo2.configuration.service-uri* | Target OData service base URI, e.g. http://services.odata.org/OData/OData.svc |  | String
+| *camel.component.olingo2.configuration.service-uri* | Target OData service base URI, e.g. \http://services.odata.org/OData/OData.svc |  | String
 | *camel.component.olingo2.configuration.socket-timeout* | HTTP request timeout in milliseconds, defaults to 30,000 (30 seconds) | 30000 | Integer
 | *camel.component.olingo2.configuration.ssl-context-parameters* | To configure security using SSLContextParameters |  | SSLContextParameters
 | *camel.component.olingo2.enabled* | Enable olingo2 component | true | Boolean
diff --git a/components/camel-olingo4/camel-olingo4-component/src/main/docs/olingo4-component.adoc b/components/camel-olingo4/camel-olingo4-component/src/main/docs/olingo4-component.adoc
index 4270311..f756520 100644
--- a/components/camel-olingo4/camel-olingo4-component/src/main/docs/olingo4-component.adoc
+++ b/components/camel-olingo4/camel-olingo4-component/src/main/docs/olingo4-component.adoc
@@ -97,7 +97,7 @@ with the following path and query parameters:
 | *httpHeaders* (common) | Custom HTTP headers to inject into every request, this could include OAuth tokens, etc. |  | Map
 | *inBody* (common) | Sets the name of a parameter to be passed in the exchange In Body |  | String
 | *proxy* (common) | HTTP proxy server configuration |  | HttpHost
-| *serviceUri* (common) | Target OData service base URI, e.g. http://services.odata.org/OData/OData.svc |  | String
+| *serviceUri* (common) | Target OData service base URI, e.g. \http://services.odata.org/OData/OData.svc |  | String
 | *socketTimeout* (common) | HTTP request timeout in milliseconds, defaults to 30,000 (30 seconds) | 30000 | int
 | *sslContextParameters* (common) | To configure security using SSLContextParameters |  | SSLContextParameters
 | *bridgeErrorHandler* (consumer) | Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored. | false | boolean
@@ -126,7 +126,7 @@ The component supports 15 options, which are listed below.
 | *camel.component.olingo4.configuration.http-headers* | Custom HTTP headers to inject into every request, this could include OAuth tokens, etc. |  | Map
 | *camel.component.olingo4.configuration.method-name* | What sub operation to use for the selected operation |  | String
 | *camel.component.olingo4.configuration.proxy* | HTTP proxy server configuration |  | HttpHost
-| *camel.component.olingo4.configuration.service-uri* | Target OData service base URI, e.g. http://services.odata.org/OData/OData.svc |  | String
+| *camel.component.olingo4.configuration.service-uri* | Target OData service base URI, e.g. \http://services.odata.org/OData/OData.svc |  | String
 | *camel.component.olingo4.configuration.socket-timeout* | HTTP request timeout in milliseconds, defaults to 30,000 (30 seconds) | 30000 | Integer
 | *camel.component.olingo4.configuration.ssl-context-parameters* | To configure security using SSLContextParameters |  | SSLContextParameters
 | *camel.component.olingo4.enabled* | Enable olingo4 component | true | Boolean
diff --git a/components/camel-servicenow/camel-servicenow-component/src/main/docs/servicenow-component.adoc b/components/camel-servicenow/camel-servicenow-component/src/main/docs/servicenow-component.adoc
index 8ca11e8..ca15d9b 100644
--- a/components/camel-servicenow/camel-servicenow-component/src/main/docs/servicenow-component.adoc
+++ b/components/camel-servicenow/camel-servicenow-component/src/main/docs/servicenow-component.adoc
@@ -94,7 +94,7 @@ with the following path and query parameters:
 | *key* (producer) | Set this parameter to true to return only scorecards for key indicators. |  | Boolean
 | *models* (producer) | Defines both request and response models |  | String
 | *perPage* (producer) | Enter the maximum number of scorecards each query can return. By default this value is 10, and the maximum is 100. | 10 | Integer
-| *release* (producer) | The ServiceNow release to target, default to Helsinki See https://docs.servicenow.com | HELSINKI | ServiceNowRelease
+| *release* (producer) | The ServiceNow release to target, default to Helsinki See \https://docs.servicenow.com | HELSINKI | ServiceNowRelease
 | *requestModels* (producer) | Defines the request model |  | String
 | *resource* (producer) | The default resource, can be overridden by header CamelServiceNowResource |  | String
 | *responseModels* (producer) | Defines the response model |  | String
@@ -123,7 +123,7 @@ with the following path and query parameters:
 | *password* (security) | *Required* ServiceNow account password, MUST be provided |  | String
 | *proxyPassword* (security) | Password for proxy authentication |  | String
 | *proxyUserName* (security) | Username for proxy authentication |  | String
-| *sslContextParameters* (security) | To configure security using SSLContextParameters. See http://camel.apache.org/camel-configuration-utilities.html |  | SSLContextParameters
+| *sslContextParameters* (security) | To configure security using SSLContextParameters. See \http://camel.apache.org/camel-configuration-utilities.html |  | SSLContextParameters
 | *userName* (security) | *Required* ServiceNow user account name, MUST be provided |  | String
 |===
 // endpoint options: END
@@ -167,14 +167,14 @@ The component supports 57 options, which are listed below.
 | *camel.component.servicenow.configuration.proxy-password* | Password for proxy authentication |  | String
 | *camel.component.servicenow.configuration.proxy-port* | The proxy port number |  | Integer
 | *camel.component.servicenow.configuration.proxy-user-name* | Username for proxy authentication |  | String
-| *camel.component.servicenow.configuration.release* | The ServiceNow release to target, default to Helsinki See https://docs.servicenow.com |  | ServiceNowRelease
+| *camel.component.servicenow.configuration.release* | The ServiceNow release to target, default to Helsinki See \https://docs.servicenow.com |  | ServiceNowRelease
 | *camel.component.servicenow.configuration.request-models* | Defines the request model |  | Map
 | *camel.component.servicenow.configuration.resource* | The default resource, can be overridden by header CamelServiceNowResource |  | String
 | *camel.component.servicenow.configuration.response-models* | Defines the response model |  | Map
 | *camel.component.servicenow.configuration.retrieve-target-record-on-import* | Set this parameter to true to retrieve the target record when using import set api. The import set result is then replaced by the target record | false | Boolean
 | *camel.component.servicenow.configuration.sort-by* | Specify the value to use when sorting results. By default, queries sort records by value. |  | String
 | *camel.component.servicenow.configuration.sort-dir* | Specify the sort direction, ascending or descending. By default, queries sort records in descending order. Use sysparm_sortdir=asc to sort in ascending order. |  | String
-| *camel.component.servicenow.configuration.ssl-context-parameters* | To configure security using SSLContextParameters. See http://camel.apache.org/camel-configuration-utilities.html |  | SSLContextParameters
+| *camel.component.servicenow.configuration.ssl-context-parameters* | To configure security using SSLContextParameters. See \http://camel.apache.org/camel-configuration-utilities.html |  | SSLContextParameters
 | *camel.component.servicenow.configuration.suppress-auto-sys-field* | True to suppress auto generation of system fields (default: false) |  | Boolean
 | *camel.component.servicenow.configuration.suppress-pagination-header* | Set this value to true to remove the Link header from the response. The Link header allows you to request additional pages of data when the number of records matching your query exceeds the query limit |  | Boolean
 | *camel.component.servicenow.configuration.table* | The default table, can be overridden by header CamelServiceNowTable |  | String
diff --git a/components/camel-zipkin/src/main/docs/zipkin.adoc b/components/camel-zipkin/src/main/docs/zipkin.adoc
index 87d5c38..d0e315b 100644
--- a/components/camel-zipkin/src/main/docs/zipkin.adoc
+++ b/components/camel-zipkin/src/main/docs/zipkin.adoc
@@ -100,7 +100,7 @@ The component supports 10 options, which are listed below.
 |===
 | Name | Description | Default | Type
 | *camel.zipkin.client-service-mappings* | Sets client service mapping(s) that matches Camel events to the given zipkin service name. The key is the pattern, the value is the service name. |  | Map
-| *camel.zipkin.endpoint* | Sets the POST URL for zipkin's <a href="http://zipkin.io/zipkin-api/#/">v2 api</a>, usually "http://zipkinhost:9411/api/v2/spans" |  | String
+| *camel.zipkin.endpoint* | Sets the POST URL for zipkin's <a href="http://zipkin.io/zipkin-api/#/">v2 api</a>, usually "\http://zipkinhost:9411/api/v2/spans" |  | String
 | *camel.zipkin.exclude-patterns* | Sets exclude pattern(s) that will disable tracing with zipkin for Camel messages that matches the pattern. |  | Set
 | *camel.zipkin.host-name* | Sets the hostname if sending spans to a remote zipkin scribe (thrift RPC) collector. |  | String
 | *camel.zipkin.include-message-body* | Whether to include the Camel message body in the zipkin traces. This is not recommended for production usage, or when having big payloads. You can limit the size by configuring camel.springboot.log-debug-max-chars option. | false | Boolean
diff --git a/tooling/maven/camel-package-maven-plugin/pom.xml b/tooling/maven/camel-package-maven-plugin/pom.xml
index a68a52f..b6156bd 100644
--- a/tooling/maven/camel-package-maven-plugin/pom.xml
+++ b/tooling/maven/camel-package-maven-plugin/pom.xml
@@ -191,6 +191,11 @@
       <version>${junit-jupiter-version}</version>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.assertj</groupId>
+      <artifactId>assertj-core</artifactId>
+      <version>${assertj-version}</version>
+    </dependency>
   </dependencies>
 
   <profiles>
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/MvelHelper.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/MvelHelper.java
new file mode 100644
index 0000000..13ea42d
--- /dev/null
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/MvelHelper.java
@@ -0,0 +1,43 @@
+/**
+ * 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
+ *
+ *      http://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.apache.camel.maven.packaging;
+
+import java.util.regex.Pattern;
+
+public final class MvelHelper {
+
+    public static final MvelHelper INSTANCE = new MvelHelper();
+
+    private static final Pattern DOLLAR_ESCAPE = Pattern.compile("\\$");
+
+    private static final Pattern URL_ESCAPE = Pattern.compile("(?<!href=\")(http(:?s)?://|(:?s)?ftp(?:s)?)");
+
+    private MvelHelper() {
+        // utility class
+    }
+
+    public static String escape(final String raw) {
+        if (raw == null) {
+            return null;
+        }
+
+        final String escapedDollars = DOLLAR_ESCAPE.matcher(raw).replaceAll("\\\\\\$");
+        final String escapedUrls = URL_ESCAPE.matcher(escapedDollars).replaceAll("\\\\$1");
+
+        return escapedUrls;
+    }
+}
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareExampleMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareExampleMojo.java
index 077a7c7..9d67358 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareExampleMojo.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareExampleMojo.java
@@ -172,7 +172,7 @@ public class PrepareExampleMojo extends AbstractMojo {
             Map<String, Object> map = new HashMap<>();
             map.put("examples", models);
             map.put("numberOfDeprecated", deprecated);
-            String out = (String) TemplateRuntime.eval(template, map);
+            String out = (String) TemplateRuntime.eval(template, map, Collections.singletonMap("util", MvelHelper.INSTANCE));
             return out;
         } catch (Exception e) {
             throw new MojoExecutionException("Error processing mvel template. Reason: " + e, e);
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareReadmeMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareReadmeMojo.java
index 358d2a5..b3ea3e3 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareReadmeMojo.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareReadmeMojo.java
@@ -475,7 +475,7 @@ public class PrepareReadmeMojo extends AbstractMojo {
             Map<String, Object> map = new HashMap<>();
             map.put("eips", models);
             map.put("numberOfDeprecated", deprecated);
-            String out = (String) TemplateRuntime.eval(template, map);
+            String out = (String) TemplateRuntime.eval(template, map, Collections.singletonMap("util", MvelHelper.INSTANCE));
             return out;
         } catch (Exception e) {
             throw new MojoExecutionException("Error processing mvel template. Reason: " + e, e);
@@ -489,7 +489,7 @@ public class PrepareReadmeMojo extends AbstractMojo {
             map.put("components", models);
             map.put("numberOfArtifacts", artifacts);
             map.put("numberOfDeprecated", deprecated);
-            String out = (String) TemplateRuntime.eval(template, map);
+            String out = (String) TemplateRuntime.eval(template, map, Collections.singletonMap("util", MvelHelper.INSTANCE));
             return out;
         } catch (Exception e) {
             throw new MojoExecutionException("Error processing mvel template. Reason: " + e, e);
@@ -503,7 +503,7 @@ public class PrepareReadmeMojo extends AbstractMojo {
             map.put("others", models);
             map.put("numberOfArtifacts", artifacts);
             map.put("numberOfDeprecated", deprecated);
-            String out = (String) TemplateRuntime.eval(template, map);
+            String out = (String) TemplateRuntime.eval(template, map, Collections.singletonMap("util", MvelHelper.INSTANCE));
             return out;
         } catch (Exception e) {
             throw new MojoExecutionException("Error processing mvel template. Reason: " + e, e);
@@ -517,7 +517,7 @@ public class PrepareReadmeMojo extends AbstractMojo {
             map.put("dataformats", models);
             map.put("numberOfArtifacts", artifacts);
             map.put("numberOfDeprecated", deprecated);
-            String out = (String) TemplateRuntime.eval(template, map);
+            String out = (String) TemplateRuntime.eval(template, map, Collections.singletonMap("util", MvelHelper.INSTANCE));
             return out;
         } catch (Exception e) {
             throw new MojoExecutionException("Error processing mvel template. Reason: " + e, e);
@@ -531,7 +531,7 @@ public class PrepareReadmeMojo extends AbstractMojo {
             map.put("languages", models);
             map.put("numberOfArtifacts", artifacts);
             map.put("numberOfDeprecated", deprecated);
-            String out = (String) TemplateRuntime.eval(template, map);
+            String out = (String) TemplateRuntime.eval(template, map, Collections.singletonMap("util", MvelHelper.INSTANCE));
             return out;
         } catch (Exception e) {
             throw new MojoExecutionException("Error processing mvel template. Reason: " + e, e);
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/UpdateReadmeMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/UpdateReadmeMojo.java
index 3cb3b22..9ebcd443 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/UpdateReadmeMojo.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/UpdateReadmeMojo.java
@@ -23,6 +23,7 @@ import java.io.InputStream;
 import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -915,7 +916,7 @@ public class UpdateReadmeMojo extends AbstractMojo {
     private static String evaluateTemplate(final String templateName, final Object model) throws MojoExecutionException {
         try (InputStream templateStream = UpdateReadmeMojo.class.getClassLoader().getResourceAsStream(templateName)) {
             String template = loadText(templateStream);
-            return (String) TemplateRuntime.eval(template, model);
+            return (String) TemplateRuntime.eval(template, model, Collections.singletonMap("util", MvelHelper.INSTANCE));
         } catch (IOException e) {
             throw new MojoExecutionException("Error processing mvel template `" + templateName + "`", e);
         }
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/UpdateSpringBootAutoConfigurationReadmeMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/UpdateSpringBootAutoConfigurationReadmeMojo.java
index a0828d7..d54e50b 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/UpdateSpringBootAutoConfigurationReadmeMojo.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/UpdateSpringBootAutoConfigurationReadmeMojo.java
@@ -23,6 +23,7 @@ import java.io.FileReader;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
 import java.util.stream.Collectors;
@@ -311,6 +312,20 @@ public class UpdateSpringBootAutoConfigurationReadmeMojo extends AbstractMojo {
                 String desc = row.getStringOrDefault("description", "");
                 String defaultValue = row.getStringOrDefault("defaultValue", "");
 
+                // is the option deprecated then include that as well in the description
+                String deprecated = row.getStringOrDefault("deprecated", "");
+                String deprecationNote = row.getStringOrDefault("deprecationNote", "");
+                if ("true".equals(deprecated)) {
+                    desc = "*Deprecated* " + desc;
+                    if (!StringHelper.isEmpty(deprecationNote)) {
+                        if (!desc.endsWith(".")) {
+                            desc = desc + ". Deprecation note: " + deprecationNote;
+                        } else {
+                            desc = desc + " Deprecation note: " + deprecationNote;
+                        }
+                    }
+                }
+
                 // skip this special option and also if not matching the filter
                 boolean skip = name.endsWith("customizer.enabled") || include != null && !name.contains("." + include + ".");
                 if (!skip) {
@@ -373,7 +388,7 @@ public class UpdateSpringBootAutoConfigurationReadmeMojo extends AbstractMojo {
 
         try {
             String template = loadText(UpdateSpringBootAutoConfigurationReadmeMojo.class.getClassLoader().getResourceAsStream("spring-boot-auto-configure-options.mvel"));
-            String out = (String) TemplateRuntime.eval(template, model);
+            String out = (String) TemplateRuntime.eval(template, model, Collections.singletonMap("util", MvelHelper.INSTANCE));
             return out;
         } catch (Exception e) {
             throw new MojoExecutionException("Error processing mvel template. Reason: " + e, e);
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/resources/component-options.mvel b/tooling/maven/camel-package-maven-plugin/src/main/resources/component-options.mvel
index 1faaccf..ac16976 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/resources/component-options.mvel
+++ b/tooling/maven/camel-package-maven-plugin/src/main/resources/component-options.mvel
@@ -8,6 +8,6 @@ The @{title} component supports @{componentOptions.size()} options, which are li
 [width="100%",cols="2,5,^1,2",options="header"]
 |===
 | Name | Description | Default | Type
-@foreach{row : componentOptions}| *@{row.getShortName(25)}* (@{row.shortGroup}) | @{row.description.replaceAll("\\$", "\\\\\\$")} | @{row.getShortDefaultValue(20)} | @{row.getShortJavaType(25)}
+@foreach{row : componentOptions}| *@{row.getShortName(25)}* (@{row.shortGroup}) | @{util.escape(row.description)} | @{row.getShortDefaultValue(20)} | @{row.getShortJavaType(25)}
 @end{}|===
 @end{}
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/resources/dataformat-options.mvel b/tooling/maven/camel-package-maven-plugin/src/main/resources/dataformat-options.mvel
index c957b75..5942392 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/resources/dataformat-options.mvel
+++ b/tooling/maven/camel-package-maven-plugin/src/main/resources/dataformat-options.mvel
@@ -8,6 +8,6 @@ The @{title} dataformat supports @{dataFormatOptions.size()} options, which are
 [width="100%",cols="2s,1m,1m,6",options="header"]
 |===
 | Name | Default | Java Type | Description
-@foreach{row : dataFormatOptions}| @{row.name} | @{row.defaultValue} | @{row.shortJavaType} | @{row.description.replaceAll("\\$", "\\\\\\$")}
+@foreach{row : dataFormatOptions}| @{row.name} | @{row.defaultValue} | @{row.shortJavaType} | @{util.escape(row.description)}
 @end{}|===
 @end{}
\ No newline at end of file
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/resources/eip-options.mvel b/tooling/maven/camel-package-maven-plugin/src/main/resources/eip-options.mvel
index 3ad7508..a11511a 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/resources/eip-options.mvel
+++ b/tooling/maven/camel-package-maven-plugin/src/main/resources/eip-options.mvel
@@ -6,6 +6,6 @@ The @{title} EIP supports @{eipOptions.size()} options which are listed below:
 [width="100%",cols="2,5,^1,2",options="header"]
 |===
 | Name | Description | Default | Type
-@foreach{row : eipOptions}| *@{row.getShortName(30)}* | @{row.description.replaceAll("\\$", "\\\\\\$")} | @{row.getShortDefaultValue(20)} | @{row.getShortJavaType(25)}
+@foreach{row : eipOptions}| *@{row.getShortName(30)}* | @{util.escape(row.description)} | @{row.getShortDefaultValue(20)} | @{row.getShortJavaType(25)}
 @end{}|===
 @end{}
\ No newline at end of file
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/resources/endpoint-options.mvel b/tooling/maven/camel-package-maven-plugin/src/main/resources/endpoint-options.mvel
index 6cec166..1c9e33b 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/resources/endpoint-options.mvel
+++ b/tooling/maven/camel-package-maven-plugin/src/main/resources/endpoint-options.mvel
@@ -14,7 +14,7 @@ The @{title} endpoint has no path parameters.
 [width="100%",cols="2,5,^1,2",options="header"]
 |===
 | Name | Description | Default | Type
-@foreach{row : endpointPathOptions}| *@{row.getShortName(30)}* | @{row.description.replaceAll("\\$", "\\\\\\$")} | @{row.getShortDefaultValue(20)} | @{row.getShortJavaType(25)}
+@foreach{row : endpointPathOptions}| *@{row.getShortName(30)}* | @{util.escape(row.description)} | @{row.getShortDefaultValue(20)} | @{row.getShortJavaType(25)}
 @end{}|===
 @end{}
 
@@ -26,6 +26,6 @@ The @{title} endpoint has no query parameters.
 [width="100%",cols="2,5,^1,2",options="header"]
 |===
 | Name | Description | Default | Type
-@foreach{row : endpointOptions}| *@{row.getShortName(30)}* (@{row.shortGroup}) | @{row.description.replaceAll("\\$", "\\\\\\$")} | @{row.getShortDefaultValue(20)} | @{row.getShortJavaType(25)}
+@foreach{row : endpointOptions}| *@{row.getShortName(30)}* (@{row.shortGroup}) | @{util.escape(row.description)} | @{row.getShortDefaultValue(20)} | @{row.getShortJavaType(25)}
 @end{}|===
 @end{}
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/resources/language-options.mvel b/tooling/maven/camel-package-maven-plugin/src/main/resources/language-options.mvel
index 01ea4d8..498d338 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/resources/language-options.mvel
+++ b/tooling/maven/camel-package-maven-plugin/src/main/resources/language-options.mvel
@@ -8,6 +8,6 @@ The @{title} language supports @{languageOptions.size()} options, which are list
 [width="100%",cols="2,1m,1m,6",options="header"]
 |===
 | Name | Default | Java Type | Description
-@foreach{row : languageOptions}| @{row.name} | @{row.defaultValue} | @{row.shortJavaType} | @{row.description.replaceAll("\\$", "\\\\\\$")}
+@foreach{row : languageOptions}| @{row.name} | @{row.defaultValue} | @{row.shortJavaType} | @{util.escape(row.description)}
 @end{}|===
 @end{}
\ No newline at end of file
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/resources/readme-components.mvel b/tooling/maven/camel-package-maven-plugin/src/main/resources/readme-components.mvel
index 765a66e2..16d3573 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/resources/readme-components.mvel
+++ b/tooling/maven/camel-package-maven-plugin/src/main/resources/readme-components.mvel
@@ -7,7 +7,7 @@ Number of Components: @{components.size} in @{numberOfArtifacts} JAR artifacts (
 | Component | Available From | Description
 @foreach{row : components}
 | link:@{row.docLink}/${row.scheme}-component.adoc[@{row.title}] (@{row.artifactId}) +
-`@{row.syntax}` | @{row.firstVersionShort} | @if{row.deprecated == "true"}*deprecated* @end{}@{row.description.replaceAll("\\$", "\\\\\\$")}
+`@{row.syntax}` | @{row.firstVersionShort} | @if{row.deprecated == "true"}*deprecated* @end{}@{util.escape(row.description)}
 @end{}
 |===
 
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/resources/readme-dataformats.mvel b/tooling/maven/camel-package-maven-plugin/src/main/resources/readme-dataformats.mvel
index 3790e21..72d12c1 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/resources/readme-dataformats.mvel
+++ b/tooling/maven/camel-package-maven-plugin/src/main/resources/readme-dataformats.mvel
@@ -6,7 +6,7 @@ Number of Data Formats: @{dataformats.size} in @{numberOfArtifacts} JAR artifact
 |===
 | Data Format | Available From | Description
 @foreach{row : dataformats}
-| link:@{row.docLink}/${row.name}-dataformat.adoc[@{row.title}] (@{row.artifactId}) | @{row.firstVersionShort} | @if{row.deprecated == "true"}*deprecated* @end{}@{row.description.replaceAll("\\$", "\\\\\\$")}
+| link:@{row.docLink}/${row.name}-dataformat.adoc[@{row.title}] (@{row.artifactId}) | @{row.firstVersionShort} | @if{row.deprecated == "true"}*deprecated* @end{}@{util.escape(row.description)}
 @end{}|===
 
 @end{}
\ No newline at end of file
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/resources/readme-eips.mvel b/tooling/maven/camel-package-maven-plugin/src/main/resources/readme-eips.mvel
index 0869927..c4ce7f3 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/resources/readme-eips.mvel
+++ b/tooling/maven/camel-package-maven-plugin/src/main/resources/readme-eips.mvel
@@ -7,7 +7,7 @@ Number of EIPs: @{eips.size} (@{numberOfDeprecated} deprecated)
 | EIP | Description
 @foreach{row : eips}
 | link:@{row.docLink}/${row.name}-eip.adoc[@{row.title}] +
-`<@{row.name}>` | @if{row.deprecated == "true"}*deprecated* @end{}@{row.description.replaceAll("\\$", "\\\\\\$")}
+`<@{row.name}>` | @if{row.deprecated == "true"}*deprecated* @end{}@{util.escape(row.description)}
 @end{}
 |===
 
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/resources/readme-examples.mvel b/tooling/maven/camel-package-maven-plugin/src/main/resources/readme-examples.mvel
index 72a3667..4001623 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/resources/readme-examples.mvel
+++ b/tooling/maven/camel-package-maven-plugin/src/main/resources/readme-examples.mvel
@@ -6,7 +6,7 @@ Number of Examples: @{examples.size} (@{numberOfDeprecated} deprecated)
 |===
 | Example | Category | Description
 @foreach{row : examples}
-| link:@{row.docLink}[@{row.title}] (@{row.fileName}) | @{row.category} | @if{row.deprecated == "true"}*deprecated* @end{}@{row.description.replaceAll("\\$", "\\\\\\$")}
+| link:@{row.docLink}[@{row.title}] (@{row.fileName}) | @{row.category} | @if{row.deprecated == "true"}*deprecated* @end{}@{util.escape(row.description)}
 @end{}|===
 
 @end{}
\ No newline at end of file
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/resources/readme-languages.mvel b/tooling/maven/camel-package-maven-plugin/src/main/resources/readme-languages.mvel
index 120662f..ba0e1ca 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/resources/readme-languages.mvel
+++ b/tooling/maven/camel-package-maven-plugin/src/main/resources/readme-languages.mvel
@@ -6,7 +6,7 @@ Number of Languages: @{languages.size} in @{numberOfArtifacts} JAR artifacts (@{
 |===
 | Language | Available From | Description
 @foreach{row : languages}
-| link:@{row.docLink}/${row.name}-language.adoc[@{row.title}] (@{row.artifactId}) | @{row.firstVersionShort} | @if{row.deprecated == "true"}*deprecated* @end{}@{row.description.replaceAll("\\$", "\\\\\\$")}
+| link:@{row.docLink}/${row.name}-language.adoc[@{row.title}] (@{row.artifactId}) | @{row.firstVersionShort} | @if{row.deprecated == "true"}*deprecated* @end{}@{util.escape(row.description)}
 @end{}|===
 
 @end{}
\ No newline at end of file
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/resources/readme-others.mvel b/tooling/maven/camel-package-maven-plugin/src/main/resources/readme-others.mvel
index 7ae9c31..cbd06ce 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/resources/readme-others.mvel
+++ b/tooling/maven/camel-package-maven-plugin/src/main/resources/readme-others.mvel
@@ -6,7 +6,7 @@ Number of Miscellaneous Components: @{others.size} in @{numberOfArtifacts} JAR a
 |===
 | Component | Available From | Description
 @foreach{row : others}
-| link:@{row.docLink}/${row.name}.adoc[@{row.title}] (@{row.artifactId}) | @{row.firstVersionShort} | @if{row.deprecated == "true"}*deprecated* @end{}@{row.description.replaceAll("\\$", "\\\\\\$")}
+| link:@{row.docLink}/${row.name}.adoc[@{row.title}] (@{row.artifactId}) | @{row.firstVersionShort} | @if{row.deprecated == "true"}*deprecated* @end{}@{util.escape(row.description)}
 @end{}|===
 
 @end{}
\ No newline at end of file
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/resources/spring-boot-auto-configure-options.mvel b/tooling/maven/camel-package-maven-plugin/src/main/resources/spring-boot-auto-configure-options.mvel
index 3b41a93..690708d 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/resources/spring-boot-auto-configure-options.mvel
+++ b/tooling/maven/camel-package-maven-plugin/src/main/resources/spring-boot-auto-configure-options.mvel
@@ -22,6 +22,6 @@ The component supports @{options.size()} options, which are listed below.
 [width="100%",cols="2,5,^1,2",options="header"]
 |===
 | Name | Description | Default | Type
-@foreach{row : options}| *@{row.name}* | @{row.description} | @{row.getShortDefaultValue(20)} | @{row.getShortJavaType(25)}
+@foreach{row : options}| *@{row.name}* | @{util.escape(row.description)} | @{row.getShortDefaultValue(20)} | @{row.getShortJavaType(25)}
 @end{}|===
 @end{}
\ No newline at end of file
diff --git a/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/MvelHelperTest.java b/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/MvelHelperTest.java
new file mode 100644
index 0000000..ac9e031
--- /dev/null
+++ b/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/MvelHelperTest.java
@@ -0,0 +1,66 @@
+/**
+ * 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
+ *
+ *      http://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.apache.camel.maven.packaging;
+
+import java.util.stream.Stream;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.params.provider.Arguments.arguments;
+
+public class MvelHelperTest {
+
+    @Test
+    public void shouldBeRobustAtEscaping() {
+        assertThat(MvelHelper.escape(null)).isNull();
+        assertThat(MvelHelper.escape("")).isEmpty();
+        assertThat(MvelHelper.escape(" ")).isEqualTo(" ");
+    }
+
+    @ParameterizedTest
+    @MethodSource("dollarEscapeCases")
+    public void shouldEscapeDollarSigns(final String given, final String expected) {
+        assertThat(MvelHelper.escape(given)).isEqualTo(expected);
+    }
+
+    @ParameterizedTest
+    @MethodSource("urlEscapeCases")
+    public void shouldUrls(final String given, final String expected) {
+        assertThat(MvelHelper.escape(given)).isEqualTo(expected);
+    }
+
+    static Stream<Arguments> dollarEscapeCases() {
+        return Stream.of(
+            arguments("$", "\\$"),
+            arguments("some ${expression} here", "some \\${expression} here"));
+    }
+
+    static Stream<Arguments> urlEscapeCases() {
+        return Stream.of(
+            arguments("http", "http"),
+            arguments("some ${expression} here", "some \\${expression} here"),
+            arguments("http://example.com", "\\http://example.com"),
+            arguments("some http://example.com here", "some \\http://example.com here"),
+            arguments("https://example.com", "\\https://example.com"),
+            arguments("ftp://example.com", "\\ftp://example.com"),
+            arguments("Sets the POST URL for zipkin's <a href=\"http://zipkin.io/zipkin-api/#/\">v2 api</a>, usually \"http://zipkinhost:9411/api/v2/spans\"", "Sets the POST URL for zipkin's <a href=\"http://zipkin.io/zipkin-api/#/\">v2 api</a>, usually \"\\http://zipkinhost:9411/api/v2/spans\""));
+    }
+}