diff --git a/spring-cloud-contract/1.0.0.RELEASE/ghpages.sh b/spring-cloud-contract/1.0.0.RELEASE/ghpages.sh new file mode 100644 index 00000000..57c5da3a --- /dev/null +++ b/spring-cloud-contract/1.0.0.RELEASE/ghpages.sh @@ -0,0 +1,330 @@ +#!/bin/bash -x + +set -e + +# Set default props like MAVEN_PATH, ROOT_FOLDER etc. +function set_default_props() { + # The script should be executed from the root folder + ROOT_FOLDER=`pwd` + echo "Current folder is ${ROOT_FOLDER}" + + if [[ ! -e "${ROOT_FOLDER}/.git" ]]; then + echo "You're not in the root folder of the project!" + exit 1 + fi + + # Prop that will let commit the changes + COMMIT_CHANGES="no" + MAVEN_PATH=${MAVEN_PATH:-} + echo "Path to Maven is [${MAVEN_PATH}]" + REPO_NAME=${PWD##*/} + echo "Repo name is [${REPO_NAME}]" + SPRING_CLOUD_STATIC_REPO=${SPRING_CLOUD_STATIC_REPO:-git@github.com:spring-cloud/spring-cloud-static.git} + echo "Spring Cloud Static repo is [${SPRING_CLOUD_STATIC_REPO}" +} + +# Check if gh-pages exists and docs have been built +function check_if_anything_to_sync() { + git remote set-url --push origin `git config remote.origin.url | sed -e 's/^git:/https:/'` + + if ! (git remote set-branches --add origin gh-pages && git fetch -q); then + echo "No gh-pages, so not syncing" + exit 0 + fi + + if ! [ -d docs/target/generated-docs ] && ! [ "${BUILD}" == "yes" ]; then + echo "No gh-pages sources in docs/target/generated-docs, so not syncing" + exit 0 + fi +} + +function retrieve_current_branch() { + # Code getting the name of the current branch. For master we want to publish as we did until now + # http://stackoverflow.com/questions/1593051/how-to-programmatically-determine-the-current-checked-out-git-branch + # If there is a branch already passed will reuse it - otherwise will try to find it + CURRENT_BRANCH=${BRANCH} + if [[ -z "${CURRENT_BRANCH}" ]] ; then + CURRENT_BRANCH=$(git symbolic-ref -q HEAD) + CURRENT_BRANCH=${CURRENT_BRANCH##refs/heads/} + CURRENT_BRANCH=${CURRENT_BRANCH:-HEAD} + fi + echo "Current branch is [${CURRENT_BRANCH}]" + git checkout ${CURRENT_BRANCH} || echo "Failed to check the branch... continuing with the script" +} + +# Switches to the provided value of the release version. We always prefix it with `v` +function switch_to_tag() { + git checkout v${VERSION} +} + +# Build the docs if switch is on +function build_docs_if_applicable() { + if [[ "${BUILD}" == "yes" ]] ; then + ./mvnw clean install -P docs -pl docs -DskipTests + fi +} + +# Get the name of the `docs.main` property +# Get whitelisted branches - assumes that a `docs` module is available under `docs` profile +function retrieve_doc_properties() { + MAIN_ADOC_VALUE=$("${MAVEN_PATH}"mvn -q \ + -Dexec.executable="echo" \ + -Dexec.args='${docs.main}' \ + --non-recursive \ + org.codehaus.mojo:exec-maven-plugin:1.3.1:exec) + echo "Extracted 'main.adoc' from Maven build [${MAIN_ADOC_VALUE}]" + + + WHITELIST_PROPERTY=${WHITELIST_PROPERTY:-"docs.whitelisted.branches"} + WHITELISTED_BRANCHES_VALUE=$("${MAVEN_PATH}"mvn -q \ + -Dexec.executable="echo" \ + -Dexec.args="\${${WHITELIST_PROPERTY}}" \ + org.codehaus.mojo:exec-maven-plugin:1.3.1:exec \ + -P docs \ + -pl docs) + echo "Extracted '${WHITELIST_PROPERTY}' from Maven build [${WHITELISTED_BRANCHES_VALUE}]" +} + +# Stash any outstanding changes +function stash_changes() { + git diff-index --quiet HEAD && dirty=$? || (echo "Failed to check if the current repo is dirty. Assuming that it is." && dirty="1") + if [ "$dirty" != "0" ]; then git stash; fi +} + +# Switch to gh-pages branch to sync it with current branch +function add_docs_from_target() { + local DESTINATION_REPO_FOLDER + if [[ -z "${DESTINATION}" && -z "${CLONE}" ]] ; then + DESTINATION_REPO_FOLDER=${ROOT_FOLDER} + elif [[ "${CLONE}" == "yes" ]]; then + mkdir -p ${ROOT_FOLDER}/target + local clonedStatic=${ROOT_FOLDER}/target/spring-cloud-static + if [[ ! -e "${clonedStatic}/.git" ]]; then + echo "Cloning Spring Cloud Static to target" + git clone ${SPRING_CLOUD_STATIC_REPO} ${clonedStatic} && git checkout gh-pages + else + echo "Spring Cloud Static already cloned - will pull changes" + cd ${clonedStatic} && git checkout gh-pages && git pull origin gh-pages + fi + DESTINATION_REPO_FOLDER=${clonedStatic}/${REPO_NAME} + mkdir -p ${DESTINATION_REPO_FOLDER} + else + if [[ ! -e "${DESTINATION}/.git" ]]; then + echo "[${DESTINATION}] is not a git repository" + exit 1 + fi + DESTINATION_REPO_FOLDER=${DESTINATION}/${REPO_NAME} + mkdir -p ${DESTINATION_REPO_FOLDER} + echo "Destination was provided [${DESTINATION}]" + fi + cd ${DESTINATION_REPO_FOLDER} + git checkout gh-pages + git pull origin gh-pages + + # Add git branches + ################################################################### + if [[ -z "${VERSION}" ]] ; then + copy_docs_for_current_version + else + copy_docs_for_provided_version + fi + commit_changes_if_applicable +} + + +# Copies the docs by using the retrieved properties from Maven build +function copy_docs_for_current_version() { + if [[ "${CURRENT_BRANCH}" == "master" ]] ; then + echo -e "Current branch is master - will copy the current docs only to the root folder" + for f in docs/target/generated-docs/*; do + file=${f#docs/target/generated-docs/*} + if ! git ls-files -i -o --exclude-standard --directory | grep -q ^$file$; then + # Not ignored... + cp -rf $f ${ROOT_FOLDER}/ + git add -A ${ROOT_FOLDER}/$file + fi + done + COMMIT_CHANGES="yes" + else + echo -e "Current branch is [${CURRENT_BRANCH}]" + # http://stackoverflow.com/questions/29300806/a-bash-script-to-check-if-a-string-is-present-in-a-comma-separated-list-of-strin + if [[ ",${WHITELISTED_BRANCHES_VALUE}," = *",${CURRENT_BRANCH},"* ]] ; then + mkdir -p ${ROOT_FOLDER}/${CURRENT_BRANCH} + echo -e "Branch [${CURRENT_BRANCH}] is whitelisted! Will copy the current docs to the [${CURRENT_BRANCH}] folder" + for f in docs/target/generated-docs/*; do + file=${f#docs/target/generated-docs/*} + if ! git ls-files -i -o --exclude-standard --directory | grep -q ^$file$; then + # Not ignored... + # We want users to access 1.0.0.RELEASE/ instead of 1.0.0.RELEASE/spring-cloud.sleuth.html + if [[ "${file}" == "${MAIN_ADOC_VALUE}.html" ]] ; then + # We don't want to copy the spring-cloud-sleuth.html + # we want it to be converted to index.html + cp -rf $f ${ROOT_FOLDER}/${CURRENT_BRANCH}/index.html + git add -A ${ROOT_FOLDER}/${CURRENT_BRANCH}/index.html + else + cp -rf $f ${ROOT_FOLDER}/${CURRENT_BRANCH} + git add -A ${ROOT_FOLDER}/${CURRENT_BRANCH}/$file + fi + fi + done + COMMIT_CHANGES="yes" + else + echo -e "Branch [${CURRENT_BRANCH}] is not on the white list! Check out the Maven [${WHITELIST_PROPERTY}] property in + [docs] module available under [docs] profile. Won't commit any changes to gh-pages for this branch." + fi + fi +} + +# Copies the docs by using the explicitly provided version +function copy_docs_for_provided_version() { + local FOLDER=${DESTINATION_REPO_FOLDER}/${VERSION} + mkdir -p ${FOLDER} + echo -e "Current tag is [v${VERSION}] Will copy the current docs to the [${FOLDER}] folder" + for f in ${ROOT_FOLDER}/docs/target/generated-docs/*; do + file=${f#${ROOT_FOLDER}/docs/target/generated-docs/*} + copy_docs_for_branch ${file} ${FOLDER} + done + COMMIT_CHANGES="yes" + CURRENT_BRANCH="v${VERSION}" +} + +# Copies the docs from target to the provided destination +# Params: +# $1 - file from target +# $2 - destination to which copy the files +function copy_docs_for_branch() { + local file=$1 + local destination=$2 + if ! git ls-files -i -o --exclude-standard --directory | grep -q ^${file}$; then + # Not ignored... + # We want users to access 1.0.0.RELEASE/ instead of 1.0.0.RELEASE/spring-cloud.sleuth.html + if [[ ("${file}" == "${MAIN_ADOC_VALUE}.html") || ("${file}" == "${REPO_NAME}.html") ]] ; then + # We don't want to copy the spring-cloud-sleuth.html + # we want it to be converted to index.html + cp -rf $f ${destination}/index.html + git add -A ${destination}/index.html + else + cp -rf $f ${destination} + git add -A ${destination}/$file + fi + fi +} + +function commit_changes_if_applicable() { + if [[ "${COMMIT_CHANGES}" == "yes" ]] ; then + COMMIT_SUCCESSFUL="no" + git commit -a -m "Sync docs from ${CURRENT_BRANCH} to gh-pages" && COMMIT_SUCCESSFUL="yes" || echo "Failed to commit changes" + + # Uncomment the following push if you want to auto push to + # the gh-pages branch whenever you commit to master locally. + # This is a little extreme. Use with care! + ################################################################### + if [[ "${COMMIT_SUCCESSFUL}" == "yes" ]] ; then + git push origin gh-pages + fi + fi +} + +# Switch back to the previous branch and exit block +function checkout_previous_branch() { + # If -version was provided we need to come back to root project + cd ${ROOT_FOLDER} + git checkout ${CURRENT_BRANCH} || echo "Failed to check the branch... continuing with the script" + if [ "$dirty" != "0" ]; then git stash pop; fi + exit 0 +} + +# Assert if properties have been properly passed +function assert_properties() { +echo "VERSION [${VERSION}], DESTINATION [${DESTINATION}], CLONE [${CLONE}]" +if [[ "${VERSION}" != "" && (-z "${DESTINATION}" && -z "${CLONE}") ]] ; then echo "Version was set but destination / clone was not!"; exit 1;fi +if [[ ("${DESTINATION}" != "" && "${CLONE}" != "") && -z "${VERSION}" ]] ; then echo "Destination / clone was set but version was not!"; exit 1;fi +if [[ "${DESTINATION}" != "" && "${CLONE}" == "yes" ]] ; then echo "Destination and clone was set. Pick one!"; exit 1;fi +} + +# Prints the usage +function print_usage() { +cat </` +- if the destination switch is passed (-d) then the script will check if the provided dir is a git repo and then will + switch to gh-pages of that repo and copy the generated docs to `docs//` + +USAGE: + +You can use the following options: + +-v|--version - the script will apply the whole procedure for a particular library version +-d|--destination - the root of destination folder where the docs should be copied. You have to use the full path. + E.g. point to spring-cloud-static folder. Can't be used with (-c) +-b|--build - will run the standard build process after checking out the branch +-c|--clone - will automatically clone the spring-cloud-static repo instead of providing the destination. + Obviously can't be used with (-d) + +EOF +} + + +# ========================================== +# ____ ____ _____ _____ _____ _______ +# / ____|/ ____| __ \|_ _| __ \__ __| +# | (___ | | | |__) | | | | |__) | | | +# \___ \| | | _ / | | | ___/ | | +# ____) | |____| | \ \ _| |_| | | | +# |_____/ \_____|_| \_\_____|_| |_| +# +# ========================================== + +while [[ $# > 0 ]] +do +key="$1" +case ${key} in + -v|--version) + VERSION="$2" + shift # past argument + ;; + -d|--destination) + DESTINATION="$2" + shift # past argument + ;; + -b|--build) + BUILD="yes" + ;; + -c|--clone) + CLONE="yes" + ;; + -h|--help) + print_usage + exit 0 + ;; + *) + echo "Invalid option: [$1]" + print_usage + exit 1 + ;; +esac +shift # past argument or value +done + +assert_properties +set_default_props +check_if_anything_to_sync +if [[ -z "${VERSION}" ]] ; then + retrieve_current_branch +else + switch_to_tag +fi +build_docs_if_applicable +retrieve_doc_properties +stash_changes +add_docs_from_target +checkout_previous_branch \ No newline at end of file diff --git a/spring-cloud-contract/1.0.0.RELEASE/images/Deps.png b/spring-cloud-contract/1.0.0.RELEASE/images/Deps.png new file mode 100644 index 00000000..14268143 Binary files /dev/null and b/spring-cloud-contract/1.0.0.RELEASE/images/Deps.png differ diff --git a/spring-cloud-contract/1.0.0.RELEASE/images/Stubs1.png b/spring-cloud-contract/1.0.0.RELEASE/images/Stubs1.png new file mode 100644 index 00000000..ebadfdb9 Binary files /dev/null and b/spring-cloud-contract/1.0.0.RELEASE/images/Stubs1.png differ diff --git a/spring-cloud-contract/1.0.0.RELEASE/images/Stubs2.png b/spring-cloud-contract/1.0.0.RELEASE/images/Stubs2.png new file mode 100644 index 00000000..e4bad249 Binary files /dev/null and b/spring-cloud-contract/1.0.0.RELEASE/images/Stubs2.png differ diff --git a/spring-cloud-contract/1.0.0.RELEASE/index.html b/spring-cloud-contract/1.0.0.RELEASE/index.html new file mode 100644 index 00000000..1313681e --- /dev/null +++ b/spring-cloud-contract/1.0.0.RELEASE/index.html @@ -0,0 +1,6397 @@ + + + + + + + +Spring Cloud Contract + + + + + +
+
+
+
+

Documentation Authors: Adam Dudczak, Marcin Grzejszczak, Jakub Kubryński, Karol Lassak, +Olga Maciaszek-Sharma, Mariusz Smykuła, Dave Syer

+
+
+

1.0.0.RELEASE

+
+
+
+
+

Spring Cloud Contract

+
+
+

What you always need is confidence in pushing new features into a new application or service in a distributed system. +This project provides support for Consumer Driven Contracts and service schemas in Spring applications, covering a +range of options for writing tests, publishing them as assets, asserting that a contract is kept by producers +and consumers, for HTTP and message-based interactions.

+
+
+
+
+

Spring Cloud Contract Verifier

+
+
+

Introduction

+ +
+ + + + + +
+
Tip
+
+The Accurest project was initially started by Marcin Grzejszczak and Jakub Kubrynski (codearte.io) +
+
+
+

Just to make long story short - Spring Cloud Contract Verifier is a tool that enables Consumer Driven Contract (CDC) development of JVM-based applications. It is shipped +with Contract Definition Language (DSL). Contract definitions are used to produce following resources:

+
+
+
    +
  • +

    JSON stub definitions to be used by WireMock when doing integration testing on the client code (client tests). +Test code must still be written by hand, test data is produced by Spring Cloud Contract Verifier.

    +
  • +
  • +

    Messaging routes if you’re using one. We’re integrating with Spring Integration, Spring Cloud Stream and Apache Camel. You can however set your own integrations if you want to

    +
  • +
  • +

    Acceptance tests (in JUnit or Spock) used to verify if server-side implementation of the API is compliant with the contract (server tests). +Full test is generated by Spring Cloud Contract Verifier.

    +
  • +
+
+
+

Spring Cloud Contract Verifier moves TDD to the level of software architecture.

+
+
+

Why?

+
+

Let us assume that we have a system comprising of multiple microservices:

+
+
+
+Microservices Architecture +
+
+
+
Testing issues
+
+

If we wanted to test the application in top left corner if it can communicate with other services then we could do one of two things:

+
+
+
    +
  • +

    deploy all microservices and perform end to end tests

    +
  • +
  • +

    mock other microservices in unit / integration tests

    +
  • +
+
+
+

Both have their advantages but also a lot of disadvantages. Let’s focus on the latter.

+
+
+

Deploy all microservices and perform end to end tests

+
+
+

Advantages:

+
+
+
    +
  • +

    simulates production

    +
  • +
  • +

    tests real communication between services

    +
  • +
+
+
+

Disadvantages:

+
+
+
    +
  • +

    to test one microservice we would have to deploy 6 microservices, a couple of databases etc.

    +
  • +
  • +

    the environment where the tests would be conducted would be locked for a single suite of tests (i.e. nobody else would be able to run the tests in the meantime).

    +
  • +
  • +

    long to run

    +
  • +
  • +

    very late feedback

    +
  • +
  • +

    extremely hard to debug

    +
  • +
+
+
+

Mock other microservices in unit / integration tests

+
+
+

Advantages:

+
+
+
    +
  • +

    very fast feedback

    +
  • +
  • +

    no infrastructure requirements

    +
  • +
+
+
+

Disadvantages:

+
+
+
    +
  • +

    the implementor of the service creates stubs thus they might have nothing to do with the reality

    +
  • +
  • +

    you can go to production with passing tests and failing production

    +
  • +
+
+
+

To solve the aforementioned issues Spring Cloud Contract Verifier with Stub Runner were created. Their main idea is to give you very fast feedback, without the need +to set up the whole world of microservices.

+
+
+
+Stubbed Services +
+
+
+

If you work on stubs then the only applications you need are those that your application is using directly.

+
+
+
+Stubbed Services +
+
+
+

Spring Cloud Contract Verifier gives you the certainty that the stubs that you’re using were created by the service that you’re calling. Also if you can use them it means that they were +tested against the producer’s side. In other words - you can trust those stubs.

+
+
+
+
+

Purposes

+
+

The main purposes of Spring Cloud Contract Verifier with Stub Runner are:

+
+
+
    +
  • +

    to ensure that WireMock / Messaging stubs (used when developing the client) are doing exactly what actual server-side implementation will do,

    +
  • +
  • +

    to promote ATDD method and Microservices architectural style,

    +
  • +
  • +

    to provide a way to publish changes in contracts that are immediately visible on both sides,

    +
  • +
  • +

    to generate boilerplate test code used on the server side.

    +
  • +
+
+
+ + + + + +
+
Important
+
+Spring Cloud Contract Verifier’s purpose is NOT to start writing business features in the contracts. +Let’s assume that we have a business use case of fraud check. If a user can be a fraud for 100 different reasons, +we would assume that you would create 2 contracts. One for the positive and one for the negative fraud case. +Contract tests are used to test contracts between applications and not to simulate full behaviour. +
+
+
+
+

Client Side

+
+

During the tests you want to have a WireMock instance / Messaging route up and running that simulates the service Y. +You would like to feed that instance with a proper stub definition. That stub definition would need +to be valid and should also be reusable on the server side.

+
+
+

Summing it up: On this side, in the stub definition, you can use patterns for request stubbing and you need exact +values for responses.

+
+
+
+

Server Side

+
+

Being a service Y since you are developing your stub, you need to be sure that it’s actually resembling your +concrete implementation. You can’t have a situation where your stub acts in one way and your application on +production behaves in a different way.

+
+
+

That’s why from the provided stub acceptance tests will be generated that will ensure +that your application behaves in the same way as you define in your stub.

+
+
+

Summing it up: On this side, in the stub definition, you need exact values as request and can use patterns/methods +for response verification.

+
+
+
+

Step by step guide to CDC

+
+

Let’s take an example of Fraud Detection and Loan Issuance process. The business scenario is such that we want to issue loans to people but don’t want them to steal the money from us. The current implementation of our system grants loans to everybody.

+
+
+

Let’s assume that the Loan Issuance is a client to the +Fraud Detection server. In the current sprint we are required to develop a new feature - if a client wants to borrow too much money then we mark him as fraud.

+
+
+

Technical remark - Fraud Detection will have artifact id http-server, Loan Issuance http-client and both have group id com.example.

+
+
+

Social remark - both client and server development teams need to communicate directly and discuss changes while +going through the process. CDC is all about communication.

+
+ +
+ + + + + +
+
Tip
+
+In this case the ownership of the contracts lays on the producer side. It means that physically +all the contract are present in the producer’s repository +
+
+
+
Technical note
+
+

If using the SNAPSHOT / Milestone / Release Candidate versions please add the following section to your

+
+
+

Maven POM

+
+
+
+
<repositories>
+	<repository>
+		<id>spring-snapshots</id>
+		<name>Spring Snapshots</name>
+		<url>https://repo.spring.io/snapshot</url>
+		<snapshots>
+			<enabled>true</enabled>
+		</snapshots>
+	</repository>
+	<repository>
+		<id>spring-milestones</id>
+		<name>Spring Milestones</name>
+		<url>https://repo.spring.io/milestone</url>
+		<snapshots>
+			<enabled>false</enabled>
+		</snapshots>
+	</repository>
+	<repository>
+		<id>spring-releases</id>
+		<name>Spring Releases</name>
+		<url>https://repo.spring.io/release</url>
+		<snapshots>
+			<enabled>false</enabled>
+		</snapshots>
+	</repository>
+</repositories>
+<pluginRepositories>
+	<pluginRepository>
+		<id>spring-snapshots</id>
+		<name>Spring Snapshots</name>
+		<url>https://repo.spring.io/snapshot</url>
+		<snapshots>
+			<enabled>true</enabled>
+		</snapshots>
+	</pluginRepository>
+	<pluginRepository>
+		<id>spring-milestones</id>
+		<name>Spring Milestones</name>
+		<url>https://repo.spring.io/milestone</url>
+		<snapshots>
+			<enabled>false</enabled>
+		</snapshots>
+	</pluginRepository>
+	<pluginRepository>
+		<id>spring-releases</id>
+		<name>Spring Releases</name>
+		<url>https://repo.spring.io/release</url>
+		<snapshots>
+			<enabled>false</enabled>
+		</snapshots>
+	</pluginRepository>
+</pluginRepositories>
+
+
+
+

Gradle build

+
+
+
+
repositories {
+	mavenCentral()
+	mavenLocal()
+	maven { url "http://repo.spring.io/snapshot" }
+	maven { url "http://repo.spring.io/milestone" }
+	maven { url "http://repo.spring.io/release" }
+}
+
+
+
+
+
Consumer side (Loan Issuance)
+
+

As a developer of the Loan Issuance service (a consumer of the Fraud Detection server):

+
+
+

start doing TDD by writing a test to your feature

+
+
+
+
@Test
+public void shouldBeRejectedDueToAbnormalLoanAmount() {
+	// given:
+	LoanApplication application = new LoanApplication(new Client("1234567890"),
+			99999);
+	// when:
+	LoanApplicationResult loanApplication = service.loanApplication(application);
+	// then:
+	assertThat(loanApplication.getLoanApplicationStatus())
+			.isEqualTo(LoanApplicationStatus.LOAN_APPLICATION_REJECTED);
+	assertThat(loanApplication.getRejectionReason()).isEqualTo("Amount too high");
+}
+
+
+
+

We’ve just written a test of our new feature. If a loan application for a big amount is received we should reject that loan application with some description.

+
+
+

write the missing implementation

+
+
+

At some point in time you need to send a request to the Fraud Detection service. Let’s assume that we’d like to send the request containing the id of the client and the amount he wants to borrow from us. We’d like to send it to the /fraudcheck url via the PUT method.

+
+
+
+
ResponseEntity<FraudServiceResponse> response =
+		restTemplate.exchange("http://localhost:" + port + "/fraudcheck", HttpMethod.PUT,
+				new HttpEntity<>(request, httpHeaders),
+				FraudServiceResponse.class);
+
+
+
+

For simplicity we’ve hardcoded the port of the Fraud Detection service at 8080 and our application is running on 8090.

+
+
+

If we’d start the written test it would obviously break since we have no service running on port 8080.

+
+
+

clone the Fraud Detection service repository locally

+
+
+

We’ll start playing around with the server side contract. That’s why we need to first clone it.

+
+
+
+
git clone https://your-git-server.com/server-side.git local-http-server-repo
+
+
+
+

define the contract locally in the repo of Fraud Detection service

+
+
+

As consumers we need to define what exactly we want to achieve. We need to formulate our expectations. That’s why we write the following contract.

+
+
+
+
package contracts
+
+org.springframework.cloud.contract.spec.Contract.make {
+			request { // (1)
+				method 'PUT' // (2)
+				url '/fraudcheck' // (3)
+				body([ // (4)
+					clientId: value(consumer(regex('[0-9]{10}'))),
+					loanAmount: 99999
+					])
+				headers { // (5)
+					header('Content-Type', 'application/vnd.fraud.v1+json')
+				}
+			}
+			response { // (6)
+				status 200 // (7)
+				body([ // (8)
+					fraudCheckStatus: "FRAUD",
+					rejectionReason: "Amount too high"
+				])
+				headers { // (9)
+					 header('Content-Type': value(
+							 producer(regex('application/vnd.fraud.v1.json.*')),
+							 consumer('application/vnd.fraud.v1+json'))
+					 )
+				}
+			}
+}
+
+/*
+Since we don't want to force on the user to hardcode values of fields that are dynamic
+(timestamps, database ids etc.), one can provide parametrize those entries by using the
+`value(consumer(...), producer(...))` method. That way what's present in the `consumer`
+section will end up in the produced stub. What's there in the `producer` will end up in the
+autogenerated test. If you provide only the regular expression side without the concrete
+value then Spring Cloud Contract will generate one for you.
+
+From the Consumer perspective, when shooting a request in the integration test:
+
+(1) - If the consumer sends a request
+(2) - With the "PUT" method
+(3) - to the URL "/fraudcheck"
+(4) - with the JSON body that
+ * has a field `clientId` that matches a regular expression `[0-9]{10}`
+ * has a field `loanAmount` that is equal to `99999`
+(5) - with header `Content-Type` equal to `application/vnd.fraud.v1+json`
+(6) - then the response will be sent with
+(7) - status equal `200`
+(8) - and JSON body equal to
+ { "fraudCheckStatus": "FRAUD", "rejectionReason": "Amount too high" }
+(9) - with header `Content-Type` equal to `application/vnd.fraud.v1+json`
+
+From the Producer perspective, in the autogenerated producer-side test:
+
+(1) - A request will be sent to the producer
+(2) - With the "PUT" method
+(3) - to the URL "/fraudcheck"
+(4) - with the JSON body that
+ * has a field `clientId` that will have a generated value that matches a regular expression `[0-9]{10}`
+ * has a field `loanAmount` that is equal to `99999`
+(5) - with header `Content-Type` equal to `application/vnd.fraud.v1+json`
+(6) - then the test will assert if the response has been sent with
+(7) - status equal `200`
+(8) - and JSON body equal to
+ { "fraudCheckStatus": "FRAUD", "rejectionReason": "Amount too high" }
+(9) - with header `Content-Type` matching `application/vnd.fraud.v1+json.*`
+ */
+
+
+
+

The Contract is written using a statically typed Groovy DSL. You might be wondering what are those +value(client(…​), server(…​)) parts. By using this notation Spring Cloud Contract allows you to +define parts of a JSON / URL / etc. which are dynamic. In case of an identifier or a timestamp you +don’t want to hardcode a value. You want to allow some different ranges of values. That’s why for +the consumer side you can set regular expressions matching those values. You can provide the body +either by means of a map notation or String with interpolations. +Consult the docs +for more information. We highly recommend using the map notation!

+
+
+ + + + + +
+
Tip
+
+It’s really important that you understand the map notation to set up contracts. Please read the +Groovy docs regarding JSON +
+
+
+

The aforementioned contract is an agreement between two sides that:

+
+
+
    +
  • +

    if an HTTP request is sent with

    +
    +
      +
    • +

      a method PUT on an endpoint /fraudcheck

      +
    • +
    • +

      JSON body with clientId matching the regular expression [0-9]{10} and loanAmount equal to 99999

      +
    • +
    • +

      and with a header Content-Type equal to application/vnd.fraud.v1+json

      +
    • +
    +
    +
  • +
  • +

    then an HTTP response would be sent to the consumer that

    +
    +
      +
    • +

      has status 200

      +
    • +
    • +

      contains JSON body with the fraudCheckStatus field containing a value FRAUD and the rejectionReason field having value Amount too high

      +
    • +
    • +

      and a Content-Type header with a value of application/vnd.fraud.v1+json

      +
    • +
    +
    +
  • +
+
+
+

Once we’re ready to check the API in practice in the integration tests we need to just install the stubs locally

+
+
+

add the Spring Cloud Contract Verifier plugin

+
+
+

We can add either Maven or Gradle plugin - in this example we’ll show how to add Maven. First we need to add the Spring Cloud Contract BOM.

+
+
+
+
<dependencyManagement>
+	<dependencies>
+		<dependency>
+			<groupId>org.springframework.cloud</groupId>
+			<artifactId>spring-cloud-dependencies</artifactId>
+			<version>${spring-cloud-dependencies.version}</version>
+			<type>pom</type>
+			<scope>import</scope>
+		</dependency>
+	</dependencies>
+</dependencyManagement>
+
+
+
+

Next, the Spring Cloud Contract Verifier Maven plugin

+
+
+
+
<plugin>
+	<groupId>org.springframework.cloud</groupId>
+	<artifactId>spring-cloud-contract-maven-plugin</artifactId>
+	<version>${spring-cloud-contract.version}</version>
+	<extensions>true</extensions>
+	<configuration>
+		<packageWithBaseClasses>com.example.fraud</packageWithBaseClasses>
+	</configuration>
+</plugin>
+
+
+
+

Since the plugin was added we get the Spring Cloud Contract Verifier features which from the provided contracts:

+
+
+
    +
  • +

    generate and run tests

    +
  • +
  • +

    produce and install stubs

    +
  • +
+
+
+

We don’t want to generate tests since we, as consumers, want only to play with the stubs. That’s why we need to skip the tests generation and execution. When we execute:

+
+
+
+
cd local-http-server-repo
+./mvnw clean install -DskipTests
+
+
+
+

In the logs we’ll see something like this:

+
+
+
+
[INFO] --- spring-cloud-contract-maven-plugin:1.0.0.BUILD-SNAPSHOT:generateStubs (default-generateStubs) @ http-server ---
+[INFO] Building jar: /some/path/http-server/target/http-server-0.0.1-SNAPSHOT-stubs.jar
+[INFO]
+[INFO] --- maven-jar-plugin:2.6:jar (default-jar) @ http-server ---
+[INFO] Building jar: /some/path/http-server/target/http-server-0.0.1-SNAPSHOT.jar
+[INFO]
+[INFO] --- spring-boot-maven-plugin:1.4.0.BUILD-SNAPSHOT:repackage (default) @ http-server ---
+[INFO]
+[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ http-server ---
+[INFO] Installing /some/path/http-server/target/http-server-0.0.1-SNAPSHOT.jar to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT.jar
+[INFO] Installing /some/path/http-server/pom.xml to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT.pom
+[INFO] Installing /some/path/http-server/target/http-server-0.0.1-SNAPSHOT-stubs.jar to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar
+
+
+
+

This line is extremely important

+
+
+
+
[INFO] Installing /some/path/http-server/target/http-server-0.0.1-SNAPSHOT-stubs.jar to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar
+
+
+
+

It’s confirming that the stubs of the http-server have been installed in the local repository.

+
+
+

run the integration tests

+
+
+

In order to profit from the Spring Cloud Contract Stub Runner functionality of automatic stub downloading you have to do the following in our consumer side project (Loan Application service).

+
+
+

Add the Spring Cloud Contract BOM

+
+
+
+
<dependencyManagement>
+	<dependencies>
+		<dependency>
+			<groupId>org.springframework.cloud</groupId>
+			<artifactId>spring-cloud-dependencies</artifactId>
+			<version>${spring-cloud-dependencies.version}</version>
+			<type>pom</type>
+			<scope>import</scope>
+		</dependency>
+	</dependencies>
+</dependencyManagement>
+
+
+
+

Add the dependency to Spring Cloud Contract Stub Runner

+
+
+
+
<dependency>
+	<groupId>org.springframework.cloud</groupId>
+	<artifactId>spring-cloud-starter-contract-stub-runner</artifactId>
+	<scope>test</scope>
+</dependency>
+
+
+
+

Annotate your test class with @AutoConfigureStubRunner. In the annotation provide the group id and artifact id for the Stub Runner to download stubs of your collaborators. Also provide the offline work switch since you’re playing with the collaborators offline (optional step).

+
+
+
+
@RunWith(SpringRunner.class)
+@SpringBootTest
+@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:8080"}, workOffline = true)
+public class LoanApplicationServiceTests {
+
+
+
+

Now if you run your tests you’ll see sth like this:

+
+
+
+
2016-07-19 14:22:25.403  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Desired version is + - will try to resolve the latest version
+2016-07-19 14:22:25.438  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Resolved version is 0.0.1-SNAPSHOT
+2016-07-19 14:22:25.439  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Resolving artifact com.example:http-server:jar:stubs:0.0.1-SNAPSHOT using remote repositories []
+2016-07-19 14:22:25.451  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Resolved artifact com.example:http-server:jar:stubs:0.0.1-SNAPSHOT to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar
+2016-07-19 14:22:25.465  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Unpacking stub from JAR [URI: file:/path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar]
+2016-07-19 14:22:25.475  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Unpacked file to [/var/folders/0p/xwq47sq106x1_g3dtv6qfm940000gq/T/contracts100276532569594265]
+2016-07-19 14:22:27.737  INFO 41050 --- [           main] o.s.c.c.stubrunner.StubRunnerExecutor    : All stubs are now running RunningStubs [namesAndPorts={com.example:http-server:0.0.1-SNAPSHOT:stubs=8080}]
+
+
+
+

Which means that Stub Runner has found your stubs and started a server for app with group id com.example, artifact id http-server with version 0.0.1-SNAPSHOT of the stubs and with stubs classifier on port 8080.

+
+
+

file a PR

+
+
+

What we did until now is an iterative process. We can play around with the contract, install it locally and work on the consumer side until we’re happy with the contract.

+
+
+

Once we’re satisfied with the results and the test passes publish a PR to the server side. Currently the consumer side work is done.

+
+
+
+
Producer side (Fraud Detection server)
+
+

As a developer of the Fraud Detection server (a server to the Loan Issuance service):

+
+
+

initial implementation

+
+
+

As a reminder here you can see the initial implementation

+
+
+
+
@RequestMapping(
+		value = "/fraudcheck",
+		method = PUT,
+		consumes = FRAUD_SERVICE_JSON_VERSION_1,
+		produces = FRAUD_SERVICE_JSON_VERSION_1)
+public FraudCheckResult fraudCheck(@RequestBody FraudCheck fraudCheck) {
+return new FraudCheckResult(FraudCheckStatus.OK, NO_REASON);
+}
+
+
+
+

take over the PR

+
+
+
+
git checkout -b contract-change-pr master
+git pull https://your-git-server.com/server-side-fork.git contract-change-pr
+
+
+
+

You have to add the dependencies needed by the autogenerated tests

+
+
+
+
	<dependency>
+	<groupId>org.springframework.cloud</groupId>
+	<artifactId>spring-cloud-starter-contract-verifier</artifactId>
+	<scope>test</scope>
+</dependency>
+
+
+
+

In the configuration of the Maven plugin we passed the baseClassForTests property

+
+
+
+
<plugin>
+	<groupId>org.springframework.cloud</groupId>
+	<artifactId>spring-cloud-contract-maven-plugin</artifactId>
+	<version>${spring-cloud-contract.version}</version>
+	<extensions>true</extensions>
+	<configuration>
+		<packageWithBaseClasses>com.example.fraud</packageWithBaseClasses>
+	</configuration>
+</plugin>
+
+
+
+

That’s because all the generated tests will extend that class. Over there you can set up your Spring Context or whatever is necessary. In our case we’re using Rest Assured MVC to start the server side FraudDetectionController.

+
+
+
+
package com.example.fraud;
+
+import com.example.fraud.FraudDetectionController;
+import com.jayway.restassured.module.mockmvc.RestAssuredMockMvc;
+
+import org.junit.Before;
+
+public class FraudBase {
+
+	@Before
+	public void setup() {
+		RestAssuredMockMvc.standaloneSetup(new FraudDetectionController());
+	}
+
+	public void assertThatRejectionReasonIsNull(Object rejectionReason) {
+		assert rejectionReason == null;
+	}
+}
+
+
+
+

Now, if you run the ./mvnw clean install you would get sth like this:

+
+
+
+
Results :
+
+Tests in error:
+  ContractVerifierTest.validate_shouldMarkClientAsFraud:32 » IllegalState Parsed...
+
+
+
+

That’s because you have a new contract from which a test was generated and it failed since you haven’t implemented the feature. The autogenerated test would look like this:

+
+
+
+
@Test
+public void validate_shouldMarkClientAsFraud() throws Exception {
+    // given:
+        MockMvcRequestSpecification request = given()
+                .header("Content-Type", "application/vnd.fraud.v1+json")
+                .body("{\"clientId\":\"1234567890\",\"loanAmount\":99999}");
+
+    // when:
+        ResponseOptions response = given().spec(request)
+                .put("/fraudcheck");
+
+    // then:
+        assertThat(response.statusCode()).isEqualTo(200);
+        assertThat(response.header("Content-Type")).matches("application/vnd.fraud.v1.json.*");
+    // and:
+        DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
+        assertThatJson(parsedJson).field("fraudCheckStatus").matches("[A-Z]{5}");
+        assertThatJson(parsedJson).field("rejectionReason").isEqualTo("Amount too high");
+}
+
+
+
+

As you can see all the producer() parts of the Contract that were present in the value(consumer(…​), producer(…​)) blocks got injected into the test.

+
+
+

What’s important here to note is that on the producer side we also are doing TDD. We have expectations in form of a test. This test is shooting a request to our own application to an URL, headers and body defined in the contract. It also is expecting very precisely defined values in the response. In other words you have is your red part of red, green and refactor. Time to convert the red into the green.

+
+
+

write the missing implementation

+
+
+

Now since we now what is the expected input and expected output let’s write the missing implementation.

+
+
+
+
@RequestMapping(
+		value = "/fraudcheck",
+		method = PUT,
+		consumes = FRAUD_SERVICE_JSON_VERSION_1,
+		produces = FRAUD_SERVICE_JSON_VERSION_1)
+public FraudCheckResult fraudCheck(@RequestBody FraudCheck fraudCheck) {
+if (amountGreaterThanThreshold(fraudCheck)) {
+	return new FraudCheckResult(FraudCheckStatus.FRAUD, AMOUNT_TOO_HIGH);
+}
+return new FraudCheckResult(FraudCheckStatus.OK, NO_REASON);
+}
+
+
+
+

If we execute ./mvnw clean install again the tests will pass. Since the Spring Cloud Contract Verifier plugin adds the tests to the generated-test-sources you can actually run those tests from your IDE.

+
+
+

deploy your app

+
+
+

Once you’ve finished your work it’s time to deploy your change. First merge the branch

+
+
+
+
git checkout master
+git merge --no-ff contract-change-pr
+git push origin master
+
+
+
+

Then we assume that your CI would run sth like ./mvnw clean deploy which would publish both the application and the stub artifcats.

+
+
+
+
Consumer side (Loan Issuance) final step
+
+

As a developer of the Loan Issuance service (a consumer of the Fraud Detection server):

+
+
+

merge branch to master

+
+
+
+
git checkout master
+git merge --no-ff contract-change-pr
+
+
+
+

work online

+
+
+

Now you can disable the offline work for Spring Cloud Contract Stub Runner ad provide where the repository with your stubs is placed. At this moment the stubs of the server side will be automatically downloaded from Nexus / Artifactory. +You can switch off the value of the workOffline parameter in your annotation. Below you can see an +example of achieving the same by changing the properties.

+
+
+
+
stubrunner:
+  ids: 'com.example:http-server-dsl:+:stubs:8080'
+  repositoryRoot: http://repo.spring.io/libs-snapshot
+
+
+
+

And that’s it!

+
+
+
+
+

Dependencies

+
+

Spring Cloud Contract Verifier and Stub Runner are using the following libraries

+
+ +
+
+ +
+

Below you can find some resources related to Spring Cloud Contract Verifier and Stub Runner. Note that some can be outdated since the Spring Cloud Contract Verifier project +is under constant development.

+
+
+
Videos
+
+

Marcin Grzejszczak and Jakub Kubryński talking about Spring Cloud Contract Verifier

+
+
+
+ +
+
+ +
+

Olga Maciaszek-Sharma talking about Accurest (Spring Cloud Contract Verifier predecessor)

+
+
+
+ +
+
+ +
+

Marcin Grzejszczak and Jakub Kubryński talking about Accurest (Spring Cloud Contract Verifier predecessor)

+
+
+
+ +
+
+ +
+ +
+
+

Samples

+
+

Here you can find some samples.

+
+
+
+
+

FAQ

+
+

Why use Spring Cloud Contract Verifier and not X ?

+
+

For the time being Spring Cloud Contract Verifier is a JVM based tool. So it could be your first pick when you’re already creating +software for the JVM. This project has a lot of really interesting features but especially quite a few of them definitely make +Spring Cloud Contract Verifier stand out on the "market" of Consumer Driven Contract (CDC) tooling. Out of many the most interesting are:

+
+
+
    +
  • +

    Possibility to do CDC with messaging

    +
  • +
  • +

    Clear and easy to use, statically typed DSL

    +
  • +
  • +

    Possibility to copy paste your current JSON file to the contract and only edit its elements

    +
  • +
  • +

    Automatic generation of tests from the defined Contract

    +
  • +
  • +

    Stub Runner functionality - the stubs are automatically downloaded at runtime from Nexus / Artifactory

    +
  • +
  • +

    Spring Cloud integration - no discovery service is needed for integration tests

    +
  • +
+
+
+
+

What is this value(consumer(), producer()) ?

+
+

One of the biggest challenges related to stubs is their reusability. Only if they can be vastly used, will they serve their purpose. +What typically makes that difficult are the hard-coded values of request / response elements. For example dates or ids. +Imagine the following JSON request

+
+
+
+
{
+    "time" : "2016-10-10 20:10:15",
+    "id" : "9febab1c-6f36-4a0b-88d6-3b6a6d81cd4a",
+    "body" : "foo"
+}
+
+
+
+

and JSON response

+
+
+
+
{
+    "time" : "2016-10-10 21:10:15",
+    "id" : "c4231e1f-3ca9-48d3-b7e7-567d55f0d051",
+    "body" : "bar"
+}
+
+
+
+

Imagine the pain required to set proper value of the time field (let’s assume that this content is generated by the +database) by changing the clock in the system or providing stub implementations of data providers. The same is related +to the field called id. Will you create a stubbed implementation of UUID generator? Makes little sense…​

+
+
+

So as a consumer you would like to send a request that matches any form of a time or any UUID. That way your system +will work as usual - will generate data and you won’t have to stub anything out. Let’s assume that in case of the aforementioned +JSON the most important part is the body field. You can focus on that and provide matching for other fields. In other words +you would like the stub to work like this:

+
+
+
+
{
+    "time" : "SOMETHING THAT MATCHES TIME",
+    "id" : "SOMETHING THAT MATCHES UUID",
+    "body" : "foo"
+}
+
+
+
+

As far as the response goes as a consumer you need a concrete value that you can operate on. So such a JSON is valid

+
+
+
+
{
+    "time" : "2016-10-10 21:10:15",
+    "id" : "c4231e1f-3ca9-48d3-b7e7-567d55f0d051",
+    "body" : "bar"
+}
+
+
+
+

As you could see in the previous sections we generate tests from contracts. So from the producer’s side the situation looks +much different. We’re parsing the provided contract and in the test we want to send a real request to your endpoints. +So for the case of a producer for the request we can’t have any sort of matching. We need concrete values that the +producer’s backend can work on. Such a JSON would be a valid one:

+
+
+
+
{
+    "time" : "2016-10-10 20:10:15",
+    "id" : "9febab1c-6f36-4a0b-88d6-3b6a6d81cd4a",
+    "body" : "foo"
+}
+
+
+
+

On the other hand from the point of view of the validity of the contract the response doesn’t necessarily have to +contain concrete values of time or id. Let’s say that you generate those on the producer side - again, you’d +have to do a lot of stubbing to ensure that you always return the same values. That’s why from the producer’s side +what you might want is the following response:

+
+
+
+
{
+    "time" : "SOMETHING THAT MATCHES TIME",
+    "id" : "SOMETHING THAT MATCHES UUID",
+    "body" : "bar"
+}
+
+
+
+

How can you then provide one time a matcher for the consumer and a concrete value for the producer and vice versa? +In Spring Cloud Contract we’re allowing you to provide a dynamic value. That means that it can differ for both +sides of the communication. You can pass the values:

+
+
+

Either via the value method

+
+
+
+
value(consumer(...), producer(...))
+value(stub(...), test(...))
+value(client(...), server(...))
+
+
+
+

or using the $() method

+
+
+
+
$(consumer(...), producer(...))
+$(stub(...), test(...))
+$(client(...), server(...))
+
+
+
+

You can read more about this in the Contract DSL section.

+
+
+

Calling value() or $() tells Spring Cloud Contract that you will be passing a dynamic value. +Inside the consumer() method you pass the value that should be used on the consumer side (in the generated stub). +Inside the producer() method you pass the value that should be used on the producer side (in the generated test).

+
+
+ + + + + +
+
Tip
+
+If on one side you have passed the regular expression and you haven’t passed the other, then the +other side will get auto-generated. +
+
+
+

Most often you will use that method together with the regex helper method. E.g. consumer(regex('[0-9]{10}')).

+
+
+

To sum it up the contract for the aforementioned scenario would look more or less like this (the regular expression +for time and UUID are simplified and most likely invalid but we want to keep things very simple in this example):

+
+
+
+
org.springframework.cloud.contract.spec.Contract.make {
+				request {
+					method 'GET'
+					url '/someUrl'
+					body([
+					    time : value(consumer(regex('[0-9]{4}-[0-9]{2}-[0-9]{2} [0-2][0-9]-[0-5][0-9]-[0-5][0-9]')),
+					    id: value(consumer(regex('[0-9a-zA-z]{8}-[0-9a-zA-z]{4}-[0-9a-zA-z]{4}-[0-9a-zA-z]{12}'))
+					    body: "foo"
+					])
+				}
+			response {
+				status 200
+				body([
+					    time : value(producer(regex('[0-9]{4}-[0-9]{2}-[0-9]{2} [0-2][0-9]-[0-5][0-9]-[0-5][0-9]')),
+					    id: value([producer(regex('[0-9a-zA-z]{8}-[0-9a-zA-z]{4}-[0-9a-zA-z]{4}-[0-9a-zA-z]{12}'))
+					    body: "bar"
+					])
+			}
+}
+
+
+
+ + + + + +
+
Important
+
+Please read the Groovy docs related to JSON to understand how to +properly structure the request / response bodies. +
+
+
+
+

How to do Stubs versioning?

+
+
API Versioning
+
+

Let’s try to answer a question what versioning really means. If you’re referring to the API version then there are +different approaches.

+
+
+
    +
  • +

    use Hypermedia, links and do not version your API by any means

    +
  • +
  • +

    pass versions through headers / urls

    +
  • +
+
+
+

I will not try to answer a question which approach is better. Whatever suit your needs and allows you to generate +business value should be picked.

+
+
+

Let’s assume that you do version your API. In that case you should provide as many contracts as many versions you support. +You can create a subfolder for every version or append it to th contract name - whatever suits you more.

+
+
+
+
JAR versioning
+
+

If by versioning you mean the version of the JAR that contains the stubs then there are essentially two main approaches.

+
+
+

Let’s assume that you’re doing Continuous Delivery / Deployment which means that you’re generating a new version of +the jar each time you go through the pipeline and that jar can go to production at any time. For example your jar version +looks like this (it got built on the 20.10.2016 at 20:15:21) :

+
+
+
+
1.0.0.20161020-201521-RELEASE
+
+
+
+

In that case your generated stub jar will look like this.

+
+
+
+
1.0.0.20161020-201521-RELEASE-stubs.jar
+
+
+
+

In this case you should inside your application.yml or @AutoConfigureStubRunner when referencing stubs provide the + latest version of the stubs. You can do that by passing the + sign. Example

+
+
+
+
@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:8080"})
+
+
+
+

If the versioning however is fixed (e.g. 1.0.4.RELEASE or 2.1.1) then you have to set the concrete value of the jar +version. Example for 2.1.1.

+
+
+
+
@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:2.1.1:stubs:8080"})
+
+
+
+
+
Dev or prod stubs
+
+

You can manipulate the classifier to run the tests against current development version of the stubs of other services + or the ones that were deployed to production. If you alter your build to deploy the stubs with the prod-stubs classifier + once you reach production deployment then you can run tests in one case with dev stubs and one with prod stubs.

+
+
+

Example of tests using development version of stubs

+
+
+
+
@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:8080"})
+
+
+
+

Example of tests using production version of stubs

+
+
+
+
@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:prod-stubs:8080"})
+
+
+
+

You can pass those values also via properties from your deployment pipeline.

+
+
+
+
+

Common repo with contracts

+
+

Another way of storing contracts other than having them with the producer is keeping them in a common place. +It can be related to security issues where the consumers can’t clone the producer’s code. Also if you keep +contracts in a single place then you, as a producer, will know how many consumers you have and which +consumer will you break with your local changes.

+
+
+
Repo structure
+
+

Let’s assume that we have a producer with coordinates com.example:server and 3 consumers: client1, +client2, client3. Then in the repository with common contracts you would have the following setup +(which you can checkout here:

+
+
+
+
├── com
+│   └── example
+│       └── server
+│           ├── client1
+│           │   └── expectation.groovy
+│           ├── client2
+│           │   └── expectation.groovy
+│           ├── client3
+│           │   └── expectation.groovy
+│           └── pom.xml
+├── mvnw
+├── mvnw.cmd
+├── pom.xml
+└── src
+    └── assembly
+        └── contracts.xml
+
+
+
+

As you can see the under the slash-delimited groupid / artifact id folder (com/example/server) you have +expectations of the 3 consumers (client1, client2 and client3). Expectations are the standard Groovy DSL +contract files as described throughout this documentation. This repository has to produce a JAR file that maps +one to one to the contents of the repo.

+
+
+

Example of a pom.xml inside the server folder.

+
+
+
+
<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+
+	<groupId>com.example</groupId>
+	<artifactId>server</artifactId>
+	<version>0.0.1-SNAPSHOT</version>
+
+	<name>Server Stubs</name>
+	<description>POM used to install locally stubs for consumer side</description>
+
+	<parent>
+		<groupId>org.springframework.boot</groupId>
+		<artifactId>spring-boot-starter-parent</artifactId>
+		<version>1.4.0.BUILD-SNAPSHOT</version>
+		<relativePath />
+	</parent>
+
+	<properties>
+		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+		<java.version>1.8</java.version>
+		<spring-cloud-contract.version>1.0.0.BUILD-SNAPSHOT</spring-cloud-contract.version>
+		<spring-cloud-dependencies.version>Camden.BUILD-SNAPSHOT</spring-cloud-dependencies.version>
+	</properties>
+
+	<dependencyManagement>
+		<dependencies>
+			<dependency>
+				<groupId>org.springframework.cloud</groupId>
+				<artifactId>spring-cloud-dependencies</artifactId>
+				<version>${spring-cloud-dependencies.version}</version>
+				<type>pom</type>
+				<scope>import</scope>
+			</dependency>
+		</dependencies>
+	</dependencyManagement>
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.springframework.cloud</groupId>
+				<artifactId>spring-cloud-contract-maven-plugin</artifactId>
+				<version>${spring-cloud-contract.version}</version>
+				<extensions>true</extensions>
+				<configuration>
+					<!-- By default it would search under src/test/resources/ -->
+					<contractsDirectory>${project.basedir}</contractsDirectory>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+
+	<repositories>
+		<repository>
+			<id>spring-snapshots</id>
+			<name>Spring Snapshots</name>
+			<url>https://repo.spring.io/snapshot</url>
+			<snapshots>
+				<enabled>true</enabled>
+			</snapshots>
+		</repository>
+		<repository>
+			<id>spring-milestones</id>
+			<name>Spring Milestones</name>
+			<url>https://repo.spring.io/milestone</url>
+			<snapshots>
+				<enabled>false</enabled>
+			</snapshots>
+		</repository>
+		<repository>
+			<id>spring-releases</id>
+			<name>Spring Releases</name>
+			<url>https://repo.spring.io/release</url>
+			<snapshots>
+				<enabled>false</enabled>
+			</snapshots>
+		</repository>
+	</repositories>
+	<pluginRepositories>
+		<pluginRepository>
+			<id>spring-snapshots</id>
+			<name>Spring Snapshots</name>
+			<url>https://repo.spring.io/snapshot</url>
+			<snapshots>
+				<enabled>true</enabled>
+			</snapshots>
+		</pluginRepository>
+		<pluginRepository>
+			<id>spring-milestones</id>
+			<name>Spring Milestones</name>
+			<url>https://repo.spring.io/milestone</url>
+			<snapshots>
+				<enabled>false</enabled>
+			</snapshots>
+		</pluginRepository>
+		<pluginRepository>
+			<id>spring-releases</id>
+			<name>Spring Releases</name>
+			<url>https://repo.spring.io/release</url>
+			<snapshots>
+				<enabled>false</enabled>
+			</snapshots>
+		</pluginRepository>
+	</pluginRepositories>
+
+</project>
+
+
+
+

As you can see there are no dependencies other than the Spring Cloud Contract Verifier Maven plugin. +Those poms are necessary for the consumer side to run mvn clean install -DskipTests to locally install + stubs of the producer project.

+
+
+

The pom.xml in the root folder can look like this:

+
+
+
+
<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+		 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+
+	<groupId>com.example.standalone</groupId>
+	<artifactId>contracts</artifactId>
+	<version>0.0.1-SNAPSHOT</version>
+
+	<name>Contracts</name>
+	<description>Contains all the Spring Cloud Contracts, well, contracts. JAR used by the producers to generate tests and stubs</description>
+
+	<properties>
+		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+	</properties>
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-assembly-plugin</artifactId>
+				<executions>
+					<execution>
+						<id>contracts</id>
+						<phase>prepare-package</phase>
+						<goals>
+							<goal>single</goal>
+						</goals>
+						<configuration>
+							<attach>true</attach>
+							<descriptor>${basedir}/src/assembly/contracts.xml</descriptor>
+							<!-- If you want an explicit classifier remove the following line -->
+							<appendAssemblyId>false</appendAssemblyId>
+						</configuration>
+					</execution>
+				</executions>
+			</plugin>
+		</plugins>
+	</build>
+
+</project>
+
+
+
+

It’s using the assembly plugin in order to build the JAR with all the contracts. Example of such setup is here:

+
+
+
+
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
+		  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+		  xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
+	<id>project</id>
+	<formats>
+		<format>jar</format>
+	</formats>
+	<includeBaseDirectory>false</includeBaseDirectory>
+	<fileSets>
+		<fileSet>
+			<directory>${project.basedir}</directory>
+			<outputDirectory>/</outputDirectory>
+			<useDefaultExcludes>true</useDefaultExcludes>
+			<excludes>
+				<exclude>**/${project.build.directory}/**</exclude>
+				<exclude>mvnw</exclude>
+				<exclude>mvnw.cmd</exclude>
+				<exclude>.mvn/**</exclude>
+				<exclude>src/**</exclude>
+			</excludes>
+		</fileSet>
+	</fileSets>
+</assembly>
+
+
+
+
+
Workflow
+
+

The workflow would look similar to the one presented in the Step by step guide to CDC. The only difference + is that the producer doesn’t own the contracts anymore. So the consumer and the producer have to work on + common contracts in a common repository.

+
+
+
Consumer
+
+

When the consumer wants to work on the contracts offline, instead of cloning the producer code, the +consumer team clones the common repository, goes to the required producer’s folder (e.g. com/example/server) +and runs mvn clean install -DskipTests to install locally the stubs converted from the contracts.

+
+
+ + + + + +
+
Tip
+
+You need to have Maven installed locally +
+
+
+
+
Producer
+
+

As a producer it’s enough to alter the Spring Cloud Contract Verifier to provide the URL and the dependency +of the JAR containing the contracts:

+
+
+
+
<plugin>
+	<groupId>org.springframework.cloud</groupId>
+	<artifactId>spring-cloud-contract-maven-plugin</artifactId>
+	<configuration>
+		<contractsRepositoryUrl>http://link/to/your/nexus/or/artifactory/or/sth</contractsRepositoryUrl>
+		<contractDependency>
+			<groupId>com.example.standalone</groupId>
+			<artifactId>contracts</artifactId>
+		</contractDependency>
+	</configuration>
+</plugin>
+
+
+
+

With this setup the JAR with groupid com.example.standalone and artifactid contracts will be downloaded +from http://link/to/your/nexus/or/artifactory/or/sth. It will be then unpacked in a local temporary folder +and contracts present under the com/example/server will be picked as the ones used to generate the +tests and the stubs. Due to this convention the producer team will know which consumer teams will be broken +when some incompatible changes are done.

+
+
+

The rest of the flow looks the same.

+
+
+
+
+
+

Can I have multiple base classes for tests?

+
+

Yes! Check out the Different base classes for contracts sections +of either Gradle or Maven plugins.

+
+
+
+
+

Spring Cloud Contract Verifier HTTP

+
+

Gradle Project

+
+
Prerequisites
+
+

In order to use Spring Cloud Contract Verifier with WireMock you have to use Gradle or Maven plugin.

+
+
+ + + + + +
+
Warning
+
+If you want to use Spock in your projects you have to add separately +the spock-core and spock-spring modules. Check Spock docs for more information +
+
+
+
Add gradle plugin with dependencies
+
+
+
buildscript {
+	repositories {
+		mavenCentral()
+	}
+	dependencies {
+	    classpath "org.springframework.boot:spring-boot-gradle-plugin:${springboot_version}"
+		classpath "org.springframework.cloud:spring-cloud-contract-gradle-plugin:${verifier_version}"
+	}
+}
+
+apply plugin: 'groovy'
+apply plugin: 'spring-cloud-contract'
+
+dependencyManagement {
+	imports {
+		mavenBom "org.springframework.cloud:spring-cloud-contract-dependencies:${verifier_version}"
+	}
+}
+
+dependencies {
+	testCompile 'org.codehaus.groovy:groovy-all:2.4.6'
+	// example with adding Spock core and Spock Spring
+	testCompile 'org.spockframework:spock-core:1.0-groovy-2.4'
+	testCompile 'org.spockframework:spock-spring:1.0-groovy-2.4'
+	testCompile 'org.springframework.cloud:spring-cloud-starter-contract-verifier'
+}
+
+
+
+
+
Snapshot versions for Gradle
+
+

Add the additional snapshot repository to your build.gradle to use snapshot versions which are automatically uploaded after every successful build:

+
+
+
+
buildscript {
+	repositories {
+		mavenCentral()
+		mavenLocal()
+		maven { url "http://repo.spring.io/snapshot" }
+		maven { url "http://repo.spring.io/milestone" }
+		maven { url "http://repo.spring.io/release" }
+	}
+}
+
+
+
+
+
Add maven plugin with dependencies
+
+
+
<dependencyManagement>
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-contract-dependencies</artifactId>
+            <version>${spring-cloud-contract.version}</version>
+            <type>pom</type>
+            <scope>import</scope>
+        </dependency>
+    </dependencies>
+</dependencyManagement>
+
+<dependencies>
+    <dependency>
+        <groupId>org.springframework.cloud</groupId>
+        <artifactId>spring-cloud-starter-contract-verifier</artifactId>
+        <scope>test</scope>
+    </dependency>
+</dependencies>
+
+<plugin>
+    <groupId>org.springframework.cloud</groupId>
+    <artifactId>spring-cloud-contract-maven-plugin</artifactId>
+    <executions>
+        <execution>
+            <goals>
+                <goal>convert</goal>
+                <goal>generateStubs</goal>
+                <goal>generateTests</goal>
+            </goals>
+        </execution>
+    </executions>
+</plugin>
+
+
+ +
+
+
Add stubs
+
+

By default Spring Cloud Contract Verifier is looking for stubs in src/test/resources/contracts directory.

+
+
+

Directory containing stub definitions is treated as a class name, and each stub definition is treated as a single test. +We assume that it contains at least one directory which will be used as test class name. If there is more than one level of nested directories all except the last one will be used as package name. +So with following structure

+
+
+
+
src/test/resources/contracts/myservice/shouldCreateUser.groovy
+src/test/resources/contracts/myservice/shouldReturnUser.groovy
+
+
+
+

Spring Cloud Contract Verifier will create test class defaultBasePackage.MyService with two methods

+
+
+
    +
  • +

    shouldCreateUser()

    +
  • +
  • +

    shouldReturnUser()

    +
  • +
+
+
+
+
+
Run plugin
+
+

Plugin registers itself to be invoked before check task. You have nothing to do as long as you want it to be part of your build process. If you just want to generate tests please invoke generateContractTests task.

+
+
+
+
Default setup
+
+

Default Gradle Plugin setup creates the following Gradle part of the build (it’s a pseudocode)

+
+
+
+
contracts {
+    targetFramework = 'JUNIT'
+    testMode = 'MockMvc'
+    generatedTestSourcesDir = project.file("${project.buildDir}/generated-test-sources/contracts")
+    contractsDslDir = "${project.rootDir}/src/test/resources/contracts"
+    basePackageForTests = 'org.springframework.cloud.verifier.tests'
+    stubsOutputDir = project.file("${project.buildDir}/stubs")
+
+    // the following properties are used when you want to provide where the JAR with contract lays
+    contractDependency = new org.springframework.cloud.contract.verifier.plugin.ContractVerifierExtension.Dependency()
+    contractsPath = ''
+    contractsWorkOffline = false
+}
+
+tasks.create(type: Jar, name: 'verifierStubsJar', dependsOn: 'generateWireMockClientStubs') {
+    baseName = project.name
+    classifier = contracts.stubsSuffix
+    from contractVerifier.stubsOutputDir
+}
+
+project.artifacts {
+    archives task
+}
+
+tasks.create(type: Copy, name: 'copyContracts') {
+    from contracts.contractsDslDir
+    into contracts.stubsOutputDir
+}
+
+verifierStubsJar.dependsOn 'copyContracts'
+
+publishing {
+    publications {
+        stubs(MavenPublication) {
+            artifactId project.name
+            artifact verifierStubsJar
+        }
+    }
+}
+
+
+
+
+
Configure plugin
+
+

To change default configuration just add contracts snippet to your Gradle config

+
+
+
+
contracts {
+	testMode = 'MockMvc'
+	baseClassForTests = 'org.mycompany.tests'
+	generatedTestSourcesDir = project.file('src/generatedContract')
+}
+
+
+
+
Configuration options
+
+
    +
  • +

    testMode - defines mode for acceptance tests. By default MockMvc which is based on Spring’s MockMvc. It can also be changed to JaxRsClient or to Explicit for real HTTP calls.

    +
  • +
  • +

    imports - array with imports that should be included in generated tests (for example ['org.myorg.Matchers']). By default empty array []

    +
  • +
  • +

    staticImports - array with static imports that should be included in generated tests(for example ['org.myorg.Matchers.*']). By default empty array []

    +
  • +
  • +

    basePackageForTests - specifies base package for all generated tests. By default set to org.springframework.cloud.verifier.tests

    +
  • +
  • +

    baseClassForTests - base class for all generated tests. By default spock.lang.Specification if using Spock tests.

    +
  • +
  • +

    packageWithBaseClasses - instead of providing a fixed value for base class you can provide a package where all the base classes lay. Takes precedence over baseClassForTests.

    +
  • +
  • +

    baseClassMappings - explicitly map contract package to a FQN of a base class. Takes precedence over packageWithBaseClasses and baseClassForTests.

    +
  • +
  • +

    ruleClassForTests - specifies Rule which should be added to generated test classes.

    +
  • +
  • +

    ignoredFiles - Ant matcher allowing defining stub files for which processing should be skipped. By default empty array []

    +
  • +
  • +

    contractsDslDir - directory containing contracts written using the GroovyDSL. By default $rootDir/src/test/resources/contracts

    +
  • +
  • +

    generatedTestSourcesDir - test source directory where tests generated from Groovy DSL should be placed. By default $buildDir/generated-test-sources/contractVerifier

    +
  • +
  • +

    stubsOutputDir - dir where the generated WireMock stubs from Groovy DSL should be placed

    +
  • +
  • +

    targetFramework - the target test framework to be used; currently Spock and JUnit are supported with JUnit being the default framework

    +
  • +
+
+
+

The following properties are used when you want to provide where the JAR with contract lays

+
+
+
    +
  • +

    contractDependency - the Dependency that provides groupid:artifactid:version:classifier coordinates. You can use the contractDependency closure to set it up

    +
  • +
  • +

    contractsPath - if contract deps are downloaded will default to groupid/artifactid where groupid will be slash separated. Otherwise will scan contracts under provided directory

    +
  • +
  • +

    contractsWorkOffline - in order not to download the dependencies each time you can download them once and work offline afterwards (reuse local Maven repo)

    +
  • +
+
+
+
+
Single base class for all tests
+
+

When using Spring Cloud Contract Verifier in default MockMvc you need to create a base specification for all generated acceptance tests. In this class you need to point to endpoint which should be verified.

+
+
+
+
abstract class BaseMockMvcSpec extends Specification {
+
+	def setup() {
+		RestAssuredMockMvc.standaloneSetup(new PairIdController())
+	}
+
+	void isProperCorrelationId(Integer correlationId) {
+		assert correlationId == 123456
+	}
+
+	void isEmpty(String value) {
+		assert value == null
+	}
+
+}
+
+
+
+

In case of using Explicit mode, you can use base class to initialize the whole tested app similarly as in regular integration tests. In case of JAXRSCLIENT mode this base class +should also contain protected WebTarget webTarget field, right now the only option to test JAX-RS API is to start a web server.

+
+
+
+
Different base classes for contracts
+
+

If your base classes differ between contracts you can tell the Spring Cloud Contract plugin which class should get +extended by the autogenerated tests. You have two options:

+
+
+
    +
  • +

    follow a convention by providing the packageWithBaseClasses

    +
  • +
  • +

    provide explicit mapping via baseClassMappings

    +
  • +
+
+
+

Convention

+
+
+

The convention is such that if you have a contract under e.g. src/test/resources/contract/foo/bar/baz/ and provide the value of the packageWithBaseClasses property +to com.example.base then we will assume that there is a BarBazBase class under com.example.base package. In other words we take last two parts of package +if they exist and form a class with a Base suffix. Takes precedence over baseClassForTests. Example of usage in the contracts closure:

+
+
+
+
packageWithBaseClasses = 'com.example.base'
+
+
+
+

Mapping

+
+
+

You can manually map a regular expression of the contract’s package to fully qualified name of the base class for the matched contract. +Let’s take a look at the following example:

+
+
+
+
baseClassForTests = "com.example.FooBase"
+baseClassMappings {
+	baseClassMapping('.*/com/.*', 'com.example.ComBase')
+	baseClassMapping('.*/bar/.*':'com.example.BarBase')
+}
+
+
+
+

Let’s assume that you have contracts under + - src/test/resources/contract/com/ + - src/test/resources/contract/foo/

+
+
+

By providing the baseClassForTests we have a fallback in case mapping didn’t succeed (you could also provide +the packageWithBaseClasses as fallback). That way the tests generated from src/test/resources/contract/com/ contracts +will be extending the com.example.ComBase whereas the rest of tests will extend com.example.FooBase.

+
+
+
+
+
Invoking generated tests
+
+

To ensure that provider side is complaint with defined contracts, you need to invoke:

+
+
+
+
./gradlew generateContractTests test
+
+
+
+
+
Spring Cloud Contract Verifier on consumer side
+
+

In consumer service you need to configure Spring Cloud Contract Verifier plugin in exactly the same way as in case of provider. If you don’t want to use Stub Runner then you need to copy contracts stored in +src/test/resources/contracts and generate WireMock json stubs using:

+
+
+
+
./gradlew generateWireMockClientStubs
+
+
+
+

Note that stubsOutputDir option has to be set for stub generation to work.

+
+
+

When present, json stubs can be used in consumer automated tests.

+
+
+
+
@ContextConfiguration(loader == SpringApplicationContextLoader, classes == Application)
+class LoanApplicationServiceSpec extends Specification {
+
+ @ClassRule
+ @Shared
+ WireMockClassRule wireMockRule == new WireMockClassRule()
+
+ @Autowired
+ LoanApplicationService sut
+
+ def 'should successfully apply for loan'() {
+   given:
+ 	LoanApplication application =
+			new LoanApplication(client: new Client(pesel: '12345678901'), amount: 123.123)
+   when:
+	LoanApplicationResult loanApplication == sut.loanApplication(application)
+   then:
+	loanApplication.loanApplicationStatus == LoanApplicationStatus.LOAN_APPLIED
+	loanApplication.rejectionReason == null
+ }
+}
+
+
+
+

Underneath LoanApplication makes a call to FraudDetection service. This request is handled by WireMock server configured using stubs generated by Spring Cloud Contract Verifier.

+
+
+
+
+

Using in your Maven project

+
+
Add maven plugin
+
+

Add the Spring Cloud Contract BOM

+
+
+
+
<dependencyManagement>
+	<dependencies>
+		<dependency>
+			<groupId>org.springframework.cloud</groupId>
+			<artifactId>spring-cloud-dependencies</artifactId>
+			<version>${spring-cloud-dependencies.version}</version>
+			<type>pom</type>
+			<scope>import</scope>
+		</dependency>
+	</dependencies>
+</dependencyManagement>
+
+
+
+

Next, the Spring Cloud Contract Verifier Maven plugin

+
+
+
+
<plugin>
+	<groupId>org.springframework.cloud</groupId>
+	<artifactId>spring-cloud-contract-maven-plugin</artifactId>
+	<version>${spring-cloud-contract.version}</version>
+	<extensions>true</extensions>
+	<configuration>
+		<packageWithBaseClasses>com.example.fraud</packageWithBaseClasses>
+	</configuration>
+</plugin>
+
+
+
+

You can read more in the Spring Cloud Contract Maven Plugin Docs

+
+
+
Snapshot versions for Maven
+
+

For Snapshot / Milestone versions you have to add the following section to your pom.xml

+
+
+
+
<repositories>
+	<repository>
+		<id>spring-snapshots</id>
+		<name>Spring Snapshots</name>
+		<url>https://repo.spring.io/snapshot</url>
+		<snapshots>
+			<enabled>true</enabled>
+		</snapshots>
+	</repository>
+	<repository>
+		<id>spring-milestones</id>
+		<name>Spring Milestones</name>
+		<url>https://repo.spring.io/milestone</url>
+		<snapshots>
+			<enabled>false</enabled>
+		</snapshots>
+	</repository>
+	<repository>
+		<id>spring-releases</id>
+		<name>Spring Releases</name>
+		<url>https://repo.spring.io/release</url>
+		<snapshots>
+			<enabled>false</enabled>
+		</snapshots>
+	</repository>
+</repositories>
+<pluginRepositories>
+	<pluginRepository>
+		<id>spring-snapshots</id>
+		<name>Spring Snapshots</name>
+		<url>https://repo.spring.io/snapshot</url>
+		<snapshots>
+			<enabled>true</enabled>
+		</snapshots>
+	</pluginRepository>
+	<pluginRepository>
+		<id>spring-milestones</id>
+		<name>Spring Milestones</name>
+		<url>https://repo.spring.io/milestone</url>
+		<snapshots>
+			<enabled>false</enabled>
+		</snapshots>
+	</pluginRepository>
+	<pluginRepository>
+		<id>spring-releases</id>
+		<name>Spring Releases</name>
+		<url>https://repo.spring.io/release</url>
+		<snapshots>
+			<enabled>false</enabled>
+		</snapshots>
+	</pluginRepository>
+</pluginRepositories>
+
+
+
+
+
+
Add stubs
+
+

By default Spring Cloud Contract Verifier is looking for stubs in src/test/resources/contracts directory. +Directory containing stub definitions is treated as a class name, and each stub definition is treated as a single test. +We assume that it contains at least one directory which will be used as test class name. If there is more than one level of nested directories all except the last one will be used as package name. +So with following structure

+
+
+
+
src/test/resources/contracts/myservice/shouldCreateUser.groovy
+src/test/resources/contracts/myservice/shouldReturnUser.groovy
+
+
+
+

Spring Cloud Contract Verifier will create test class defaultBasePackage.MyService with two methods + - shouldCreateUser() + - shouldReturnUser()

+
+
+
+
Run plugin
+
+

Plugin goal generateTests is assigned to be invoked in phase generate-test-sources. You have nothing to do as long as you want it to be part of your build process. If you just want to generate tests please invoke generateTests goal.

+
+
+
+
Configure plugin
+
+

To change default configuration just add configuration section to plugin definition or execution definition.

+
+
+
+
<plugin>
+    <groupId>org.springframework.cloud</groupId>
+    <artifactId>spring-cloud-contract-maven-plugin</artifactId>
+    <executions>
+        <execution>
+            <goals>
+                <goal>convert</goal>
+                <goal>generateStubs</goal>
+                <goal>generateTests</goal>
+            </goals>
+        </execution>
+    </executions>
+    <configuration>
+        <basePackageForTests>org.springframework.cloud.verifier.twitter.place</basePackageForTests>
+        <baseClassForTests>org.springframework.cloud.verifier.twitter.place.BaseMockMvcSpec</baseClassForTests>
+    </configuration>
+</plugin>
+
+
+
+
Important configuration options
+
+
    +
  • +

    testMode - defines mode for acceptance tests. By default MockMvc which is based on Spring’s MockMvc. It can also be changed to JaxRsClient or to Explicit for real HTTP calls.

    +
  • +
  • +

    basePackageForTests - specifies base package for all generated tests. By default set to org.springframework.cloud.verifier.tests.

    +
  • +
  • +

    ruleClassForTests - specifies Rule which should be added to generated test classes.

    +
  • +
  • +

    baseClassForTests - base class for generated tests. By default spock.lang.Specification if using Spock tests.

    +
  • +
  • +

    contractsDir - directory containing contracts written using the GroovyDSL. By default /src/test/resources/contracts.

    +
  • +
  • +

    testFramework - the target test framework to be used; currently Spock and JUnit are supported with JUnit being the default framework

    +
  • +
  • +

    packageWithBaseClasses - instead of providing a fixed value for base class you can provide a package where all the base classes lay. +The convention is such that if you have a contract under src/test/resources/contract/foo/bar/baz/ and provide the value of this property +to com.example.base then we will assume that there is a BarBazBase class under com.example.base package. Takes precedence +over baseClassForTests

    +
  • +
  • +

    baseClassMappings - list of base class mappings that where you have to provide contractPackageRegex which is checked +against the package in which the contract lays and baseClassFQN that maps to fully qualified name of the base class for the matched +contract. If you have a contract under src/test/resources/contract/foo/bar/baz/ and map the property .*com.example.base.BaseClass then +the test class generated from these contracts will extend com.example.base.BaseClass. Takes precedence over packageWithBaseClasses + and baseClassForTests.

    +
  • +
+
+
+

If you want to download your contract definitions from a Maven repository you can use

+
+
+
    +
  • +

    contractsRepositoryUrl - URL to a repo with the artifacts with contracts, if not provided should use the current Maven ones

    +
  • +
  • +

    contractDependency - the contract dependency that contains all the packaged contracts

    +
  • +
  • +

    contractsPath - path to concrete contracts in the JAR with packaged contracts. Defaults to groupid/artifactid where gropuid is slash separated.

    +
  • +
  • +

    contractsWorkOffline - if the dependencies should be downloaded or local Maven only should be reused

    +
  • +
+
+
+

For complete information take a look at Plugin Documentation

+
+
+
+
Single base class for all tests
+
+

When using Spring Cloud Contract Verifier in default MockMvc you need to create a base specification for all generated acceptance tests. +In this class you need to point to endpoint which should be verified.

+
+
+
+
package org.mycompany.tests
+
+import org.mycompany.ExampleSpringController
+import com.jayway.restassured.module.mockmvc.RestAssuredMockMvc
+import spock.lang.Specification
+
+class  MvcSpec extends Specification {
+  def setup() {
+   RestAssuredMockMvc.standaloneSetup(new ExampleSpringController())
+  }
+}
+
+
+
+

In case of using Explicit mode, you can use base class to initialize the whole tested app similarly as in regular integration tests. In case of JAXRSCLIENT mode this base class should also contain protected WebTarget webTarget field, right now the only option to test JAX-RS API is to start a web server.

+
+
+
+
Different base classes for contracts
+
+

If your base classes differ between contracts you can tell the Spring Cloud Contract plugin which class should get +extended by the autogenerated tests. You have two options:

+
+
+
    +
  • +

    follow a convention by providing the packageWithBaseClasses

    +
  • +
  • +

    provide explicit mapping via baseClassMappings

    +
  • +
+
+
+

Convention

+
+
+

The convention is such that if you have a contract under e.g. src/test/resources/contract/hello/v1/ and provide the value of the packageWithBaseClasses property +to hello then we will assume that there is a HelloV1Base class under hello package. In other words we take last two parts of package +if they exist and form a class with a Base suffix. Takes precedence over baseClassForTests. Example of usage in the contracts closure:

+
+
+
+
			<plugin>
+				<groupId>org.springframework.cloud</groupId>
+				<artifactId>spring-cloud-contract-maven-plugin</artifactId>
+				<configuration>
+					<packageWithBaseClasses>hello</packageWithBaseClasses>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+
+</project>
+
+
+
+

Mapping

+
+
+

You can manually map a regular expression of the contract’s package to fully qualified name of the base class for the matched contract. +You have to provide a list baseClassMappings of baseClassMapping that takes a contractPackageRegex to baseClassFQN mapping. +Let’s take a look at the following example:

+
+
+
+
<plugin>
+	<groupId>org.springframework.cloud</groupId>
+	<artifactId>spring-cloud-contract-maven-plugin</artifactId>
+	<configuration>
+		<baseClassForTests>com.example.FooBase</baseClassForTests>
+		<baseClassMappings>
+			<baseClassMapping>
+				<contractPackageRegex>.*com.*</contractPackageRegex>
+				<baseClassFQN>com.example.TestBase</baseClassFQN>
+			</baseClassMapping >
+		</baseClassMappings>
+	</configuration>
+</plugin>
+
+
+
+

Let’s assume that you have contracts under + - src/test/resources/contract/com/ + - src/test/resources/contract/foo/

+
+
+

By providing the baseClassForTests we have a fallback in case mapping didn’t succeed (you could also provide +the packageWithBaseClasses as fallback). That way the tests generated from src/test/resources/contract/com/ contracts +will be extending the com.example.ComBase whereas the rest of tests will extend com.example.FooBase.

+
+
+
+
+
Invoking generated tests
+
+

Spring Cloud Contract Verifier Maven Plugin generates verification code into directory /generated-test-sources/contractVerifier and attach this directory to testCompile goal.

+
+
+

For Groovy Spock code use:

+
+
+
+
<plugin>
+	<groupId>org.codehaus.gmavenplus</groupId>
+	<artifactId>gmavenplus-plugin</artifactId>
+	<version>1.5</version>
+	<executions>
+		<execution>
+			<goals>
+				<goal>testCompile</goal>
+			</goals>
+		</execution>
+	</executions>
+	<configuration>
+		<testSources>
+			<testSource>
+				<directory>${project.basedir}/src/test/groovy</directory>
+				<includes>
+					<include>**/*.groovy</include>
+				</includes>
+			</testSource>
+			<testSource>
+				<directory>${project.build.directory}/generated-test-sources/contractVerifier</directory>
+				<includes>
+					<include>**/*.groovy</include>
+				</includes>
+			</testSource>
+		</testSources>
+	</configuration>
+</plugin>
+
+
+
+

To ensure that provider side is complaint with defined contracts, you need to invoke mvn generateTest test

+
+
+
+
Spring Cloud Contract Verifier on consumer side
+
+

You can actually use the Spring Cloud Contract Verifier also for the consumer side! +You can use the plugin so that it only converts the contracts and generates the stubs. +To achieve that you need to configure Spring Cloud Contract Verifier plugin in exactly +the same way as in case of provider. You need to copy contracts stored in +src/test/resources/contracts and generate WireMock json stubs using: +mvn generateStubs command. By default generated WireMock mapping is +stored in directory target/mappings. Your project should create from +this generated mappings additional artifact with classifier stubs for +easy deploy to maven repository.

+
+
+

Sample configuration:

+
+
+
+
<plugin>
+    <groupId>org.springframework.cloud</groupId>
+    <artifactId>spring-cloud-contract-maven-plugin</artifactId>
+    <version>${verifier-plugin.version}</version>
+    <executions>
+        <execution>
+            <goals>
+                <goal>convert</goal>
+                <goal>generateStubs</goal>
+            </goals>
+        </execution>
+    </executions>
+</plugin>
+
+
+
+

When present, json stubs can be used in consumer automated tests.

+
+
+
+
@RunWith(SpringTestRunner.class)
+@SpringBootTest
+@AutoConfigureStubRunner
+public class LoanApplicationServiceTests {
+
+  @Autowired
+  LoanApplicationService service;
+
+  @Test
+  public void shouldSuccessfullyApplyForLoan() {
+    //given:
+ 	LoanApplication application =
+			new LoanApplication(new Client("12345678901"), 123.123);
+    //when:
+	LoanApplicationResult loanApplication = service.loanApplication(application);
+    // then:
+	assertThat(loanApplication.loanApplicationStatus).isEqualTo(LoanApplicationStatus.LOAN_APPLIED);
+	assertThat(loanApplication.rejectionReason).isNull();
+  }
+}
+
+
+
+

Underneath LoanApplication makes a call to the FraudDetection service. This request is handled by +a WireMock server configured using stubs generated by Spring Cloud Contract Verifier.

+
+
+
+
+

Scenarios

+
+

It’s possible to handle scenarios with Spring Cloud Contract Verifier. All you need to do is to stick to proper naming convention while creating your contracts. The convention requires to include order number followed by the underscore.

+
+
+
+
my_contracts_dir\
+  scenario1\
+    1_login.groovy
+    2_showCart.groovy
+    3_logout.groovy
+
+
+
+

Such tree will cause Spring Cloud Contract Verifier generating WireMock’s scenario with name scenario1 and three steps:

+
+
+
    +
  • +

    login marked as Started pointing to:

    +
  • +
  • +

    showCart marked as Step1 pointing to:

    +
  • +
  • +

    logout marked as Step2 which will close the scenario.

    +
  • +
+
+
+

More details about WireMock scenarios can be found under http://wiremock.org/stateful-behaviour.html

+
+
+

Spring Cloud Contract Verifier will also generate tests with guaranteed order of execution.

+
+
+
+

Stubs and transitive dependencies

+
+

The Maven and Gradle plugin that we’re created are adding the tasks that create the stubs jar for you. What can be problematic +is that when reusing the stubs you can by mistake import all of that stub dependencies! When building a Maven artifact +even though you have a couple of different jars, all of them share one pom:

+
+
+
+
├── github-webhook-0.0.1.BUILD-20160903.075506-1-stubs.jar
+├── github-webhook-0.0.1.BUILD-20160903.075506-1-stubs.jar.sha1
+├── github-webhook-0.0.1.BUILD-20160903.075655-2-stubs.jar
+├── github-webhook-0.0.1.BUILD-20160903.075655-2-stubs.jar.sha1
+├── github-webhook-0.0.1.BUILD-SNAPSHOT.jar
+├── github-webhook-0.0.1.BUILD-SNAPSHOT.pom
+├── github-webhook-0.0.1.BUILD-SNAPSHOT-stubs.jar
+├── ...
+└── ...
+
+
+
+

There are three possibilities of working with those dependencies so as not to have any issues with transitive dependencies.

+
+
+

Mark all application dependencies as optional

+
+
+

If in the github-webhook application we would mark all of our dependencies as optional, when you include the +github-webhook stubs in another application (or when that dependency gets downloaded by Stub Runner) then, since +all of the depenencies are optional, they will not get downloaded.

+
+
+

Create a separate artifactid for stubs

+
+
+

If you create a separate artifactid then you can set it up in whatever way you wish. For example by having no dependencies at all.

+
+
+

Exclude dependencies on the consumer side

+
+
+

As a consumer, if you add the stub dependency to your classpath you can explicitly exclude the unwanted dependencies.

+
+
+
+
+

Spring Cloud Contract Verifier Messaging

+
+

Spring Cloud Contract Verifier allows you to verify your application that uses messaging as means of communication. +All of our integrations are working with Spring but you can also create one yourself and use it.

+
+
+

Integrations

+
+

You can use one of the three integration configurations:

+
+
+
    +
  • +

    Apache Camel

    +
  • +
  • +

    Spring Integration

    +
  • +
  • +

    Spring Cloud Stream

    +
  • +
+
+
+

Since we’re using Spring Boot then if you have added one of the aforementioned libraries +to the classpath then automatically all the messaging configuration will be set up.

+
+
+ + + + + +
+
Important
+
+Remember to put @AutoConfigureMessageVerifier on the base class of your +generated tests. Otherwise messaging part of Spring Cloud Contract Verifier will not work. +
+
+
+
+

Manual Integration Testing

+
+

The main interface used by the tests is the org.springframework.cloud.contract.verifier.messaging.MessageVerifier. +It defines how to send and receive messages. You can create your own implementation to achieve the +same goal.

+
+
+

In the a test you can inject a ContractVerifierMessageExchange to send and receive messages that follow the contract. +Then add @AutoConfigureMessageVerifier to your test, e.g.

+
+
+
+
@RunWith(SpringTestRunner.class)
+@SpringBootTest
+@AutoConfigureMessageVerifier
+public static class MessagingContractTests {
+
+  @Autowired
+  private MessageVerifier verifier;
+  ...
+}
+
+
+
+ + + + + +
+
Note
+
+If your tests require stubs as well, then +@AutoConfigureStubRunner includes the messaging configuration, so +you only need the one annotation. +
+
+
+
+

Publisher side test generation

+
+

Having the input or outputMessage sections in your DSL will result in creation of tests on the publisher’s side. By default +JUnit tests will be created, however there is also a possibility to create Spock tests.

+
+
+

There are 3 main scenarios that we should take into consideration:

+
+
+
    +
  • +

    Scenario 1: there is no input message that produces an output one. The output message is triggered by a component +inside the application (e.g. scheduler)

    +
  • +
  • +

    Scenario 2: the input message triggers an output message

    +
  • +
  • +

    Scenario 3: the input message is consumed and there is no output message

    +
  • +
+
+
+
Scenario 1 (no input message)
+
+

For the given contract:

+
+
+
+
def contractDsl = Contract.make {
+	label 'some_label'
+	input {
+		triggeredBy('bookReturnedTriggered()')
+	}
+	outputMessage {
+		sentTo('activemq:output')
+		body('''{ "bookName" : "foo" }''')
+		headers {
+			header('BOOK-NAME', 'foo')
+		}
+	}
+}
+
+
+
+

The following JUnit test will be created:

+
+
+
+
'''
+ // when:
+  bookReturnedTriggered();
+
+ // then:
+  ContractVerifierMessage response = contractVerifierMessaging.receive("activemq:output");
+  assertThat(response).isNotNull();
+  assertThat(response.getHeader("BOOK-NAME")).isEqualTo("foo");
+ // and:
+  DocumentContext parsedJson = JsonPath.parse(contractVerifierObjectMapper.writeValueAsString(response.getPayload()));
+  assertThatJson(parsedJson).field("bookName").isEqualTo("foo");
+'''
+
+
+
+

And the following Spock test would be created:

+
+
+
+
'''
+ when:
+  bookReturnedTriggered()
+
+ then:
+  ContractVerifierMessage response = contractVerifierMessaging.receive('activemq:output')
+  assert response != null
+  response.getHeader('BOOK-NAME')  == 'foo'
+ and:
+  DocumentContext parsedJson = JsonPath.parse(contractVerifierObjectMapper.writeValueAsString(response.payload))
+  assertThatJson(parsedJson).field("bookName").isEqualTo("foo")
+
+'''
+
+
+
+
+
Scenario 2 (output triggered by input)
+
+

For the given contract:

+
+
+
+
def contractDsl = Contract.make {
+	label 'some_label'
+	input {
+		messageFrom('jms:input')
+		messageBody([
+				bookName: 'foo'
+		])
+		messageHeaders {
+			header('sample', 'header')
+		}
+	}
+	outputMessage {
+		sentTo('jms:output')
+		body([
+				bookName: 'foo'
+		])
+		headers {
+			header('BOOK-NAME', 'foo')
+		}
+	}
+}
+
+
+
+

The following JUnit test will be created:

+
+
+
+
'''
+// given:
+ ContractVerifierMessage inputMessage = contractVerifierMessaging.create(
+  "{\\"bookName\\":\\"foo\\"}"
+, headers()
+  .header("sample", "header"));
+
+// when:
+ contractVerifierMessaging.send(inputMessage, "jms:input");
+
+// then:
+ ContractVerifierMessage response = contractVerifierMessaging.receive("jms:output");
+ assertThat(response).isNotNull();
+ assertThat(response.getHeader("BOOK-NAME")).isEqualTo("foo");
+// and:
+ DocumentContext parsedJson = JsonPath.parse(contractVerifierObjectMapper.writeValueAsString(response.getPayload()));
+ assertThatJson(parsedJson).field("bookName").isEqualTo("foo");
+'''
+
+
+
+

And the following Spock test would be created:

+
+
+
+
"""\
+given:
+   ContractVerifierMessage inputMessage = contractVerifierMessaging.create(
+    '''{"bookName":"foo"}''',
+    ['sample': 'header']
+  )
+
+when:
+   contractVerifierMessaging.send(inputMessage, 'jms:input')
+
+then:
+   ContractVerifierMessage response = contractVerifierMessaging.receive('jms:output')
+   assert response !- null
+   response.getHeader('BOOK-NAME')  == 'foo'
+and:
+   DocumentContext parsedJson = JsonPath.parse(contractVerifierObjectMapper.writeValueAsString(response.payload))
+   assertThatJson(parsedJson).field("bookName").isEqualTo("foo")
+"""
+
+
+
+
+
Scenario 3 (no output message)
+
+

For the given contract:

+
+
+
+
def contractDsl = Contract.make {
+	label 'some_label'
+	input {
+		messageFrom('jms:delete')
+		messageBody([
+				bookName: 'foo'
+		])
+		messageHeaders {
+			header('sample', 'header')
+		}
+		assertThat('bookWasDeleted()')
+	}
+}
+
+
+
+

The following JUnit test will be created:

+
+
+
+
'''
+// given:
+ ContractVerifierMessage inputMessage = contractVerifierMessaging.create(
+	"{\\"bookName\\":\\"foo\\"}"
+, headers()
+	.header("sample", "header"));
+
+// when:
+ contractVerifierMessaging.send(inputMessage, "jms:delete");
+
+// then:
+ bookWasDeleted();
+'''
+
+
+
+

And the following Spock test would be created:

+
+
+
+
'''
+given:
+	 ContractVerifierMessage inputMessage = contractVerifierMessaging.create(
+		\'\'\'{"bookName":"foo"}\'\'\',
+		['sample': 'header']
+	)
+
+when:
+	 contractVerifierMessaging.send(inputMessage, 'jms:delete')
+
+then:
+	 noExceptionThrown()
+	 bookWasDeleted()
+'''
+
+
+
+
+
+

Consumer Stub Side generation

+
+

Unlike the HTTP part - in Messaging we need to publish the Groovy DSL inside the JAR with a stub. Then it’s parsed on the consumer side +and proper stubbed routes are created.

+
+
+

For more information please consult the Stub Runner Messaging sections.

+
+
+
Gradle Setup
+
+

Example of Spring Cloud Contract Verifier Gradle setup:

+
+
+
+
ext {
+	contractsDir = file("mappings")
+	stubsOutputDirRoot = file("${project.buildDir}/production/${project.name}-stubs/")
+}
+
+// Automatically added by plugin:
+// copyContracts - copies contracts to the output folder from which JAR will be created
+// verifierStubsJar - JAR with a provided stub suffix
+// the presented publication is also added by the plugin but you can modify it as you wish
+
+publishing {
+	publications {
+		stubs(MavenPublication) {
+			artifactId "${project.name}-stubs"
+			artifact verifierStubsJar
+		}
+	}
+}
+
+
+
+
+
Maven Setup
+
+

Example of Maven can be found in the Stream Sink sample

+
+
+
+
+
+

Spring Cloud Contract Stub Runner

+
+

One of the issues that you could have encountered while using Spring Cloud Contract Verifier was to pass the generated WireMock JSON stubs from the server side to the client side (or various clients). + The same takes place in terms of client side generation for messaging.

+
+
+

Copying the JSON files / setting the client side for messaging manually is out of the question.

+
+
+

That’s why we’ll introduce Spring Cloud Contract Stub Runner that can download and run the stubs +automatically for you.

+
+
+

Snapshot versions

+
+

Add the additional snapshot repository to your build.gradle to use snapshot versions which are automatically uploaded after every successful build:

+
+
+
+
buildscript {
+	repositories {
+		mavenCentral()
+		mavenLocal()
+		maven { url "http://repo.spring.io/snapshot" }
+		maven { url "http://repo.spring.io/milestone" }
+		maven { url "http://repo.spring.io/release" }
+	}
+}
+
+
+
+

for Maven

+
+
+
+
<repositories>
+	<repository>
+		<id>spring-snapshots</id>
+		<name>Spring Snapshots</name>
+		<url>https://repo.spring.io/snapshot</url>
+		<snapshots>
+			<enabled>true</enabled>
+		</snapshots>
+	</repository>
+	<repository>
+		<id>spring-milestones</id>
+		<name>Spring Milestones</name>
+		<url>https://repo.spring.io/milestone</url>
+		<snapshots>
+			<enabled>false</enabled>
+		</snapshots>
+	</repository>
+	<repository>
+		<id>spring-releases</id>
+		<name>Spring Releases</name>
+		<url>https://repo.spring.io/release</url>
+		<snapshots>
+			<enabled>false</enabled>
+		</snapshots>
+	</repository>
+</repositories>
+<pluginRepositories>
+	<pluginRepository>
+		<id>spring-snapshots</id>
+		<name>Spring Snapshots</name>
+		<url>https://repo.spring.io/snapshot</url>
+		<snapshots>
+			<enabled>true</enabled>
+		</snapshots>
+	</pluginRepository>
+	<pluginRepository>
+		<id>spring-milestones</id>
+		<name>Spring Milestones</name>
+		<url>https://repo.spring.io/milestone</url>
+		<snapshots>
+			<enabled>false</enabled>
+		</snapshots>
+	</pluginRepository>
+	<pluginRepository>
+		<id>spring-releases</id>
+		<name>Spring Releases</name>
+		<url>https://repo.spring.io/release</url>
+		<snapshots>
+			<enabled>false</enabled>
+		</snapshots>
+	</pluginRepository>
+</pluginRepositories>
+
+
+
+
+

Publishing stubs as JARs

+
+

The easiest approach would be to centralize the way stubs are kept. For example you can keep them as JARs in a Maven repository.

+
+
+
Gradle
+
+

Example of Spring Cloud Contract Verifier Gradle setup:

+
+
+
+
ext {
+	contractsDir = file("mappings")
+	stubsOutputDirRoot = file("${project.buildDir}/production/${project.name}-stubs/")
+}
+
+// Automatically added by plugin:
+// copyContracts - copies contracts to the output folder from which JAR will be created
+// verifierStubsJar - JAR with a provided stub suffix
+// the presented publication is also added by the plugin but you can modify it as you wish
+
+publishing {
+	publications {
+		stubs(MavenPublication) {
+			artifactId "${project.name}-stubs"
+			artifact verifierStubsJar
+		}
+	}
+}
+
+
+
+
+
Maven
+
+

Example of Maven can be found in the Spring Cloud Contract Verifier README

+
+
+
+
+

Modules

+ +
+
+
+

Stub Runner Core

+
+

Runs stubs for service collaborators. Treating stubs as contracts of services allows to use stub-runner as an implementation of +Consumer Driven Contracts.

+
+
+

Stub Runner allows you to automatically download the stubs of the provided dependencies, start WireMock servers for them and feed them with proper stub definitions. +For messaging, special stub routes are defined.

+
+
+

Running stubs

+
+
Running using main app
+
+

You can set the following options to the main class:

+
+
+
+
-maxp (--maxPort) N            : Maximum port value to be assigned to the
+                                 Wiremock instance. Defaults to 15000
+                                 (default: 15000)
+-minp (--minPort) N            : Minimal port value to be assigned to the
+                                 Wiremock instance. Defaults to 10000
+                                 (default: 10000)
+-s (--stubs) VAL               : Comma separated list of Ivy representation of
+                                 jars with stubs. Eg. groupid:artifactid1,group
+                                 id2:artifactid2:version:classifier
+-sr (--stubRepositoryRoot) VAL : Location of a Jar containing server where you
+                                 keep your stubs (e.g. http://nexus.net/content
+                                 /repositories/repository)
+-ss (--stubsSuffix) VAL        : Suffix for the jar containing stubs (e.g.
+                                 'stubs' if the stub jar would have a 'stubs'
+                                 classifier for stubs: foobar-stubs ).
+                                 Defaults to 'stubs' (default: stubs)
+-wo (--workOffline)            : Switch to work offline. Defaults to 'false'
+                                 (default: false)
+
+
+
+
+
HTTP Stubs
+
+

Stubs are defined in JSON documents, whose syntax is defined in WireMock documentation

+
+
+

Example:

+
+
+
+
{
+    "request": {
+        "method": "GET",
+        "url": "/ping"
+    },
+    "response": {
+        "status": 200,
+        "body": "pong",
+        "headers": {
+            "Content-Type": "text/plain"
+        }
+    }
+}
+
+
+
+
+
Viewing registered mappings
+
+

Every stubbed collaborator exposes list of defined mappings under __/admin/ endpoint.

+
+
+
+
Messaging Stubs
+
+

Depending on the provided Stub Runner dependency and the DSL the messaging routes are automatically set up.

+
+
+
+
+
+

Stub Runner JUnit Rule

+
+

Stub Runner comes with a JUnit rule thanks to which you can very easily download and run stubs for given group and artifact id:

+
+
+
+
@ClassRule public static StubRunnerRule rule = new StubRunnerRule()
+		.repoRoot(repoRoot())
+		.downloadStub("org.springframework.cloud.contract.verifier.stubs", "loanIssuance")
+		.downloadStub("org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer");
+
+
+
+

After that rule gets executed Stub Runner connects to your Maven repository and for the given list of dependencies tries to:

+
+
+
    +
  • +

    download them

    +
  • +
  • +

    cache them locally

    +
  • +
  • +

    unzip them to a temporary folder

    +
  • +
  • +

    start a WireMock server for each Maven dependency on a random port from the provided range of ports / provided port

    +
  • +
  • +

    feed the WireMock server with all JSON files that are valid WireMock definitions

    +
  • +
+
+
+

Stub Runner uses Eclipse Aether mechanism to download the Maven dependencies. +Check their docs for more information.

+
+
+

Since the StubRunnerRule implements the StubFinder it allows you to find the started stubs:

+
+
+
+
/*
+ *  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
+ *
+ *       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.springframework.cloud.contract.stubrunner;
+
+import java.net.URL;
+import java.util.Collection;
+import java.util.Map;
+
+import org.springframework.cloud.contract.spec.Contract;
+
+public interface StubFinder extends StubTrigger {
+	/**
+	 * For the given groupId and artifactId tries to find the matching
+	 * URL of the running stub.
+	 *
+	 * @param groupId - might be null. In that case a search only via artifactId takes place
+	 * @return URL of a running stub or null if not found
+	 */
+	URL findStubUrl(String groupId, String artifactId);
+
+	/**
+	 * For the given Ivy notation {@code groupId:artifactId} tries to find the matching
+	 * URL of the running stub. You can also pass only {@code artifactId}.
+	 *
+	 * @param ivyNotation - Ivy representation of the Maven artifact
+	 * @return URL of a running stub or null if not found
+	 */
+	URL findStubUrl(String ivyNotation);
+
+	/**
+	 * Returns all running stubs
+	 */
+	RunningStubs findAllRunningStubs();
+
+	/**
+	 * Returns the list of Contracts
+	 */
+	Map<StubConfiguration, Collection<Contract>> getContracts();
+}
+
+
+
+

Example of usage in Spock tests:

+
+
+
+
@ClassRule @Shared StubRunnerRule rule = new StubRunnerRule()
+		.repoRoot(StubRunnerRuleSpec.getResource("/m2repo/repository").toURI().toString())
+		.downloadStub("org.springframework.cloud.contract.verifier.stubs", "loanIssuance")
+		.downloadStub("org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer")
+
+def 'should start WireMock servers'() {
+	expect: 'WireMocks are running'
+		rule.findStubUrl('org.springframework.cloud.contract.verifier.stubs', 'loanIssuance') != null
+		rule.findStubUrl('loanIssuance') != null
+		rule.findStubUrl('loanIssuance') == rule.findStubUrl('org.springframework.cloud.contract.verifier.stubs', 'loanIssuance')
+		rule.findStubUrl('org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer') != null
+	and:
+		rule.findAllRunningStubs().isPresent('loanIssuance')
+		rule.findAllRunningStubs().isPresent('org.springframework.cloud.contract.verifier.stubs', 'fraudDetectionServer')
+		rule.findAllRunningStubs().isPresent('org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer')
+	and: 'Stubs were registered'
+		"${rule.findStubUrl('loanIssuance').toString()}/name".toURL().text == 'loanIssuance'
+		"${rule.findStubUrl('fraudDetectionServer').toString()}/name".toURL().text == 'fraudDetectionServer'
+}
+
+
+
+

Example of usage in JUnit tests:

+
+
+
+
@Test
+public void should_start_wiremock_servers() throws Exception {
+	// expect: 'WireMocks are running'
+		then(rule.findStubUrl("org.springframework.cloud.contract.verifier.stubs", "loanIssuance")).isNotNull();
+		then(rule.findStubUrl("loanIssuance")).isNotNull();
+		then(rule.findStubUrl("loanIssuance")).isEqualTo(rule.findStubUrl("org.springframework.cloud.contract.verifier.stubs", "loanIssuance"));
+		then(rule.findStubUrl("org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer")).isNotNull();
+	// and:
+		then(rule.findAllRunningStubs().isPresent("loanIssuance")).isTrue();
+		then(rule.findAllRunningStubs().isPresent("org.springframework.cloud.contract.verifier.stubs", "fraudDetectionServer")).isTrue();
+		then(rule.findAllRunningStubs().isPresent("org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer")).isTrue();
+	// and: 'Stubs were registered'
+		then(httpGet(rule.findStubUrl("loanIssuance").toString() + "/name")).isEqualTo("loanIssuance");
+		then(httpGet(rule.findStubUrl("fraudDetectionServer").toString() + "/name")).isEqualTo("fraudDetectionServer");
+}
+
+
+
+

Check the Common properties for JUnit and Spring for more information on how to apply global configuration of Stub Runner.

+
+
+

Providing fixed ports

+
+

You can also run your stubs on fixed ports. You can do it in two different ways. One is to pass it in the properties, and the other via fluent API of +JUnit rule.

+
+
+
+

Fluent API

+
+

When using the StubRunnerRule you can add a stub to download and then pass the port for the last downloaded stub.

+
+
+
+
@ClassRule public static StubRunnerRule rule = new StubRunnerRule()
+		.repoRoot(repoRoot())
+		.downloadStub("org.springframework.cloud.contract.verifier.stubs", "loanIssuance")
+		.withPort(12345)
+		.downloadStub("org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer:12346");
+
+
+
+

You can see that for this example the following test is valid:

+
+
+
+
then(rule.findStubUrl("loanIssuance")).isEqualTo(URI.create("http://localhost:12345").toURL());
+then(rule.findStubUrl("fraudDetectionServer")).isEqualTo(URI.create("http://localhost:12346").toURL());
+
+
+
+
+

Stub Runner with Spring

+
+

Sets up Spring configuration of the Stub Runner project.

+
+
+

By providing a list of stubs inside your configuration file the Stub Runner automatically downloads +and registers in WireMock the selected stubs.

+
+
+

If you want to find the URL of your stubbed dependency you can autowire the StubFinder interface and use +its methods as presented below:

+
+
+
+
@ContextConfiguration(classes = Config, loader = SpringBootContextLoader)
+@IntegrationTest(["stubrunner.cloud.enabled=false", "stubrunner.camel.enabled=false"])
+@AutoConfigureStubRunner
+@DirtiesContext
+@ActiveProfiles("test")
+class StubRunnerConfigurationSpec extends Specification {
+
+	@Autowired StubFinder stubFinder
+
+	@BeforeClass
+	@AfterClass
+	void setupProps() {
+		System.clearProperty("stubrunner.repository.root");
+		System.clearProperty("stubrunner.classifier");
+	}
+
+	def 'should start WireMock servers'() {
+		expect: 'WireMocks are running'
+			stubFinder.findStubUrl('org.springframework.cloud.contract.verifier.stubs', 'loanIssuance') != null
+			stubFinder.findStubUrl('loanIssuance') != null
+			stubFinder.findStubUrl('loanIssuance') == stubFinder.findStubUrl('org.springframework.cloud.contract.verifier.stubs', 'loanIssuance')
+			stubFinder.findStubUrl('org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer') != null
+		and:
+			stubFinder.findAllRunningStubs().isPresent('loanIssuance')
+			stubFinder.findAllRunningStubs().isPresent('org.springframework.cloud.contract.verifier.stubs', 'fraudDetectionServer')
+			stubFinder.findAllRunningStubs().isPresent('org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer')
+		and: 'Stubs were registered'
+			"${stubFinder.findStubUrl('loanIssuance').toString()}/name".toURL().text == 'loanIssuance'
+			"${stubFinder.findStubUrl('fraudDetectionServer').toString()}/name".toURL().text == 'fraudDetectionServer'
+	}
+
+	@Configuration
+	@EnableAutoConfiguration
+	static class Config {}
+}
+
+
+
+

for the following configuration file:

+
+
+
+
stubrunner:
+  repositoryRoot: classpath:m2repo/repository/
+  ids:
+    - org.springframework.cloud.contract.verifier.stubs:loanIssuance
+    - org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer
+    - org.springframework.cloud.contract.verifier.stubs:bootService
+
+
+
+

Instead of using the properties you can also use the properties inside the @AutoConfigureStubRunner. +Below you can find an example of achieving the same result by setting values on the annotation.

+
+
+
+
@AutoConfigureStubRunner(
+		ids = ["org.springframework.cloud.contract.verifier.stubs:loanIssuance",
+		"org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer",
+		"org.springframework.cloud.contract.verifier.stubs:bootService"],
+		repositoryRoot = "classpath:m2repo/repository/")
+
+
+
+
+
+

Stub Runner Spring Cloud

+
+

Stub Runner can integrate with Spring Cloud.

+
+
+

Stubbing Service Discovery

+
+

The most important feature of Stub Runner Spring Cloud is the fact that it’s stubbing

+
+
+
    +
  • +

    DiscoveryClient

    +
  • +
  • +

    Ribbon ServerList

    +
  • +
+
+
+

that means that regardless of the fact whether you’re using Zookeeper, Consul, Eureka or anything else, you don’t need that in your tests. +We’re starting WireMock instances of your dependencies and we’re telling your application whenever you’re using Feign, load balanced RestTemplate +or DiscoveryClient directly, to call those stubbed servers instead of calling the real Service Discovery tool.

+
+
+

For example this test will pass

+
+
+
+
def 'should make service discovery work'() {
+	expect: 'WireMocks are running'
+		"${stubFinder.findStubUrl('loanIssuance').toString()}/name".toURL().text == 'loanIssuance'
+		"${stubFinder.findStubUrl('fraudDetectionServer').toString()}/name".toURL().text == 'fraudDetectionServer'
+	and: 'Stubs can be reached via load service discovery'
+		restTemplate.getForObject('http://loanIssuance/name', String) == 'loanIssuance'
+		restTemplate.getForObject('http://someNameThatShouldMapFraudDetectionServer/name', String) == 'fraudDetectionServer'
+}
+
+
+
+

for the following configuration file

+
+
+
+
spring.cloud:
+  zookeeper.enabled: false
+  consul.enabled: false
+eureka.client.enabled: false
+stubrunner:
+  camel.enabled: false
+  idsToServiceIds:
+    ivyNotation: someValueInsideYourCode
+    fraudDetectionServer: someNameThatShouldMapFraudDetectionServer
+
+
+
+
+

Additional Configuration

+
+

You can match the artifactId of the stub with the name of your app by using the stubrunner.idsToServiceIds: map. +You can disable Stub Runner Ribbon support by providing: stubrunner.cloud.ribbon.enabled equal to false +You can disable Stub Runner support by providing: stubrunner.cloud.enabled equal to false

+
+
+ + + + + +
+
Tip
+
+By default all service discovery will be stubbed. That means that regardless of the fact if you have +an existing DiscoveryClient its results will be ignored. However, if you want to reuse it, just set + stubrunner.cloud.delegate.enabled to true and then your existing DiscoveryClient results will be + merged with the stubbed ones. +
+
+
+
+
+

Stub Runner Boot Application

+
+

Spring Cloud Contract Verifier Stub Runner Boot is a Spring Boot application that exposes REST endpoints to +trigger the messaging labels and to access started WireMock servers.

+
+
+

One of the use-cases is to run some smoke (end to end) tests on a deployed application. You can read + more about this in the "Microservice Deployment" article at Too Much Coding blog.

+
+
+

How to use it?

+
+

Just add the

+
+
+
+
compile "org.springframework.cloud:spring-cloud-starter-stub-runner"
+
+
+
+

Annotate a class with @EnableStubRunnerServer, build a fat-jar and you’re ready to go!

+
+
+

For the properties check the Stub Runner Spring section.

+
+
+
+

Endpoints

+
+
HTTP
+
+
    +
  • +

    GET /stubs - returns a list of all running stubs in ivy:integer notation

    +
  • +
  • +

    GET /stubs/{ivy} - returns a port for the given ivy notation (when calling the endpoint ivy can also be artifactId only)

    +
  • +
+
+
+
+
Messaging
+
+

For Messaging

+
+
+
    +
  • +

    GET /triggers - returns a list of all running labels in ivy : [ label1, label2 …​] notation

    +
  • +
  • +

    POST /triggers/{label} - executes a trigger with label

    +
  • +
  • +

    POST /triggers/{ivy}/{label} - executes a trigger with label for the given ivy notation (when calling the endpoint ivy can also be artifactId only)

    +
  • +
+
+
+
+
+

Example

+
+
+
@ContextConfiguration(classes = StubRunnerBoot, loader = SpringBootContextLoader)
+@IntegrationTest("spring.cloud.zookeeper.enabled=false")
+@ActiveProfiles("test")
+class StubRunnerBootSpec extends Specification {
+
+	@Autowired StubRunning stubRunning
+
+	def setup() {
+		RestAssuredMockMvc.standaloneSetup(new HttpStubsController(stubRunning),
+				new TriggerController(stubRunning))
+	}
+
+	def 'should return a list of running stub servers in "full ivy:port" notation'() {
+		when:
+			String response = RestAssuredMockMvc.get('/stubs').body.asString()
+		then:
+			def root = new JsonSlurper().parseText(response)
+			root.'org.springframework.cloud.contract.verifier.stubs:bootService:0.0.1-SNAPSHOT:stubs' instanceof Integer
+	}
+
+	def 'should return a port on which a [#stubId] stub is running'() {
+		when:
+			def response = RestAssuredMockMvc.get("/stubs/${stubId}")
+		then:
+			response.statusCode == 200
+			response.body.as(Integer) > 0
+		where:
+			stubId << ['org.springframework.cloud.contract.verifier.stubs:bootService:+:stubs',
+					   'org.springframework.cloud.contract.verifier.stubs:bootService:0.0.1-SNAPSHOT:stubs',
+					   'org.springframework.cloud.contract.verifier.stubs:bootService:+',
+					   'org.springframework.cloud.contract.verifier.stubs:bootService',
+					   'bootService']
+	}
+
+	def 'should return 404 when missing stub was called'() {
+		when:
+			def response = RestAssuredMockMvc.get("/stubs/a:b:c:d")
+		then:
+			response.statusCode == 404
+	}
+
+	def 'should return a list of messaging labels that can be triggered when version and classifier are passed'() {
+		when:
+			String response = RestAssuredMockMvc.get('/triggers').body.asString()
+		then:
+			def root = new JsonSlurper().parseText(response)
+			root.'org.springframework.cloud.contract.verifier.stubs:bootService:0.0.1-SNAPSHOT:stubs'?.containsAll(["delete_book","return_book_1","return_book_2"])
+	}
+
+	def 'should trigger a messaging label'() {
+		given:
+			StubRunning stubRunning = Mock()
+			RestAssuredMockMvc.standaloneSetup(new HttpStubsController(stubRunning), new TriggerController(stubRunning))
+		when:
+			def response = RestAssuredMockMvc.post("/triggers/delete_book")
+		then:
+			response.statusCode == 200
+		and:
+			1 * stubRunning.trigger('delete_book')
+	}
+
+	def 'should trigger a messaging label for a stub with [#stubId] ivy notation'() {
+		given:
+			StubRunning stubRunning = Mock()
+			RestAssuredMockMvc.standaloneSetup(new HttpStubsController(stubRunning), new TriggerController(stubRunning))
+		when:
+			def response = RestAssuredMockMvc.post("/triggers/$stubId/delete_book")
+		then:
+			response.statusCode == 200
+		and:
+			1 * stubRunning.trigger(stubId, 'delete_book')
+		where:
+			stubId << ['org.springframework.cloud.contract.verifier.stubs:bootService:stubs', 'org.springframework.cloud.contract.verifier.stubs:bootService', 'bootService']
+	}
+
+	def 'should return when trigger is missing'() {
+		when:
+			def response = RestAssuredMockMvc.post("/triggers/missing_label")
+		then:
+			response.statusCode == 404
+			def root = new JsonSlurper().parseText(response.body.asString())
+			root.'org.springframework.cloud.contract.verifier.stubs:bootService:0.0.1-SNAPSHOT:stubs'?.containsAll(["delete_book","return_book_1","return_book_2"])
+	}
+
+}
+
+
+
+
+

Stub Runner Boot with Service Discovery

+
+

One of the possibilities of using Stub Runner Boot is to use it as a feed of stubs for "smoke-tests". What does it mean? + Let’s assume that you don’t want to deploy 50 microservice to a test environment in order + to check if your application is working fine. You’ve already executed a suite of tests during the build process + but you would also like to ensure that the packaging of your application is fine. What you can do + is to deploy your application to an environment, start it and run a couple of tests on it to see if + it’s working fine. We can call those tests smoke-tests since their idea is to check only a handful + of testing scenarios.

+
+
+

The problem with this approach is such that if you’re doing microservices most likely you’re + using a service discovery tool. Stub Runner Boot allows you to solve this issue by starting the + required stubs and register them in a service discovery tool. Let’s take a look at an example of + such a setup with Eureka. Let’s assume that Eureka was already running.

+
+
+
+
@SpringBootApplication
+@EnableStubRunnerServer
+@EnableEurekaClient
+@AutoConfigureStubRunner
+public class StubRunnerBootEurekaExample {
+
+	public static void main(String[] args) {
+		SpringApplication.run(StubRunnerBootEurekaExample.class, args);
+	}
+
+}
+
+
+
+

As you can see we want to start a Stub Runner Boot server @EnableStubRunnerServer, enable Eureka client @EnableEurekaClient +and we want to have the stub runner feature turned on @AutoConfigureStubRunner.

+
+
+

Now let’s assume that we want to start this application so that the stubs get automatically registered. + We can do it by running the app java -jar ${SYSTEM_PROPS} stub-runner-boot-eureka-example.jar where + ${SYSTEM_PROPS} would contain the following list of properties

+
+
+
+
-Dstubrunner.repositoryRoot=http://repo.spring.io/snapshots (1)
+-Dstubrunner.cloud.stubbed.discovery.enabled=false (2)
+-Dstubrunner.ids=org.springframework.cloud.contract.verifier.stubs:loanIssuance,org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer,org.springframework.cloud.contract.verifier.stubs:bootService (3)
+-Dstubrunner.idsToServiceIds.fraudDetectionServer=someNameThatShouldMapFraudDetectionServer (4)
+
+(1) - we tell Stub Runner where all the stubs reside
+(2) - we don't want the default behaviour where the discovery service is stubbed. That's why the stub registration will be picked
+(3) - we provide a list of stubs to download
+(4) - we provide a list of artifactId to serviceId mapping
+
+
+
+

That way your deployed application can send requests to started WireMock servers via the service +discovery. Most likely points 1-3 could be set by default in application.yml cause they are not +likely to change. That way you can provide only the list of stubs to download whenever you start +the Stub Runner Boot.

+
+
+
+

Common properties for JUnit and Spring

+
+

Some of the properties that are repetitive can be set using system properties or configuration properties (for Spring). Here are their names with their default values:

+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Property nameDefault valueDescription

stubrunner.minPort

10000

Minimal value of a port for a started WireMock with stubs

stubrunner.maxPort

15000

Minimal value of a port for a started WireMock with stubs

stubrunner.repositoryRoot

Maven repo url. If blank then will call the local maven repo

stubrunner.classifier

stubs

Default classifier for the stub artifacts

stubrunner.workOffline

false

If true then will not contact any remote repositories to download stubs

stubrunner.ids

Array of Ivy notation stubs to download

+
+
Stub runner stubs ids
+
+

You can provide the stubs to download via the stubrunner.ids system property. They follow the following pattern:

+
+
+
+
groupId:artifactId:version:classifier:port
+
+
+
+

version, classifier and port are optional.

+
+
+
    +
  • +

    If you don’t provide the port then a random one will be picked

    +
  • +
  • +

    If you don’t provide the classifier then the default one will be taken.

    +
  • +
  • +

    If you don’t provide the version then the + will be passed and the latest one will be downloaded

    +
  • +
+
+
+

Where port means the port of the WireMock server.

+
+
+
+
+
+

Stub Runner for Messaging

+
+

Stub Runner has the functionality to run the published stubs in memory. It can integrate with the following frameworks out of the box

+
+
+
    +
  • +

    Spring Integration

    +
  • +
  • +

    Spring Cloud Stream

    +
  • +
  • +

    Apache Camel

    +
  • +
+
+
+

It also provides points of entry to integrate with any other solution on the market.

+
+
+

Stub triggering

+
+

To trigger a message it’s enough to use the StubTrigger interface:

+
+
+
+
/*
+ *  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
+ *
+ *       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.springframework.cloud.contract.stubrunner;
+
+import java.util.Collection;
+import java.util.Map;
+
+public interface StubTrigger {
+
+	/**
+	 * Triggers an event by a given label for a given {@code groupid:artifactid} notation. You can use only {@code artifactId} too.
+	 *
+	 * Feature related to messaging.
+	 *
+	 * @return true - if managed to run a trigger
+	 */
+	boolean trigger(String ivyNotation, String labelName);
+
+	/**
+	 * Triggers an event by a given label.
+	 *
+	 * Feature related to messaging.
+	 *
+	 * @return true - if managed to run a trigger
+	 */
+	boolean trigger(String labelName);
+
+	/**
+	 * Triggers all possible events.
+	 *
+	 * Feature related to messaging.
+	 *
+	 * @return true - if managed to run a trigger
+	 */
+	boolean trigger();
+
+	/**
+	 * Returns a mapping of ivy notation of a dependency to all the labels it has.
+	 *
+	 * Feature related to messaging.
+	 */
+	Map<String, Collection<String>> labels();
+}
+
+
+
+

For convenience the StubFinder interface extends StubTrigger so it’s enough to use only one in your tests.

+
+
+

StubTrigger gives you the following options to trigger a message:

+
+
+
Trigger by label
+
+
+
stubFinder.trigger('return_book_1')
+
+
+
+
Trigger by group and artifact ids
+
+
+
stubFinder.trigger('org.springframework.cloud.contract.verifier.stubs:camelService', 'return_book_1')
+
+
+
+
+
Trigger by artifact ids
+
+
+
stubFinder.trigger('camelService', 'return_book_1')
+
+
+
+
+
+
Trigger all messages
+
+
+
stubFinder.trigger()
+
+
+
+
+
+
+

Stub Runner Camel

+
+

Spring Cloud Contract Verifier Stub Runner’s messaging module gives you an easy way to integrate with Apache Camel. +For the provided artifacts it will automatically download the stubs and register the required +routes.

+
+
+

Adding it to the project

+
+

It’s enough to have both Apache Camel and Spring Cloud Contract Stub Runner on classpath. +Remember to annotate your test class with @AutoConfigureMessageVerifier.

+
+
+
+

Examples

+
+
Stubs structure
+
+

Let us assume that we have the following Maven repository with a deployed stubs for the +camelService application.

+
+
+
+
└── .m2
+    └── repository
+        └── io
+            └── codearte
+                └── accurest
+                    └── stubs
+                        └── camelService
+                            ├── 0.0.1-SNAPSHOT
+                            │   ├── camelService-0.0.1-SNAPSHOT.pom
+                            │   ├── camelService-0.0.1-SNAPSHOT-stubs.jar
+                            │   └── maven-metadata-local.xml
+                            └── maven-metadata-local.xml
+
+
+
+

And the stubs contain the following structure:

+
+
+
+
├── META-INF
+│   └── MANIFEST.MF
+└── repository
+    ├── accurest
+    │   ├── bookDeleted.groovy
+    │   ├── bookReturned1.groovy
+    │   └── bookReturned2.groovy
+    └── mappings
+
+
+
+

Let’s consider the following contracts (let' number it with 1):

+
+
+
+
Contract.make {
+	label 'return_book_1'
+	input {
+		triggeredBy('bookReturnedTriggered()')
+	}
+	outputMessage {
+		sentTo('jms:output')
+		body('''{ "bookName" : "foo" }''')
+		headers {
+			header('BOOK-NAME', 'foo')
+		}
+	}
+}
+
+
+
+

and number 2

+
+
+
+
Contract.make {
+	label 'return_book_2'
+	input {
+		messageFrom('jms:input')
+		messageBody([
+				bookName: 'foo'
+		])
+		messageHeaders {
+			header('sample', 'header')
+		}
+	}
+	outputMessage {
+		sentTo('jms:output')
+		body([
+				bookName: 'foo'
+		])
+		headers {
+			header('BOOK-NAME', 'foo')
+		}
+	}
+}
+
+
+
+
+
Scenario 1 (no input message)
+
+

So as to trigger a message via the return_book_1 label we’ll use the StubTigger interface as follows

+
+
+
+
stubFinder.trigger('return_book_1')
+
+
+
+

Next we’ll want to listen to the output of the message sent to jms:output

+
+
+
+
Exchange receivedMessage = camelContext.createConsumerTemplate().receive('jms:output', 5000)
+
+
+
+

And the received message would pass the following assertions

+
+
+
+
receivedMessage != null
+assertThatBodyContainsBookNameFoo(receivedMessage.in.body)
+receivedMessage.in.headers.get('BOOK-NAME') == 'foo'
+
+
+
+
+
Scenario 2 (output triggered by input)
+
+

Since the route is set for you it’s enough to just send a message to the jms:output destination.

+
+
+
+
camelContext.createProducerTemplate().sendBodyAndHeaders('jms:input', new BookReturned('foo'), [sample: 'header'])
+
+
+
+

Next we’ll want to listen to the output of the message sent to jms:output

+
+
+
+
Exchange receivedMessage = camelContext.createConsumerTemplate().receive('jms:output', 5000)
+
+
+
+

And the received message would pass the following assertions

+
+
+
+
receivedMessage != null
+assertThatBodyContainsBookNameFoo(receivedMessage.in.body)
+receivedMessage.in.headers.get('BOOK-NAME') == 'foo'
+
+
+
+
+
Scenario 3 (input with no output)
+
+

Since the route is set for you it’s enough to just send a message to the jms:output destination.

+
+
+
+
camelContext.createProducerTemplate().sendBodyAndHeaders('jms:delete', new BookReturned('foo'), [sample: 'header'])
+
+
+
+
+
+
+

Stub Runner Integration

+
+

Spring Cloud Contract Verifier Stub Runner’s messaging module gives you an easy way to integrate with Spring Integration. +For the provided artifacts it will automatically download the stubs and register the required +routes.

+
+
+

Adding it to the project

+
+

It’s enough to have both Apache Camel and Spring Cloud Contract Stub Runner on classpath. +Remember to annotate your test class with @AutoConfigureMessageVerifier.

+
+
+
+

Examples

+
+
Stubs structure
+
+

Let us assume that we have the following Maven repository with a deployed stubs for the +integrationService application.

+
+
+
+
└── .m2
+    └── repository
+        └── io
+            └── codearte
+                └── accurest
+                    └── stubs
+                        └── integrationService
+                            ├── 0.0.1-SNAPSHOT
+                            │   ├── integrationService-0.0.1-SNAPSHOT.pom
+                            │   ├── integrationService-0.0.1-SNAPSHOT-stubs.jar
+                            │   └── maven-metadata-local.xml
+                            └── maven-metadata-local.xml
+
+
+
+

And the stubs contain the following structure:

+
+
+
+
├── META-INF
+│   └── MANIFEST.MF
+└── repository
+    ├── accurest
+    │   ├── bookDeleted.groovy
+    │   ├── bookReturned1.groovy
+    │   └── bookReturned2.groovy
+    └── mappings
+
+
+
+

Let’s consider the following contracts (let' number it with 1):

+
+
+
+
Contract.make {
+	label 'return_book_1'
+	input {
+		triggeredBy('bookReturnedTriggered()')
+	}
+	outputMessage {
+		sentTo('output')
+		body('''{ "bookName" : "foo" }''')
+		headers {
+			header('BOOK-NAME', 'foo')
+		}
+	}
+}
+
+
+
+

and number 2

+
+
+
+
Contract.make {
+	label 'return_book_2'
+	input {
+		messageFrom('input')
+		messageBody([
+				bookName: 'foo'
+		])
+		messageHeaders {
+			header('sample', 'header')
+		}
+	}
+	outputMessage {
+		sentTo('output')
+		body([
+				bookName: 'foo'
+		])
+		headers {
+			header('BOOK-NAME', 'foo')
+		}
+	}
+}
+
+
+
+

and the following Spring Integration Route:

+
+
+
+
<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~  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
+  ~
+  ~       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.
+  -->
+
+<beans:beans xmlns="http://www.springframework.org/schema/integration"
+			 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+			 xmlns:beans="http://www.springframework.org/schema/beans"
+			 xsi:schemaLocation="http://www.springframework.org/schema/beans
+			http://www.springframework.org/schema/beans/spring-beans.xsd
+			http://www.springframework.org/schema/integration
+			http://www.springframework.org/schema/integration/spring-integration.xsd">
+
+
+	<!-- REQUIRED FOR TESTING -->
+	<bridge input-channel="output"
+			output-channel="outputTest"/>
+
+	<channel id="outputTest">
+		<queue/>
+	</channel>
+
+</beans:beans>
+
+
+
+
+
Scenario 1 (no input message)
+
+

So as to trigger a message via the return_book_1 label we’ll use the StubTigger interface as follows

+
+
+
+
stubFinder.trigger('return_book_1')
+
+
+
+

Next we’ll want to listen to the output of the message sent to output

+
+
+
+
Message<?> receivedMessage = messaging.receive('outputTest')
+
+
+
+

And the received message would pass the following assertions

+
+
+
+
receivedMessage != null
+assertJsons(receivedMessage.payload)
+receivedMessage.headers.get('BOOK-NAME') == 'foo'
+
+
+
+
+
Scenario 2 (output triggered by input)
+
+

Since the route is set for you it’s enough to just send a message to the output destination.

+
+
+
+
messaging.send(new BookReturned('foo'), [sample: 'header'], 'input')
+
+
+
+

Next we’ll want to listen to the output of the message sent to output

+
+
+
+
Message<?> receivedMessage = messaging.receive('outputTest')
+
+
+
+

And the received message would pass the following assertions

+
+
+
+
receivedMessage != null
+assertJsons(receivedMessage.payload)
+receivedMessage.headers.get('BOOK-NAME') == 'foo'
+
+
+
+
+
Scenario 3 (input with no output)
+
+

Since the route is set for you it’s enough to just send a message to the input destination.

+
+
+
+
messaging.send(new BookReturned('foo'), [sample: 'header'], 'delete')
+
+
+
+
+
+
+

Stub Runner Stream

+
+

Spring Cloud Contract Verifier Stub Runner’s messaging module gives you an easy way to integrate with Spring Stream. +For the provided artifacts it will automatically download the stubs and register the required +routes.

+
+
+ + + + + +
+
Warning
+
+In Stub Runner’s integration with Stream the messageFrom or sentTo Strings are resolved +first as a destination of a channel, and then if there is no such destination it’s resolved as a +channel name. +
+
+
+

Adding it to the project

+
+

It’s enough to have both Apache Camel and Spring Cloud Contract Stub Runner on classpath. +Remember to annotate your test class with @AutoConfigureMessageVerifier.

+
+
+
+

Examples

+
+
Stubs structure
+
+

Let us assume that we have the following Maven repository with a deployed stubs for the +streamService application.

+
+
+
+
└── .m2
+    └── repository
+        └── io
+            └── codearte
+                └── accurest
+                    └── stubs
+                        └── streamService
+                            ├── 0.0.1-SNAPSHOT
+                            │   ├── streamService-0.0.1-SNAPSHOT.pom
+                            │   ├── streamService-0.0.1-SNAPSHOT-stubs.jar
+                            │   └── maven-metadata-local.xml
+                            └── maven-metadata-local.xml
+
+
+
+

And the stubs contain the following structure:

+
+
+
+
├── META-INF
+│   └── MANIFEST.MF
+└── repository
+    ├── accurest
+    │   ├── bookDeleted.groovy
+    │   ├── bookReturned1.groovy
+    │   └── bookReturned2.groovy
+    └── mappings
+
+
+
+

Let’s consider the following contracts (let' number it with 1):

+
+
+
+
Contract.make {
+	label 'return_book_1'
+	input { triggeredBy('bookReturnedTriggered()') }
+	outputMessage {
+		sentTo('returnBook')
+		body('''{ "bookName" : "foo" }''')
+		headers { header('BOOK-NAME', 'foo') }
+	}
+}
+
+
+
+

and number 2

+
+
+
+
Contract.make {
+	label 'return_book_2'
+	input {
+		messageFrom('bookStorage')
+		messageBody([
+			bookName: 'foo'
+		])
+		messageHeaders { header('sample', 'header') }
+	}
+	outputMessage {
+		sentTo('returnBook')
+		body([
+			bookName: 'foo'
+		])
+		headers { header('BOOK-NAME', 'foo') }
+	}
+}
+
+
+
+

and the following Spring configuration:

+
+
+
+
stubrunner.repositoryRoot: classpath:m2repo/repository/
+stubrunner.ids: org.springframework.cloud.contract.verifier.stubs:streamService:0.0.1-SNAPSHOT:stubs
+
+spring:
+  cloud:
+    stream:
+      bindings:
+        output:
+          destination: returnBook
+        input:
+          destination: bookStorage
+
+
+
+
+
Scenario 1 (no input message)
+
+

So as to trigger a message via the return_book_1 label we’ll use the StubTrigger interface as follows

+
+
+
+
stubFinder.trigger('return_book_1')
+
+
+
+

Next we’ll want to listen to the output of the message sent to a channel whose destination is returnBook

+
+
+
+
Message<?> receivedMessage = messaging.receive('returnBook')
+
+
+
+

And the received message would pass the following assertions

+
+
+
+
receivedMessage != null
+assertJsons(receivedMessage.payload)
+receivedMessage.headers.get('BOOK-NAME') == 'foo'
+
+
+
+
+
Scenario 2 (output triggered by input)
+
+

Since the route is set for you it’s enough to just send a message to the bookStorage destination.

+
+
+
+
messaging.send(new BookReturned('foo'), [sample: 'header'], 'bookStorage')
+
+
+
+

Next we’ll want to listen to the output of the message sent to returnBook

+
+
+
+
Message<?> receivedMessage = messaging.receive('returnBook')
+
+
+
+

And the received message would pass the following assertions

+
+
+
+
receivedMessage != null
+assertJsons(receivedMessage.payload)
+receivedMessage.headers.get('BOOK-NAME') == 'foo'
+
+
+
+
+
Scenario 3 (input with no output)
+
+

Since the route is set for you it’s enough to just send a message to the output destination.

+
+
+
+
messaging.send(new BookReturned('foo'), [sample: 'header'], 'delete')
+
+
+
+
+
+
+

Contract DSL

+
+ + + + + +
+
Important
+
+Remember that inside the contract file you have to provide the fully qualified name to +the Contract class and the make static import i.e. org.springframework.cloud.spec.Contract.make { …​ }. +You can also provide an import to the Contract class import org.springframework.cloud.spec.Contract and then call + Contract.make { …​ } +
+
+
+

Contract DSL is written in Groovy, but don’t be alarmed if you didn’t use Groovy before. Knowledge of the language is not really needed as our DSL uses only +a tiny subset of it (namely literals, method calls and closures). What’s more the DSL is designed to be programmer-readable without any knowledge of the DSL itself - + it’s statically typed.

+
+
+

The Contract is present in the spring-cloud-contract-spec module of the Spring Cloud Contract Verifier repository.

+
+
+

Let’s look at full example of a contract definition.

+
+
+
+
org.springframework.cloud.contract.spec.Contract.make {
+	request {
+		method 'PUT'
+		url '/api/12'
+		headers {
+			header 'Content-Type': 'application/vnd.org.springframework.cloud.contract.verifier.twitter-places-analyzer.v1+json'
+		}
+		body '''\
+		[{
+			"created_at": "Sat Jul 26 09:38:57 +0000 2014",
+			"id": 492967299297845248,
+			"id_str": "492967299297845248",
+			"text": "Gonna see you at Warsaw",
+			"place":
+			{
+				"attributes":{},
+				"bounding_box":
+				{
+					"coordinates":
+						[[
+							[-77.119759,38.791645],
+							[-76.909393,38.791645],
+							[-76.909393,38.995548],
+							[-77.119759,38.995548]
+						]],
+					"type":"Polygon"
+				},
+				"country":"United States",
+				"country_code":"US",
+				"full_name":"Washington, DC",
+				"id":"01fbe706f872cb32",
+				"name":"Washington",
+				"place_type":"city",
+				"url": "http://api.twitter.com/1/geo/id/01fbe706f872cb32.json"
+			}
+		}]
+	'''
+	}
+	response {
+		status 200
+	}
+}
+
+
+
+

Not all features of the DSL are used in example above. If you didn’t find what you are looking for, please check next paragraphs on this page.

+
+
+
+
+

You can easily compile Contracts to WireMock stubs mapping using standalone maven command: mvn org.springframework.cloud:spring-cloud-contract-maven-plugin:convert.

+
+
+
+
+

Limitations

+
+ + + + + +
+
Warning
+
+Spring Cloud Contract Verifier doesn’t support XML properly. Please use JSON or help us implement this feature. +
+
+
+ + + + + +
+
Warning
+
+Spring Cloud Contract Verifier supports equality check on text response. Regular expressions are not yet available. +
+
+
+ + + + + +
+
Warning
+
+The support for the verification of size of JSON arrays is experimental. If you want to turn it on please provide +the value of a system property spring.cloud.contract.verifier.assert.size equal to true. By default this feature is set to +false. You can also provide the assertJsonSize property in the plugin configuration. +
+
+
+ + + + + +
+
Warning
+
+Due to the fact that JSON structure can have any form it’s sometimes impossible to parse it properly when using +the value(consumer(…​), producer(…​)) notation when using that in GString. That’s why we highly recommend using the +Groovy Map notation. +
+
+
+
+

HTTP Top-Level Elements

+
+

Following methods can be called in the top-level closure of a contract definition. Request and response are mandatory, priority is optional.

+
+
+
+
org.springframework.cloud.contract.spec.Contract.make {
+	// Definition of HTTP request part of the contract
+	// (this can be a valid request or invalid depending
+	// on type of contract being specified).
+	request {
+		//...
+	}
+
+	// Definition of HTTP response part of the contract
+	// (a service implementing this contract should respond
+	// with following response after receiving request
+	// specified in "request" part above).
+	response {
+		//...
+	}
+
+	// Contract priority, which can be used for overriding
+	// contracts (1 is highest). Priority is optional.
+	priority 1
+}
+
+
+
+
+

Request

+
+

HTTP protocol requires only method and address to be specified in a request. The same information is mandatory in request definition of the Contract.

+
+
+
+
org.springframework.cloud.contract.spec.Contract.make {
+	request {
+		// HTTP request method (GET/POST/PUT/DELETE).
+		method 'GET'
+
+		// Path component of request URL is specified as follows.
+		urlPath('/users')
+	}
+
+	response {
+		//...
+	}
+}
+
+
+
+

It is possible to specify whole url instead of just path, but urlPath is the recommended way as it makes the tests host-independent.

+
+
+
+
org.springframework.cloud.contract.spec.Contract.make {
+	request {
+		method 'GET'
+
+		// Specifying `url` and `urlPath` in one contract is illegal.
+		url('http://localhost:8888/users')
+	}
+
+	response {
+		//...
+	}
+}
+
+
+
+

Request may contain query parameters, which are specified in a closure nested in a call to urlPath or url.

+
+
+
+
org.springframework.cloud.contract.spec.Contract.make {
+	request {
+		//...
+
+		urlPath('/users') {
+
+			// Each parameter is specified in form
+			// `'paramName' : paramValue` where parameter value
+			// may be a simple literal or one of matcher functions,
+			// all of which are used in this example.
+			queryParameters {
+
+				// If a simple literal is used as value
+				// default matcher function is used (equalTo)
+				parameter 'limit': 100
+
+				// `equalTo` function simply compares passed value
+				// using identity operator (==).
+				parameter 'filter': equalTo("email")
+
+				// `containing` function matches strings
+				// that contains passed substring.
+				parameter 'gender': value(consumer(containing("[mf]")), producer('mf'))
+
+				// `matching` function tests parameter
+				// against passed regular expression.
+				parameter 'offset': value(consumer(matching("[0-9]+")), producer(123))
+
+				// `notMatching` functions tests if parameter
+				// does not match passed regular expression.
+				parameter 'loginStartsWith': value(consumer(notMatching(".{0,2}")), producer(3))
+			}
+		}
+
+		//...
+	}
+
+	response {
+		//...
+	}
+}
+
+
+
+

It may contain additional request headers…​

+
+
+
+
org.springframework.cloud.contract.spec.Contract.make {
+	request {
+		//...
+
+		// Each header is added in form `'Header-Name' : 'Header-Value'`.
+		headers {
+			header 'Content-Type': 'application/json'
+		}
+
+		//...
+	}
+
+	response {
+		//...
+	}
+}
+
+
+
+

…​and a request body.

+
+
+
+
org.springframework.cloud.contract.spec.Contract.make {
+	request {
+		//...
+
+		// Currently only JSON format of request body is supported.
+		// Format will be determined from a header or body's content.
+		body '''{ "login" : "john", "name": "John The Contract" }'''
+	}
+
+	response {
+		//...
+	}
+}
+
+
+
+
+

Response

+
+

Minimal response must contain HTTP status code.

+
+
+
+
org.springframework.cloud.contract.spec.Contract.make {
+	request {
+		//...
+	}
+	response {
+		// Status code sent by the server
+		// in response to request specified above.
+		status 200
+	}
+}
+
+
+
+

Besides status response may contain headers and body, which are specified the same way as in the request (see previous paragraph).

+
+
+
+

Dynamic properties

+
+

The contract can contain some dynamic properties - timestamps / ids etc. You don’t want to enforce the consumers to stub their +clocks to always return the same value of time so that it gets matched by the stub. That’s why we allow you to provide the dynamic +parts in your contracts in the following way

+
+
+

either via the value method

+
+
+
+
value(consumer(...), producer(...))
+value(stub(...), test(...))
+value(client(...), server(...))
+
+
+
+

or if you’re using the Groovy map notation for body you can use the $() method

+
+
+
+
$(consumer(...), producer(...))
+$(stub(...), test(...))
+$(client(...), server(...))
+
+
+
+

All of the aforementioned approaches are equal. That means that stub and client methods are aliases over the consumer +method. Let’s take a closer look at what we can do with those values in the subsequent sections.

+
+
+
+

Regular expressions

+
+

You can use regular expressions to write your requests in Contract DSL. It is particularly useful when you want to indicate that a given response +should be provided for requests that follow a given pattern. Also, you can use it when you need to use patterns and not exact values both +for your test and your server side tests.

+
+
+

Please see the example below:

+
+
+
+
org.springframework.cloud.contract.spec.Contract.make {
+	request {
+		method('GET')
+		url $(consumer(~/\/[0-9]{2}/), producer('/12'))
+	}
+	response {
+		status 200
+		body(
+				id: value(
+						consumer('123'),
+						producer(regex('[0-9]+'))
+				),
+				surname: $(
+						consumer('Kowalsky'),
+						producer(regex('[a-zA-Z]+'))
+				),
+				name: 'Jan',
+				created: $(consumer('2014-02-02 12:23:43'), producer(execute('currentDate(it)'))),
+				correlationId: value(consumer('5d1f9fef-e0dc-4f3d-a7e4-72d2220dd827'),
+						producer(regex('[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}'))
+				)
+		)
+		headers {
+			header 'Content-Type': 'text/plain'
+		}
+	}
+}
+
+
+
+

You can also provide only one side of the communication using a regular expression. If you do that then automatically we’ll +provide the generated string that matches the provided regular expression. For example:

+
+
+
+
org.springframework.cloud.contract.spec.Contract.make {
+	request {
+		method 'PUT'
+		url value(consumer(regex('/foo/[0-9]{5}')))
+		body([
+			requestElement: value(consumer(regex('[0-9]{5}')))
+		])
+		headers {
+			header('header', value(consumer(regex('application\\/vnd\\.fraud\\.v1\\+json;.*'))))
+		}
+	}
+	response {
+		status 200
+		body([
+			responseElement: value(producer(regex('[0-9]{7}')))
+		])
+		headers {
+			header('Content-Type': value(
+					producer(regex('application/vnd.fraud.v1.json.*')),
+					consumer('application/vnd.fraud.v1+json'))
+			)
+		}
+	}
+}
+
+
+
+

In this example for request and response the opposite side of the communication will have the respective data generated.

+
+
+

Spring Cloud Contract comes with a series of predefined regular expressions that you can use in your contracts.

+
+
+
+
private static final Pattern TRUE_OR_FALSE = Pattern.compile(/(true|false)/)
+private static final Pattern ONLY_ALPHA_UNICODE = Pattern.compile(/[\p{L}]*/)
+private static final Pattern NUMBER = Pattern.compile('-?\\d*(\\.\\d+)?')
+private static final Pattern IP_ADDRESS = Pattern.compile('([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])');
+private static final Pattern HOSTNAME_PATTERN = Pattern.compile('((http[s]?|ftp):\\/)\\/?([^:\\/\\s]+)(:[0-9]{1,5})?');
+private static final Pattern EMAIL = Pattern.compile('[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,4}');
+private static final Pattern URL = Pattern.compile('((www\\.|(http|https|ftp|news|file)+\\:\\/\\/)[_.a-z0-9-]+\\.[a-z0-9\\/_:@=.+?,##%&~-]*[^.|\\\'|\\# |!|\\(|?|,| |>|<|;|\\)])')
+
+String onlyAlphaUnicode() {
+	return ONLY_ALPHA_UNICODE.pattern()
+}
+
+String number() {
+	return NUMBER.pattern()
+}
+
+String anyBoolean() {
+	return TRUE_OR_FALSE.pattern()
+}
+
+String ipAddress() {
+	return IP_ADDRESS.pattern()
+}
+
+String hostname() {
+	return HOSTNAME_PATTERN.pattern()
+}
+
+String email() {
+	return EMAIL.pattern()
+}
+
+String url() {
+	return URL.pattern()
+}
+
+
+
+

so in your contract you can use it like this

+
+
+
+
Contract dslWithOptionalsInString = Contract.make {
+	priority 1
+	request {
+		method 'POST'
+		url '/users/password'
+		headers {
+			header 'Content-Type': 'application/json'
+		}
+		body(
+				email: $(consumer(optional(regex(email()))), producer('abc@abc.com')),
+				callback_url: $(consumer(regex(hostname())), producer('http://partners.com'))
+		)
+	}
+	response {
+		status 404
+		headers {
+			header 'Content-Type': 'application/json'
+		}
+		body(
+				code: value(consumer("123123"), producer(optional("123123"))),
+				message: "User not found by email = [${value(producer(regex(email())), consumer('not.existing@user.com'))}]"
+		)
+	}
+}
+
+
+
+
+

Passing optional parameters

+
+

It is possible to provide optional parameters in your contract. It’s only possible to have optional parameter for the:

+
+
+
    +
  • +

    STUB side of the Request

    +
  • +
  • +

    TEST side of the Response

    +
  • +
+
+
+

Example:

+
+
+
+
org.springframework.cloud.contract.spec.Contract.make {
+	priority 1
+	request {
+		method 'POST'
+		url '/users/password'
+		headers {
+			header 'Content-Type': 'application/json'
+		}
+		body(
+				email: $(consumer(optional(regex(email()))), producer('abc@abc.com')),
+				callback_url: $(consumer(regex(hostname())), producer('http://partners.com'))
+		)
+	}
+	response {
+		status 404
+		headers {
+			header 'Content-Type': 'application/json'
+		}
+		body(
+				code: value(consumer("123123"), producer(optional("123123")))
+		)
+	}
+}
+
+
+
+

By wrapping a part of the body with the optional() method you are in fact creating a regular expression that should be present 0 or more times.

+
+
+

That way for the example above the following test would be generated if you pick Spock:

+
+
+
+
"""
+ given:
+  def request = given()
+    .header('Content-Type', 'application/json')
+    .body('''{"email":"abc@abc.com","callback_url":"http://partners.com"}''')
+
+ when:
+  def response = given().spec(request)
+    .post("/users/password")
+
+ then:
+  response.statusCode == 404
+  response.header('Content-Type')  == 'application/json'
+ and:
+  DocumentContext parsedJson = JsonPath.parse(response.body.asString())
+  assertThatJson(parsedJson).field("code").matches("(123123)?")
+"""
+
+
+
+

and the following stub:

+
+
+
+
'''
+{
+  "request" : {
+    "url" : "/users/password",
+    "method" : "POST",
+    "bodyPatterns" : [ {
+      "matchesJsonPath" : "$[?(@.email =~ /([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[a-zA-Z]{2,4})?/)]"
+    }, {
+      "matchesJsonPath" : "$[?(@.callback_url =~ /((http[s]?|ftp):\\\\/)\\\\/?([^:\\\\/\\\\s]+)(:[0-9]{1,5})?/)]"
+    } ],
+    "headers" : {
+      "Content-Type" : {
+        "equalTo" : "application/json"
+      }
+    }
+  },
+  "response" : {
+    "status" : 404,
+    "body" : "{\\"code\\":\\"123123\\",\\"message\\":\\"User not found by email == [not.existing@user.com]\\"}",
+    "headers" : {
+      "Content-Type" : "application/json"
+    }
+  },
+  "priority" : 1
+}
+'''
+
+
+
+
+

Executing custom methods on server side

+
+

It is also possible to define a method call to be executed on the server side during the test. Such a method can be added to the class defined as "baseClassForTests" +in the configuration. Please see the examples below:

+
+
+
Contract DSL
+
+
+
org.springframework.cloud.contract.spec.Contract.make {
+	request {
+		method 'PUT'
+		url $(consumer(regex('^/api/[0-9]{2}$')), producer('/api/12'))
+		headers {
+			header 'Content-Type': 'application/json'
+		}
+		body '''\
+				[{
+					"text": "Gonna see you at Warsaw"
+				}]
+			'''
+	}
+	response {
+		body (
+				path: $(consumer('/api/12'), producer(regex('^/api/[0-9]{2}$'))),
+				correlationId: $(consumer('1223456'), producer(execute('isProperCorrelationId($it)')))
+		)
+		status 200
+	}
+}
+
+
+
+
+
Base Mock Spec
+
+
+
abstract class BaseMockMvcSpec extends Specification {
+
+	def setup() {
+		RestAssuredMockMvc.standaloneSetup(new PairIdController())
+	}
+
+	void isProperCorrelationId(Integer correlationId) {
+		assert correlationId == 123456
+	}
+
+	void isEmpty(String value) {
+		assert value == null
+	}
+
+}
+
+
+
+
+
+

JAX-RS support

+
+

Starting with release 0.8.0 we support JAX-RS 2 Client API. Base class needs to define protected WebTarget webTarget and server initialization, right now the only option how to test JAX-RS API is to start a web server.

+
+
+

Request with a body needs to have a content type set otherwise application/octet-stream is going to be used.

+
+
+

In order to use JAX-RS mode, use the following settings:

+
+
+
+
testMode === 'JAXRSCLIENT'
+
+
+
+

Example of a test API generated:

+
+
+
+
'''
+ // when:
+  Response response = webTarget
+    .path("/users")
+    .queryParam("limit", "10")
+    .queryParam("offset", "20")
+    .queryParam("filter", "email")
+    .queryParam("sort", "name")
+    .queryParam("search", "55")
+    .queryParam("age", "99")
+    .queryParam("name", "Denis.Stepanov")
+    .queryParam("email", "bob@email.com")
+    .request()
+    .method("GET");
+
+  String responseAsString = response.readEntity(String.class);
+
+ // then:
+  assertThat(response.getStatus()).isEqualTo(200);
+ // and:
+  DocumentContext parsedJson = JsonPath.parse(responseAsString);
+  assertThatJson(parsedJson).field("property1").isEqualTo("a");
+'''
+
+
+
+
+

Async support

+
+

If you’re using asynchronous communication on the server side (your controllers are returning +Callable, DeferredResult etc. then inside your contract you have to provide in the response +section a async() method. Example:

+
+
+
+
org.springframework.cloud.contract.spec.Contract.make {
+    request {
+        method 'GET'
+        url '/get'
+    }
+    response {
+        status 200
+        body 'Passed'
+        async()
+    }
+}
+
+
+
+
+

Messaging Top-Level Elements

+
+

The DSL for messaging looks a little bit different than the one that focuses on HTTP.

+
+
+
Output triggered by a method
+
+

The output message can be triggered by calling a method (e.g. a Scheduler was started and a message was sent)

+
+
+
+
def dsl = Contract.make {
+	// Human readable description
+	description 'Some description'
+	// Label by means of which the output message can be triggered
+	label 'some_label'
+	// input to the contract
+	input {
+		// the contract will be triggered by a method
+		triggeredBy('bookReturnedTriggered()')
+	}
+	// output message of the contract
+	outputMessage {
+		// destination to which the output message will be sent
+		sentTo('output')
+		// the body of the output message
+		body('''{ "bookName" : "foo" }''')
+		// the headers of the output message
+		headers {
+			header('BOOK-NAME', 'foo')
+		}
+	}
+}
+
+
+
+

In this case the output message will be sent to output if a method called bookReturnedTriggered will be executed. In the message publisher’s side +we will generate a test that will call that method to trigger the message. On the consumer side you can use the some_label to trigger the message.

+
+
+
+
Output triggered by a message
+
+

The output message can be triggered by receiving a message.

+
+
+
+
def dsl = Contract.make {
+	description 'Some Description'
+	label 'some_label'
+	// input is a message
+	input {
+		// the message was received from this destination
+		messageFrom('input')
+		// has the following body
+		messageBody([
+		        bookName: 'foo'
+		])
+		// and the following headers
+		messageHeaders {
+			header('sample', 'header')
+		}
+	}
+	outputMessage {
+		sentTo('output')
+		body([
+		        bookName: 'foo'
+		])
+		headers {
+			header('BOOK-NAME', 'foo')
+		}
+	}
+}
+
+
+
+

In this case the output message will be sent to output if a proper message will be received on the input destination. In the message publisher’s side +we will generate a test that will send the input message to the defined destination. On the consumer side you can either send a message to the input +destination or use the some_label to trigger the message.

+
+
+
+
Consumer / Producer
+
+

In HTTP you have a notion of client/stub and `server/test notation. You can use them also in messaging but we’re providing also the consumer and produer methods +as presented below (note you can use either $ or value methods to provide consumer and producer parts)

+
+
+
+
Contract.make {
+	label 'some_label'
+	input {
+		messageFrom value(consumer('jms:output'), producer('jms:input'))
+		messageBody([
+				bookName: 'foo'
+		])
+		messageHeaders {
+			header('sample', 'header')
+		}
+	}
+	outputMessage {
+		sentTo $(consumer('jms:input'), producer('jms:output'))
+		body([
+				bookName: 'foo'
+		])
+	}
+}
+
+
+
+
+
+ +
+
+
+

Spring Cloud Contract WireMock

+
+
+

Modules giving you the possibility to use +WireMock with different servers by using the +"ambient" server embedded in a Spring Boot application. Check out the +samples +for more details.

+
+
+

If you have a Spring Boot application that uses Tomcat as an embedded +server, for example (the default with spring-boot-starter-web), then +you can simply add spring-cloud-contract-wiremock to your classpath +and add @AutoConfigureWireMock in order to be able to use Wiremock +in your tests. Wiremock runs as a stub server and you can register +stub behaviour using a Java API or via static JSON declarations as +part of your test. Here’s a simple example:

+
+
+
+
@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
+@AutoConfigureWireMock(port = 0)
+public class WiremockForDocsTests {
+	// A service that calls out over HTTP
+	@Autowired private Service service;
+
+	// Using the WireMock APIs in the normal way:
+	@Test
+	public void contextLoads() throws Exception {
+		// Stubbing WireMock
+		stubFor(get(urlEqualTo("/resource"))
+				.willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!")));
+		// We're asserting if WireMock responded properly
+		assertThat(this.service.go()).isEqualTo("Hello World!");
+	}
+
+}
+
+
+
+

To start the stub server on a different port use @AutoConfigureWireMock(port=9999) (for example), and for a random port use the value 0. The stub server port will be bindable in the test application context as "wiremock.server.port". Using @AutoConfigureWireMock adds a bean of type WiremockConfiguration to your test application context, where it will be cached in between methods and classes having the same context, just like for normal Spring integration tests.

+
+
+

Registering Stubs Automatically

+
+

If you add a stubs attribute to your @AutoConfigureWireMock then +it will register WireMock JSON stubs from the file system or +classpath. The stubs attribute can be a resource pattern (ant-style) +or a directory, in which case */.json is appended. Example:

+
+
+
+
@RunWith(SpringRunner.class)
+@SpringBootTest
+@AutoConfigureWireMock(stubs="classpath:/stubs")
+public class WiremockImportApplicationTests {
+
+	@Autowired
+	private Service service;
+
+	@Test
+	public void contextLoads() throws Exception {
+		assertThat(this.service.go()).isEqualTo("Hello World!");
+	}
+
+}
+
+
+
+
+

Alternative: Using JUnit Rules

+
+

For a more conventional WireMock experience, using JUnit @Rules to +start and stop the server, just use the WireMockSpring convenience +class to obtain an Options instance:

+
+
+
+
@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
+@AutoConfigureWireMock
+public class WiremockForDocsClassRuleTests {
+
+	// Start WireMock on some dynamic port
+	@ClassRule
+	public static WireMockClassRule wiremock = new WireMockClassRule(
+			WireMockSpring.options().dynamicPort());
+	// A service that calls out over HTTP to localhost:${wiremock.port}
+	@Autowired
+	private Service service;
+
+	// Using the WireMock APIs in the normal way:
+	@Test
+	public void contextLoads() throws Exception {
+		// Stubbing WireMock
+		wiremock.stubFor(get(urlEqualTo("/resource"))
+				.willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!")));
+		// We're asserting if WireMock responded properly
+		assertThat(this.service.go()).isEqualTo("Hello World!");
+	}
+
+}
+
+
+
+

The use @ClassRule means that the server will shut down after all the methods in this class.

+
+
+
+
+
+

WireMock and Spring MVC Mocks

+
+
+

Spring Cloud Contract provides a convenience class that can load JSON WireMock stubs into a +Spring MockRestServiceServer. Here’s an example:

+
+
+
+
@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = WebEnvironment.NONE)
+public class WiremockForDocsMockServerApplicationTests {
+
+	@Autowired
+	private RestTemplate restTemplate;
+
+	@Autowired
+	private Service service;
+
+	@Test
+	public void contextLoads() throws Exception {
+		// will read stubs classpath
+		MockRestServiceServer server = WireMockRestServiceServer.with(this.restTemplate)
+				.baseUrl("http://example.org").stubs("classpath:/stubs/resource.json")
+				.build();
+		// We're asserting if WireMock responded properly
+		assertThat(this.service.go()).isEqualTo("Hello World");
+		server.verify();
+	}
+}
+
+
+
+

The baseUrl is prepended to all mock calls, and the stubs() +method takes a stub path resource pattern as an argument. So in this +example the stub defined at /stubs/resource.json is loaded into the +mock server, so if the RestTemplate is asked to visit +http://example.org/ it will get the responses as declared +there. More than one stub pattern can be specified, and each one can +be a directory (for a recursive list of all ".json"), or a fixed +filename (like in the example above) or an ant-style pattern. The JSON +format is the normal WireMock format which you can read about in the +WireMock website.

+
+
+

Currently we support Tomcat, Jetty and Undertow as Spring Boot +embedded servers, and Wiremock itself has "native" support for a +particular version of Jetty (currently 9.2). To use the native Jetty +you need to add the native wiremock dependencies and exclude the +Spring Boot container if there is one.

+
+
+
+
+

Generating Stubs using RestDocs

+
+
+

Spring RestDocs can be +used to generate documentation (e.g. in asciidoctor format) for an +HTTP API with Spring MockMvc or RestEasy. At the same time as you +generate documentation for your API, you can also generate WireMock +stubs, by using Spring Cloud Contract WireMock. Just write your normal +RestDocs test cases and use @AutoConfigureRestDocs to have stubs +automatically in the restdocs output directory. For example:

+
+
+
+
@RunWith(SpringRunner.class)
+@SpringBootTest
+@AutoConfigureRestDocs(outputDir = "target/snippets")
+@AutoConfigureMockMvc
+public class ApplicationTests {
+
+	@Autowired
+	private MockMvc mockMvc;
+
+	@Test
+	public void contextLoads() throws Exception {
+		mockMvc.perform(get("/resource"))
+				.andExpect(content().string("Hello World"))
+				.andDo(document("resource"));
+	}
+}
+
+
+
+

From this test will be generated a WireMock stub at +"target/snippets/stubs/resource.json". It matches all GET requests to +the "/resource" path.

+
+
+

Without any additional configuration this will create a stub with a +request matcher for the HTTP method and all headers except "host" and +"content-length". To match the request more precisely, for example to +match the body of a POST or PUT, we need to explicitly create a +request matcher. This will do two things: 1) create a stub that only +matches the way you specify, 2) assert that the request in the test +case also matches the same conditions.

+
+
+

The main entry point for this is WireMockRestDocs.verify() which can +be used as a substitute for the document() convenience method. For +example:

+
+
+
+
@RunWith(SpringRunner.class)
+@SpringBootTest
+@AutoConfigureRestDocs(outputDir = "target/snippets")
+@AutoConfigureMockMvc
+public class ApplicationTests {
+
+	@Autowired
+	private MockMvc mockMvc;
+
+	@Test
+	public void contextLoads() throws Exception {
+		mockMvc.perform(post("/resource")
+                .content("{\"id\":\"123456\",\"message\":\"Hello World\"}"))
+				.andExpect(status.isOk())
+				.andDo(verify().jsonPath("$.id")
+                        .stub("resource"));
+	}
+}
+
+
+
+

So this contract is saying: any valid POST with an "id" field will get +back an the same response as in this test. You can chain together +calls to .jsonPath() to add additional matchers. The +JayWay documentation can help you +to get up to speed with JSON Path if it is unfamiliar to you.

+
+
+

Instead of the jsonPath and contentType convenience methods, you +can also use the WireMock APIs to verify the request matches the +created stub. Example:

+
+
+
+
@Test
+public void contextLoads() throws Exception {
+	mockMvc.perform(post("/resource")
+               .content("{\"id\":\"123456\",\"message\":\"Hello World\"}"))
+			.andExpect(status.isOk())
+			.andDo(verify()
+					.wiremock(WireMock.post(
+						urlPathEquals("/resource"))
+						.withRequestBody(matchingJsonPath("$.id"))
+                       .stub("post-resource"));
+}
+
+
+
+

The WireMock API is rich - you can match headers, query parameters, +and request body by regex as well as by json path - so this can useful +to create stubs with a wider range of parameters. The above example +will generate a stub something like this:

+
+
+
post-resource.json
+
+
{
+  "request" : {
+    "url" : "/resource",
+    "method" : "POST",
+    "bodyPatterns" : [ {
+      "matchesJsonPath" : "$.id"
+    }]
+  },
+  "response" : {
+    "status" : 200,
+    "body" : "Hello World",
+    "headers" : {
+      "X-Application-Context" : "application:-1",
+      "Content-Type" : "text/plain"
+    }
+  }
+}
+
+
+
+ + + + + +
+
Note
+
+You can use either the wiremock() method or the jsonPath() +and contentType() methods to create request matchers, but not both. +
+
+
+

On the consumer side, assuming the resource.json generated above is +available on the classpath, you can create a stub using WireMock in a +number of different ways, including as described above using +@AutoConfigureWireMock(stubs="classpath:resource.json").

+
+
+
+
+ + \ No newline at end of file diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/complex-content.html b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/complex-content.html new file mode 100644 index 00000000..3feeeefe --- /dev/null +++ b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/complex-content.html @@ -0,0 +1,260 @@ + + + + + + + + + Spring Cloud Contract Verifier Maven Plugin – + + + + + + + + + + + + + + + + + Fork me on GitHub + + + + + + + + + +
+ + + + + +
+
+ +
+ + +
+ +
+

More Complex Plugin Configuration

+
+
+

Sample more complex configuration for Java Project with JUnit tests.

+
+
+

Project configuration for Spring Cloud Contract Verifier with JUnit tests and stub publishing

+
+
+
Unresolved directive in <stdin> - include::{root_folder}/src/test/projects/complex-configuration/pom.xml[tags=plugin]
+
+
+
+
+

Base Test class

+
+
+
Unresolved directive in <stdin> - include::{root_folder}/src/test/projects/complex-configuration/src/test/java/com/blogspot/toomuchcoding/frauddetection/BaseAccurest.java[]
+
+
+
+
+

Sample additional matcher

+
+
+
Unresolved directive in <stdin> - include::{root_folder}/src/test/projects/complex-configuration/src/test/java/com/blogspot/toomuchcoding/frauddetection/matchers/CustomMatchers.java[]
+
+
+
+
+

Sample contract using matcher

+
+
+
Unresolved directive in <stdin> - include::{root_folder}/src/test/projects/complex-configuration/src/test/contracts/shouldMarkClientAsNotFraud.groovy[]
+
+
+
+ +
+
+
+
+
+ +
+ +
+
+
+

Copyright © 2016 + Spring. + All rights reserved. +

+
+ + +
+
+ + diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/complex.html b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/complex.html new file mode 100644 index 00000000..3df11086 --- /dev/null +++ b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/complex.html @@ -0,0 +1,393 @@ + + + + + + + + + Spring Cloud Contract Verifier Maven Plugin – + + + + + + + + + + + + + + + + + Fork me on GitHub + + + + + + + + + +
+ + + + + +
+
+ +
+ + +
+ +
+

More Complex Plugin Configuration

+
+
+

Sample more complex configuration for Java Project with JUnit tests.

+
+
+

Project configuration for Spring Cloud Contract Verifier with JUnit tests and stub publishing

+
+
+
            <plugin>
+                <groupId>org.springframework.cloud</groupId>
+                <artifactId>spring-cloud-contract-maven-plugin</artifactId>
+                <version>${spring-cloud-verifier-plugin.version}</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>convert</goal>
+                            <goal>generateStubs</goal>
+                            <goal>generateTests</goal>
+                        </goals>
+                        <configuration>
+                            <contractsDirectory>src/test/accurest</contractsDirectory>
+                            <basePackageForTests>com.blogspot.toomuchcoding.frauddetection</basePackageForTests>
+                            <testMode>MOCKMVC</testMode>
+                            <testFramework>JUNIT</testFramework>
+                            <classifier>stubs</classifier>
+                            <nameSuffixForTests>Test</nameSuffixForTests>
+                            <ruleClassForTests>org.junit.rules.ErrorCollector</ruleClassForTests>
+                            <staticImports>
+                                <staticImport>com.blogspot.toomuchcoding.frauddetection.matchers.CustomMatchers.*</staticImport>
+                            </staticImports>
+                            <imports>
+                                <import>com.blogspot.toomuchcoding.frauddetection.matchers.CustomMatchers</import>
+                            </imports>
+                            <ignoredFiles>
+                                <ignoredFile>broken**</ignoredFile>
+                            </ignoredFiles>
+                            <excludedFiles>
+                                <param>shouldMarkClientAsFraud.groovy</param>
+                            </excludedFiles>
+                        </configuration>
+                    </execution>
+                </executions>
+                <configuration>
+                    <baseClassForTests>com.blogspot.toomuchcoding.frauddetection.BaseAccurest</baseClassForTests>
+                </configuration>
+            </plugin>
+
+
+
+
+

Base Test class

+
+
+
/**
+ *
+ *  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
+ *
+ *       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 com.blogspot.toomuchcoding.frauddetection;
+
+import com.jayway.restassured.module.mockmvc.RestAssuredMockMvc;
+
+import org.junit.Before;
+
+public class BaseAccurest {
+
+        @Before
+        public void setup() {
+                RestAssuredMockMvc.standaloneSetup(new FraudDetectionController());
+        }
+
+}
+
+
+
+
+

Sample additional matcher

+
+
+
/**
+ *
+ *  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
+ *
+ *       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 com.blogspot.toomuchcoding.frauddetection.matchers;
+
+import org.junit.Assert;
+
+public class CustomMatchers {
+
+        public static void assertThatRejectionReasonIsNull(String rejectionReason) {
+                Assert.assertNull(rejectionReason);
+        }
+
+}
+
+
+
+
+

Sample contract using matcher

+
+
+
/**
+ *
+ *  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
+ *
+ *       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.
+ */
+org.springframework.cloud.contract.spec.Contract.make {
+                                request {
+                                        method 'PUT'
+                                        url '/fraudcheck'
+                                        body("""
+                                                {
+                                                "clientPesel":"${value(consumer(regex('[0-9]{10}')), producer('1234567890'))}",
+                                                "loanAmount":123.123
+                                                }
+                                        """
+                                        )
+                                        headers {
+                                                header('Content-Type', 'application/vnd.fraud.v1+json')
+                                        }
+
+                                }
+                        response {
+                                status 200
+                                body(
+                                                fraudCheckStatus: "OK",
+                                                rejectionReason: $(consumer(null), producer(execute('assertThatRejectionReasonIsNull($it)')))
+                                )
+                                headers {
+                                         header('Content-Type': 'application/vnd.fraud.v1+json')
+                                }
+                        }
+
+}
+
+
+
+ +
+
+
+
+
+ +
+ +
+
+
+

Copyright © 2016 + Spring. + All rights reserved. +

+
+ + +
+
+ + diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/css/apache-maven-fluido-1.5.min.css b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/css/apache-maven-fluido-1.5.min.css new file mode 100644 index 00000000..38762711 --- /dev/null +++ b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/css/apache-maven-fluido-1.5.min.css @@ -0,0 +1,9 @@ +/*! + * Bootstrap v2.3.2 + * + * Copyright 2013 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world by @mdo and @fat. + */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}a:hover,a:active{outline:0}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{width:auto\9;height:auto;max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}#map_canvas img,.google-maps img{max-width:none}button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle}button,input{*overflow:visible;line-height:normal}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}button,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}label,select,button,input[type="button"],input[type="reset"],input[type="submit"],input[type="radio"],input[type="checkbox"]{cursor:pointer}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}textarea{overflow:auto;vertical-align:top}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:20px;color:#333;background-color:#fff}a{color:#08c;text-decoration:none}a:hover,a:focus{color:#005580;text-decoration:underline}.img-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.1);box-shadow:0 1px 3px rgba(0,0,0,0.1)}.img-circle{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px}.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.span12{width:940px}.span11{width:860px}.span10{width:780px}.span9{width:700px}.span8{width:620px}.span7{width:540px}.span6{width:460px}.span5{width:380px}.span4{width:300px}.span3{width:220px}.span2{width:140px}.span1{width:60px}.offset12{margin-left:980px}.offset11{margin-left:900px}.offset10{margin-left:820px}.offset9{margin-left:740px}.offset8{margin-left:660px}.offset7{margin-left:580px}.offset6{margin-left:500px}.offset5{margin-left:420px}.offset4{margin-left:340px}.offset3{margin-left:260px}.offset2{margin-left:180px}.offset1{margin-left:100px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.127659574468085%;*margin-left:2.074468085106383%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.127659574468085%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%}.row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%}.row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%}.row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%}.row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%}.row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%}.row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%}.row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%}.row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%}.row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%}.row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%}.row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%}.row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%}.row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%}.row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%}.row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%}.row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%}.row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%}.row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%}.row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%}.row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%}.row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%}.row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%}.row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%}.row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%}.row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%}.row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%}.row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%}.row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%}.row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%}.row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%}.row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%}.row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%}.row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%}.row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%}[class*="span"].hide,.row-fluid [class*="span"].hide{display:none}[class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right}.container{margin-right:auto;margin-left:auto;*zoom:1}.container:before,.container:after{display:table;line-height:0;content:""}.container:after{clear:both}.container-fluid{padding-right:20px;padding-left:20px;*zoom:1}.container-fluid:before,.container-fluid:after{display:table;line-height:0;content:""}.container-fluid:after{clear:both}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:21px;font-weight:200;line-height:30px}small{font-size:85%}strong{font-weight:bold}em{font-style:italic}cite{font-style:normal}.muted{color:#999}a.muted:hover,a.muted:focus{color:#808080}.text-warning{color:#c09853}a.text-warning:hover,a.text-warning:focus{color:#a47e3c}.text-error{color:#b94a48}a.text-error:hover,a.text-error:focus{color:#953b39}.text-info{color:#3a87ad}a.text-info:hover,a.text-info:focus{color:#2d6987}.text-success{color:#468847}a.text-success:hover,a.text-success:focus{color:#356635}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit;text-rendering:optimizelegibility}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#999}h1,h2,h3{line-height:40px}h1{font-size:38.5px}h2{font-size:31.5px}h3{font-size:24.5px}h4{font-size:17.5px}h5{font-size:14px}h6{font-size:11.9px}h1 small{font-size:24.5px}h2 small{font-size:17.5px}h3 small{font-size:14px}h4 small{font-size:14px}.page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eee}ul,ol{padding:0;margin:0 0 10px 25px}ul ul,ul ol,ol ol,ol ul{margin-bottom:0}li{line-height:20px}ul.unstyled,ol.unstyled{margin-left:0;list-style:none}ul.inline,ol.inline{margin-left:0;list-style:none}ul.inline>li,ol.inline>li{display:inline-block;*display:inline;padding-right:5px;padding-left:5px;*zoom:1}dl{margin-bottom:20px}dt,dd{line-height:20px}dt{font-weight:bold}dd{margin-left:10px}.dl-horizontal{*zoom:1}.dl-horizontal:before,.dl-horizontal:after{display:table;line-height:0;content:""}.dl-horizontal:after{clear:both}.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}hr{margin:20px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{margin-bottom:0;font-size:17.5px;font-weight:300;line-height:1.25}blockquote small{display:block;line-height:20px;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}blockquote.pull-right small:before{content:''}blockquote.pull-right small:after{content:'\00A0 \2014'}q:before,q:after,blockquote:before,blockquote:after{content:""}address{display:block;margin-bottom:20px;font-style:normal;line-height:20px}code,pre{padding:0 3px 2px;font-family:Monaco,Menlo,Consolas,"Courier New",monospace;font-size:12px;color:#333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}code{padding:2px 4px;color:#d14;white-space:nowrap;background-color:#f7f7f9;border:1px solid #e1e1e8}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}pre.prettyprint{margin-bottom:20px}pre code{padding:0;color:inherit;white-space:pre;white-space:pre-wrap;background-color:transparent;border:0}.pre-scrollable{max-height:340px;overflow-y:scroll}form{margin:0 0 20px}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:40px;color:#333;border:0;border-bottom:1px solid #e5e5e5}legend small{font-size:15px;color:#999}label,input,button,select,textarea{font-size:14px;font-weight:normal;line-height:20px}input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}label{display:block;margin-bottom:5px}select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:10px;font-size:14px;line-height:20px;color:#555;vertical-align:middle;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}input,textarea,.uneditable-input{width:206px}textarea{height:auto}textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#fff;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border linear .2s,box-shadow linear .2s;-moz-transition:border linear .2s,box-shadow linear .2s;-o-transition:border linear .2s,box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82,168,236,0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6)}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;*margin-top:0;line-height:normal}input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto}select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px}select{width:220px;background-color:#fff;border:1px solid #ccc}select[multiple],select[size]{height:auto}select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.uneditable-input,.uneditable-textarea{color:#999;cursor:not-allowed;background-color:#fcfcfc;border-color:#ccc;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);box-shadow:inset 0 1px 2px rgba(0,0,0,0.025)}.uneditable-input{overflow:hidden;white-space:nowrap}.uneditable-textarea{width:auto;height:auto}input:-moz-placeholder,textarea:-moz-placeholder{color:#999}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999}.radio,.checkbox{min-height:20px;padding-left:20px}.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-20px}.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px}.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle}.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px}.input-mini{width:60px}.input-small{width:90px}.input-medium{width:150px}.input-large{width:210px}.input-xlarge{width:270px}.input-xxlarge{width:530px}input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0}.input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:926px}input.span11,textarea.span11,.uneditable-input.span11{width:846px}input.span10,textarea.span10,.uneditable-input.span10{width:766px}input.span9,textarea.span9,.uneditable-input.span9{width:686px}input.span8,textarea.span8,.uneditable-input.span8{width:606px}input.span7,textarea.span7,.uneditable-input.span7{width:526px}input.span6,textarea.span6,.uneditable-input.span6{width:446px}input.span5,textarea.span5,.uneditable-input.span5{width:366px}input.span4,textarea.span4,.uneditable-input.span4{width:286px}input.span3,textarea.span3,.uneditable-input.span3{width:206px}input.span2,textarea.span2,.uneditable-input.span2{width:126px}input.span1,textarea.span1,.uneditable-input.span1{width:46px}.controls-row{*zoom:1}.controls-row:before,.controls-row:after{display:table;line-height:0;content:""}.controls-row:after{clear:both}.controls-row [class*="span"],.row-fluid .controls-row [class*="span"]{float:left}.controls-row .checkbox[class*="span"],.controls-row .radio[class*="span"]{padding-top:5px}input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eee}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent}.control-group.warning .control-label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853}.control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853}.control-group.warning input,.control-group.warning select,.control-group.warning textarea{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.control-group.error .control-label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48}.control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48}.control-group.error input,.control-group.error select,.control-group.error textarea{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.control-group.success .control-label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847}.control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847}.control-group.success input,.control-group.success select,.control-group.success textarea{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847}.control-group.info .control-label,.control-group.info .help-block,.control-group.info .help-inline{color:#3a87ad}.control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad}.control-group.info input,.control-group.info select,.control-group.info textarea{border-color:#3a87ad;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.info input:focus,.control-group.info select:focus,.control-group.info textarea:focus{border-color:#2d6987;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3}.control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad}input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#b94a48;border-color:#ee5f5b}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7}.form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1}.form-actions:before,.form-actions:after{display:table;line-height:0;content:""}.form-actions:after{clear:both}.help-block,.help-inline{color:#595959}.help-block{display:block;margin-bottom:10px}.help-inline{display:inline-block;*display:inline;padding-left:5px;vertical-align:middle;*zoom:1}.input-append,.input-prepend{display:inline-block;margin-bottom:10px;font-size:0;white-space:nowrap;vertical-align:middle}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input,.input-append .dropdown-menu,.input-prepend .dropdown-menu,.input-append .popover,.input-prepend .popover{font-size:14px}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:top;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2}.input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:14px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #fff;background-color:#eee;border:1px solid #ccc}.input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn,.input-append .btn-group>.dropdown-toggle,.input-prepend .btn-group>.dropdown-toggle{vertical-align:top;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546}.input-prepend .add-on,.input-prepend .btn{margin-right:-1px}.input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input,.input-append select,.input-append .uneditable-input{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input+.btn-group .btn:last-child,.input-append select+.btn-group .btn:last-child,.input-append .uneditable-input+.btn-group .btn:last-child{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append .add-on,.input-append .btn,.input-append .btn-group{margin-left:-1px}.input-append .add-on:last-child,.input-append .btn:last-child,.input-append .btn-group:last-child>.dropdown-toggle{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend.input-append input+.btn-group .btn,.input-prepend.input-append select+.btn-group .btn,.input-prepend.input-append .uneditable-input+.btn-group .btn{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append .btn-group:first-child{margin-left:0}input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.form-search .input-append .search-query,.form-search .input-prepend .search-query{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.form-search .input-append .search-query{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search .input-append .btn{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .search-query{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .btn{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;margin-bottom:0;vertical-align:middle;*zoom:1}.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none}.form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block}.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0}.form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle}.form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0}.control-group{margin-bottom:10px}legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate}.form-horizontal .control-group{margin-bottom:20px;*zoom:1}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;line-height:0;content:""}.form-horizontal .control-group:after{clear:both}.form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right}.form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0}.form-horizontal .controls:first-child{*padding-left:180px}.form-horizontal .help-block{margin-bottom:0}.form-horizontal input+.help-block,.form-horizontal select+.help-block,.form-horizontal textarea+.help-block,.form-horizontal .uneditable-input+.help-block,.form-horizontal .input-prepend+.help-block,.form-horizontal .input-append+.help-block{margin-top:10px}.form-horizontal .form-actions{padding-left:180px}table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}.table{width:100%;margin-bottom:20px}.table th,.table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #ddd}.table th{font-weight:bold}.table thead th{vertical-align:bottom}.table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0}.table tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed th,.table-condensed td{padding:4px 5px}.table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.table-bordered th,.table-bordered td{border-left:1px solid #ddd}.table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0}.table-bordered thead:first-child tr:first-child>th:first-child,.table-bordered tbody:first-child tr:first-child>td:first-child,.table-bordered tbody:first-child tr:first-child>th:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered thead:first-child tr:first-child>th:last-child,.table-bordered tbody:first-child tr:first-child>td:last-child,.table-bordered tbody:first-child tr:first-child>th:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-bordered thead:last-child tr:last-child>th:first-child,.table-bordered tbody:last-child tr:last-child>td:first-child,.table-bordered tbody:last-child tr:last-child>th:first-child,.table-bordered tfoot:last-child tr:last-child>td:first-child,.table-bordered tfoot:last-child tr:last-child>th:first-child{-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px}.table-bordered thead:last-child tr:last-child>th:last-child,.table-bordered tbody:last-child tr:last-child>td:last-child,.table-bordered tbody:last-child tr:last-child>th:last-child,.table-bordered tfoot:last-child tr:last-child>td:last-child,.table-bordered tfoot:last-child tr:last-child>th:last-child{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px}.table-bordered tfoot+tbody:last-child tr:last-child td:first-child{-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0;-moz-border-radius-bottomleft:0}.table-bordered tfoot+tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0;-moz-border-radius-bottomright:0}.table-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-striped tbody>tr:nth-child(odd)>td,.table-striped tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover tbody tr:hover>td,.table-hover tbody tr:hover>th{background-color:#f5f5f5}table td[class*="span"],table th[class*="span"],.row-fluid table td[class*="span"],.row-fluid table th[class*="span"]{display:table-cell;float:none;margin-left:0}.table td.span1,.table th.span1{float:none;width:44px;margin-left:0}.table td.span2,.table th.span2{float:none;width:124px;margin-left:0}.table td.span3,.table th.span3{float:none;width:204px;margin-left:0}.table td.span4,.table th.span4{float:none;width:284px;margin-left:0}.table td.span5,.table th.span5{float:none;width:364px;margin-left:0}.table td.span6,.table th.span6{float:none;width:444px;margin-left:0}.table td.span7,.table th.span7{float:none;width:524px;margin-left:0}.table td.span8,.table th.span8{float:none;width:604px;margin-left:0}.table td.span9,.table th.span9{float:none;width:684px;margin-left:0}.table td.span10,.table th.span10{float:none;width:764px;margin-left:0}.table td.span11,.table th.span11{float:none;width:844px;margin-left:0}.table td.span12,.table th.span12{float:none;width:924px;margin-left:0}.table tbody tr.success>td{background-color:#dff0d8}.table tbody tr.error>td{background-color:#f2dede}.table tbody tr.warning>td{background-color:#fcf8e3}.table tbody tr.info>td{background-color:#d9edf7}.table-hover tbody tr.success:hover>td{background-color:#d0e9c6}.table-hover tbody tr.error:hover>td{background-color:#ebcccc}.table-hover tbody tr.warning:hover>td{background-color:#faf2cc}.table-hover tbody tr.info:hover>td{background-color:#c4e3f3}[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;margin-top:1px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat}.icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:focus>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>li>a:focus>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:focus>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"],.dropdown-submenu:focus>a>[class*=" icon-"]{background-image:url("../img/glyphicons-halflings-white.png")}.icon-glass{background-position:0 0}.icon-music{background-position:-24px 0}.icon-search{background-position:-48px 0}.icon-envelope{background-position:-72px 0}.icon-heart{background-position:-96px 0}.icon-star{background-position:-120px 0}.icon-star-empty{background-position:-144px 0}.icon-user{background-position:-168px 0}.icon-film{background-position:-192px 0}.icon-th-large{background-position:-216px 0}.icon-th{background-position:-240px 0}.icon-th-list{background-position:-264px 0}.icon-ok{background-position:-288px 0}.icon-remove{background-position:-312px 0}.icon-zoom-in{background-position:-336px 0}.icon-zoom-out{background-position:-360px 0}.icon-off{background-position:-384px 0}.icon-signal{background-position:-408px 0}.icon-cog{background-position:-432px 0}.icon-trash{background-position:-456px 0}.icon-home{background-position:0 -24px}.icon-file{background-position:-24px -24px}.icon-time{background-position:-48px -24px}.icon-road{background-position:-72px -24px}.icon-download-alt{background-position:-96px -24px}.icon-download{background-position:-120px -24px}.icon-upload{background-position:-144px -24px}.icon-inbox{background-position:-168px -24px}.icon-play-circle{background-position:-192px -24px}.icon-repeat{background-position:-216px -24px}.icon-refresh{background-position:-240px -24px}.icon-list-alt{background-position:-264px -24px}.icon-lock{background-position:-287px -24px}.icon-flag{background-position:-312px -24px}.icon-headphones{background-position:-336px -24px}.icon-volume-off{background-position:-360px -24px}.icon-volume-down{background-position:-384px -24px}.icon-volume-up{background-position:-408px -24px}.icon-qrcode{background-position:-432px -24px}.icon-barcode{background-position:-456px -24px}.icon-tag{background-position:0 -48px}.icon-tags{background-position:-25px -48px}.icon-book{background-position:-48px -48px}.icon-bookmark{background-position:-72px -48px}.icon-print{background-position:-96px -48px}.icon-camera{background-position:-120px -48px}.icon-font{background-position:-144px -48px}.icon-bold{background-position:-167px -48px}.icon-italic{background-position:-192px -48px}.icon-text-height{background-position:-216px -48px}.icon-text-width{background-position:-240px -48px}.icon-align-left{background-position:-264px -48px}.icon-align-center{background-position:-288px -48px}.icon-align-right{background-position:-312px -48px}.icon-align-justify{background-position:-336px -48px}.icon-list{background-position:-360px -48px}.icon-indent-left{background-position:-384px -48px}.icon-indent-right{background-position:-408px -48px}.icon-facetime-video{background-position:-432px -48px}.icon-picture{background-position:-456px -48px}.icon-pencil{background-position:0 -72px}.icon-map-marker{background-position:-24px -72px}.icon-adjust{background-position:-48px -72px}.icon-tint{background-position:-72px -72px}.icon-edit{background-position:-96px -72px}.icon-share{background-position:-120px -72px}.icon-check{background-position:-144px -72px}.icon-move{background-position:-168px -72px}.icon-step-backward{background-position:-192px -72px}.icon-fast-backward{background-position:-216px -72px}.icon-backward{background-position:-240px -72px}.icon-play{background-position:-264px -72px}.icon-pause{background-position:-288px -72px}.icon-stop{background-position:-312px -72px}.icon-forward{background-position:-336px -72px}.icon-fast-forward{background-position:-360px -72px}.icon-step-forward{background-position:-384px -72px}.icon-eject{background-position:-408px -72px}.icon-chevron-left{background-position:-432px -72px}.icon-chevron-right{background-position:-456px -72px}.icon-plus-sign{background-position:0 -96px}.icon-minus-sign{background-position:-24px -96px}.icon-remove-sign{background-position:-48px -96px}.icon-ok-sign{background-position:-72px -96px}.icon-question-sign{background-position:-96px -96px}.icon-info-sign{background-position:-120px -96px}.icon-screenshot{background-position:-144px -96px}.icon-remove-circle{background-position:-168px -96px}.icon-ok-circle{background-position:-192px -96px}.icon-ban-circle{background-position:-216px -96px}.icon-arrow-left{background-position:-240px -96px}.icon-arrow-right{background-position:-264px -96px}.icon-arrow-up{background-position:-289px -96px}.icon-arrow-down{background-position:-312px -96px}.icon-share-alt{background-position:-336px -96px}.icon-resize-full{background-position:-360px -96px}.icon-resize-small{background-position:-384px -96px}.icon-plus{background-position:-408px -96px}.icon-minus{background-position:-433px -96px}.icon-asterisk{background-position:-456px -96px}.icon-exclamation-sign{background-position:0 -120px}.icon-gift{background-position:-24px -120px}.icon-leaf{background-position:-48px -120px}.icon-fire{background-position:-72px -120px}.icon-eye-open{background-position:-96px -120px}.icon-eye-close{background-position:-120px -120px}.icon-warning-sign{background-position:-144px -120px}.icon-plane{background-position:-168px -120px}.icon-calendar{background-position:-192px -120px}.icon-random{width:16px;background-position:-216px -120px}.icon-comment{background-position:-240px -120px}.icon-magnet{background-position:-264px -120px}.icon-chevron-up{background-position:-288px -120px}.icon-chevron-down{background-position:-313px -119px}.icon-retweet{background-position:-336px -120px}.icon-shopping-cart{background-position:-360px -120px}.icon-folder-close{width:16px;background-position:-384px -120px}.icon-folder-open{width:16px;background-position:-408px -120px}.icon-resize-vertical{background-position:-432px -119px}.icon-resize-horizontal{background-position:-456px -118px}.icon-hdd{background-position:0 -144px}.icon-bullhorn{background-position:-24px -144px}.icon-bell{background-position:-48px -144px}.icon-certificate{background-position:-72px -144px}.icon-thumbs-up{background-position:-96px -144px}.icon-thumbs-down{background-position:-120px -144px}.icon-hand-right{background-position:-144px -144px}.icon-hand-left{background-position:-168px -144px}.icon-hand-up{background-position:-192px -144px}.icon-hand-down{background-position:-216px -144px}.icon-circle-arrow-right{background-position:-240px -144px}.icon-circle-arrow-left{background-position:-264px -144px}.icon-circle-arrow-up{background-position:-288px -144px}.icon-circle-arrow-down{background-position:-312px -144px}.icon-globe{background-position:-336px -144px}.icon-wrench{background-position:-360px -144px}.icon-tasks{background-position:-384px -144px}.icon-filter{background-position:-408px -144px}.icon-briefcase{background-position:-432px -144px}.icon-fullscreen{background-position:-456px -144px}.dropup,.dropdown{position:relative}.dropdown-toggle{*margin-bottom:-3px}.dropdown-toggle:active,.open .dropdown-toggle{outline:0}.caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:""}.dropdown .caret{margin-top:8px;margin-left:2px}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus,.dropdown-submenu:hover>a,.dropdown-submenu:focus>a{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;outline:0;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:default;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open{*z-index:1000}.open>.dropdown-menu{display:block}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}.dropdown-submenu{position:relative}.dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px}.dropdown-submenu:hover>.dropdown-menu{display:block}.dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;-webkit-border-radius:5px 5px 5px 0;-moz-border-radius:5px 5px 5px 0;border-radius:5px 5px 5px 0}.dropdown-submenu>a:after{display:block;float:right;width:0;height:0;margin-top:5px;margin-right:-10px;border-color:transparent;border-left-color:#ccc;border-style:solid;border-width:5px 0 5px 5px;content:" "}.dropdown-submenu:hover>a:after{border-left-color:#fff}.dropdown-submenu.pull-left{float:none}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.dropdown .dropdown-menu .nav-header{padding-right:20px;padding-left:20px}.typeahead{z-index:1051;margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.fade{opacity:0;-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-moz-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.collapse.in{height:auto}.close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.btn{display:inline-block;*display:inline;padding:4px 12px;margin-bottom:0;*margin-left:.3em;font-size:14px;line-height:20px;color:#333;text-align:center;text-shadow:0 1px 1px rgba(255,255,255,0.75);vertical-align:middle;cursor:pointer;background-color:#f5f5f5;*background-color:#e6e6e6;background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-repeat:repeat-x;border:1px solid #ccc;*border:0;border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);*zoom:1;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn:hover,.btn:focus,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333;background-color:#e6e6e6;*background-color:#d9d9d9}.btn:active,.btn.active{background-color:#ccc \9}.btn:first-child{*margin-left:0}.btn:hover,.btn:focus{color:#333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn.disabled,.btn[disabled]{cursor:default;background-image:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-large{padding:11px 19px;font-size:17.5px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.btn-large [class^="icon-"],.btn-large [class*=" icon-"]{margin-top:4px}.btn-small{padding:2px 10px;font-size:11.9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.btn-small [class^="icon-"],.btn-small [class*=" icon-"]{margin-top:0}.btn-mini [class^="icon-"],.btn-mini [class*=" icon-"]{margin-top:-1px}.btn-mini{padding:0 6px;font-size:10.5px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255,255,255,0.75)}.btn-primary{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#006dcc;*background-color:#04c;background-image:-moz-linear-gradient(top,#08c,#04c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(to bottom,#08c,#04c);background-repeat:repeat-x;border-color:#04c #0044cc #002a80;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0044cc',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#fff;background-color:#04c;*background-color:#003bb3}.btn-primary:active,.btn-primary.active{background-color:#039 \9}.btn-warning{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#faa732;*background-color:#f89406;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;border-color:#f89406 #f89406 #ad6704;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#fff;background-color:#f89406;*background-color:#df8505}.btn-warning:active,.btn-warning.active{background-color:#c67605 \9}.btn-danger{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#da4f49;*background-color:#bd362f;background-image:-moz-linear-gradient(top,#ee5f5b,#bd362f);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#bd362f));background-image:-webkit-linear-gradient(top,#ee5f5b,#bd362f);background-image:-o-linear-gradient(top,#ee5f5b,#bd362f);background-image:linear-gradient(to bottom,#ee5f5b,#bd362f);background-repeat:repeat-x;border-color:#bd362f #bd362f #802420;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffbd362f',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#fff;background-color:#bd362f;*background-color:#a9302a}.btn-danger:active,.btn-danger.active{background-color:#942a25 \9}.btn-success{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#5bb75b;*background-color:#51a351;background-image:-moz-linear-gradient(top,#62c462,#51a351);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#51a351));background-image:-webkit-linear-gradient(top,#62c462,#51a351);background-image:-o-linear-gradient(top,#62c462,#51a351);background-image:linear-gradient(to bottom,#62c462,#51a351);background-repeat:repeat-x;border-color:#51a351 #51a351 #387038;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff51a351',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#fff;background-color:#51a351;*background-color:#499249}.btn-success:active,.btn-success.active{background-color:#408140 \9}.btn-info{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#49afcd;*background-color:#2f96b4;background-image:-moz-linear-gradient(top,#5bc0de,#2f96b4);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#2f96b4));background-image:-webkit-linear-gradient(top,#5bc0de,#2f96b4);background-image:-o-linear-gradient(top,#5bc0de,#2f96b4);background-image:linear-gradient(to bottom,#5bc0de,#2f96b4);background-repeat:repeat-x;border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff2f96b4',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#fff;background-color:#2f96b4;*background-color:#2a85a0}.btn-info:active,.btn-info.active{background-color:#24748c \9}.btn-inverse{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#363636;*background-color:#222;background-image:-moz-linear-gradient(top,#444,#222);background-image:-webkit-gradient(linear,0 0,0 100%,from(#444),to(#222));background-image:-webkit-linear-gradient(top,#444,#222);background-image:-o-linear-gradient(top,#444,#222);background-image:linear-gradient(to bottom,#444,#222);background-repeat:repeat-x;border-color:#222 #222222 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444',endColorstr='#ff222222',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-inverse:hover,.btn-inverse:focus,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#fff;background-color:#222;*background-color:#151515}.btn-inverse:active,.btn-inverse.active{background-color:#080808 \9}button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0}button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px}button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px}button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px}.btn-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-link{color:#08c;cursor:pointer;border-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-link:hover,.btn-link:focus{color:#005580;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,.btn-link[disabled]:focus{color:#333;text-decoration:none}.btn-group{position:relative;display:inline-block;*display:inline;*margin-left:.3em;font-size:0;white-space:nowrap;vertical-align:middle;*zoom:1}.btn-group:first-child{*margin-left:0}.btn-group+.btn-group{margin-left:5px}.btn-toolbar{margin-top:10px;margin-bottom:10px;font-size:0}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group{margin-left:5px}.btn-group>.btn{position:relative;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group>.btn+.btn{margin-left:-1px}.btn-group>.btn,.btn-group>.dropdown-menu,.btn-group>.popover{font-size:14px}.btn-group>.btn-mini{font-size:10.5px}.btn-group>.btn-small{font-size:11.9px}.btn-group>.btn-large{font-size:17.5px}.btn-group>.btn:first-child{margin-left:0;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.btn-group>.btn.large:first-child{margin-left:0;-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{*padding-top:5px;padding-right:8px;*padding-bottom:5px;padding-left:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn-group>.btn-mini+.dropdown-toggle{*padding-top:2px;padding-right:5px;*padding-bottom:2px;padding-left:5px}.btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px}.btn-group>.btn-large+.dropdown-toggle{*padding-top:7px;padding-right:12px;*padding-bottom:7px;padding-left:12px}.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6}.btn-group.open .btn-primary.dropdown-toggle{background-color:#04c}.btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406}.btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f}.btn-group.open .btn-success.dropdown-toggle{background-color:#51a351}.btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4}.btn-group.open .btn-inverse.dropdown-toggle{background-color:#222}.btn .caret{margin-top:8px;margin-left:0}.btn-large .caret{margin-top:6px}.btn-large .caret{border-top-width:5px;border-right-width:5px;border-left-width:5px}.btn-mini .caret,.btn-small .caret{margin-top:8px}.dropup .btn-large .caret{border-bottom-width:5px}.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#fff;border-bottom-color:#fff}.btn-group-vertical{display:inline-block;*display:inline;*zoom:1}.btn-group-vertical>.btn{display:block;float:none;max-width:100%;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group-vertical>.btn+.btn{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:first-child{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.btn-group-vertical>.btn:last-child{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.btn-group-vertical>.btn-large:first-child{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0}.btn-group-vertical>.btn-large:last-child{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.alert{padding:8px 35px 8px 14px;margin-bottom:20px;text-shadow:0 1px 0 rgba(255,255,255,0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.alert,.alert h4{color:#c09853}.alert h4{margin:0}.alert .close{position:relative;top:-2px;right:-21px;line-height:20px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-success h4{color:#468847}.alert-danger,.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-danger h4,.alert-error h4{color:#b94a48}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-info h4{color:#3a87ad}.alert-block{padding-top:14px;padding-bottom:14px}.alert-block>p,.alert-block>ul{margin-bottom:0}.alert-block p+p{margin-top:5px}.nav{margin-bottom:20px;margin-left:0;list-style:none}.nav>li>a{display:block}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li>a>img{max-width:none}.nav>.pull-right{float:right}.nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999;text-shadow:0 1px 0 rgba(255,255,255,0.5);text-transform:uppercase}.nav li+.nav-header{margin-top:9px}.nav-list{padding-right:15px;padding-left:15px;margin-bottom:0}.nav-list>li>a,.nav-list .nav-header{margin-right:-15px;margin-left:-15px;text-shadow:0 1px 0 rgba(255,255,255,0.5)}.nav-list>li>a{padding:3px 15px}.nav-list>.active>a,.nav-list>.active>a:hover,.nav-list>.active>a:focus{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.2);background-color:#08c}.nav-list [class^="icon-"],.nav-list [class*=" icon-"]{margin-right:2px}.nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.nav-tabs,.nav-pills{*zoom:1}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;line-height:0;content:""}.nav-tabs:after,.nav-pills:after{clear:both}.nav-tabs>li,.nav-pills>li{float:left}.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{margin-bottom:-1px}.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover,.nav-tabs>li>a:focus{border-color:#eee #eeeeee #ddd}.nav-tabs>.active>a,.nav-tabs>.active>a:hover,.nav-tabs>.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.nav-pills>.active>a,.nav-pills>.active>a:hover,.nav-pills>.active>a:focus{color:#fff;background-color:#08c}.nav-stacked>li{float:none}.nav-stacked>li>a{margin-right:0}.nav-tabs.nav-stacked{border-bottom:0}.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-topleft:4px}.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomright:4px;-moz-border-radius-bottomleft:4px}.nav-tabs.nav-stacked>li>a:hover,.nav-tabs.nav-stacked>li>a:focus{z-index:2;border-color:#ddd}.nav-pills.nav-stacked>li>a{margin-bottom:3px}.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}.nav-tabs .dropdown-menu{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.nav-pills .dropdown-menu{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.nav .dropdown-toggle .caret{margin-top:6px;border-top-color:#08c;border-bottom-color:#08c}.nav .dropdown-toggle:hover .caret,.nav .dropdown-toggle:focus .caret{border-top-color:#005580;border-bottom-color:#005580}.nav-tabs .dropdown-toggle .caret{margin-top:8px}.nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.nav-tabs .active .dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.nav>.dropdown.active>a:hover,.nav>.dropdown.active>a:focus{cursor:pointer}.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover,.nav>li.dropdown.open.active>a:focus{color:#fff;background-color:#999;border-color:#999}.nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret,.nav li.dropdown.open a:focus .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1;filter:alpha(opacity=100)}.tabs-stacked .open>a:hover,.tabs-stacked .open>a:focus{border-color:#999}.tabbable{*zoom:1}.tabbable:before,.tabbable:after{display:table;line-height:0;content:""}.tabbable:after{clear:both}.tab-content{overflow:auto}.tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0}.tab-content>.tab-pane,.pill-content>.pill-pane{display:none}.tab-content>.active,.pill-content>.active{display:block}.tabs-below>.nav-tabs{border-top:1px solid #ddd}.tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0}.tabs-below>.nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.tabs-below>.nav-tabs>li>a:hover,.tabs-below>.nav-tabs>li>a:focus{border-top-color:#ddd;border-bottom-color:transparent}.tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover,.tabs-below>.nav-tabs>.active>a:focus{border-color:transparent #ddd #ddd #ddd}.tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none}.tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px}.tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd}.tabs-left>.nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.tabs-left>.nav-tabs>li>a:hover,.tabs-left>.nav-tabs>li>a:focus{border-color:#eee #dddddd #eee #eeeeee}.tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover,.tabs-left>.nav-tabs .active>a:focus{border-color:#ddd transparent #ddd #ddd;*border-right-color:#fff}.tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd}.tabs-right>.nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.tabs-right>.nav-tabs>li>a:hover,.tabs-right>.nav-tabs>li>a:focus{border-color:#eee #eeeeee #eee #dddddd}.tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover,.tabs-right>.nav-tabs .active>a:focus{border-color:#ddd #ddd #ddd transparent;*border-left-color:#fff}.nav>.disabled>a{color:#999}.nav>.disabled>a:hover,.nav>.disabled>a:focus{text-decoration:none;cursor:default;background-color:transparent}.navbar{*position:relative;*z-index:2;margin-bottom:20px;overflow:visible}.navbar-inner{min-height:40px;padding-right:20px;padding-left:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top,#fff,#f2f2f2);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#f2f2f2));background-image:-webkit-linear-gradient(top,#fff,#f2f2f2);background-image:-o-linear-gradient(top,#fff,#f2f2f2);background-image:linear-gradient(to bottom,#fff,#f2f2f2);background-repeat:repeat-x;border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff2f2f2',GradientType=0);*zoom:1;-webkit-box-shadow:0 1px 4px rgba(0,0,0,0.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,0.065);box-shadow:0 1px 4px rgba(0,0,0,0.065)}.navbar-inner:before,.navbar-inner:after{display:table;line-height:0;content:""}.navbar-inner:after{clear:both}.navbar .container{width:auto}.nav-collapse.collapse{height:auto;overflow:visible}.navbar .brand{display:block;float:left;padding:10px 20px 10px;margin-left:-20px;font-size:20px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff}.navbar .brand:hover,.navbar .brand:focus{text-decoration:none}.navbar-text{margin-bottom:0;line-height:40px;color:#777}.navbar-link{color:#777}.navbar-link:hover,.navbar-link:focus{color:#333}.navbar .divider-vertical{height:40px;margin:0 9px;border-right:1px solid #fff;border-left:1px solid #f2f2f2}.navbar .btn,.navbar .btn-group{margin-top:5px}.navbar .btn-group .btn,.navbar .input-prepend .btn,.navbar .input-append .btn,.navbar .input-prepend .btn-group,.navbar .input-append .btn-group{margin-top:0}.navbar-form{margin-bottom:0;*zoom:1}.navbar-form:before,.navbar-form:after{display:table;line-height:0;content:""}.navbar-form:after{clear:both}.navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px}.navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0}.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px}.navbar-form .input-append,.navbar-form .input-prepend{margin-top:5px;white-space:nowrap}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0}.navbar-search{position:relative;float:left;margin-top:5px;margin-bottom:0}.navbar-search .search-query{padding:4px 14px;margin-bottom:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.navbar-static-top{position:static;margin-bottom:0}.navbar-static-top .navbar-inner{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border-width:0 0 1px}.navbar-fixed-bottom .navbar-inner{border-width:1px 0 0}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-right:0;padding-left:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.navbar-fixed-top{top:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:0 1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 10px rgba(0,0,0,0.1);box-shadow:0 1px 10px rgba(0,0,0,0.1)}.navbar-fixed-bottom{bottom:0}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:0 -1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,0.1);box-shadow:0 -1px 10px rgba(0,0,0,0.1)}.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}.navbar .nav.pull-right{float:right;margin-right:0}.navbar .nav>li{float:left}.navbar .nav>li>a{float:none;padding:10px 15px 10px;color:#777;text-decoration:none;text-shadow:0 1px 0 #fff}.navbar .nav .dropdown-toggle .caret{margin-top:8px}.navbar .nav>li>a:focus,.navbar .nav>li>a:hover{color:#333;text-decoration:none;background-color:transparent}.navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);box-shadow:inset 0 3px 8px rgba(0,0,0,0.125)}.navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-right:5px;margin-left:5px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#ededed;*background-color:#e5e5e5;background-image:-moz-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f2f2f2),to(#e5e5e5));background-image:-webkit-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-o-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:linear-gradient(to bottom,#f2f2f2,#e5e5e5);background-repeat:repeat-x;border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2',endColorstr='#ffe5e5e5',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075)}.navbar .btn-navbar:hover,.navbar .btn-navbar:focus,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#fff;background-color:#e5e5e5;*background-color:#d9d9d9}.navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#ccc \9}.navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,0.25);-moz-box-shadow:0 1px 0 rgba(0,0,0,0.25);box-shadow:0 1px 0 rgba(0,0,0,0.25)}.btn-navbar .icon-bar+.icon-bar{margin-top:3px}.navbar .nav>li>.dropdown-menu:before{position:absolute;top:-7px;left:9px;display:inline-block;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-left:7px solid transparent;border-bottom-color:rgba(0,0,0,0.2);content:''}.navbar .nav>li>.dropdown-menu:after{position:absolute;top:-6px;left:10px;display:inline-block;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent;content:''}.navbar-fixed-bottom .nav>li>.dropdown-menu:before{top:auto;bottom:-7px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.navbar-fixed-bottom .nav>li>.dropdown-menu:after{top:auto;bottom:-6px;border-top:6px solid #fff;border-bottom:0}.navbar .nav li.dropdown>a:hover .caret,.navbar .nav li.dropdown>a:focus .caret{border-top-color:#333;border-bottom-color:#333}.navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{color:#555;background-color:#e5e5e5}.navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777;border-bottom-color:#777}.navbar .nav li.dropdown.open>.dropdown-toggle .caret,.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.navbar .pull-right>li>.dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar .pull-right>li>.dropdown-menu:before,.navbar .nav>li>.dropdown-menu.pull-right:before{right:12px;left:auto}.navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{right:13px;left:auto}.navbar .pull-right>li>.dropdown-menu .dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{right:100%;left:auto;margin-right:-1px;margin-left:0;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top,#222,#111);background-image:-webkit-gradient(linear,0 0,0 100%,from(#222),to(#111));background-image:-webkit-linear-gradient(top,#222,#111);background-image:-o-linear-gradient(top,#222,#111);background-image:linear-gradient(to bottom,#222,#111);background-repeat:repeat-x;border-color:#252525;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222',endColorstr='#ff111111',GradientType=0)}.navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover,.navbar-inverse .brand:focus,.navbar-inverse .nav>li>a:focus{color:#fff}.navbar-inverse .brand{color:#999}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#fff;background-color:#111}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover,.navbar-inverse .navbar-link:focus{color:#fff}.navbar-inverse .divider-vertical{border-right-color:#222;border-left-color:#111}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{color:#fff;background-color:#111}.navbar-inverse .nav li.dropdown>a:hover .caret,.navbar-inverse .nav li.dropdown>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-search .search-query{color:#fff;background-color:#515151;border-color:#111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333;text-shadow:0 1px 0 #fff;background-color:#fff;border:0;outline:0;-webkit-box-shadow:0 0 3px rgba(0,0,0,0.15);-moz-box-shadow:0 0 3px rgba(0,0,0,0.15);box-shadow:0 0 3px rgba(0,0,0,0.15)}.navbar-inverse .btn-navbar{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e0e0e;*background-color:#040404;background-image:-moz-linear-gradient(top,#151515,#040404);background-image:-webkit-gradient(linear,0 0,0 100%,from(#151515),to(#040404));background-image:-webkit-linear-gradient(top,#151515,#040404);background-image:-o-linear-gradient(top,#151515,#040404);background-image:linear-gradient(to bottom,#151515,#040404);background-repeat:repeat-x;border-color:#040404 #040404 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515',endColorstr='#ff040404',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar:focus,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#fff;background-color:#040404;*background-color:#000}.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000 \9}.breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.breadcrumb>li{display:inline-block;*display:inline;text-shadow:0 1px 0 #fff;*zoom:1}.breadcrumb>li>.divider{padding:0 5px;color:#ccc}.breadcrumb>.active{color:#999}.pagination{margin:20px 0}.pagination ul{display:inline-block;*display:inline;margin-bottom:0;margin-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*zoom:1;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.pagination ul>li{display:inline}.pagination ul>li>a,.pagination ul>li>span{float:left;padding:4px 12px;line-height:20px;text-decoration:none;background-color:#fff;border:1px solid #ddd;border-left-width:0}.pagination ul>li>a:hover,.pagination ul>li>a:focus,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#f5f5f5}.pagination ul>.active>a,.pagination ul>.active>span{color:#999;cursor:default}.pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover,.pagination ul>.disabled>a:focus{color:#999;cursor:default;background-color:transparent}.pagination ul>li:first-child>a,.pagination ul>li:first-child>span{border-left-width:1px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.pagination ul>li:last-child>a,.pagination ul>li:last-child>span{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.pagination-centered{text-align:center}.pagination-right{text-align:right}.pagination-large ul>li>a,.pagination-large ul>li>span{padding:11px 19px;font-size:17.5px}.pagination-large ul>li:first-child>a,.pagination-large ul>li:first-child>span{-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.pagination-large ul>li:last-child>a,.pagination-large ul>li:last-child>span{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.pagination-mini ul>li:first-child>a,.pagination-small ul>li:first-child>a,.pagination-mini ul>li:first-child>span,.pagination-small ul>li:first-child>span{-webkit-border-bottom-left-radius:3px;border-bottom-left-radius:3px;-webkit-border-top-left-radius:3px;border-top-left-radius:3px;-moz-border-radius-bottomleft:3px;-moz-border-radius-topleft:3px}.pagination-mini ul>li:last-child>a,.pagination-small ul>li:last-child>a,.pagination-mini ul>li:last-child>span,.pagination-small ul>li:last-child>span{-webkit-border-top-right-radius:3px;border-top-right-radius:3px;-webkit-border-bottom-right-radius:3px;border-bottom-right-radius:3px;-moz-border-radius-topright:3px;-moz-border-radius-bottomright:3px}.pagination-small ul>li>a,.pagination-small ul>li>span{padding:2px 10px;font-size:11.9px}.pagination-mini ul>li>a,.pagination-mini ul>li>span{padding:0 6px;font-size:10.5px}.pager{margin:20px 0;text-align:center;list-style:none;*zoom:1}.pager:before,.pager:after{display:table;line-height:0;content:""}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#f5f5f5}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;cursor:default;background-color:#fff}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop,.modal-backdrop.fade.in{opacity:.8;filter:alpha(opacity=80)}.modal{position:fixed;top:10%;left:50%;z-index:1050;width:560px;margin-left:-280px;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;outline:0;-webkit-box-shadow:0 3px 7px rgba(0,0,0,0.3);-moz-box-shadow:0 3px 7px rgba(0,0,0,0.3);box-shadow:0 3px 7px rgba(0,0,0,0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box}.modal.fade{top:-25%;-webkit-transition:opacity .3s linear,top .3s ease-out;-moz-transition:opacity .3s linear,top .3s ease-out;-o-transition:opacity .3s linear,top .3s ease-out;transition:opacity .3s linear,top .3s ease-out}.modal.fade.in{top:10%}.modal-header{padding:9px 15px;border-bottom:1px solid #eee}.modal-header .close{margin-top:2px}.modal-header h3{margin:0;line-height:30px}.modal-body{position:relative;max-height:400px;padding:15px;overflow-y:auto}.modal-form{margin-bottom:0}.modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;*zoom:1;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff}.modal-footer:before,.modal-footer:after{display:table;line-height:0;content:""}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.tooltip{position:absolute;z-index:1030;display:block;font-size:11px;line-height:1.4;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.8;filter:alpha(opacity=80)}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.popover-title:empty{display:none}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0}.thumbnails{margin-left:-20px;list-style:none;*zoom:1}.thumbnails:before,.thumbnails:after{display:table;line-height:0;content:""}.thumbnails:after{clear:both}.row-fluid .thumbnails{margin-left:0}.thumbnails>li{float:left;margin-bottom:20px;margin-left:20px}.thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.055);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.055);box-shadow:0 1px 3px rgba(0,0,0,0.055);-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}a.thumbnail:hover,a.thumbnail:focus{border-color:#08c;-webkit-box-shadow:0 1px 4px rgba(0,105,214,0.25);-moz-box-shadow:0 1px 4px rgba(0,105,214,0.25);box-shadow:0 1px 4px rgba(0,105,214,0.25)}.thumbnail>img{display:block;max-width:100%;margin-right:auto;margin-left:auto}.thumbnail .caption{padding:9px;color:#555}.media,.media-body{overflow:hidden;*overflow:visible;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{margin-left:0;list-style:none}.label,.badge{display:inline-block;padding:2px 4px;font-size:11.844px;font-weight:bold;line-height:14px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);white-space:nowrap;vertical-align:baseline;background-color:#999}.label{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.badge{padding-right:9px;padding-left:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px}.label:empty,.badge:empty{display:none}a.label:hover,a.label:focus,a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}.label-important,.badge-important{background-color:#b94a48}.label-important[href],.badge-important[href]{background-color:#953b39}.label-warning,.badge-warning{background-color:#f89406}.label-warning[href],.badge-warning[href]{background-color:#c67605}.label-success,.badge-success{background-color:#468847}.label-success[href],.badge-success[href]{background-color:#356635}.label-info,.badge-info{background-color:#3a87ad}.label-info[href],.badge-info[href]{background-color:#2d6987}.label-inverse,.badge-inverse{background-color:#333}.label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a}.btn .label,.btn .badge{position:relative;top:-1px}.btn-mini .label,.btn-mini .badge{top:0}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f7f7f7;background-image:-moz-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f5f5f5),to(#f9f9f9));background-image:-webkit-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-o-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:linear-gradient(to bottom,#f5f5f5,#f9f9f9);background-repeat:repeat-x;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#fff9f9f9',GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress .bar{float:left;width:0;height:100%;font-size:12px;color:#fff;text-align:center;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top,#149bdf,#0480be);background-image:-webkit-gradient(linear,0 0,0 100%,from(#149bdf),to(#0480be));background-image:-webkit-linear-gradient(top,#149bdf,#0480be);background-image:-o-linear-gradient(top,#149bdf,#0480be);background-image:linear-gradient(to bottom,#149bdf,#0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf',endColorstr='#ff0480be',GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width .6s ease;-moz-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15)}.progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px}.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-danger .bar,.progress .bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top,#ee5f5b,#c43c35);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#c43c35));background-image:-webkit-linear-gradient(top,#ee5f5b,#c43c35);background-image:-o-linear-gradient(top,#ee5f5b,#c43c35);background-image:linear-gradient(to bottom,#ee5f5b,#c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffc43c35',GradientType=0)}.progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-success .bar,.progress .bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top,#62c462,#57a957);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#57a957));background-image:-webkit-linear-gradient(top,#62c462,#57a957);background-image:-o-linear-gradient(top,#62c462,#57a957);background-image:linear-gradient(to bottom,#62c462,#57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff57a957',GradientType=0)}.progress-success.progress-striped .bar,.progress-striped .bar-success{background-color:#62c462;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-info .bar,.progress .bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top,#5bc0de,#339bb9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#339bb9));background-image:-webkit-linear-gradient(top,#5bc0de,#339bb9);background-image:-o-linear-gradient(top,#5bc0de,#339bb9);background-image:linear-gradient(to bottom,#5bc0de,#339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff339bb9',GradientType=0)}.progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-warning .bar,.progress .bar-warning{background-color:#faa732;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0)}.progress-warning.progress-striped .bar,.progress-striped .bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.accordion{margin-bottom:20px}.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.accordion-heading{border-bottom:0}.accordion-heading .accordion-toggle{display:block;padding:8px 15px}.accordion-toggle{cursor:pointer}.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5}.carousel{position:relative;margin-bottom:20px;line-height:1}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-moz-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#fff;text-align:center;background:#222;border:3px solid #fff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:.5;filter:alpha(opacity=50)}.carousel-control.right{right:15px;left:auto}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-indicators{position:absolute;top:15px;right:15px;z-index:5;margin:0;list-style:none}.carousel-indicators li{display:block;float:left;width:10px;height:10px;margin-left:5px;text-indent:-999px;background-color:#ccc;background-color:rgba(255,255,255,0.25);border-radius:5px}.carousel-indicators .active{background-color:#fff}.carousel-caption{position:absolute;right:0;bottom:0;left:0;padding:15px;background:#333;background:rgba(0,0,0,0.75)}.carousel-caption h4,.carousel-caption p{line-height:20px;color:#fff}.carousel-caption h4{margin:0 0 5px}.carousel-caption p{margin-bottom:0}.hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:30px;color:inherit;background-color:#eee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;color:inherit}.hero-unit li{line-height:30px}.pull-right{float:right}.pull-left{float:left}.hide{display:none}.show{display:block}.invisible{visibility:hidden}.affix{position:fixed}.clear{clear:both;visibility:hidden}.clear hr{display:none}.section p,.section p,.section dt,.section dt{margin-right:7px;margin-left:7px}#ohloh{margin-bottom:10px}#poweredBy{text-align:center}a.externalLink{padding-right:18px}a.newWindow{background:url('../images/window-new.png') right center no-repeat;padding-right:18px}a.externalLink[href^=http]{background:url('../images/internet-web-browser.png') right center no-repeat;padding-right:18px}a.externalLink[href$=".asc"]{background:url('../images/accessories-text-editor.png') right center no-repeat;padding-right:18px}a.externalLink[href$=".jpg"],a.externalLink[href$=".jpeg"],a.externalLink[href$=".gif"],a.externalLink[href$=".png"]{background:url('../images/image-x-generic.png') right center no-repeat;padding-right:18px}a.externalLink[href$=".tar.gz"],a.externalLink[href$=".zip"]{background:url('../images/package-x-generic.png') right center no-repeat;padding-right:18px}a.externalLink[href$=".md5"],a.externalLink[href$=".sha1"]{background:url('../images/document-properties.png') right center no-repeat;padding-right:18px}a.externalLink[href^=https]{background:url('../images/application-certificate.png') right center no-repeat;padding-right:18px}a.externalLink[href^=file]{background:url('../images/drive-harddisk.png') right center no-repeat;padding-right:18px}a.externalLink[href^=ftp]{background:url('../images/network-server.png') right center no-repeat;padding-right:18px}a.externalLink[href^=mailto]{background:url('../images/contact-new.png') right center no-repeat;padding-right:18px}li.none{list-style:none}.search-query{background-image:url(https://cse.google.com/cse/images/google_custom_search_watermark.gif);background-attachment:initial;background-origin:initial;background-clip:initial;background-color:#fff;background-position:0 50%;background-repeat:no-repeat no-repeat;width:95%}body.topBarEnabled{padding-top:60px}body.topBarDisabled{padding-top:20px}.builtBy{display:block}img.builtBy{margin:10px auto}#search-form{margin-left:9px;margin-right:9px}.hero-unit h2{font-size:60px}tt{padding:0 3px 2px;font-family:Monaco,Andale Mono,Courier New,monospace;font-size:.9em;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;background-color:#fee9cc;color:rgba(0,0,0,0.75);padding:1px 3px}li{color:#404040}table.zebra-striped{background-color:#FFF}.footer{background-color:#EEE}.sidebar-nav{padding-left:0;padding-right:0}.sidebar-nav .icon-chevron-right,.sidebar-nav .icon-chevron-down{margin-top:2px;margin-right:-6px;float:right;opacity:.25}li.pull-right{margin-left:3px;margin-right:3px}.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0;padding-left:15px}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} \ No newline at end of file diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/css/print.css b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/css/print.css new file mode 100644 index 00000000..46c5e810 --- /dev/null +++ b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/css/print.css @@ -0,0 +1,23 @@ +/* + * 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. + */ + +/* $Id: print.css 1201871 2011-11-14 20:18:24Z simonetripodi $ */ + +#banner, #footer, #leftcol, #breadcrumbs, .docs #toc, .docs .courtesylinks, #leftColumn, #navColumn {display: none !important;} +#bodyColumn, body.docs div.docs {margin: 0 !important;border: none !important} diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/css/site.css b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/css/site.css new file mode 100644 index 00000000..055e7e28 --- /dev/null +++ b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/css/site.css @@ -0,0 +1 @@ +/* You can override this file with your own styles */ \ No newline at end of file diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/fonts/glyphicons-halflings-regular.eot b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/fonts/glyphicons-halflings-regular.eot new file mode 100644 index 00000000..af587a81 Binary files /dev/null and b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/fonts/glyphicons-halflings-regular.eot differ diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/fonts/glyphicons-halflings-regular.svg b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/fonts/glyphicons-halflings-regular.svg new file mode 100644 index 00000000..c8f06d9a --- /dev/null +++ b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/fonts/glyphicons-halflings-regular.svg @@ -0,0 +1,229 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/fonts/glyphicons-halflings-regular.ttf b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/fonts/glyphicons-halflings-regular.ttf new file mode 100644 index 00000000..8681f1ec Binary files /dev/null and b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/fonts/glyphicons-halflings-regular.ttf differ diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/fonts/glyphicons-halflings-regular.woff b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/fonts/glyphicons-halflings-regular.woff new file mode 100644 index 00000000..1e69f489 Binary files /dev/null and b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/fonts/glyphicons-halflings-regular.woff differ diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/accessories-text-editor.png b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/accessories-text-editor.png new file mode 100644 index 00000000..abc3366e Binary files /dev/null and b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/accessories-text-editor.png differ diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/add.gif b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/add.gif new file mode 100644 index 00000000..1cb3dbf9 Binary files /dev/null and b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/add.gif differ diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/apache-maven-project-2.png b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/apache-maven-project-2.png new file mode 100644 index 00000000..a44db6ed Binary files /dev/null and b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/apache-maven-project-2.png differ diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/application-certificate.png b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/application-certificate.png new file mode 100644 index 00000000..cc6aff61 Binary files /dev/null and b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/application-certificate.png differ diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/contact-new.png b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/contact-new.png new file mode 100644 index 00000000..ebc4316d Binary files /dev/null and b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/contact-new.png differ diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/document-properties.png b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/document-properties.png new file mode 100644 index 00000000..34c2409a Binary files /dev/null and b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/document-properties.png differ diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/drive-harddisk.png b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/drive-harddisk.png new file mode 100644 index 00000000..d7ce475f Binary files /dev/null and b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/drive-harddisk.png differ diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/fix.gif b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/fix.gif new file mode 100644 index 00000000..b7eb3dc4 Binary files /dev/null and b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/fix.gif differ diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/icon_error_sml.gif b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/icon_error_sml.gif new file mode 100644 index 00000000..12e9a01a Binary files /dev/null and b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/icon_error_sml.gif differ diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/icon_help_sml.gif b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/icon_help_sml.gif new file mode 100644 index 00000000..aaf20e6e Binary files /dev/null and b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/icon_help_sml.gif differ diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/icon_info_sml.gif b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/icon_info_sml.gif new file mode 100644 index 00000000..b7763267 Binary files /dev/null and b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/icon_info_sml.gif differ diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/icon_success_sml.gif b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/icon_success_sml.gif new file mode 100644 index 00000000..0a195279 Binary files /dev/null and b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/icon_success_sml.gif differ diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/icon_warning_sml.gif b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/icon_warning_sml.gif new file mode 100644 index 00000000..ac6ad6ad Binary files /dev/null and b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/icon_warning_sml.gif differ diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/image-x-generic.png b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/image-x-generic.png new file mode 100644 index 00000000..ab49efb3 Binary files /dev/null and b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/image-x-generic.png differ diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/internet-web-browser.png b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/internet-web-browser.png new file mode 100644 index 00000000..307d6aca Binary files /dev/null and b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/internet-web-browser.png differ diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/logos/build-by-maven-black.png b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/logos/build-by-maven-black.png new file mode 100644 index 00000000..919fd0f6 Binary files /dev/null and b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/logos/build-by-maven-black.png differ diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/logos/build-by-maven-white.png b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/logos/build-by-maven-white.png new file mode 100644 index 00000000..7d44c9c2 Binary files /dev/null and b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/logos/build-by-maven-white.png differ diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/logos/maven-feather.png b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/logos/maven-feather.png new file mode 100644 index 00000000..b5ada836 Binary files /dev/null and b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/logos/maven-feather.png differ diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/network-server.png b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/network-server.png new file mode 100644 index 00000000..1d12e193 Binary files /dev/null and b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/network-server.png differ diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/package-x-generic.png b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/package-x-generic.png new file mode 100644 index 00000000..8b7e9e67 Binary files /dev/null and b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/package-x-generic.png differ diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/profiles/pre-release.png b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/profiles/pre-release.png new file mode 100644 index 00000000..d448e850 Binary files /dev/null and b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/profiles/pre-release.png differ diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/profiles/retired.png b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/profiles/retired.png new file mode 100644 index 00000000..f89f6a29 Binary files /dev/null and b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/profiles/retired.png differ diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/profiles/sandbox.png b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/profiles/sandbox.png new file mode 100644 index 00000000..f88b3626 Binary files /dev/null and b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/profiles/sandbox.png differ diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/remove.gif b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/remove.gif new file mode 100644 index 00000000..fc65631c Binary files /dev/null and b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/remove.gif differ diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/rss.png b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/rss.png new file mode 100644 index 00000000..a9850ee2 Binary files /dev/null and b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/rss.png differ diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/update.gif b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/update.gif new file mode 100644 index 00000000..b2a6d0bf Binary files /dev/null and b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/update.gif differ diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/window-new.png b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/window-new.png new file mode 100644 index 00000000..0e12ef95 Binary files /dev/null and b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/images/window-new.png differ diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/img/glyphicons-halflings-white.png b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/img/glyphicons-halflings-white.png new file mode 100644 index 00000000..3bf6484a Binary files /dev/null and b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/img/glyphicons-halflings-white.png differ diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/img/glyphicons-halflings.png b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/img/glyphicons-halflings.png new file mode 100644 index 00000000..a9969993 Binary files /dev/null and b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/img/glyphicons-halflings.png differ diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/index.html b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/index.html new file mode 100644 index 00000000..8392510a --- /dev/null +++ b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/index.html @@ -0,0 +1,229 @@ + + + + + + + + + Spring Cloud Contract Verifier Maven Plugin – + + + + + + + + + + + + + + + + + Fork me on GitHub + + + + + + + + + +
+ + + + + +
+
+ +
+ + +
+ +

Spring Cloud Contract Verifier Maven Plugin

+
+

Just to make long story short - Spring Cloud Contract Verifier is a tool that enables Consumer Driven Contract (CDC) development of JVM-based applications.

+
+
+
    +
  • +

    Stubs mappings to be used by WireMock when doing integration testing on the client code (client tests).

    +
  • +
  • +

    Acceptance tests used to verify if server-side implementation of the API is compliant with the contract (server tests).

    +
  • +
+
+
+

Spring Cloud Contract Verifier moves TDD to the level of software architecture.

+
+
+
+
+ +
+ +
+
+
+

Copyright © 2016 + Spring. + All rights reserved. +

+
+ + +
+
+ + diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/js/apache-maven-fluido-1.5.min.js b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/js/apache-maven-fluido-1.5.min.js new file mode 100644 index 00000000..0537c09d --- /dev/null +++ b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/js/apache-maven-fluido-1.5.min.js @@ -0,0 +1,25 @@ +/*! + * jQuery JavaScript Library v1.11.2 + * http://jquery.com/ + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * + * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2014-12-17T15:27Z + */ +(function(b,a){if(typeof module==="object"&&typeof module.exports==="object"){module.exports=b.document?a(b,true):function(c){if(!c.document){throw new Error("jQuery requires a window with a document")}return a(c)}}else{a(b)}}(typeof window!=="undefined"?window:this,function(a5,av){var aP=[];var P=aP.slice;var az=aP.concat;var x=aP.push;var bU=aP.indexOf;var ac={};var y=ac.toString;var K=ac.hasOwnProperty;var D={};var ai="1.11.2",bI=function(e,i){return new bI.fn.init(e,i)},E=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,bS=/^-ms-/,aW=/-([\da-z])/gi,O=function(e,i){return i.toUpperCase()};bI.fn=bI.prototype={jquery:ai,constructor:bI,selector:"",length:0,toArray:function(){return P.call(this)},get:function(e){return e!=null?(e<0?this[e+this.length]:this[e]):P.call(this)},pushStack:function(e){var i=bI.merge(this.constructor(),e);i.prevObject=this;i.context=this.context;return i},each:function(i,e){return bI.each(this,i,e)},map:function(e){return this.pushStack(bI.map(this,function(b7,b6){return e.call(b7,b6,b7)}))},slice:function(){return this.pushStack(P.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(b7){var e=this.length,b6=+b7+(b7<0?e:0);return this.pushStack(b6>=0&&b6=0},isEmptyObject:function(i){var e;for(e in i){return false}return true},isPlainObject:function(b7){var i;if(!b7||bI.type(b7)!=="object"||b7.nodeType||bI.isWindow(b7)){return false}try{if(b7.constructor&&!K.call(b7,"constructor")&&!K.call(b7.constructor.prototype,"isPrototypeOf")){return false}}catch(b6){return false}if(D.ownLast){for(i in b7){return K.call(b7,i)}}for(i in b7){}return i===undefined||K.call(b7,i)},type:function(e){if(e==null){return e+""}return typeof e==="object"||typeof e==="function"?ac[y.call(e)]||"object":typeof e},globalEval:function(e){if(e&&bI.trim(e)){(a5.execScript||function(i){a5["eval"].call(a5,i)})(e)}},camelCase:function(e){return e.replace(bS,"ms-").replace(aW,O)},nodeName:function(i,e){return i.nodeName&&i.nodeName.toLowerCase()===e.toLowerCase()},each:function(ca,cb,b6){var b9,b7=0,b8=ca.length,e=ad(ca);if(b6){if(e){for(;b70&&(i-1) in b6}var m= +/*! + * Sizzle CSS Selector Engine v2.2.0-pre + * http://sizzlejs.com/ + * + * Copyright 2008, 2014 jQuery Foundation, Inc. and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2014-12-16 + */ +(function(de){var cy,dh,cn,cH,cK,ci,cW,dg,dm,cI,cX,cZ,cC,co,c8,c3,df,ce,cF,da="sizzle"+1*new Date(),cJ=de.document,di=0,c4=0,b9=cA(),c9=cA(),cG=cA(),cE=function(i,e){if(i===e){cX=true}return 0},cQ=1<<31,cO=({}).hasOwnProperty,dc=[],dd=dc.pop,cM=dc.push,b7=dc.push,cm=dc.slice,cd=function(dq,dp){var dn=0,e=dq.length;for(;dn+~]|"+cp+")"+cp+"*"),ct=new RegExp("="+cp+"*([^\\]'\"]*?)"+cp+"*\\]","g"),cS=new RegExp(ck),cU=new RegExp("^"+cL+"$"),c2={ID:new RegExp("^#("+b6+")"),CLASS:new RegExp("^\\.("+b6+")"),TAG:new RegExp("^("+b6.replace("w","w*")+")"),ATTR:new RegExp("^"+c6),PSEUDO:new RegExp("^"+ck),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+cp+"*(even|odd|(([+-]|)(\\d*)n|)"+cp+"*(?:([+-]|)"+cp+"*(\\d+)|))"+cp+"*\\)|)","i"),bool:new RegExp("^(?:"+b8+")$","i"),needsContext:new RegExp("^"+cp+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+cp+"*((?:-\\d)?\\d*)"+cp+"*\\)|)(?=[^-]|$)","i")},cc=/^(?:input|select|textarea|button)$/i,cl=/^h\d$/i,cP=/^[^{]+\{\s*\[native \w/,cR=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,c1=/[+~]/,cN=/'|\\/g,cs=new RegExp("\\\\([\\da-f]{1,6}"+cp+"?|("+cp+")|.)","ig"),c5=function(e,dp,i){var dn="0x"+dp-65536;return dn!==dn||i?dp:dn<0?String.fromCharCode(dn+65536):String.fromCharCode(dn>>10|55296,dn&1023|56320)},dl=function(){cZ()};try{b7.apply((dc=cm.call(cJ.childNodes)),cJ.childNodes);dc[cJ.childNodes.length].nodeType}catch(cD){b7={apply:dc.length?function(i,e){cM.apply(i,cm.call(e))}:function(dq,dp){var e=dq.length,dn=0;while((dq[e++]=dp[dn++])){}dq.length=e-1}}}function cw(dv,dn,dz,dB){var dA,ds,dt,dx,dy,dr,dq,e,dp,dw;if((dn?dn.ownerDocument||dn:cJ)!==cC){cZ(dn)}dn=dn||cC;dz=dz||[];dx=dn.nodeType;if(typeof dv!=="string"||!dv||dx!==1&&dx!==9&&dx!==11){return dz}if(!dB&&c8){if(dx!==11&&(dA=cR.exec(dv))){if((dt=dA[1])){if(dx===9){ds=dn.getElementById(dt);if(ds&&ds.parentNode){if(ds.id===dt){dz.push(ds);return dz}}else{return dz}}else{if(dn.ownerDocument&&(ds=dn.ownerDocument.getElementById(dt))&&cF(dn,ds)&&ds.id===dt){dz.push(ds);return dz}}}else{if(dA[2]){b7.apply(dz,dn.getElementsByTagName(dv));return dz}else{if((dt=dA[3])&&dh.getElementsByClassName){b7.apply(dz,dn.getElementsByClassName(dt));return dz}}}}if(dh.qsa&&(!c3||!c3.test(dv))){e=dq=da;dp=dn;dw=dx!==1&&dv;if(dx===1&&dn.nodeName.toLowerCase()!=="object"){dr=ci(dv);if((dq=dn.getAttribute("id"))){e=dq.replace(cN,"\\$&")}else{dn.setAttribute("id",e)}e="[id='"+e+"'] ";dy=dr.length;while(dy--){dr[dy]=e+ch(dr[dy])}dp=c1.test(dv)&&cT(dn.parentNode)||dn;dw=dr.join(",")}if(dw){try{b7.apply(dz,dp.querySelectorAll(dw));return dz}catch(du){}finally{if(!dq){dn.removeAttribute("id")}}}}}return dg(dv.replace(cr,"$1"),dn,dz,dB)}function cA(){var i=[];function e(dn,dp){if(i.push(dn+" ")>cn.cacheLength){delete e[i.shift()]}return(e[dn+" "]=dp)}return e}function cj(e){e[da]=true;return e}function cf(i){var dp=cC.createElement("div");try{return !!i(dp)}catch(dn){return false}finally{if(dp.parentNode){dp.parentNode.removeChild(dp)}dp=null}}function dj(dn,dq){var e=dn.split("|"),dp=dn.length;while(dp--){cn.attrHandle[e[dp]]=dq}}function ca(i,e){var dp=e&&i,dn=dp&&i.nodeType===1&&e.nodeType===1&&(~e.sourceIndex||cQ)-(~i.sourceIndex||cQ);if(dn){return dn}if(dp){while((dp=dp.nextSibling)){if(dp===e){return -1}}}return i?1:-1}function cx(e){return function(dn){var i=dn.nodeName.toLowerCase();return i==="input"&&dn.type===e}}function cb(e){return function(dn){var i=dn.nodeName.toLowerCase();return(i==="input"||i==="button")&&dn.type===e}}function c7(e){return cj(function(i){i=+i;return cj(function(dn,ds){var dq,dp=e([],dn.length,i),dr=dp.length;while(dr--){if(dn[(dq=dp[dr])]){dn[dq]=!(ds[dq]=dn[dq])}}})})}function cT(e){return e&&typeof e.getElementsByTagName!=="undefined"&&e}dh=cw.support={};cK=cw.isXML=function(e){var i=e&&(e.ownerDocument||e).documentElement;return i?i.nodeName!=="HTML":false};cZ=cw.setDocument=function(dn){var e,i,dp=dn?dn.ownerDocument||dn:cJ;if(dp===cC||dp.nodeType!==9||!dp.documentElement){return cC}cC=dp;co=dp.documentElement;i=dp.defaultView;if(i&&i!==i.top){if(i.addEventListener){i.addEventListener("unload",dl,false)}else{if(i.attachEvent){i.attachEvent("onunload",dl)}}}c8=!cK(dp);dh.attributes=cf(function(dq){dq.className="i";return !dq.getAttribute("className")});dh.getElementsByTagName=cf(function(dq){dq.appendChild(dp.createComment(""));return !dq.getElementsByTagName("*").length});dh.getElementsByClassName=cP.test(dp.getElementsByClassName);dh.getById=cf(function(dq){co.appendChild(dq).id=da;return !dp.getElementsByName||!dp.getElementsByName(da).length});if(dh.getById){cn.find.ID=function(ds,dr){if(typeof dr.getElementById!=="undefined"&&c8){var dq=dr.getElementById(ds);return dq&&dq.parentNode?[dq]:[]}};cn.filter.ID=function(dr){var dq=dr.replace(cs,c5);return function(ds){return ds.getAttribute("id")===dq}}}else{delete cn.find.ID;cn.filter.ID=function(dr){var dq=dr.replace(cs,c5);return function(dt){var ds=typeof dt.getAttributeNode!=="undefined"&&dt.getAttributeNode("id");return ds&&ds.value===dq}}}cn.find.TAG=dh.getElementsByTagName?function(dq,dr){if(typeof dr.getElementsByTagName!=="undefined"){return dr.getElementsByTagName(dq)}else{if(dh.qsa){return dr.querySelectorAll(dq)}}}:function(dq,du){var dv,dt=[],ds=0,dr=du.getElementsByTagName(dq);if(dq==="*"){while((dv=dr[ds++])){if(dv.nodeType===1){dt.push(dv)}}return dt}return dr};cn.find.CLASS=dh.getElementsByClassName&&function(dr,dq){if(c8){return dq.getElementsByClassName(dr)}};df=[];c3=[];if((dh.qsa=cP.test(dp.querySelectorAll))){cf(function(dq){co.appendChild(dq).innerHTML="";if(dq.querySelectorAll("[msallowcapture^='']").length){c3.push("[*^$]="+cp+"*(?:''|\"\")")}if(!dq.querySelectorAll("[selected]").length){c3.push("\\["+cp+"*(?:value|"+b8+")")}if(!dq.querySelectorAll("[id~="+da+"-]").length){c3.push("~=")}if(!dq.querySelectorAll(":checked").length){c3.push(":checked")}if(!dq.querySelectorAll("a#"+da+"+*").length){c3.push(".#.+[+~]")}});cf(function(dr){var dq=dp.createElement("input");dq.setAttribute("type","hidden");dr.appendChild(dq).setAttribute("name","D");if(dr.querySelectorAll("[name=d]").length){c3.push("name"+cp+"*[*^$|!~]?=")}if(!dr.querySelectorAll(":enabled").length){c3.push(":enabled",":disabled")}dr.querySelectorAll("*,:x");c3.push(",.*:")})}if((dh.matchesSelector=cP.test((ce=co.matches||co.webkitMatchesSelector||co.mozMatchesSelector||co.oMatchesSelector||co.msMatchesSelector)))){cf(function(dq){dh.disconnectedMatch=ce.call(dq,"div");ce.call(dq,"[s!='']:x");df.push("!=",ck)})}c3=c3.length&&new RegExp(c3.join("|"));df=df.length&&new RegExp(df.join("|"));e=cP.test(co.compareDocumentPosition);cF=e||cP.test(co.contains)?function(dr,dq){var dt=dr.nodeType===9?dr.documentElement:dr,ds=dq&&dq.parentNode;return dr===ds||!!(ds&&ds.nodeType===1&&(dt.contains?dt.contains(ds):dr.compareDocumentPosition&&dr.compareDocumentPosition(ds)&16))}:function(dr,dq){if(dq){while((dq=dq.parentNode)){if(dq===dr){return true}}}return false};cE=e?function(dr,dq){if(dr===dq){cX=true;return 0}var ds=!dr.compareDocumentPosition-!dq.compareDocumentPosition;if(ds){return ds}ds=(dr.ownerDocument||dr)===(dq.ownerDocument||dq)?dr.compareDocumentPosition(dq):1;if(ds&1||(!dh.sortDetached&&dq.compareDocumentPosition(dr)===ds)){if(dr===dp||dr.ownerDocument===cJ&&cF(cJ,dr)){return -1}if(dq===dp||dq.ownerDocument===cJ&&cF(cJ,dq)){return 1}return cI?(cd(cI,dr)-cd(cI,dq)):0}return ds&4?-1:1}:function(dr,dq){if(dr===dq){cX=true;return 0}var dx,du=0,dw=dr.parentNode,dt=dq.parentNode,ds=[dr],dv=[dq];if(!dw||!dt){return dr===dp?-1:dq===dp?1:dw?-1:dt?1:cI?(cd(cI,dr)-cd(cI,dq)):0}else{if(dw===dt){return ca(dr,dq)}}dx=dr;while((dx=dx.parentNode)){ds.unshift(dx)}dx=dq;while((dx=dx.parentNode)){dv.unshift(dx)}while(ds[du]===dv[du]){du++}return du?ca(ds[du],dv[du]):ds[du]===cJ?-1:dv[du]===cJ?1:0};return dp};cw.matches=function(i,e){return cw(i,null,null,e)};cw.matchesSelector=function(dn,dq){if((dn.ownerDocument||dn)!==cC){cZ(dn)}dq=dq.replace(ct,"='$1']");if(dh.matchesSelector&&c8&&(!df||!df.test(dq))&&(!c3||!c3.test(dq))){try{var i=ce.call(dn,dq);if(i||dh.disconnectedMatch||dn.document&&dn.document.nodeType!==11){return i}}catch(dp){}}return cw(dq,cC,null,[dn]).length>0};cw.contains=function(e,i){if((e.ownerDocument||e)!==cC){cZ(e)}return cF(e,i)};cw.attr=function(dn,e){if((dn.ownerDocument||dn)!==cC){cZ(dn)}var i=cn.attrHandle[e.toLowerCase()],dp=i&&cO.call(cn.attrHandle,e.toLowerCase())?i(dn,e,!c8):undefined;return dp!==undefined?dp:dh.attributes||!c8?dn.getAttribute(e):(dp=dn.getAttributeNode(e))&&dp.specified?dp.value:null};cw.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)};cw.uniqueSort=function(dp){var dq,dr=[],e=0,dn=0;cX=!dh.detectDuplicates;cI=!dh.sortStable&&dp.slice(0);dp.sort(cE);if(cX){while((dq=dp[dn++])){if(dq===dp[dn]){e=dr.push(dn)}}while(e--){dp.splice(dr[e],1)}}cI=null;return dp};cH=cw.getText=function(dr){var dq,dn="",dp=0,e=dr.nodeType;if(!e){while((dq=dr[dp++])){dn+=cH(dq)}}else{if(e===1||e===9||e===11){if(typeof dr.textContent==="string"){return dr.textContent}else{for(dr=dr.firstChild;dr;dr=dr.nextSibling){dn+=cH(dr)}}}else{if(e===3||e===4){return dr.nodeValue}}}return dn};cn=cw.selectors={cacheLength:50,createPseudo:cj,match:c2,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:true}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:true},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){e[1]=e[1].replace(cs,c5);e[3]=(e[3]||e[4]||e[5]||"").replace(cs,c5);if(e[2]==="~="){e[3]=" "+e[3]+" "}return e.slice(0,4)},CHILD:function(e){e[1]=e[1].toLowerCase();if(e[1].slice(0,3)==="nth"){if(!e[3]){cw.error(e[0])}e[4]=+(e[4]?e[5]+(e[6]||1):2*(e[3]==="even"||e[3]==="odd"));e[5]=+((e[7]+e[8])||e[3]==="odd")}else{if(e[3]){cw.error(e[0])}}return e},PSEUDO:function(i){var e,dn=!i[6]&&i[2];if(c2.CHILD.test(i[0])){return null}if(i[3]){i[2]=i[4]||i[5]||""}else{if(dn&&cS.test(dn)&&(e=ci(dn,true))&&(e=dn.indexOf(")",dn.length-e)-dn.length)){i[0]=i[0].slice(0,e);i[2]=dn.slice(0,e)}}return i.slice(0,3)}},filter:{TAG:function(i){var e=i.replace(cs,c5).toLowerCase();return i==="*"?function(){return true}:function(dn){return dn.nodeName&&dn.nodeName.toLowerCase()===e}},CLASS:function(e){var i=b9[e+" "];return i||(i=new RegExp("(^|"+cp+")"+e+"("+cp+"|$)"))&&b9(e,function(dn){return i.test(typeof dn.className==="string"&&dn.className||typeof dn.getAttribute!=="undefined"&&dn.getAttribute("class")||"")})},ATTR:function(dn,i,e){return function(dq){var dp=cw.attr(dq,dn);if(dp==null){return i==="!="}if(!i){return true}dp+="";return i==="="?dp===e:i==="!="?dp!==e:i==="^="?e&&dp.indexOf(e)===0:i==="*="?e&&dp.indexOf(e)>-1:i==="$="?e&&dp.slice(-e.length)===e:i==="~="?(" "+dp.replace(cu," ")+" ").indexOf(e)>-1:i==="|="?dp===e||dp.slice(0,e.length+1)===e+"-":false}},CHILD:function(i,dq,dp,dr,dn){var dt=i.slice(0,3)!=="nth",e=i.slice(-4)!=="last",ds=dq==="of-type";return dr===1&&dn===0?function(du){return !!du.parentNode}:function(dA,dy,dD){var du,dG,dB,dF,dC,dx,dz=dt!==e?"nextSibling":"previousSibling",dE=dA.parentNode,dw=ds&&dA.nodeName.toLowerCase(),dv=!dD&&!ds;if(dE){if(dt){while(dz){dB=dA;while((dB=dB[dz])){if(ds?dB.nodeName.toLowerCase()===dw:dB.nodeType===1){return false}}dx=dz=i==="only"&&!dx&&"nextSibling"}return true}dx=[e?dE.firstChild:dE.lastChild];if(e&&dv){dG=dE[da]||(dE[da]={});du=dG[i]||[];dC=du[0]===di&&du[1];dF=du[0]===di&&du[2];dB=dC&&dE.childNodes[dC];while((dB=++dC&&dB&&dB[dz]||(dF=dC=0)||dx.pop())){if(dB.nodeType===1&&++dF&&dB===dA){dG[i]=[di,dC,dF];break}}}else{if(dv&&(du=(dA[da]||(dA[da]={}))[i])&&du[0]===di){dF=du[1]}else{while((dB=++dC&&dB&&dB[dz]||(dF=dC=0)||dx.pop())){if((ds?dB.nodeName.toLowerCase()===dw:dB.nodeType===1)&&++dF){if(dv){(dB[da]||(dB[da]={}))[i]=[di,dF]}if(dB===dA){break}}}}}dF-=dn;return dF===dr||(dF%dr===0&&dF/dr>=0)}}},PSEUDO:function(dp,dn){var e,i=cn.pseudos[dp]||cn.setFilters[dp.toLowerCase()]||cw.error("unsupported pseudo: "+dp);if(i[da]){return i(dn)}if(i.length>1){e=[dp,dp,"",dn];return cn.setFilters.hasOwnProperty(dp.toLowerCase())?cj(function(ds,du){var dr,dq=i(ds,dn),dt=dq.length;while(dt--){dr=cd(ds,dq[dt]);ds[dr]=!(du[dr]=dq[dt])}}):function(dq){return i(dq,0,e)}}return i}},pseudos:{not:cj(function(e){var i=[],dn=[],dp=cW(e.replace(cr,"$1"));return dp[da]?cj(function(dr,dw,du,ds){var dv,dq=dp(dr,null,ds,[]),dt=dr.length;while(dt--){if((dv=dq[dt])){dr[dt]=!(dw[dt]=dv)}}}):function(ds,dr,dq){i[0]=ds;dp(i,null,dq,dn);i[0]=null;return !dn.pop()}}),has:cj(function(e){return function(i){return cw(e,i).length>0}}),contains:cj(function(e){e=e.replace(cs,c5);return function(i){return(i.textContent||i.innerText||cH(i)).indexOf(e)>-1}}),lang:cj(function(e){if(!cU.test(e||"")){cw.error("unsupported lang: "+e)}e=e.replace(cs,c5).toLowerCase();return function(dn){var i;do{if((i=c8?dn.lang:dn.getAttribute("xml:lang")||dn.getAttribute("lang"))){i=i.toLowerCase();return i===e||i.indexOf(e+"-")===0}}while((dn=dn.parentNode)&&dn.nodeType===1);return false}}),target:function(e){var i=de.location&&de.location.hash;return i&&i.slice(1)===e.id},root:function(e){return e===co},focus:function(e){return e===cC.activeElement&&(!cC.hasFocus||cC.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===false},disabled:function(e){return e.disabled===true},checked:function(e){var i=e.nodeName.toLowerCase();return(i==="input"&&!!e.checked)||(i==="option"&&!!e.selected)},selected:function(e){if(e.parentNode){e.parentNode.selectedIndex}return e.selected===true},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling){if(e.nodeType<6){return false}}return true},parent:function(e){return !cn.pseudos.empty(e)},header:function(e){return cl.test(e.nodeName)},input:function(e){return cc.test(e.nodeName)},button:function(i){var e=i.nodeName.toLowerCase();return e==="input"&&i.type==="button"||e==="button"},text:function(i){var e;return i.nodeName.toLowerCase()==="input"&&i.type==="text"&&((e=i.getAttribute("type"))==null||e.toLowerCase()==="text")},first:c7(function(){return[0]}),last:c7(function(e,i){return[i-1]}),eq:c7(function(e,dn,i){return[i<0?i+dn:i]}),even:c7(function(e,dp){var dn=0;for(;dn=0;){e.push(dn)}return e}),gt:c7(function(e,dq,dp){var dn=dp<0?dp+dq:dp;for(;++dn1?function(dr,dq,dn){var dp=e.length;while(dp--){if(!e[dp](dr,dq,dn)){return false}}return true}:e[0]}function cz(dn,dr,dq){var dp=0,e=dr.length;for(;dp-1){dC[dE]=!(dz[dE]=dw)}}}}else{dy=c0(dy===dz?dy.splice(dt,dy.length):dy);if(dr){dr(null,dz,dy,dB)}else{b7.apply(dz,dy)}}})}function db(dt){var dn,dr,dp,ds=dt.length,dw=cn.relative[dt[0].type],dx=dw||cn.relative[" "],dq=dw?1:0,du=cq(function(i){return i===dn},dx,true),dv=cq(function(i){return cd(dn,i)>-1},dx,true),e=[function(dA,dz,dy){var i=(!dw&&(dy||dz!==dm))||((dn=dz).nodeType?du(dA,dz,dy):dv(dA,dz,dy));dn=null;return i}];for(;dq1&&dk(e),dq>1&&ch(dt.slice(0,dq-1).concat({value:dt[dq-2].type===" "?"*":""})).replace(cr,"$1"),dr,dq0,dq=dp.length>0,i=function(dA,du,dz,dy,dD){var dv,dw,dB,dF=0,dx="0",dr=dA&&[],dG=[],dE=dm,dt=dA||dq&&cn.find.TAG("*",dD),ds=(di+=dE==null?1:Math.random()||0.1),dC=dt.length;if(dD){dm=du!==cC&&du}for(;dx!==dC&&(dv=dt[dx])!=null;dx++){if(dq&&dv){dw=0;while((dB=dp[dw++])){if(dB(dv,du,dz)){dy.push(dv);break}}if(dD){di=ds}}if(e){if((dv=!dB&&dv)){dF--}if(dA){dr.push(dv)}}}dF+=dx;if(e&&dx!==dF){dw=0;while((dB=dn[dw++])){dB(dr,dG,du,dz)}if(dA){if(dF>0){while(dx--){if(!(dr[dx]||dG[dx])){dG[dx]=dd.call(dy)}}}dG=c0(dG)}b7.apply(dy,dG);if(dD&&!dA&&dG.length>0&&(dF+dn.length)>1){cw.uniqueSort(dy)}}if(dD){di=ds;dm=dE}return dr};return e?cj(i):i}cW=cw.compile=function(e,dp){var dq,dn=[],ds=[],dr=cG[e+" "];if(!dr){if(!dp){dp=ci(e)}dq=dp.length;while(dq--){dr=db(dp[dq]);if(dr[da]){dn.push(dr)}else{ds.push(dr)}}dr=cG(e,cY(ds,dn));dr.selector=e}return dr};dg=cw.select=function(dp,e,dq,dt){var dr,dw,dn,dx,du,dv=typeof dp==="function"&&dp,ds=!dt&&ci((dp=dv.selector||dp));dq=dq||[];if(ds.length===1){dw=ds[0]=ds[0].slice(0);if(dw.length>2&&(dn=dw[0]).type==="ID"&&dh.getById&&e.nodeType===9&&c8&&cn.relative[dw[1].type]){e=(cn.find.ID(dn.matches[0].replace(cs,c5),e)||[])[0];if(!e){return dq}else{if(dv){e=e.parentNode}}dp=dp.slice(dw.shift().value.length)}dr=c2.needsContext.test(dp)?0:dw.length;while(dr--){dn=dw[dr];if(cn.relative[(dx=dn.type)]){break}if((du=cn.find[dx])){if((dt=du(dn.matches[0].replace(cs,c5),c1.test(dw[0].type)&&cT(e.parentNode)||e))){dw.splice(dr,1);dp=dt.length&&ch(dw);if(!dp){b7.apply(dq,dt);return dq}break}}}}(dv||cW(dp,ds))(dt,e,!c8,dq,c1.test(dp)&&cT(e.parentNode)||e);return dq};dh.sortStable=da.split("").sort(cE).join("")===da;dh.detectDuplicates=!!cX;cZ();dh.sortDetached=cf(function(e){return e.compareDocumentPosition(cC.createElement("div"))&1});if(!cf(function(e){e.innerHTML="";return e.firstChild.getAttribute("href")==="#"})){dj("type|href|height|width",function(i,e,dn){if(!dn){return i.getAttribute(e,e.toLowerCase()==="type"?1:2)}})}if(!dh.attributes||!cf(function(e){e.innerHTML="";e.firstChild.setAttribute("value","");return e.firstChild.getAttribute("value")===""})){dj("value",function(i,e,dn){if(!dn&&i.nodeName.toLowerCase()==="input"){return i.defaultValue}})}if(!cf(function(e){return e.getAttribute("disabled")==null})){dj(b8,function(i,e,dp){var dn;if(!dp){return i[e]===true?e.toLowerCase():(dn=i.getAttributeNode(e))&&dn.specified?dn.value:null}})}return cw})(a5);bI.find=m;bI.expr=m.selectors;bI.expr[":"]=bI.expr.pseudos;bI.unique=m.uniqueSort;bI.text=m.getText;bI.isXMLDoc=m.isXML;bI.contains=m.contains;var A=bI.expr.match.needsContext;var a=(/^<(\w+)\s*\/?>(?:<\/\1>|)$/);var aL=/^.[^:#\[\.,]*$/;function aR(b6,e,i){if(bI.isFunction(e)){return bI.grep(b6,function(b8,b7){return !!e.call(b8,b7,b8)!==i})}if(e.nodeType){return bI.grep(b6,function(b7){return(b7===e)!==i})}if(typeof e==="string"){if(aL.test(e)){return bI.filter(e,b6,i)}e=bI.filter(e,b6)}return bI.grep(b6,function(b7){return(bI.inArray(b7,e)>=0)!==i})}bI.filter=function(b7,e,b6){var i=e[0];if(b6){b7=":not("+b7+")"}return e.length===1&&i.nodeType===1?bI.find.matchesSelector(i,b7)?[i]:[]:bI.find.matches(b7,bI.grep(e,function(b8){return b8.nodeType===1}))};bI.fn.extend({find:function(b6){var b9,b8=[],b7=this,e=b7.length;if(typeof b6!=="string"){return this.pushStack(bI(b6).filter(function(){for(b9=0;b91?bI.unique(b8):b8);b8.selector=this.selector?this.selector+" "+b6:b6;return b8},filter:function(e){return this.pushStack(aR(this,e||[],false))},not:function(e){return this.pushStack(aR(this,e||[],true))},is:function(e){return !!aR(this,typeof e==="string"&&A.test(e)?bI(e):e||[],false).length}});var z,n=a5.document,bt=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,bV=bI.fn.init=function(e,b6){var i,b7;if(!e){return this}if(typeof e==="string"){if(e.charAt(0)==="<"&&e.charAt(e.length-1)===">"&&e.length>=3){i=[null,e,null]}else{i=bt.exec(e)}if(i&&(i[1]||!b6)){if(i[1]){b6=b6 instanceof bI?b6[0]:b6;bI.merge(this,bI.parseHTML(i[1],b6&&b6.nodeType?b6.ownerDocument||b6:n,true));if(a.test(i[1])&&bI.isPlainObject(b6)){for(i in b6){if(bI.isFunction(this[i])){this[i](b6[i])}else{this.attr(i,b6[i])}}}return this}else{b7=n.getElementById(i[2]);if(b7&&b7.parentNode){if(b7.id!==i[2]){return z.find(e)}this.length=1;this[0]=b7}this.context=n;this.selector=e;return this}}else{if(!b6||b6.jquery){return(b6||z).find(e)}else{return this.constructor(b6).find(e)}}}else{if(e.nodeType){this.context=this[0]=e;this.length=1;return this}else{if(bI.isFunction(e)){return typeof z.ready!=="undefined"?z.ready(e):e(bI)}}}if(e.selector!==undefined){this.selector=e.selector;this.context=e.context}return bI.makeArray(e,this)};bV.prototype=bI.fn;z=bI(n);var bv=/^(?:parents|prev(?:Until|All))/,bz={children:true,contents:true,next:true,prev:true};bI.extend({dir:function(b6,i,b8){var e=[],b7=b6[i];while(b7&&b7.nodeType!==9&&(b8===undefined||b7.nodeType!==1||!bI(b7).is(b8))){if(b7.nodeType===1){e.push(b7)}b7=b7[i]}return e},sibling:function(b6,i){var e=[];for(;b6;b6=b6.nextSibling){if(b6.nodeType===1&&b6!==i){e.push(b6)}}return e}});bI.fn.extend({has:function(b8){var b7,b6=bI(b8,this),e=b6.length;return this.filter(function(){for(b7=0;b7-1:ca.nodeType===1&&bI.find.matchesSelector(ca,b9))){e.push(ca);break}}}return this.pushStack(e.length>1?bI.unique(e):e)},index:function(e){if(!e){return(this[0]&&this[0].parentNode)?this.first().prevAll().length:-1}if(typeof e==="string"){return bI.inArray(this[0],bI(e))}return bI.inArray(e.jquery?e[0]:e,this)},add:function(e,i){return this.pushStack(bI.unique(bI.merge(this.get(),bI(e,i))))},addBack:function(e){return this.add(e==null?this.prevObject:this.prevObject.filter(e))}});function aY(i,e){do{i=i[e]}while(i&&i.nodeType!==1);return i}bI.each({parent:function(i){var e=i.parentNode;return e&&e.nodeType!==11?e:null},parents:function(e){return bI.dir(e,"parentNode")},parentsUntil:function(b6,e,b7){return bI.dir(b6,"parentNode",b7)},next:function(e){return aY(e,"nextSibling")},prev:function(e){return aY(e,"previousSibling")},nextAll:function(e){return bI.dir(e,"nextSibling")},prevAll:function(e){return bI.dir(e,"previousSibling")},nextUntil:function(b6,e,b7){return bI.dir(b6,"nextSibling",b7)},prevUntil:function(b6,e,b7){return bI.dir(b6,"previousSibling",b7)},siblings:function(e){return bI.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return bI.sibling(e.firstChild)},contents:function(e){return bI.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:bI.merge([],e.childNodes)}},function(e,i){bI.fn[e]=function(b8,b6){var b7=bI.map(this,i,b8);if(e.slice(-5)!=="Until"){b6=b8}if(b6&&typeof b6==="string"){b7=bI.filter(b6,b7)}if(this.length>1){if(!bz[e]){b7=bI.unique(b7)}if(bv.test(e)){b7=b7.reverse()}}return this.pushStack(b7)}});var aF=(/\S+/g);var b2={};function af(i){var e=b2[i]={};bI.each(i.match(aF)||[],function(b7,b6){e[b6]=true});return e}bI.Callbacks=function(ce){ce=typeof ce==="string"?(b2[ce]||af(ce)):bI.extend({},ce);var b8,b7,e,b9,ca,b6,cb=[],cc=!ce.once&&[],i=function(cf){b7=ce.memory&&cf;e=true;ca=b6||0;b6=0;b9=cb.length;b8=true;for(;cb&&ca-1){cb.splice(cg,1);if(b8){if(cg<=b9){b9--}if(cg<=ca){ca--}}}})}return this},has:function(cf){return cf?bI.inArray(cf,cb)>-1:!!(cb&&cb.length)},empty:function(){cb=[];b9=0;return this},disable:function(){cb=cc=b7=undefined;return this},disabled:function(){return !cb},lock:function(){cc=undefined;if(!b7){cd.disable()}return this},locked:function(){return !cc},fireWith:function(cg,cf){if(cb&&(!e||cc)){cf=cf||[];cf=[cg,cf.slice?cf.slice():cf];if(b8){cc.push(cf)}else{i(cf)}}return this},fire:function(){cd.fireWith(this,arguments);return this},fired:function(){return !!e}};return cd};bI.extend({Deferred:function(b6){var i=[["resolve","done",bI.Callbacks("once memory"),"resolved"],["reject","fail",bI.Callbacks("once memory"),"rejected"],["notify","progress",bI.Callbacks("memory")]],b7="pending",b8={state:function(){return b7},always:function(){e.done(arguments).fail(arguments);return this},then:function(){var b9=arguments;return bI.Deferred(function(ca){bI.each(i,function(cc,cb){var cd=bI.isFunction(b9[cc])&&b9[cc];e[cb[1]](function(){var ce=cd&&cd.apply(this,arguments);if(ce&&bI.isFunction(ce.promise)){ce.promise().done(ca.resolve).fail(ca.reject).progress(ca.notify)}else{ca[cb[0]+"With"](this===b8?ca.promise():this,cd?[ce]:arguments)}})});b9=null}).promise()},promise:function(b9){return b9!=null?bI.extend(b9,b8):b8}},e={};b8.pipe=b8.then;bI.each(i,function(ca,b9){var cc=b9[2],cb=b9[3];b8[b9[1]]=cc.add;if(cb){cc.add(function(){b7=cb},i[ca^1][2].disable,i[2][2].lock)}e[b9[0]]=function(){e[b9[0]+"With"](this===e?b8:this,arguments);return this};e[b9[0]+"With"]=cc.fireWith});b8.promise(e);if(b6){b6.call(e,e)}return e},when:function(b9){var b7=0,cb=P.call(arguments),e=cb.length,b6=e!==1||(b9&&bI.isFunction(b9.promise))?e:0,ce=b6===1?b9:bI.Deferred(),b8=function(cg,ch,cf){return function(i){ch[cg]=this;cf[cg]=arguments.length>1?P.call(arguments):i;if(cf===cd){ce.notifyWith(ch,cf)}else{if(!(--b6)){ce.resolveWith(ch,cf)}}}},cd,ca,cc;if(e>1){cd=new Array(e);ca=new Array(e);cc=new Array(e);for(;b70){return}ak.resolveWith(n,[bI]);if(bI.fn.triggerHandler){bI(n).triggerHandler("ready");bI(n).off("ready")}}});function bm(){if(n.addEventListener){n.removeEventListener("DOMContentLoaded",bZ,false);a5.removeEventListener("load",bZ,false)}else{n.detachEvent("onreadystatechange",bZ);a5.detachEvent("onload",bZ)}}function bZ(){if(n.addEventListener||event.type==="load"||n.readyState==="complete"){bm();bI.ready()}}bI.ready.promise=function(b8){if(!ak){ak=bI.Deferred();if(n.readyState==="complete"){setTimeout(bI.ready)}else{if(n.addEventListener){n.addEventListener("DOMContentLoaded",bZ,false);a5.addEventListener("load",bZ,false)}else{n.attachEvent("onreadystatechange",bZ);a5.attachEvent("onload",bZ);var b7=false;try{b7=a5.frameElement==null&&n.documentElement}catch(b6){}if(b7&&b7.doScroll){(function i(){if(!bI.isReady){try{b7.doScroll("left")}catch(b9){return setTimeout(i,50)}bm();bI.ready()}})()}}}}return ak.promise(b8)};var aC=typeof undefined;var bh;for(bh in bI(D)){break}D.ownLast=bh!=="0";D.inlineBlockNeedsLayout=false;bI(function(){var b6,b7,e,i;e=n.getElementsByTagName("body")[0];if(!e||!e.style){return}b7=n.createElement("div");i=n.createElement("div");i.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px";e.appendChild(i).appendChild(b7);if(typeof b7.style.zoom!==aC){b7.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1";D.inlineBlockNeedsLayout=b6=b7.offsetWidth===3;if(b6){e.style.zoom=1}}e.removeChild(i)});(function(){var b6=n.createElement("div");if(D.deleteExpando==null){D.deleteExpando=true;try{delete b6.test}catch(i){D.deleteExpando=false}}b6=null})();bI.acceptData=function(b6){var i=bI.noData[(b6.nodeName+" ").toLowerCase()],e=+b6.nodeType||1;return e!==1&&e!==9?false:!i||i!==true&&b6.getAttribute("classid")===i};var by=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,aQ=/([A-Z])/g;function bA(b7,b6,b8){if(b8===undefined&&b7.nodeType===1){var i="data-"+b6.replace(aQ,"-$1").toLowerCase();b8=b7.getAttribute(i);if(typeof b8==="string"){try{b8=b8==="true"?true:b8==="false"?false:b8==="null"?null:+b8+""===b8?+b8:by.test(b8)?bI.parseJSON(b8):b8}catch(b9){}bI.data(b7,b6,b8)}else{b8=undefined}}return b8}function Q(i){var e;for(e in i){if(e==="data"&&bI.isEmptyObject(i[e])){continue}if(e!=="toJSON"){return false}}return true}function bc(b7,i,b9,b8){if(!bI.acceptData(b7)){return}var cb,ca,cc=bI.expando,cd=b7.nodeType,e=cd?bI.cache:b7,b6=cd?b7[cc]:b7[cc]&&cc;if((!b6||!e[b6]||(!b8&&!e[b6].data))&&b9===undefined&&typeof i==="string"){return}if(!b6){if(cd){b6=b7[cc]=aP.pop()||bI.guid++}else{b6=cc}}if(!e[b6]){e[b6]=cd?{}:{toJSON:bI.noop}}if(typeof i==="object"||typeof i==="function"){if(b8){e[b6]=bI.extend(e[b6],i)}else{e[b6].data=bI.extend(e[b6].data,i)}}ca=e[b6];if(!b8){if(!ca.data){ca.data={}}ca=ca.data}if(b9!==undefined){ca[bI.camelCase(i)]=b9}if(typeof i==="string"){cb=ca[i];if(cb==null){cb=ca[bI.camelCase(i)]}}else{cb=ca}return cb}function ab(b9,b7,e){if(!bI.acceptData(b9)){return}var cb,b8,ca=b9.nodeType,b6=ca?bI.cache:b9,cc=ca?b9[bI.expando]:bI.expando;if(!b6[cc]){return}if(b7){cb=e?b6[cc]:b6[cc].data;if(cb){if(!bI.isArray(b7)){if(b7 in cb){b7=[b7]}else{b7=bI.camelCase(b7);if(b7 in cb){b7=[b7]}else{b7=b7.split(" ")}}}else{b7=b7.concat(bI.map(b7,bI.camelCase))}b8=b7.length;while(b8--){delete cb[b7[b8]]}if(e?!Q(cb):!bI.isEmptyObject(cb)){return}}}if(!e){delete b6[cc].data;if(!Q(b6[cc])){return}}if(ca){bI.cleanData([b9],true)}else{if(D.deleteExpando||b6!=b6.window){delete b6[cc]}else{b6[cc]=null}}}bI.extend({cache:{},noData:{"applet ":true,"embed ":true,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(e){e=e.nodeType?bI.cache[e[bI.expando]]:e[bI.expando];return !!e&&!Q(e)},data:function(i,e,b6){return bc(i,e,b6)},removeData:function(i,e){return ab(i,e)},_data:function(i,e,b6){return bc(i,e,b6,true)},_removeData:function(i,e){return ab(i,e,true)}});bI.fn.extend({data:function(b8,cb){var b7,b6,ca,b9=this[0],e=b9&&b9.attributes;if(b8===undefined){if(this.length){ca=bI.data(b9);if(b9.nodeType===1&&!bI._data(b9,"parsedAttrs")){b7=e.length;while(b7--){if(e[b7]){b6=e[b7].name;if(b6.indexOf("data-")===0){b6=bI.camelCase(b6.slice(5));bA(b9,b6,ca[b6])}}}bI._data(b9,"parsedAttrs",true)}}return ca}if(typeof b8==="object"){return this.each(function(){bI.data(this,b8)})}return arguments.length>1?this.each(function(){bI.data(this,b8,cb)}):b9?bA(b9,b8,bI.data(b9,b8)):undefined},removeData:function(e){return this.each(function(){bI.removeData(this,e)})}});bI.extend({queue:function(b6,i,b7){var e;if(b6){i=(i||"fx")+"queue";e=bI._data(b6,i);if(b7){if(!e||bI.isArray(b7)){e=bI._data(b6,i,bI.makeArray(b7))}else{e.push(b7)}}return e||[]}},dequeue:function(b9,b8){b8=b8||"fx";var i=bI.queue(b9,b8),ca=i.length,b7=i.shift(),e=bI._queueHooks(b9,b8),b6=function(){bI.dequeue(b9,b8)};if(b7==="inprogress"){b7=i.shift();ca--}if(b7){if(b8==="fx"){i.unshift("inprogress")}delete e.stop;b7.call(b9,b6,e)}if(!ca&&e){e.empty.fire()}},_queueHooks:function(b6,i){var e=i+"queueHooks";return bI._data(b6,e)||bI._data(b6,e,{empty:bI.Callbacks("once memory").add(function(){bI._removeData(b6,i+"queue");bI._removeData(b6,e)})})}});bI.fn.extend({queue:function(e,i){var b6=2;if(typeof e!=="string"){i=e;e="fx";b6--}if(arguments.length
a";D.leadingWhitespace=b8.firstChild.nodeType===3;D.tbody=!b8.getElementsByTagName("tbody").length;D.htmlSerialize=!!b8.getElementsByTagName("link").length;D.html5Clone=n.createElement("nav").cloneNode(true).outerHTML!=="<:nav>";i.type="checkbox";i.checked=true;b6.appendChild(i);D.appendChecked=i.checked;b8.innerHTML="";D.noCloneChecked=!!b8.cloneNode(true).lastChild.defaultValue;b6.appendChild(b8);b8.innerHTML="";D.checkClone=b8.cloneNode(true).cloneNode(true).lastChild.checked;D.noCloneEvent=true;if(b8.attachEvent){b8.attachEvent("onclick",function(){D.noCloneEvent=false});b8.cloneNode(true).click()}if(D.deleteExpando==null){D.deleteExpando=true;try{delete b8.test}catch(b7){D.deleteExpando=false}}})();(function(){var b6,e,b7=n.createElement("div");for(b6 in {submit:true,change:true,focusin:true}){e="on"+b6;if(!(D[b6+"Bubbles"]=e in a5)){b7.setAttribute(e,"t");D[b6+"Bubbles"]=b7.attributes[e].expando===false}}b7=null})();var bG=/^(?:input|select|textarea)$/i,a6=/^key/,bM=/^(?:mouse|pointer|contextmenu)|click/,bC=/^(?:focusinfocus|focusoutblur)$/,bx=/^([^.]*)(?:\.(.+)|)$/;function U(){return true}function Z(){return false}function am(){try{return n.activeElement}catch(e){}}bI.event={global:{},add:function(b8,cd,ci,ca,b9){var cb,cj,ck,b6,cf,cc,ch,b7,cg,e,i,ce=bI._data(b8);if(!ce){return}if(ci.handler){b6=ci;ci=b6.handler;b9=b6.selector}if(!ci.guid){ci.guid=bI.guid++}if(!(cj=ce.events)){cj=ce.events={}}if(!(cc=ce.handle)){cc=ce.handle=function(cl){return typeof bI!==aC&&(!cl||bI.event.triggered!==cl.type)?bI.event.dispatch.apply(cc.elem,arguments):undefined};cc.elem=b8}cd=(cd||"").match(aF)||[""];ck=cd.length;while(ck--){cb=bx.exec(cd[ck])||[];cg=i=cb[1];e=(cb[2]||"").split(".").sort();if(!cg){continue}cf=bI.event.special[cg]||{};cg=(b9?cf.delegateType:cf.bindType)||cg;cf=bI.event.special[cg]||{};ch=bI.extend({type:cg,origType:i,data:ca,handler:ci,guid:ci.guid,selector:b9,needsContext:b9&&bI.expr.match.needsContext.test(b9),namespace:e.join(".")},b6);if(!(b7=cj[cg])){b7=cj[cg]=[];b7.delegateCount=0;if(!cf.setup||cf.setup.call(b8,ca,e,cc)===false){if(b8.addEventListener){b8.addEventListener(cg,cc,false)}else{if(b8.attachEvent){b8.attachEvent("on"+cg,cc)}}}}if(cf.add){cf.add.call(b8,ch);if(!ch.handler.guid){ch.handler.guid=ci.guid}}if(b9){b7.splice(b7.delegateCount++,0,ch)}else{b7.push(ch)}bI.event.global[cg]=true}b8=null},remove:function(b7,cd,ck,b8,cc){var ca,ch,cb,b9,cj,ci,cf,b6,cg,e,i,ce=bI.hasData(b7)&&bI._data(b7);if(!ce||!(ci=ce.events)){return}cd=(cd||"").match(aF)||[""];cj=cd.length;while(cj--){cb=bx.exec(cd[cj])||[];cg=i=cb[1];e=(cb[2]||"").split(".").sort();if(!cg){for(cg in ci){bI.event.remove(b7,cg+cd[cj],ck,b8,true)}continue}cf=bI.event.special[cg]||{};cg=(b8?cf.delegateType:cf.bindType)||cg;b6=ci[cg]||[];cb=cb[2]&&new RegExp("(^|\\.)"+e.join("\\.(?:.*\\.|)")+"(\\.|$)");b9=ca=b6.length;while(ca--){ch=b6[ca];if((cc||i===ch.origType)&&(!ck||ck.guid===ch.guid)&&(!cb||cb.test(ch.namespace))&&(!b8||b8===ch.selector||b8==="**"&&ch.selector)){b6.splice(ca,1);if(ch.selector){b6.delegateCount--}if(cf.remove){cf.remove.call(b7,ch)}}}if(b9&&!b6.length){if(!cf.teardown||cf.teardown.call(b7,e,ce.handle)===false){bI.removeEvent(b7,cg,ce.handle)}delete ci[cg]}}if(bI.isEmptyObject(ci)){delete ce.handle;bI._removeData(b7,"events")}},trigger:function(b6,cd,b9,ck){var ce,b8,ci,cj,cg,cc,cb,ca=[b9||n],ch=K.call(b6,"type")?b6.type:b6,b7=K.call(b6,"namespace")?b6.namespace.split("."):[];ci=cc=b9=b9||n;if(b9.nodeType===3||b9.nodeType===8){return}if(bC.test(ch+bI.event.triggered)){return}if(ch.indexOf(".")>=0){b7=ch.split(".");ch=b7.shift();b7.sort()}b8=ch.indexOf(":")<0&&"on"+ch;b6=b6[bI.expando]?b6:new bI.Event(ch,typeof b6==="object"&&b6);b6.isTrigger=ck?2:3;b6.namespace=b7.join(".");b6.namespace_re=b6.namespace?new RegExp("(^|\\.)"+b7.join("\\.(?:.*\\.|)")+"(\\.|$)"):null;b6.result=undefined;if(!b6.target){b6.target=b9}cd=cd==null?[b6]:bI.makeArray(cd,[b6]);cg=bI.event.special[ch]||{};if(!ck&&cg.trigger&&cg.trigger.apply(b9,cd)===false){return}if(!ck&&!cg.noBubble&&!bI.isWindow(b9)){cj=cg.delegateType||ch;if(!bC.test(cj+ch)){ci=ci.parentNode}for(;ci;ci=ci.parentNode){ca.push(ci);cc=ci}if(cc===(b9.ownerDocument||n)){ca.push(cc.defaultView||cc.parentWindow||a5)}}cb=0;while((ci=ca[cb++])&&!b6.isPropagationStopped()){b6.type=cb>1?cj:cg.bindType||ch;ce=(bI._data(ci,"events")||{})[b6.type]&&bI._data(ci,"handle");if(ce){ce.apply(ci,cd)}ce=b8&&ci[b8];if(ce&&ce.apply&&bI.acceptData(ci)){b6.result=ce.apply(ci,cd);if(b6.result===false){b6.preventDefault()}}}b6.type=ch;if(!ck&&!b6.isDefaultPrevented()){if((!cg._default||cg._default.apply(ca.pop(),cd)===false)&&bI.acceptData(b9)){if(b8&&b9[ch]&&!bI.isWindow(b9)){cc=b9[b8];if(cc){b9[b8]=null}bI.event.triggered=ch;try{b9[ch]()}catch(cf){}bI.event.triggered=undefined;if(cc){b9[b8]=cc}}}}return b6.result},dispatch:function(e){e=bI.event.fix(e);var b9,ca,ce,b6,b8,cd=[],cc=P.call(arguments),b7=(bI._data(this,"events")||{})[e.type]||[],cb=bI.event.special[e.type]||{};cc[0]=e;e.delegateTarget=this;if(cb.preDispatch&&cb.preDispatch.call(this,e)===false){return}cd=bI.event.handlers.call(this,e,b7);b9=0;while((b6=cd[b9++])&&!e.isPropagationStopped()){e.currentTarget=b6.elem;b8=0;while((ce=b6.handlers[b8++])&&!e.isImmediatePropagationStopped()){if(!e.namespace_re||e.namespace_re.test(ce.namespace)){e.handleObj=ce;e.data=ce.data;ca=((bI.event.special[ce.origType]||{}).handle||ce.handler).apply(b6.elem,cc);if(ca!==undefined){if((e.result=ca)===false){e.preventDefault();e.stopPropagation()}}}}}if(cb.postDispatch){cb.postDispatch.call(this,e)}return e.result},handlers:function(e,b7){var b6,cc,ca,b9,cb=[],b8=b7.delegateCount,cd=e.target;if(b8&&cd.nodeType&&(!e.button||e.type!=="click")){for(;cd!=this;cd=cd.parentNode||this){if(cd.nodeType===1&&(cd.disabled!==true||e.type!=="click")){ca=[];for(b9=0;b9=0:bI.find(b6,this,null,[cd]).length}if(ca[b6]){ca.push(cc)}}if(ca.length){cb.push({elem:cd,handlers:ca})}}}}if(b8]","i"),b5=/^\s+/,aH=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,o=/<([\w:]+)/,b0=/\s*$/g,W={option:[1,""],legend:[1,"
","
"],area:[1,"",""],param:[1,"",""],thead:[1,"","
"],tr:[2,"","
"],col:[2,"","
"],td:[3,"","
"],_default:D.htmlSerialize?[0,"",""]:[1,"X
","
"]},aT=B(n),k=aT.appendChild(n.createElement("div"));W.optgroup=W.option;W.tbody=W.tfoot=W.colgroup=W.caption=W.thead;W.th=W.td;function l(b8,e){var b6,b9,b7=0,ca=typeof b8.getElementsByTagName!==aC?b8.getElementsByTagName(e||"*"):typeof b8.querySelectorAll!==aC?b8.querySelectorAll(e||"*"):undefined;if(!ca){for(ca=[],b6=b8.childNodes||b8;(b9=b6[b7])!=null;b7++){if(!e||bI.nodeName(b9,e)){ca.push(b9)}else{bI.merge(ca,l(b9,e))}}}return e===undefined||e&&bI.nodeName(b8,e)?bI.merge([b8],ca):ca}function bY(e){if(aM.test(e.type)){e.defaultChecked=e.checked}}function a3(i,e){return bI.nodeName(i,"table")&&bI.nodeName(e.nodeType!==11?e:e.firstChild,"tr")?i.getElementsByTagName("tbody")[0]||i.appendChild(i.ownerDocument.createElement("tbody")):i}function u(e){e.type=(bI.find.attr(e,"type")!==null)+"/"+e.type;return e}function bf(i){var e=ar.exec(i.type);if(e){i.type=e[1]}else{i.removeAttribute("type")}return i}function bu(e,b7){var b8,b6=0;for(;(b8=e[b6])!=null;b6++){bI._data(b8,"globalEval",!b7||bI._data(b7[b6],"globalEval"))}}function at(cc,b6){if(b6.nodeType!==1||!bI.hasData(cc)){return}var b9,b8,e,cb=bI._data(cc),ca=bI._data(b6,cb),b7=cb.events;if(b7){delete ca.handle;ca.events={};for(b9 in b7){for(b8=0,e=b7[b9].length;b8")){cd=b6.cloneNode(true)}else{k.innerHTML=b6.outerHTML;k.removeChild(cd=k.firstChild)}if((!D.noCloneEvent||!D.noCloneChecked)&&(b6.nodeType===1||b6.nodeType===11)&&!bI.isXMLDoc(b6)){ca=l(cd);cb=l(b6);for(b9=0;(b7=cb[b9])!=null;++b9){if(ca[b9]){T(b7,ca[b9])}}}if(b8){if(e){cb=cb||l(b6);ca=ca||l(cd);for(b9=0;(b7=cb[b9])!=null;b9++){at(b7,ca[b9])}}else{at(b6,cd)}}ca=l(cd,"script");if(ca.length>0){bu(ca,!cc&&l(b6,"script"))}ca=cb=b7=null;return cd},buildFragment:function(b6,b8,cd,ci){var ce,ca,cc,ch,cj,cg,b7,cb=b6.length,b9=B(b8),e=[],cf=0;for(;cf")+b7[2];ce=b7[0];while(ce--){ch=ch.lastChild}if(!D.leadingWhitespace&&b5.test(ca)){e.push(b8.createTextNode(b5.exec(ca)[0]))}if(!D.tbody){ca=cj==="table"&&!b0.test(ca)?ch.firstChild:b7[1]===""&&!b0.test(ca)?ch:0;ce=ca&&ca.childNodes.length;while(ce--){if(bI.nodeName((cg=ca.childNodes[ce]),"tbody")&&!cg.childNodes.length){ca.removeChild(cg)}}}bI.merge(e,ch.childNodes);ch.textContent="";while(ch.firstChild){ch.removeChild(ch.firstChild)}ch=b9.lastChild}}}}if(ch){b9.removeChild(ch)}if(!D.appendChecked){bI.grep(l(e,"input"),bY)}cf=0;while((ca=e[cf++])){if(ci&&bI.inArray(ca,ci)!==-1){continue}cc=bI.contains(ca.ownerDocument,ca);ch=l(b9.appendChild(ca),"script");if(cc){bu(ch)}if(cd){ce=0;while((ca=ch[ce++])){if(bB.test(ca.type||"")){cd.push(ca)}}}}ch=null;return b9},cleanData:function(b6,ce){var b8,cd,b7,b9,ca=0,cf=bI.expando,e=bI.cache,cb=D.deleteExpando,cc=bI.event.special;for(;(b8=b6[ca])!=null;ca++){if(ce||bI.acceptData(b8)){b7=b8[cf];b9=b7&&e[b7];if(b9){if(b9.events){for(cd in b9.events){if(cc[cd]){bI.event.remove(b8,cd)}else{bI.removeEvent(b8,cd,b9.handle)}}}if(e[b7]){delete e[b7];if(cb){delete b8[cf]}else{if(typeof b8.removeAttribute!==aC){b8.removeAttribute(cf)}else{b8[cf]=null}}aP.push(b7)}}}}}});bI.fn.extend({text:function(e){return aB(this,function(i){return i===undefined?bI.text(this):this.empty().append((this[0]&&this[0].ownerDocument||n).createTextNode(i))},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(this.nodeType===1||this.nodeType===11||this.nodeType===9){var i=a3(this,e);i.appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(this.nodeType===1||this.nodeType===11||this.nodeType===9){var i=a3(this,e);i.insertBefore(e,i.firstChild)}})},before:function(){return this.domManip(arguments,function(e){if(this.parentNode){this.parentNode.insertBefore(e,this)}})},after:function(){return this.domManip(arguments,function(e){if(this.parentNode){this.parentNode.insertBefore(e,this.nextSibling)}})},remove:function(e,b9){var b8,b6=e?bI.filter(e,this):this,b7=0;for(;(b8=b6[b7])!=null;b7++){if(!b9&&b8.nodeType===1){bI.cleanData(l(b8))}if(b8.parentNode){if(b9&&bI.contains(b8.ownerDocument,b8)){bu(l(b8,"script"))}b8.parentNode.removeChild(b8)}}return this},empty:function(){var b6,e=0;for(;(b6=this[e])!=null;e++){if(b6.nodeType===1){bI.cleanData(l(b6,false))}while(b6.firstChild){b6.removeChild(b6.firstChild)}if(b6.options&&bI.nodeName(b6,"select")){b6.options.length=0}}return this},clone:function(i,e){i=i==null?false:i;e=e==null?i:e;return this.map(function(){return bI.clone(this,i,e)})},html:function(e){return aB(this,function(b9){var b8=this[0]||{},b7=0,b6=this.length;if(b9===undefined){return b8.nodeType===1?b8.innerHTML.replace(aD,""):undefined}if(typeof b9==="string"&&!an.test(b9)&&(D.htmlSerialize||!M.test(b9))&&(D.leadingWhitespace||!b5.test(b9))&&!W[(o.exec(b9)||["",""])[1].toLowerCase()]){b9=b9.replace(aH,"<$1>");try{for(;b71&&typeof ce==="string"&&!D.checkClone&&bW.test(ce))){return this.each(function(cj){var i=cf.eq(cj);if(b6){cd[0]=ce.call(this,cj,i.html())}i.domManip(cd,ci)})}if(b8){cc=bI.buildFragment(cd,this[0].ownerDocument,false,this);cb=cc.firstChild;if(cc.childNodes.length===1){cc=cb}if(cb){b9=bI.map(l(cc,"script"),u);e=b9.length;for(;ca")).appendTo(i.documentElement);i=(aI[0].contentWindow||aI[0].contentDocument).document;i.write();i.close();e=a4(b6,i);aI.detach()}bl[b6]=e}return e}(function(){var e;D.shrinkWrapBlocks=function(){if(e!=null){return e}e=false;var b7,i,b6;i=n.getElementsByTagName("body")[0];if(!i||!i.style){return}b7=n.createElement("div");b6=n.createElement("div");b6.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px";i.appendChild(b6).appendChild(b7);if(typeof b7.style.zoom!==aC){b7.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:1px;width:1px;zoom:1";b7.appendChild(n.createElement("div")).style.width="5px";e=b7.offsetWidth!==3}i.removeChild(b6);return e}})();var aZ=(/^margin/);var Y=new RegExp("^("+aE+")(?!px)[a-z%]+$","i");var bq,G,bo=/^(top|right|bottom|left)$/;if(a5.getComputedStyle){bq=function(e){if(e.ownerDocument.defaultView.opener){return e.ownerDocument.defaultView.getComputedStyle(e,null)}return a5.getComputedStyle(e,null)};G=function(cb,i,ca){var b8,b7,b9,e,b6=cb.style;ca=ca||bq(cb);e=ca?ca.getPropertyValue(i)||ca[i]:undefined;if(ca){if(e===""&&!bI.contains(cb.ownerDocument,cb)){e=bI.style(cb,i)}if(Y.test(e)&&aZ.test(i)){b8=b6.width;b7=b6.minWidth;b9=b6.maxWidth;b6.minWidth=b6.maxWidth=b6.width=e;e=ca.width;b6.width=b8;b6.minWidth=b7;b6.maxWidth=b9}}return e===undefined?e:e+""}}else{if(n.documentElement.currentStyle){bq=function(e){return e.currentStyle};G=function(ca,b7,b9){var cb,i,e,b6,b8=ca.style;b9=b9||bq(ca);b6=b9?b9[b7]:undefined;if(b6==null&&b8&&b8[b7]){b6=b8[b7]}if(Y.test(b6)&&!bo.test(b7)){cb=b8.left;i=ca.runtimeStyle;e=i&&i.left;if(e){i.left=ca.currentStyle.left}b8.left=b7==="fontSize"?"1em":b6;b6=b8.pixelLeft+"px";b8.left=cb;if(e){i.left=e}}return b6===undefined?b6:b6+""||"auto"}}}function a7(e,i){return{get:function(){var b6=e();if(b6==null){return}if(b6){delete this.get;return}return(this.get=i).apply(this,arguments)}}}(function(){var cb,b9,b7,ca,b6,b8,i;cb=n.createElement("div");cb.innerHTML="
a";b7=cb.getElementsByTagName("a")[0];b9=b7&&b7.style;if(!b9){return}b9.cssText="float:left;opacity:.5";D.opacity=b9.opacity==="0.5";D.cssFloat=!!b9.cssFloat;cb.style.backgroundClip="content-box";cb.cloneNode(true).style.backgroundClip="";D.clearCloneStyle=cb.style.backgroundClip==="content-box";D.boxSizing=b9.boxSizing===""||b9.MozBoxSizing===""||b9.WebkitBoxSizing==="";bI.extend(D,{reliableHiddenOffsets:function(){if(b8==null){e()}return b8},boxSizingReliable:function(){if(b6==null){e()}return b6},pixelPosition:function(){if(ca==null){e()}return ca},reliableMarginRight:function(){if(i==null){e()}return i}});function e(){var cf,cc,cd,ce;cc=n.getElementsByTagName("body")[0];if(!cc||!cc.style){return}cf=n.createElement("div");cd=n.createElement("div");cd.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px";cc.appendChild(cd).appendChild(cf);cf.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:block;margin-top:1%;top:1%;border:1px;padding:1px;width:4px;position:absolute";ca=b6=false;i=true;if(a5.getComputedStyle){ca=(a5.getComputedStyle(cf,null)||{}).top!=="1%";b6=(a5.getComputedStyle(cf,null)||{width:"4px"}).width==="4px";ce=cf.appendChild(n.createElement("div"));ce.style.cssText=cf.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0";ce.style.marginRight=ce.style.width="0";cf.style.width="1px";i=!parseFloat((a5.getComputedStyle(ce,null)||{}).marginRight);cf.removeChild(ce)}cf.innerHTML="
t
";ce=cf.getElementsByTagName("td");ce[0].style.cssText="margin:0;border:0;padding:0;display:none";b8=ce[0].offsetHeight===0;if(b8){ce[0].style.display="";ce[1].style.display="none";b8=ce[0].offsetHeight===0}cc.removeChild(cd)}})();bI.swap=function(b9,b8,ca,b7){var b6,i,e={};for(i in b8){e[i]=b9.style[i];b9.style[i]=b8[i]}b6=ca.apply(b9,b7||[]);for(i in b8){b9.style[i]=e[i]}return b6};var bj=/alpha\([^)]*\)/i,aU=/opacity\s*=\s*([^)]*)/,H=/^(none|table(?!-c[ea]).+)/,bb=new RegExp("^("+aE+")(.*)$","i"),V=new RegExp("^([+-])=("+aE+")","i"),be={position:"absolute",visibility:"hidden",display:"block"},bD={letterSpacing:"0",fontWeight:"400"},aw=["Webkit","O","Moz","ms"];function c(b8,b6){if(b6 in b8){return b6}var b9=b6.charAt(0).toUpperCase()+b6.slice(1),e=b6,b7=aw.length;while(b7--){b6=aw[b7]+b9;if(b6 in b8){return b6}}return e}function s(ca,e){var cb,b8,b9,i=[],b6=0,b7=ca.length;for(;b6=1||b9==="")&&bI.trim(b6.replace(bj,""))===""&&b7.removeAttribute){b7.removeAttribute("filter");if(b9===""||i&&!i.filter){return}}b7.filter=bj.test(b6)?b6.replace(bj,e):b6+" "+e}}}bI.cssHooks.marginRight=a7(D.reliableMarginRight,function(i,e){if(e){return bI.swap(i,{display:"inline-block"},G,[i,"marginRight"])}});bI.each({margin:"",padding:"",border:"Width"},function(e,i){bI.cssHooks[e+i]={expand:function(b8){var b7=0,b6={},b9=typeof b8==="string"?b8.split(" "):[b8];for(;b7<4;b7++){b6[e+bT[b7]+i]=b9[b7]||b9[b7-2]||b9[0]}return b6}};if(!aZ.test(e)){bI.cssHooks[e+i].set=aN}});bI.fn.extend({css:function(e,i){return aB(this,function(ca,b7,cb){var b9,b6,cc={},b8=0;if(bI.isArray(b7)){b9=bq(ca);b6=b7.length;for(;b81)},show:function(){return s(this,true)},hide:function(){return s(this)},toggle:function(e){if(typeof e==="boolean"){return e?this.show():this.hide()}return this.each(function(){if(S(this)){bI(this).show()}else{bI(this).hide()}})}});function J(b6,i,b8,e,b7){return new J.prototype.init(b6,i,b8,e,b7)}bI.Tween=J;J.prototype={constructor:J,init:function(b7,i,b9,e,b8,b6){this.elem=b7;this.prop=b9;this.easing=b8||"swing";this.options=i;this.start=this.now=this.cur();this.end=e;this.unit=b6||(bI.cssNumber[b9]?"":"px")},cur:function(){var e=J.propHooks[this.prop];return e&&e.get?e.get(this):J.propHooks._default.get(this)},run:function(b6){var i,e=J.propHooks[this.prop];if(this.options.duration){this.pos=i=bI.easing[this.easing](b6,this.options.duration*b6,0,1,this.options.duration)}else{this.pos=i=b6}this.now=(this.end-this.start)*i+this.start;if(this.options.step){this.options.step.call(this.elem,this.now,this)}if(e&&e.set){e.set(this)}else{J.propHooks._default.set(this)}return this}};J.prototype.init.prototype=J.prototype;J.propHooks={_default:{get:function(i){var e;if(i.elem[i.prop]!=null&&(!i.elem.style||i.elem.style[i.prop]==null)){return i.elem[i.prop]}e=bI.css(i.elem,i.prop,"");return !e||e==="auto"?0:e},set:function(e){if(bI.fx.step[e.prop]){bI.fx.step[e.prop](e)}else{if(e.elem.style&&(e.elem.style[bI.cssProps[e.prop]]!=null||bI.cssHooks[e.prop])){bI.style(e.elem,e.prop,e.now+e.unit)}else{e.elem[e.prop]=e.now}}}}};J.propHooks.scrollTop=J.propHooks.scrollLeft={set:function(e){if(e.elem.nodeType&&e.elem.parentNode){e.elem[e.prop]=e.now}}};bI.easing={linear:function(e){return e},swing:function(e){return 0.5-Math.cos(e*Math.PI)/2}};bI.fx=J.prototype.init;bI.fx.step={};var N,ae,bR=/^(?:toggle|show|hide)$/,bJ=new RegExp("^(?:([+-])=|)("+aE+")([a-z%]*)$","i"),bP=/queueHooks$/,aG=[h],a2={"*":[function(e,ca){var cc=this.createTween(e,ca),b8=cc.cur(),b7=bJ.exec(ca),cb=b7&&b7[3]||(bI.cssNumber[e]?"":"px"),i=(bI.cssNumber[e]||cb!=="px"&&+b8)&&bJ.exec(bI.css(cc.elem,e)),b6=1,b9=20;if(i&&i[3]!==cb){cb=cb||i[3];b7=b7||[];i=+b8||1;do{b6=b6||".5";i=i/b6;bI.style(cc.elem,e,i+cb)}while(b6!==(b6=cc.cur()/b8)&&b6!==1&&--b9)}if(b7){i=cc.start=+i||+b8||0;cc.unit=cb;cc.end=b7[1]?i+(b7[1]+1)*b7[2]:+b7[2]}return cc}]};function bn(){setTimeout(function(){N=undefined});return(N=bI.now())}function bH(b7,b9){var b8,e={height:b7},b6=0;b9=b9?1:0;for(;b6<4;b6+=2-b9){b8=bT[b6];e["margin"+b8]=e["padding"+b8]=b7}if(b9){e.opacity=e.width=b7}return e}function bd(b8,ca,b7){var i,b9=(a2[ca]||[]).concat(a2["*"]),e=0,b6=b9.length;for(;e
a";i=b8.getElementsByTagName("a")[0];e=n.createElement("select");b7=e.appendChild(n.createElement("option"));b6=b8.getElementsByTagName("input")[0];i.style.cssText="top:1px";D.getSetAttribute=b8.className!=="t";D.style=/top/.test(i.getAttribute("style"));D.hrefNormalized=i.getAttribute("href")==="/a";D.checkOn=!!b6.value;D.optSelected=b7.selected;D.enctype=!!n.createElement("form").enctype;e.disabled=true;D.optDisabled=!b7.disabled;b6=n.createElement("input");b6.setAttribute("value","");D.input=b6.getAttribute("value")==="";b6.value="t";b6.setAttribute("type","radio");D.radioValue=b6.value==="t"})();var al=/\r/g;bI.fn.extend({val:function(b7){var e,i,b8,b6=this[0];if(!arguments.length){if(b6){e=bI.valHooks[b6.type]||bI.valHooks[b6.nodeName.toLowerCase()];if(e&&"get" in e&&(i=e.get(b6,"value"))!==undefined){return i}i=b6.value;return typeof i==="string"?i.replace(al,""):i==null?"":i}return}b8=bI.isFunction(b7);return this.each(function(b9){var ca;if(this.nodeType!==1){return}if(b8){ca=b7.call(this,b9,bI(this).val())}else{ca=b7}if(ca==null){ca=""}else{if(typeof ca==="number"){ca+=""}else{if(bI.isArray(ca)){ca=bI.map(ca,function(cb){return cb==null?"":cb+""})}}}e=bI.valHooks[this.type]||bI.valHooks[this.nodeName.toLowerCase()];if(!e||!("set" in e)||e.set(this,ca,"value")===undefined){this.value=ca}})}});bI.extend({valHooks:{option:{get:function(e){var i=bI.find.attr(e,"value");return i!=null?i:bI.trim(bI.text(e))}},select:{get:function(e){var cb,b7,cd=e.options,b9=e.selectedIndex,b8=e.type==="select-one"||b9<0,cc=b8?null:[],ca=b8?b9+1:cd.length,b6=b9<0?ca:b8?b9:0;for(;b6=0){try{b9.selected=cc=true}catch(b6){b9.scrollHeight}}else{b9.selected=false}}if(!cc){ca.selectedIndex=-1}return b7}}}});bI.each(["radio","checkbox"],function(){bI.valHooks[this]={set:function(e,i){if(bI.isArray(i)){return(e.checked=bI.inArray(bI(e).val(),i)>=0)}}};if(!D.checkOn){bI.valHooks[this].get=function(e){return e.getAttribute("value")===null?"on":e.value}}});var ba,b3,bO=bI.expr.attrHandle,aq=/^(?:checked|selected)$/i,bN=D.getSetAttribute,bF=D.input;bI.fn.extend({attr:function(e,i){return aB(this,bI.attr,e,i,arguments.length>1)},removeAttr:function(e){return this.each(function(){bI.removeAttr(this,e)})}});bI.extend({attr:function(b8,b7,b9){var e,b6,i=b8.nodeType;if(!b8||i===3||i===8||i===2){return}if(typeof b8.getAttribute===aC){return bI.prop(b8,b7,b9)}if(i!==1||!bI.isXMLDoc(b8)){b7=b7.toLowerCase();e=bI.attrHooks[b7]||(bI.expr.match.bool.test(b7)?b3:ba)}if(b9!==undefined){if(b9===null){bI.removeAttr(b8,b7)}else{if(e&&"set" in e&&(b6=e.set(b8,b9,b7))!==undefined){return b6}else{b8.setAttribute(b7,b9+"");return b9}}}else{if(e&&"get" in e&&(b6=e.get(b8,b7))!==null){return b6}else{b6=bI.find.attr(b8,b7);return b6==null?undefined:b6}}},removeAttr:function(b7,b9){var e,b8,b6=0,ca=b9&&b9.match(aF);if(ca&&b7.nodeType===1){while((e=ca[b6++])){b8=bI.propFix[e]||e;if(bI.expr.match.bool.test(e)){if(bF&&bN||!aq.test(e)){b7[b8]=false}else{b7[bI.camelCase("default-"+e)]=b7[b8]=false}}else{bI.attr(b7,e,"")}b7.removeAttribute(bN?e:b8)}}},attrHooks:{type:{set:function(e,i){if(!D.radioValue&&i==="radio"&&bI.nodeName(e,"input")){var b6=e.value;e.setAttribute("type",i);if(b6){e.value=b6}return i}}}}});b3={set:function(i,b6,e){if(b6===false){bI.removeAttr(i,e)}else{if(bF&&bN||!aq.test(e)){i.setAttribute(!bN&&bI.propFix[e]||e,e)}else{i[bI.camelCase("default-"+e)]=i[e]=true}}return e}};bI.each(bI.expr.match.bool.source.match(/\w+/g),function(b7,b6){var e=bO[b6]||bI.find.attr;bO[b6]=bF&&bN||!aq.test(b6)?function(b9,b8,cb){var i,ca;if(!cb){ca=bO[b8];bO[b8]=i;i=e(b9,b8,cb)!=null?b8.toLowerCase():null;bO[b8]=ca}return i}:function(b8,i,b9){if(!b9){return b8[bI.camelCase("default-"+i)]?i.toLowerCase():null}}});if(!bF||!bN){bI.attrHooks.value={set:function(i,b6,e){if(bI.nodeName(i,"input")){i.defaultValue=b6}else{return ba&&ba.set(i,b6,e)}}}}if(!bN){ba={set:function(b6,b7,i){var e=b6.getAttributeNode(i);if(!e){b6.setAttributeNode((e=b6.ownerDocument.createAttribute(i)))}e.value=b7+="";if(i==="value"||b7===b6.getAttribute(i)){return b7}}};bO.id=bO.name=bO.coords=function(b6,i,b7){var e;if(!b7){return(e=b6.getAttributeNode(i))&&e.value!==""?e.value:null}};bI.valHooks.button={get:function(b6,i){var e=b6.getAttributeNode(i);if(e&&e.specified){return e.value}},set:ba.set};bI.attrHooks.contenteditable={set:function(i,b6,e){ba.set(i,b6===""?false:b6,e)}};bI.each(["width","height"],function(b6,e){bI.attrHooks[e]={set:function(i,b7){if(b7===""){i.setAttribute(e,"auto");return b7}}}})}if(!D.style){bI.attrHooks.style={get:function(e){return e.style.cssText||undefined},set:function(e,i){return(e.style.cssText=i+"")}}}var aJ=/^(?:input|select|textarea|button|object)$/i,F=/^(?:a|area)$/i;bI.fn.extend({prop:function(e,i){return aB(this,bI.prop,e,i,arguments.length>1)},removeProp:function(e){e=bI.propFix[e]||e;return this.each(function(){try{this[e]=undefined;delete this[e]}catch(i){}})}});bI.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(b9,b7,ca){var b6,e,b8,i=b9.nodeType;if(!b9||i===3||i===8||i===2){return}b8=i!==1||!bI.isXMLDoc(b9);if(b8){b7=bI.propFix[b7]||b7;e=bI.propHooks[b7]}if(ca!==undefined){return e&&"set" in e&&(b6=e.set(b9,ca,b7))!==undefined?b6:(b9[b7]=ca)}else{return e&&"get" in e&&(b6=e.get(b9,b7))!==null?b6:b9[b7]}},propHooks:{tabIndex:{get:function(i){var e=bI.find.attr(i,"tabindex");return e?parseInt(e,10):aJ.test(i.nodeName)||F.test(i.nodeName)&&i.href?0:-1}}}});if(!D.hrefNormalized){bI.each(["href","src"],function(b6,e){bI.propHooks[e]={get:function(i){return i.getAttribute(e,4)}}})}if(!D.optSelected){bI.propHooks.selected={get:function(i){var e=i.parentNode;if(e){e.selectedIndex;if(e.parentNode){e.parentNode.selectedIndex}}return null}}}bI.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){bI.propFix[this.toLowerCase()]=this});if(!D.enctype){bI.propFix.enctype="encoding"}var bL=/[\t\r\n\f]/g;bI.fn.extend({addClass:function(cd){var b7,b6,ce,cb,b8,e,b9=0,ca=this.length,cc=typeof cd==="string"&&cd;if(bI.isFunction(cd)){return this.each(function(i){bI(this).addClass(cd.call(this,i,this.className))})}if(cc){b7=(cd||"").match(aF)||[];for(;b9=0){ce=ce.replace(" "+cb+" "," ")}}e=cd?bI.trim(ce):"";if(b6.className!==e){b6.className=e}}}}return this},toggleClass:function(b6,e){var i=typeof b6;if(typeof e==="boolean"&&i==="string"){return e?this.addClass(b6):this.removeClass(b6)}if(bI.isFunction(b6)){return this.each(function(b7){bI(this).toggleClass(b6.call(this,b7,this.className,e),e)})}return this.each(function(){if(i==="string"){var b9,b8=0,b7=bI(this),ca=b6.match(aF)||[];while((b9=ca[b8++])){if(b7.hasClass(b9)){b7.removeClass(b9)}else{b7.addClass(b9)}}}else{if(i===aC||i==="boolean"){if(this.className){bI._data(this,"__className__",this.className)}this.className=this.className||b6===false?"":bI._data(this,"__className__")||""}}})},hasClass:function(e){var b8=" "+e+" ",b7=0,b6=this.length;for(;b7=0){return true}}return false}});bI.each(("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu").split(" "),function(b6,e){bI.fn[e]=function(b7,i){return arguments.length>0?this.on(e,null,b7,i):this.trigger(e)}});bI.fn.extend({hover:function(e,i){return this.mouseenter(e).mouseleave(i||e)},bind:function(e,b6,i){return this.on(e,null,b6,i)},unbind:function(e,i){return this.off(e,null,i)},delegate:function(e,i,b7,b6){return this.on(i,e,b7,b6)},undelegate:function(e,i,b6){return arguments.length===1?this.off(e,"**"):this.off(i,e||"**",b6)}});var bp=bI.now();var bQ=(/\?/);var a1=/(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;bI.parseJSON=function(e){if(a5.JSON&&a5.JSON.parse){return a5.JSON.parse(e+"")}var b7,b6=null,i=bI.trim(e+"");return i&&!bI.trim(i.replace(a1,function(ca,b8,b9,cb){if(b7&&b8){b6=0}if(b6===0){return ca}b7=b9||b8;b6+=!cb-!b9;return""}))?(Function("return "+i))():bI.error("Invalid JSON: "+e)};bI.parseXML=function(b7){var i,b6;if(!b7||typeof b7!=="string"){return null}try{if(a5.DOMParser){b6=new DOMParser();i=b6.parseFromString(b7,"text/xml")}else{i=new ActiveXObject("Microsoft.XMLDOM");i.async="false";i.loadXML(b7)}}catch(b8){i=undefined}if(!i||!i.documentElement||i.getElementsByTagName("parsererror").length){bI.error("Invalid XML: "+b7)}return i};var b4,aa,ap=/#.*$/,R=/([?&])_=[^&]*/,ah=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,C=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,r=/^(?:GET|HEAD)$/,aK=/^\/\//,aV=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,w={},a9={},aX="*/".concat("*");try{aa=location.href}catch(bi){aa=n.createElement("a");aa.href="";aa=aa.href}b4=aV.exec(aa.toLowerCase())||[];function bK(e){return function(b9,ca){if(typeof b9!=="string"){ca=b9;b9="*"}var b6,b7=0,b8=b9.toLowerCase().match(aF)||[];if(bI.isFunction(ca)){while((b6=b8[b7++])){if(b6.charAt(0)==="+"){b6=b6.slice(1)||"*";(e[b6]=e[b6]||[]).unshift(ca)}else{(e[b6]=e[b6]||[]).push(ca)}}}}}function p(e,b6,ca,b7){var i={},b8=(e===a9);function b9(cb){var cc;i[cb]=true;bI.each(e[cb]||[],function(ce,cd){var cf=cd(b6,ca,b7);if(typeof cf==="string"&&!b8&&!i[cf]){b6.dataTypes.unshift(cf);b9(cf);return false}else{if(b8){return !(cc=cf)}}});return cc}return b9(b6.dataTypes[0])||!i["*"]&&b9("*")}function t(b6,b7){var e,i,b8=bI.ajaxSettings.flatOptions||{};for(i in b7){if(b7[i]!==undefined){(b8[i]?b6:(e||(e={})))[i]=b7[i]}}if(e){bI.extend(true,b6,e)}return b6}function g(cc,cb,b8){var e,b7,b6,b9,i=cc.contents,ca=cc.dataTypes;while(ca[0]==="*"){ca.shift();if(b7===undefined){b7=cc.mimeType||cb.getResponseHeader("Content-Type")}}if(b7){for(b9 in i){if(i[b9]&&i[b9].test(b7)){ca.unshift(b9);break}}}if(ca[0] in b8){b6=ca[0]}else{for(b9 in b8){if(!ca[0]||cc.converters[b9+" "+ca[0]]){b6=b9;break}if(!e){e=b9}}b6=b6||e}if(b6){if(b6!==ca[0]){ca.unshift(b6)}return b8[b6]}}function ag(cg,b8,cd,b6){var i,cb,ce,b9,b7,cf={},cc=cg.dataTypes.slice();if(cc[1]){for(ce in cg.converters){cf[ce.toLowerCase()]=cg.converters[ce]}}cb=cc.shift();while(cb){if(cg.responseFields[cb]){cd[cg.responseFields[cb]]=b8}if(!b7&&b6&&cg.dataFilter){b8=cg.dataFilter(b8,cg.dataType)}b7=cb;cb=cc.shift();if(cb){if(cb==="*"){cb=b7}else{if(b7!=="*"&&b7!==cb){ce=cf[b7+" "+cb]||cf["* "+cb];if(!ce){for(i in cf){b9=i.split(" ");if(b9[1]===cb){ce=cf[b7+" "+b9[0]]||cf["* "+b9[0]];if(ce){if(ce===true){ce=cf[i]}else{if(cf[i]!==true){cb=b9[0];cc.unshift(b9[1])}}break}}}}if(ce!==true){if(ce&&cg["throws"]){b8=ce(b8)}else{try{b8=ce(b8)}catch(ca){return{state:"parsererror",error:ce?ca:"No conversion from "+b7+" to "+cb}}}}}}}}return{state:"success",data:b8}}bI.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:aa,type:"GET",isLocal:C.test(b4[1]),global:true,processData:true,async:true,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":aX,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"},converters:{"* text":String,"text html":true,"text json":bI.parseJSON,"text xml":bI.parseXML},flatOptions:{url:true,context:true}},ajaxSetup:function(i,e){return e?t(t(i,bI.ajaxSettings),e):t(bI.ajaxSettings,i)},ajaxPrefilter:bK(w),ajaxTransport:bK(a9),ajax:function(ca,b7){if(typeof ca==="object"){b7=ca;ca=undefined}b7=b7||{};var cj,cl,cb,cq,cf,b6,cm,b8,ce=bI.ajaxSetup({},b7),cs=ce.context||ce,ch=ce.context&&(cs.nodeType||cs.jquery)?bI(cs):bI.event,cr=bI.Deferred(),co=bI.Callbacks("once memory"),cc=ce.statusCode||{},ci={},cp={},b9=0,cd="canceled",ck={readyState:0,getResponseHeader:function(i){var e;if(b9===2){if(!b8){b8={};while((e=ah.exec(cq))){b8[e[1].toLowerCase()]=e[2]}}e=b8[i.toLowerCase()]}return e==null?null:e},getAllResponseHeaders:function(){return b9===2?cq:null},setRequestHeader:function(i,ct){var e=i.toLowerCase();if(!b9){i=cp[e]=cp[e]||i;ci[i]=ct}return this},overrideMimeType:function(e){if(!b9){ce.mimeType=e}return this},statusCode:function(i){var e;if(i){if(b9<2){for(e in i){cc[e]=[cc[e],i[e]]}}else{ck.always(i[ck.status])}}return this},abort:function(i){var e=i||cd;if(cm){cm.abort(e)}cg(0,e);return this}};cr.promise(ck).complete=co.add;ck.success=ck.done;ck.error=ck.fail;ce.url=((ca||ce.url||aa)+"").replace(ap,"").replace(aK,b4[1]+"//");ce.type=b7.method||b7.type||ce.method||ce.type;ce.dataTypes=bI.trim(ce.dataType||"*").toLowerCase().match(aF)||[""];if(ce.crossDomain==null){cj=aV.exec(ce.url.toLowerCase());ce.crossDomain=!!(cj&&(cj[1]!==b4[1]||cj[2]!==b4[2]||(cj[3]||(cj[1]==="http:"?"80":"443"))!==(b4[3]||(b4[1]==="http:"?"80":"443"))))}if(ce.data&&ce.processData&&typeof ce.data!=="string"){ce.data=bI.param(ce.data,ce.traditional)}p(w,ce,b7,ck);if(b9===2){return ck}b6=bI.event&&ce.global;if(b6&&bI.active++===0){bI.event.trigger("ajaxStart")}ce.type=ce.type.toUpperCase();ce.hasContent=!r.test(ce.type);cb=ce.url;if(!ce.hasContent){if(ce.data){cb=(ce.url+=(bQ.test(cb)?"&":"?")+ce.data);delete ce.data}if(ce.cache===false){ce.url=R.test(cb)?cb.replace(R,"$1_="+bp++):cb+(bQ.test(cb)?"&":"?")+"_="+bp++}}if(ce.ifModified){if(bI.lastModified[cb]){ck.setRequestHeader("If-Modified-Since",bI.lastModified[cb])}if(bI.etag[cb]){ck.setRequestHeader("If-None-Match",bI.etag[cb])}}if(ce.data&&ce.hasContent&&ce.contentType!==false||b7.contentType){ck.setRequestHeader("Content-Type",ce.contentType)}ck.setRequestHeader("Accept",ce.dataTypes[0]&&ce.accepts[ce.dataTypes[0]]?ce.accepts[ce.dataTypes[0]]+(ce.dataTypes[0]!=="*"?", "+aX+"; q=0.01":""):ce.accepts["*"]);for(cl in ce.headers){ck.setRequestHeader(cl,ce.headers[cl])}if(ce.beforeSend&&(ce.beforeSend.call(cs,ck,ce)===false||b9===2)){return ck.abort()}cd="abort";for(cl in {success:1,error:1,complete:1}){ck[cl](ce[cl])}cm=p(a9,ce,b7,ck);if(!cm){cg(-1,"No Transport")}else{ck.readyState=1;if(b6){ch.trigger("ajaxSend",[ck,ce])}if(ce.async&&ce.timeout>0){cf=setTimeout(function(){ck.abort("timeout")},ce.timeout)}try{b9=1;cm.send(ci,cg)}catch(cn){if(b9<2){cg(-1,cn)}else{throw cn}}}function cg(cw,i,cx,cu){var e,cA,cy,cv,cz,ct=i;if(b9===2){return}b9=2;if(cf){clearTimeout(cf)}cm=undefined;cq=cu||"";ck.readyState=cw>0?4:0;e=cw>=200&&cw<300||cw===304;if(cx){cv=g(ce,ck,cx)}cv=ag(ce,cv,ck,e);if(e){if(ce.ifModified){cz=ck.getResponseHeader("Last-Modified");if(cz){bI.lastModified[cb]=cz}cz=ck.getResponseHeader("etag");if(cz){bI.etag[cb]=cz}}if(cw===204||ce.type==="HEAD"){ct="nocontent"}else{if(cw===304){ct="notmodified"}else{ct=cv.state;cA=cv.data;cy=cv.error;e=!cy}}}else{cy=ct;if(cw||!ct){ct="error";if(cw<0){cw=0}}}ck.status=cw;ck.statusText=(i||ct)+"";if(e){cr.resolveWith(cs,[cA,ct,ck])}else{cr.rejectWith(cs,[ck,ct,cy])}ck.statusCode(cc);cc=undefined;if(b6){ch.trigger(e?"ajaxSuccess":"ajaxError",[ck,ce,e?cA:cy])}co.fireWith(cs,[ck,ct]);if(b6){ch.trigger("ajaxComplete",[ck,ce]);if(!(--bI.active)){bI.event.trigger("ajaxStop")}}}return ck},getJSON:function(e,i,b6){return bI.get(e,i,b6,"json")},getScript:function(e,i){return bI.get(e,undefined,i,"script")}});bI.each(["get","post"],function(e,b6){bI[b6]=function(i,b8,b9,b7){if(bI.isFunction(b8)){b7=b7||b9;b9=b8;b8=undefined}return bI.ajax({url:i,type:b6,dataType:b7,data:b8,success:b9})}});bI._evalUrl=function(e){return bI.ajax({url:e,type:"GET",dataType:"script",async:false,global:false,"throws":true})};bI.fn.extend({wrapAll:function(e){if(bI.isFunction(e)){return this.each(function(b6){bI(this).wrapAll(e.call(this,b6))})}if(this[0]){var i=bI(e,this[0].ownerDocument).eq(0).clone(true);if(this[0].parentNode){i.insertBefore(this[0])}i.map(function(){var b6=this;while(b6.firstChild&&b6.firstChild.nodeType===1){b6=b6.firstChild}return b6}).append(this)}return this},wrapInner:function(e){if(bI.isFunction(e)){return this.each(function(b6){bI(this).wrapInner(e.call(this,b6))})}return this.each(function(){var i=bI(this),b6=i.contents();if(b6.length){b6.wrapAll(e)}else{i.append(e)}})},wrap:function(e){var i=bI.isFunction(e);return this.each(function(b6){bI(this).wrapAll(i?e.call(this,b6):e)})},unwrap:function(){return this.parent().each(function(){if(!bI.nodeName(this,"body")){bI(this).replaceWith(this.childNodes)}}).end()}});bI.expr.filters.hidden=function(e){return e.offsetWidth<=0&&e.offsetHeight<=0||(!D.reliableHiddenOffsets()&&((e.style&&e.style.display)||bI.css(e,"display"))==="none")};bI.expr.filters.visible=function(e){return !bI.expr.filters.hidden(e)};var bw=/%20/g,aS=/\[\]$/,X=/\r?\n/g,b=/^(?:submit|button|image|reset|file)$/i,au=/^(?:input|select|textarea|keygen)/i;function j(b6,b8,i,b7){var e;if(bI.isArray(b8)){bI.each(b8,function(ca,b9){if(i||aS.test(b6)){b7(b6,b9)}else{j(b6+"["+(typeof b9==="object"?ca:"")+"]",b9,i,b7)}})}else{if(!i&&bI.type(b8)==="object"){for(e in b8){j(b6+"["+e+"]",b8[e],i,b7)}}else{b7(b6,b8)}}}bI.param=function(e,b6){var b7,i=[],b8=function(b9,ca){ca=bI.isFunction(ca)?ca():(ca==null?"":ca);i[i.length]=encodeURIComponent(b9)+"="+encodeURIComponent(ca)};if(b6===undefined){b6=bI.ajaxSettings&&bI.ajaxSettings.traditional}if(bI.isArray(e)||(e.jquery&&!bI.isPlainObject(e))){bI.each(e,function(){b8(this.name,this.value)})}else{for(b7 in e){j(b7,e[b7],b6,b8)}}return i.join("&").replace(bw,"+")};bI.fn.extend({serialize:function(){return bI.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=bI.prop(this,"elements");return e?bI.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!bI(this).is(":disabled")&&au.test(this.nodeName)&&!b.test(e)&&(this.checked||!aM.test(e))}).map(function(e,b6){var b7=bI(this).val();return b7==null?null:bI.isArray(b7)?bI.map(b7,function(i){return{name:b6.name,value:i.replace(X,"\r\n")}}):{name:b6.name,value:b7.replace(X,"\r\n")}}).get()}});bI.ajaxSettings.xhr=a5.ActiveXObject!==undefined?function(){return !this.isLocal&&/^(get|post|head|put|delete|options)$/i.test(this.type)&&bE()||bg()}:bE;var aA=0,aj={},ay=bI.ajaxSettings.xhr();if(a5.attachEvent){a5.attachEvent("onunload",function(){for(var e in aj){aj[e](undefined,true)}})}D.cors=!!ay&&("withCredentials" in ay);ay=D.ajax=!!ay;if(ay){bI.ajaxTransport(function(e){if(!e.crossDomain||D.cors){var i;return{send:function(b9,b6){var b7,b8=e.xhr(),ca=++aA;b8.open(e.type,e.url,e.async,e.username,e.password);if(e.xhrFields){for(b7 in e.xhrFields){b8[b7]=e.xhrFields[b7]}}if(e.mimeType&&b8.overrideMimeType){b8.overrideMimeType(e.mimeType)}if(!e.crossDomain&&!b9["X-Requested-With"]){b9["X-Requested-With"]="XMLHttpRequest"}for(b7 in b9){if(b9[b7]!==undefined){b8.setRequestHeader(b7,b9[b7]+"")}}b8.send((e.hasContent&&e.data)||null);i=function(cd,cc){var cb,cg,ce;if(i&&(cc||b8.readyState===4)){delete aj[ca];i=undefined;b8.onreadystatechange=bI.noop;if(cc){if(b8.readyState!==4){b8.abort()}}else{ce={};cb=b8.status;if(typeof b8.responseText==="string"){ce.text=b8.responseText}try{cg=b8.statusText}catch(cf){cg=""}if(!cb&&e.isLocal&&!e.crossDomain){cb=ce.text?200:404}else{if(cb===1223){cb=204}}}}if(ce){b6(cb,cg,ce,b8.getAllResponseHeaders())}};if(!e.async){i()}else{if(b8.readyState===4){setTimeout(i)}else{b8.onreadystatechange=aj[ca]=i}}},abort:function(){if(i){i(undefined,true)}}}}})}function bE(){try{return new a5.XMLHttpRequest()}catch(i){}}function bg(){try{return new a5.ActiveXObject("Microsoft.XMLHTTP")}catch(i){}}bI.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){bI.globalEval(e);return e}}});bI.ajaxPrefilter("script",function(e){if(e.cache===undefined){e.cache=false}if(e.crossDomain){e.type="GET";e.global=false}});bI.ajaxTransport("script",function(b6){if(b6.crossDomain){var e,i=n.head||bI("head")[0]||n.documentElement;return{send:function(b7,b8){e=n.createElement("script");e.async=true;if(b6.scriptCharset){e.charset=b6.scriptCharset}e.src=b6.url;e.onload=e.onreadystatechange=function(ca,b9){if(b9||!e.readyState||/loaded|complete/.test(e.readyState)){e.onload=e.onreadystatechange=null;if(e.parentNode){e.parentNode.removeChild(e)}e=null;if(!b9){b8(200,"success")}}};i.insertBefore(e,i.firstChild)},abort:function(){if(e){e.onload(undefined,true)}}}}});var bs=[],a8=/(=)\?(?=&|$)|\?\?/;bI.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=bs.pop()||(bI.expando+"_"+(bp++));this[e]=true;return e}});bI.ajaxPrefilter("json jsonp",function(b7,e,b8){var ca,i,b6,b9=b7.jsonp!==false&&(a8.test(b7.url)?"url":typeof b7.data==="string"&&!(b7.contentType||"").indexOf("application/x-www-form-urlencoded")&&a8.test(b7.data)&&"data");if(b9||b7.dataTypes[0]==="jsonp"){ca=b7.jsonpCallback=bI.isFunction(b7.jsonpCallback)?b7.jsonpCallback():b7.jsonpCallback;if(b9){b7[b9]=b7[b9].replace(a8,"$1"+ca)}else{if(b7.jsonp!==false){b7.url+=(bQ.test(b7.url)?"&":"?")+b7.jsonp+"="+ca}}b7.converters["script json"]=function(){if(!b6){bI.error(ca+" was not called")}return b6[0]};b7.dataTypes[0]="json";i=a5[ca];a5[ca]=function(){b6=arguments};b8.always(function(){a5[ca]=i;if(b7[ca]){b7.jsonpCallback=e.jsonpCallback;bs.push(ca)}if(b6&&bI.isFunction(i)){i(b6[0])}b6=i=undefined});return"script"}});bI.parseHTML=function(b8,b6,b7){if(!b8||typeof b8!=="string"){return null}if(typeof b6==="boolean"){b7=b6;b6=false}b6=b6||n;var i=a.exec(b8),e=!b7&&[];if(i){return[b6.createElement(i[1])]}i=bI.buildFragment([b8],b6,e);if(e&&e.length){bI(e).remove()}return bI.merge([],i.childNodes)};var b1=bI.fn.load;bI.fn.load=function(b7,ca,cb){if(typeof b7!=="string"&&b1){return b1.apply(this,arguments)}var e,b6,b8,i=this,b9=b7.indexOf(" ");if(b9>=0){e=bI.trim(b7.slice(b9,b7.length));b7=b7.slice(0,b9)}if(bI.isFunction(ca)){cb=ca;ca=undefined}else{if(ca&&typeof ca==="object"){b8="POST"}}if(i.length>0){bI.ajax({url:b7,type:b8,dataType:"html",data:ca}).done(function(cc){b6=arguments;i.html(e?bI("
").append(bI.parseHTML(cc)).find(e):cc)}).complete(cb&&function(cd,cc){i.each(cb,b6||[cd.responseText,cc,cd])})}return this};bI.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,b6){bI.fn[b6]=function(i){return this.on(b6,i)}});bI.expr.filters.animated=function(e){return bI.grep(bI.timers,function(i){return e===i.elem}).length};var bX=a5.document.documentElement;function br(e){return bI.isWindow(e)?e:e.nodeType===9?e.defaultView||e.parentWindow:false}bI.offset={setOffset:function(b7,ch,cb){var cd,ca,e,b8,b6,cf,cg,cc=bI.css(b7,"position"),b9=bI(b7),ce={};if(cc==="static"){b7.style.position="relative"}b6=b9.offset();e=bI.css(b7,"top");cf=bI.css(b7,"left");cg=(cc==="absolute"||cc==="fixed")&&bI.inArray("auto",[e,cf])>-1;if(cg){cd=b9.position();b8=cd.top;ca=cd.left}else{b8=parseFloat(e)||0;ca=parseFloat(cf)||0}if(bI.isFunction(ch)){ch=ch.call(b7,cb,b6)}if(ch.top!=null){ce.top=(ch.top-b6.top)+b8}if(ch.left!=null){ce.left=(ch.left-b6.left)+ca}if("using" in ch){ch.using.call(b7,ce)}else{b9.css(ce)}}};bI.fn.extend({offset:function(i){if(arguments.length){return i===undefined?this:this.each(function(ca){bI.offset.setOffset(this,i,ca)})}var e,b9,b7={top:0,left:0},b6=this[0],b8=b6&&b6.ownerDocument;if(!b8){return}e=b8.documentElement;if(!bI.contains(e,b6)){return b7}if(typeof b6.getBoundingClientRect!==aC){b7=b6.getBoundingClientRect()}b9=br(b8);return{top:b7.top+(b9.pageYOffset||e.scrollTop)-(e.clientTop||0),left:b7.left+(b9.pageXOffset||e.scrollLeft)-(e.clientLeft||0)}},position:function(){if(!this[0]){return}var b6,b7,e={top:0,left:0},i=this[0];if(bI.css(i,"position")==="fixed"){b7=i.getBoundingClientRect()}else{b6=this.offsetParent();b7=this.offset();if(!bI.nodeName(b6[0],"html")){e=b6.offset()}e.top+=bI.css(b6[0],"borderTopWidth",true);e.left+=bI.css(b6[0],"borderLeftWidth",true)}return{top:b7.top-e.top-bI.css(i,"marginTop",true),left:b7.left-e.left-bI.css(i,"marginLeft",true)}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||bX;while(e&&(!bI.nodeName(e,"html")&&bI.css(e,"position")==="static")){e=e.offsetParent}return e||bX})}});bI.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(b6,i){var e=/Y/.test(i);bI.fn[b6]=function(b7){return aB(this,function(b8,cb,ca){var b9=br(b8);if(ca===undefined){return b9?(i in b9)?b9[i]:b9.document.documentElement[cb]:b8[cb]}if(b9){b9.scrollTo(!e?ca:bI(b9).scrollLeft(),e?ca:bI(b9).scrollTop())}else{b8[cb]=ca}},b6,b7,arguments.length,null)}});bI.each(["top","left"],function(e,b6){bI.cssHooks[b6]=a7(D.pixelPosition,function(b7,i){if(i){i=G(b7,b6);return Y.test(i)?bI(b7).position()[b6]+"px":i}})});bI.each({Height:"height",Width:"width"},function(e,i){bI.each({padding:"inner"+e,content:i,"":"outer"+e},function(b6,b7){bI.fn[b7]=function(cb,ca){var b9=arguments.length&&(b6||typeof cb!=="boolean"),b8=b6||(cb===true||ca===true?"margin":"border");return aB(this,function(cd,cc,ce){var cf;if(bI.isWindow(cd)){return cd.document.documentElement["client"+e]}if(cd.nodeType===9){cf=cd.documentElement;return Math.max(cd.body["scroll"+e],cf["scroll"+e],cd.body["offset"+e],cf["offset"+e],cf["client"+e])}return ce===undefined?bI.css(cd,cc,b8):bI.style(cd,cc,ce,b8)},i,b9?cb:undefined,b9,null)}})});bI.fn.size=function(){return this.length};bI.fn.andSelf=bI.fn.addBack;if(typeof define==="function"&&define.amd){define("jquery",[],function(){return bI})}var bk=a5.jQuery,I=a5.$;bI.noConflict=function(e){if(a5.$===bI){a5.$=I}if(e&&a5.jQuery===bI){a5.jQuery=bk}return bI};if(typeof av===aC){a5.jQuery=a5.$=bI}return bI}));!function(a){a(function(){a.support.transition=(function(){var b=(function(){var e=document.createElement("bootstrap"),d={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},c;for(c in d){if(e.style[c]!==undefined){return d[c]}}}());return b&&{end:b}})()})}(window.jQuery);!function(d){var c='[data-dismiss="alert"]',b=function(e){d(e).on("click",c,this.close)};b.prototype.close=function(j){var i=d(this),g=i.attr("data-target"),h;if(!g){g=i.attr("href");g=g&&g.replace(/.*(?=#[^\s]*$)/,"")}h=d(g);j&&j.preventDefault();h.length||(h=i.hasClass("alert")?i:i.parent());h.trigger(j=d.Event("close"));if(j.isDefaultPrevented()){return}h.removeClass("in");function f(){h.trigger("closed").remove()}d.support.transition&&h.hasClass("fade")?h.on(d.support.transition.end,f):f()};var a=d.fn.alert;d.fn.alert=function(e){return this.each(function(){var g=d(this),f=g.data("alert");if(!f){g.data("alert",(f=new b(this)))}if(typeof e=="string"){f[e].call(g)}})};d.fn.alert.Constructor=b;d.fn.alert.noConflict=function(){d.fn.alert=a;return this};d(document).on("click.alert.data-api",c,b.prototype.close)}(window.jQuery);!function(c){var b=function(e,d){this.$element=c(e);this.options=c.extend({},c.fn.button.defaults,d)};b.prototype.setState=function(g){var i="disabled",e=this.$element,f=e.data(),h=e.is("input")?"val":"html";g=g+"Text";f.resetText||e.data("resetText",e[h]());e[h](f[g]||this.options[g]);setTimeout(function(){g=="loadingText"?e.addClass(i).attr(i,i):e.removeClass(i).removeAttr(i)},0)};b.prototype.toggle=function(){var d=this.$element.closest('[data-toggle="buttons-radio"]');d&&d.find(".active").removeClass("active");this.$element.toggleClass("active")};var a=c.fn.button;c.fn.button=function(d){return this.each(function(){var g=c(this),f=g.data("button"),e=typeof d=="object"&&d;if(!f){g.data("button",(f=new b(this,e)))}if(d=="toggle"){f.toggle()}else{if(d){f.setState(d)}}})};c.fn.button.defaults={loadingText:"loading..."};c.fn.button.Constructor=b;c.fn.button.noConflict=function(){c.fn.button=a;return this};c(document).on("click.button.data-api","[data-toggle^=button]",function(f){var d=c(f.target);if(!d.hasClass("btn")){d=d.closest(".btn")}d.button("toggle")})}(window.jQuery);!function(b){var c=function(e,d){this.$element=b(e);this.$indicators=this.$element.find(".carousel-indicators");this.options=d;this.options.pause=="hover"&&this.$element.on("mouseenter",b.proxy(this.pause,this)).on("mouseleave",b.proxy(this.cycle,this))};c.prototype={cycle:function(d){if(!d){this.paused=false}if(this.interval){clearInterval(this.interval)}this.options.interval&&!this.paused&&(this.interval=setInterval(b.proxy(this.next,this),this.options.interval));return this},getActiveIndex:function(){this.$active=this.$element.find(".item.active");this.$items=this.$active.parent().children();return this.$items.index(this.$active)},to:function(f){var d=this.getActiveIndex(),e=this;if(f>(this.$items.length-1)||f<0){return}if(this.sliding){return this.$element.one("slid",function(){e.to(f)})}if(d==f){return this.pause().cycle()}return this.slide(f>d?"next":"prev",b(this.$items[f]))},pause:function(d){if(!d){this.paused=true}if(this.$element.find(".next, .prev").length&&b.support.transition.end){this.$element.trigger(b.support.transition.end);this.cycle(true)}clearInterval(this.interval);this.interval=null;return this},next:function(){if(this.sliding){return}return this.slide("next")},prev:function(){if(this.sliding){return}return this.slide("prev")},slide:function(k,f){var m=this.$element.find(".item.active"),d=f||m[k](),j=this.interval,l=k=="next"?"left":"right",g=k=="next"?"first":"last",h=this,i;this.sliding=true;j&&this.pause();d=d.length?d:this.$element.find(".item")[g]();i=b.Event("slide",{relatedTarget:d[0],direction:l});if(d.hasClass("active")){return}if(this.$indicators.length){this.$indicators.find(".active").removeClass("active");this.$element.one("slid",function(){var e=b(h.$indicators.children()[h.getActiveIndex()]);e&&e.addClass("active")})}if(b.support.transition&&this.$element.hasClass("slide")){this.$element.trigger(i);if(i.isDefaultPrevented()){return}d.addClass(k);d[0].offsetWidth;m.addClass(l);d.addClass(l);this.$element.one(b.support.transition.end,function(){d.removeClass([k,l].join(" ")).addClass("active");m.removeClass(["active",l].join(" "));h.sliding=false;setTimeout(function(){h.$element.trigger("slid")},0)})}else{this.$element.trigger(i);if(i.isDefaultPrevented()){return}m.removeClass("active");d.addClass("active");this.sliding=false;this.$element.trigger("slid")}j&&this.cycle();return this}};var a=b.fn.carousel;b.fn.carousel=function(d){return this.each(function(){var h=b(this),g=h.data("carousel"),e=b.extend({},b.fn.carousel.defaults,typeof d=="object"&&d),f=typeof d=="string"?d:e.slide;if(!g){h.data("carousel",(g=new c(this,e)))}if(typeof d=="number"){g.to(d)}else{if(f){g[f]()}else{if(e.interval){g.pause().cycle()}}}})};b.fn.carousel.defaults={interval:5000,pause:"hover"};b.fn.carousel.Constructor=c;b.fn.carousel.noConflict=function(){b.fn.carousel=a;return this};b(document).on("click.carousel.data-api","[data-slide], [data-slide-to]",function(j){var i=b(this),f,d=b(i.attr("data-target")||(f=i.attr("href"))&&f.replace(/.*(?=#[^\s]+$)/,"")),g=b.extend({},d.data(),i.data()),h;d.carousel(g);if(h=i.attr("data-slide-to")){d.data("carousel").pause().to(h).cycle()}j.preventDefault()})}(window.jQuery);!function(b){var c=function(e,d){this.$element=b(e);this.options=b.extend({},b.fn.collapse.defaults,d);if(this.options.parent){this.$parent=b(this.options.parent)}this.options.toggle&&this.toggle()};c.prototype={constructor:c,dimension:function(){var d=this.$element.hasClass("width");return d?"width":"height"},show:function(){var g,d,f,e;if(this.transitioning||this.$element.hasClass("in")){return}g=this.dimension();d=b.camelCase(["scroll",g].join("-"));f=this.$parent&&this.$parent.find("> .accordion-group > .in");if(f&&f.length){e=f.data("collapse");if(e&&e.transitioning){return}f.collapse("hide");e||f.data("collapse",null)}this.$element[g](0);this.transition("addClass",b.Event("show"),"shown");b.support.transition&&this.$element[g](this.$element[0][d])},hide:function(){var d;if(this.transitioning||!this.$element.hasClass("in")){return}d=this.dimension();this.reset(this.$element[d]());this.transition("removeClass",b.Event("hide"),"hidden");this.$element[d](0)},reset:function(d){var e=this.dimension();this.$element.removeClass("collapse")[e](d||"auto")[0].offsetWidth;this.$element[d!==null?"addClass":"removeClass"]("collapse");return this},transition:function(h,e,f){var g=this,d=function(){if(e.type=="show"){g.reset()}g.transitioning=0;g.$element.trigger(f)};this.$element.trigger(e);if(e.isDefaultPrevented()){return}this.transitioning=1;this.$element[h]("in");b.support.transition&&this.$element.hasClass("collapse")?this.$element.one(b.support.transition.end,d):d()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}};var a=b.fn.collapse;b.fn.collapse=function(d){return this.each(function(){var g=b(this),f=g.data("collapse"),e=b.extend({},b.fn.collapse.defaults,g.data(),typeof d=="object"&&d);if(!f){g.data("collapse",(f=new c(this,e)))}if(typeof d=="string"){f[d]()}})};b.fn.collapse.defaults={toggle:true};b.fn.collapse.Constructor=c;b.fn.collapse.noConflict=function(){b.fn.collapse=a;return this};b(document).on("click.collapse.data-api","[data-toggle=collapse]",function(i){var h=b(this),d,g=h.attr("data-target")||i.preventDefault()||(d=h.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""),f=b(g).data("collapse")?"toggle":h.data();h[b(g).hasClass("in")?"addClass":"removeClass"]("collapsed");b(g).collapse(f)})}(window.jQuery);!function(f){var b="[data-toggle=dropdown]",a=function(h){var g=f(h).on("click.dropdown.data-api",this.toggle);f("html").on("click.dropdown.data-api",function(){g.parent().removeClass("open")})};a.prototype={constructor:a,toggle:function(j){var i=f(this),h,g;if(i.is(".disabled, :disabled")){return}h=e(i);g=h.hasClass("open");d();if(!g){if("ontouchstart" in document.documentElement){f(' + +
+ + + + + +
+
+ +
+ + +
+ +
+

Java Project with JUnit Tests

+
+
+

Sample minimal configuration for Java Project with JUnit tests.

+
+
+

Test dependencies for generated contract verification tests

+
+
+
        <dependency>
+            <groupId>com.jayway.restassured</groupId>
+            <artifactId>rest-assured</artifactId>
+            <version>2.9.0</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.jayway.restassured</groupId>
+            <artifactId>spring-mock-mvc</artifactId>
+            <version>2.9.0</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.toomuchcoding.jsonassert</groupId>
+            <artifactId>jsonassert</artifactId>
+            <version>0.4.7</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.assertj</groupId>
+            <artifactId>assertj-core</artifactId>
+            <version>2.4.1</version>
+            <scope>test</scope>
+        </dependency>
+
+
+
+
+

Project configuration for Spring Cloud Contract Verifier with JUnit tests and stub publishing

+
+
+
            <plugin>
+                <groupId>org.springframework.cloud</groupId>
+                <artifactId>spring-cloud-contract-maven-plugin</artifactId>
+                <version>${spring-cloud-verifier-plugin.version}</version>
+                <extensions>true</extensions>
+                <configuration>
+                    <baseClassForTests>hello.BaseAccurest</baseClassForTests>
+                </configuration>
+            </plugin>
+
+
+
+
+

Base Test class

+
+
+
/**
+ *
+ *  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
+ *
+ *       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 hello;
+
+import com.jayway.restassured.module.mockmvc.RestAssuredMockMvc;
+
+import org.junit.Before;
+
+public class BaseAccurest {
+
+    @Before
+    public void setup() {
+        RestAssuredMockMvc.standaloneSetup(new GreetingController());
+    }
+
+}
+
+
+
+ +
+
+
+
+
+ +
+ +
+
+
+

Copyright © 2016 + Spring. + All rights reserved. +

+
+ + +
+
+ + diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/sitemap.html b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/sitemap.html new file mode 100644 index 00000000..59401353 --- /dev/null +++ b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/sitemap.html @@ -0,0 +1,243 @@ + + + + + + + + + Spring Cloud Contract Verifier Maven Plugin – Sitemap + + + + + + + + + + + + + + + + + Fork me on GitHub + + + + + + + +
+ +
+ + + + + +
+
+ +
+ + +
+ +
+

Sitemap

+ +

This page lists all entries of the navigation menu in expanded form.

+ +
+ +
+

Related Projects


+ +
+
+
+
+ +
+ +
+
+
+

Copyright © 2016 + Spring. + All rights reserved. +

+
+ + +
+
+ + diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/spock.html b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/spock.html new file mode 100644 index 00000000..d23f032e --- /dev/null +++ b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/spock.html @@ -0,0 +1,346 @@ + + + + + + + + + Spring Cloud Contract Verifier Maven Plugin – + + + + + + + + + + + + + + + + + Fork me on GitHub + + + + + + + + + +
+ + + + + +
+
+ +
+ + +
+ +
+

Groovy Project with Spock Specifications

+
+
+

Sample minimal configuration for Groovy Project with Spock Specification

+
+
+

Test dependencies for generated contract verification tests

+
+
+
        <dependency>
+            <groupId>org.spockframework</groupId>
+            <artifactId>spock-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.jayway.restassured</groupId>
+            <artifactId>rest-assured</artifactId>
+            <version>2.9.0</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.jayway.restassured</groupId>
+            <artifactId>spring-mock-mvc</artifactId>
+            <version>2.9.0</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.toomuchcoding.jsonassert</groupId>
+            <artifactId>jsonassert</artifactId>
+            <version>0.4.7</version>
+            <scope>test</scope>
+        </dependency>
+
+
+
+
+

Project configuration for Spring Cloud Contract Verifier, Groovy, Spock specifications and stub publishing

+
+
+
            <plugin>
+                <groupId>org.springframework.cloud</groupId>
+                <artifactId>spring-cloud-contract-maven-plugin</artifactId>
+                <version>${spring-cloud-verifier-plugin.version}</version>
+                <extensions>true</extensions>
+                <configuration>
+                    <baseClassForTests>hello.BaseAccurest</baseClassForTests>
+                    <testFramework>SPOCK</testFramework>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <groupId>org.codehaus.gmavenplus</groupId>
+                <artifactId>gmavenplus-plugin</artifactId>
+                <version>1.5</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>testCompile</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    <testSources>
+                        <testSource>
+                            <directory>${project.basedir}/src/test/groovy</directory>
+                            <includes>
+                                <include>**/*.groovy</include>
+                            </includes>
+                        </testSource>
+                        <testSource>
+                            <directory>${project.build.directory}/generated-test-sources/contracts</directory>
+                            <includes>
+                                <include>**/*.groovy</include>
+                            </includes>
+                        </testSource>
+                    </testSources>
+                </configuration>
+            </plugin>
+            <plugin>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <version>2.19</version>
+                <configuration>
+                    <includes>
+                        <include>**/*Spec.java</include>
+                    </includes>
+                </configuration>
+            </plugin>
+
+
+
+
+

Base Specification class

+
+
+
/**
+ *
+ *  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
+ *
+ *       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 hello
+
+import com.jayway.restassured.module.mockmvc.RestAssuredMockMvc
+import spock.lang.Specification
+
+public class BaseAccurest extends Specification {
+
+    def setup() {
+        RestAssuredMockMvc.standaloneSetup(new GreetingController())
+    }
+
+}
+
+
+
+ +
+
+
+
+
+ +
+ +
+
+
+

Copyright © 2016 + Spring. + All rights reserved. +

+
+ + +
+
+ + diff --git a/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/usage.html b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/usage.html new file mode 100644 index 00000000..5d195bd2 --- /dev/null +++ b/spring-cloud-contract/1.0.0.RELEASE/spring-cloud-contract-maven-plugin/usage.html @@ -0,0 +1,292 @@ + + + + + + + + + Spring Cloud Contract Verifier Maven Plugin – + + + + + + + + + + + + + + + + + Fork me on GitHub + + + + + + + + + +
+ + + + + +
+
+ +
+ + +
+ +

Usage

+
+

Converting Spring Cloud Contract DSL into WireMock stub mappings

+
+
+
+
mvn org.springramework.cloud:spring-cloud-contract-maven-plugin:convert
+
+
+
+

or shortly [1]

+
+
+
+
mvn spring-cloud-contract-verifier:convert
+
+
+
+

For more information please go to the Spring Cloud Contract Wiki or Plugin Documentation Site.

+
+
+
+
+

Spring Cloud Contract Stub Runner

+
+
+

Run stubs mappings from current directory:

+
+
+
+
mvn org.springramework.cloud:spring-cloud-contract-maven-plugin:run
+
+
+
+

or shortly [1]

+
+
+
+
mvn spring-cloud-contract-verifier:run
+
+
+
+
+
+

Running stubs from repository

+
+
+
+
mvn spring-cloud-contract-verifier:run -Dstubs="org.springframework:gs-rest-service"
+
+
+
+

where org.springframework:gs-rest-service is artifact with stubs classifier contains WireMock mappings.

+
+
+
+
+

Project configuration

+
+
+
+
            <plugin>
+                <groupId>org.springframework.cloud</groupId>
+                <artifactId>spring-cloud-contract-maven-plugin</artifactId>
+                <version>${spring-cloud-verifier-plugin.version}</version>
+                <extensions>true</extensions>
+                <configuration>
+                    <baseClassForTests>hello.BaseAccurest</baseClassForTests>
+                </configuration>
+            </plugin>
+
+
+
+
+
+
+
+1. Additional configuration inside ~/.m2/settings.xml is required: <pluginGroups><pluginGroup>io.codearte.Spring Cloud Contract</pluginGroup></pluginGroups>. +
+
+
+
+
+ +
+ + + +