README (README.md)
Spring AI [](https://github.com/spring-projects/spring-ai/actions/workflows/continuous-integration.yml) [](https://central.sonatype.com/artifact/org.springframework.ai/spring-ai-model)
The Spring AI project provides a Spring-friendly API and abstractions for developing AI applications.
Its goal is to apply Spring ecosystem design principles, such as portability and modular design, to the AI domain and promote using strongly-typed data structures and APIs as the building blocks of an application.
At its core, Spring AI addresses the fundamental challenge of AI integration: connecting your enterprise __Data__ and __APIs__ with the __AI Models__.
Getting Started
The reference documentation includes a Getting Started guide.
Spring Boot Version Compatibility:
Project Resources
- Reference documentation
- Javadoc
- Upgrade notes
- Awesome Spring AI - A curated list of awesome resources, tools, tutorials, and projects for building generative AI applications using Spring AI
- Spring AI Examples - Contains example projects that explain specific features in more detail.
- Spring AI Community - A community-driven organization for building Spring-based integrations with AI models, agents, vector databases, and more.
Contributing
We welcome contributions of all kinds!
Please read our contribution guidelines before submitting a pull request or an issue.
Features
This is a high level feature overview.
- Support for all major AI Model providers such as Anthropic, OpenAI, Amazon Bedrock, Google, Ollama, Mistral AI, DeepSeek, and more.
Supported model types include:
- Chat
- Embedding
- Text to Image
- Audio Transcription
- Text to Speech
- Moderation
- Portable API support across AI providers for both synchronous and streaming options.
Access to model-specific features is also available.
- Structured Outputs - Mapping of AI Model output to POJOs.
- Support for all major Vector Store providers such as Amazon Bedrock Knowledge Base, Amazon S3, Apache Cassandra, Azure Vector Search, Chroma, Couchbase, Elasticsearch, GemFire, MariaDB, Milvus, MongoDB Atlas, Neo4j, OpenSearch, Oracle, PostgreSQL/PGVector, Pinecone, Qdrant, Redis, Typesense, and Weaviate.
- Portable API across Vector Store providers, including a novel SQL-like metadata filter API.
- Tool Calling - Permits the model to request the execution of client-side tools and functions, thereby accessing necessary real-time information as required.
- Observability - Provides insights into AI-related operations.
- Document injection ETL framework for Data Engineering.
- AI Model Evaluation - Utilities to help evaluate generated content and protect against hallucinated response.
- ChatClient API - Fluent API for communicating with AI Chat Models, idiomatically similar to the WebClient and RestClient APIs.
- Advisors API - Encapsulates recurring Generative AI patterns, transforms data sent to and from Language Models (LLMs), and provides portability across various models and use cases.
- MCP (Model Context Protocol) - First-class support via Boot Starters and MCP Java Annotations for building AI applications that consume MCP servers or expose Spring-based services to the AI ecosystem, with STDIO, SSE, and Streamable-HTTP transport support.
- Support for Chat Conversation Memory with pluggable persistent backends (JDBC, Cassandra, MongoDB, Neo4j, Redis) and Retrieval Augmented Generation (RAG).
- Spring Boot Auto Configuration and Starters for all AI Models and Vector Stores - use start.spring.io to select the Model or Vector Store of choice.
Building from source
You don’t need to build from source to use Spring AI.
If you want to try out the latest and greatest, Spring AI can be built and published to your local Maven repository:
./mvnw clean installThis command builds all modules, runs unit tests, and publishes artifacts to your local Maven repository.
Please read our contribution guidelines for more details.
AGENTS (AGENTS.md)
Follow CONTRIBUTING.md for code style, commit messages, pull requests and to learn the most useful build commands.
CLAUDE (CLAUDE.md)
Follow @CONTRIBUTING.md for code style, commit messages, pull requests and to learn the most useful build commands.
CONTRIBUTING (CONTRIBUTING.md)
Contributing to Spring AI
Spring AI is released under the Apache 2.0 license. If you would like to contribute something, or want to hack on the code, this document should help you get started.
Code of Conduct
This project adheres to the Contributor Covenant code of conduct.
By participating, you are expected to uphold this code.
Please report unacceptable behavior to [email protected].
We accept contributions created with the help of AI coding agents, but they must be carefully reviewed by a human who remains accountable for the quality of the contribution.
Contributions submitted by GitHub accounts controlled by autonomous AI bots are forbidden and will result in permanent bans.
Reporting Security Vulnerabilities
If you think you have found a security vulnerability in Spring AI please DO NOT disclose it publicly until we've had a chance to fix it.
Please don't report security vulnerabilities using GitHub issues or pull requests, instead head over to https://spring.io/security-policy and learn how to disclose them responsibly.
Ask questions
If you have a question, check Stack Overflow using this list of tags or Spring AI discussions.
Find an existing discussion, or start a new one if necessary.
How to contribute
Search first
Is there already an existing issue or a pull request that addresses your concern?
Search to see if you can find something similar before creating a new one.
Submit an issue
If you are reporting a bug, please help to speed up problem diagnosis by providing as much information as possible.
Ideally, that would include a small sample project that reproduces the problem, shared with a link to a related source repository or attached as an archive with instructions on how to reproduce.
You can also submit an enhancement or a new feature proposal.
The issue title is used to generate the changelog so please use a short and descriptive text with types or filenames enclosed in backticks.
Submit a pull request
Should you create an issue first?
No, just create the pull request and use the description to provide context and motivation, as you would for an issue.
You only have to create an issue if you want to start a discussion first.
Please don't submit pull requests:
- With GitHub accounts managed by autonomous AI bots
- For already assigned issues (as the assignee is or plans to work on it)
- For straightforward or polish-style changes
The pull request title is used to generate the changelog so please use a short and descriptive text with types or filenames enclosed in backticks.
If your pull request is related to an issue, please mention the related issue with its number in the PR description (not in the title), for example "Fixes #123".
Before submitting a pull request:
- Add new tests that exercise the code you have added or modified
- Run the build and tests locally with
./mvnw clean package - If possible run integration tests related to the part you modify (see related documentation below)
- Any code needs to be carefully reviewed by a human, especially when generated by a coding agent
Commit message
A commit message should include a short title (if possible less than 50 characters) starting with an uppercase verb.
The title should not include prefixes like fix:, feat: or docs: or the issue/PR number.
- ✅ Add Contribution Guidelines
- ❌ GH-123: Add Contribution Guidelines
- ❌ docs: Add Contribution Guidelines
- ❌ Add Contribution Guidelines (#123)
The commit description should be wrapped at approximately 72 characters.
Commit messages should allow discoverability of related issues and PRs by linking them after the description with for example Closes #123 if the issue number is 123.
That allows bi-directional navigation from the commit to the issue/PR, but also in the other way around as related mentions are added by GitHub.
All commits must include a __Signed-off-by__ trailer at the end of each commit message to indicate that the contributor agrees to the Developer Certificate of Origin.
For additional details, please refer to the blog post Hello DCO, Goodbye CLA: Simplifying Contributions to Spring.
Please find below the example of a typical commit message:
Add Contribution Guidelines
This commit adds CONTRIBUTING.md describing the Contribution
procedure, mentions Contribution Guidelines in the README.md and
mentions CODE_OF_CONDUCT in the README.md.
Fixes #123
Signed-off-by: Firstname LastnameIf you want to only reference some issue or PR without closing it, you can use See #123.
Annotations should be enclosed in backticks to avoid mentioning potential related GitHub users.
If the commit has both an issue and a PR associated, the Spring AI committer merging the PR should reference both the issue and the PR and ensure the title does not contain the number of the PR, for example with an issue #123 and a PR #456:
Add Contribution Guidelines
...
Fixes #123
Closes #456
Signed-off-by: Firstname LastnameSource code style
Spring AI source code style follows the checkstyle guidelines used by the core Spring Framework project with some exceptions.
See also related IntelliJ IDEA Editor Settings.
The code is formatted using the java-format plugin as part of the build.
Correct formatting is enforced by CI.
To format the code specifically:
./mvnw process-sourcesNote that this will not format the import order which is documented below.
Formatting
Please carefully follow the whitespace and formatting conventions already present in the framework.
- UTF-8 encoding
- Tabs, not spaces
- Unix (LF), not DOS (CRLF) line endings
- Eliminate all trailing whitespace
- Wrap Javadoc at 90 characters
- Aim to wrap code at 120 characters, but favor readability over wrapping
- Preserve existing formatting; i.e. do not reformat code for its own sake
- For plain text documents like
.adocor.md, one sentence per line
The import statements are structured as follows:
- import
java.* - blank line
- import
javax.* - import
jakarta.* - blank line
- import all other imports
- blank line
- import
org.springframework.* - blank line
- import static all other imports
Static imports should not be used in production code, but they should be used in test code, especially for things like import static org.assertj.core.api.Assertions.assertThat;.
Although static imports are generally forbidden in production code, the following are use cases for which static imports are permissible.
- constants (including enum constants): such as those in
java.nio.charset.StandardCharsetsororg.springframework.core.annotation.MergedAnnotations.SearchStrategy - static factory methods for third-party DSLs: such as the methods in
org.junit.platform.engine.discovery.DiscoverySelectorswhen used with the JUnit PlatformLauncherAPI
Wildcard imports such as import java.util. or import static org.assertj.core.api.Assertions. are forbidden, even in test code.
Source file structure
A source file consists of the following, in this exact order:
- License
- Package statement
- Import statements
- Exactly one top-level class
Exactly one blank line separates each of the above sections.
License
/*
* Copyright 2023-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/`@since` tags
Use @since tags for newly-added public API types and methods e.g.
/**
* ...
*
* @since 2.0.0
*/Working with the code
Building from source
The project can be built from the root directory using the standard Maven command:
./mvnw clean package##### JDK
The project targets and builds artifacts compatible with Java 17+, and requires a JDK with support for the -XDaddTypeAnnotationsToSymbol javac argument, like Liberica 17.0.19+, for nullability checks.
The recommended JDK is specified in the .sdkmanrc file, which can be installed and configured with the SDKMAN! tool:
sdk env installto install the related JDK locallysdk envto use the related JDK
NOTE: Make sure to use a JDK with the same architecture as your processor, not an emulated one (for example with Rosetta on Mac) as Spring AI requires components that depend on your specific CPU architecture (PyTorch for example). If you are unsure if you have the correct JDK distribution for your CPU, run the command java -XshowSettings:properties -version 2>&1 | grep os.arch to validate that it matches your machine.
##### Maven build-cache extension
The Maven build-cache extension is enabled by default to speedup builds.
If you suspect the build cache is in an invalid state (build broken for no identified reason), try to run the build while disabling the build cache, for example with:
./mvnw -Dmaven.build.cache.enabled=false clean packageIf the build passes without the cache, please file an issue describing with as much detail as possible how that happened, and remove the local cache as a workaround:
rm -rf ~/.m2/build-cache/Integration Tests
There are many integration tests, so it often isn't realistic to run them all at once.
Note that you should set API key environment variables for model providers before running.
If the API key isn't set for a specific model provider, the integration test is skipped.
To run the integration test for a specific module:
./mvnw -am -pl spring-ai-spring-boot-testcontainers -Pintegration-tests verifyTo run a specific integration test allowing for up to two attempts to succeed (this is useful when a hosted service is not reliable or times out):
./mvnw -am -pl vector-stores/spring-ai-pgvector-store -Pintegration-tests -Dfailsafe.failIfNoSpecifiedTests=false -Dfailsafe.rerunFailingTestsCount=2 -Dit.test=PgVectorStoreIT verifyA quick pass through the most important pathways that runs integration tests can be done with the profile -Pci-fast-integration-tests and is used in the main CI build of this project.
Full integration tests are done regularly in the Spring AI Integration Tests repository.
Javadocs
To check javadocs using the javadoc:javadoc:
./mvnw javadoc:javadocReference documentation
To build the docs:
./mvnw -pl spring-ai-docs antoraThe generated documentation is available at spring-ai-docs/target/antora/site/index.html.
LICENSE (LICENSE.txt)
Apache License
Version 2.0, January 2004
https://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Auto Configurations/Mcp/Spring Ai Autoconfigure Mcp Client Common/Src/Test/Resources/Test Config.Json (auto-configurations/mcp/spring-ai-autoconfigure-mcp-client-common/src/test/resources/test-config.json)
{
"name": "test-config",
"description": "Test JSON file in root test resources folder",
"version": "1.0.0",
"properties": {
"testProperty1": "value1"
}
}
Auto Configurations/Mcp/Spring Ai Autoconfigure Mcp Client Common/Src/Test/Resources/Nested/Nested Config.Json (auto-configurations/mcp/spring-ai-autoconfigure-mcp-client-common/src/test/resources/nested/nested-config.json)
{
"name": "nested-config",
"description": "Test JSON file in nested subfolder of test resources",
"version": "1.0.0",
"nestedProperties": {
"nestedProperty1": "nestedValue1"
}
}
Auto Configurations/Mcp/Spring Ai Autoconfigure Mcp Client Httpclient/Src/Test/Resources/Test Config.Json (auto-configurations/mcp/spring-ai-autoconfigure-mcp-client-httpclient/src/test/resources/test-config.json)
{
"name": "test-config",
"description": "Test JSON file in root test resources folder",
"version": "1.0.0",
"properties": {
"testProperty1": "value1"
}
}
Auto Configurations/Mcp/Spring Ai Autoconfigure Mcp Client Httpclient/Src/Test/Resources/Nested/Nested Config.Json (auto-configurations/mcp/spring-ai-autoconfigure-mcp-client-httpclient/src/test/resources/nested/nested-config.json)
{
"name": "nested-config",
"description": "Test JSON file in nested subfolder of test resources",
"version": "1.0.0",
"nestedProperties": {
"nestedProperty1": "nestedValue1"
}
}
Auto Configurations/Mcp/Spring Ai Autoconfigure Mcp Client Webflux/Src/Test/Resources/Test Config.Json (auto-configurations/mcp/spring-ai-autoconfigure-mcp-client-webflux/src/test/resources/test-config.json)
{
"name": "test-config",
"description": "Test JSON file in root test resources folder",
"version": "1.0.0",
"properties": {
"testProperty1": "value1"
}
}
Auto Configurations/Mcp/Spring Ai Autoconfigure Mcp Client Webflux/Src/Test/Resources/Nested/Nested Config.Json (auto-configurations/mcp/spring-ai-autoconfigure-mcp-client-webflux/src/test/resources/nested/nested-config.json)
{
"name": "nested-config",
"description": "Test JSON file in nested subfolder of test resources",
"version": "1.0.0",
"nestedProperties": {
"nestedProperty1": "nestedValue1"
}
}
Auto Configurations/Models/Chat/Client/Spring Ai Autoconfigure Model Chat Client/Src/Main/Resources/META INF/Additional Spring Configuration Metadata.Json (auto-configurations/models/chat/client/spring-ai-autoconfigure-model-chat-client/src/main/resources/META-INF/additional-spring-configuration-metadata.json)
{
"properties": [
{
"name": "spring.ai.model.chat",
"type": "java.lang.String",
"description": "The primary ChatModel to autoconfigure. If not set, each ChatModel auto-configuration is enabled by default.",
"defaultValue": ""
},
{
"name": "spring.ai.model.embedding",
"type": "java.lang.String",
"description": "The primary EmbeddingModel to autoconfigure. If not set, each EmbeddingModel auto-configuration is enabled by default.",
"defaultValue": ""
},
{
"name": "spring.ai.model.embedding.text",
"type": "java.lang.String",
"description": "The primary EmbeddingModel for text embeddings to autoconfigure. If not set, each text EmbeddingModel auto-configuration is enabled by default.",
"defaultValue": ""
},
{
"name": "spring.ai.model.embedding.multimodal",
"type": "java.lang.String",
"description": "The primary EmbeddingModel for multimodal embeddings to autoconfigure. If not set, each multimodal EmbeddingModel auto-configuration is enabled by default.",
"defaultValue": ""
},
{
"name": "spring.ai.model.image",
"type": "java.lang.String",
"description": "The primary ImageModel to autoconfigure. If not set, each ImageModel auto-configuration is enabled by default.",
"defaultValue": ""
},
{
"name": "spring.ai.model.audio.transcription",
"type": "java.lang.String",
"description": "The primary TranscriptionModel to autoconfigure. If not set, each TranscriptionModel auto-configuration is enabled by default.",
"defaultValue": ""
},
{
"name": "spring.ai.model.audio.speech",
"type": "java.lang.String",
"description": "The primary SpeechModel to autoconfigure. If not set, each SpeechModel auto-configuration is enabled by default.",
"defaultValue": ""
},
{
"name": "spring.ai.model.moderation",
"type": "java.lang.String",
"description": "The primary ModerationModel to autoconfigure. If not set, each ModerationModel auto-configuration is enabled by default.",
"defaultValue": ""
}
]
}
Auto Configurations/Models/Spring Ai Autoconfigure Model Google Genai/MIGRATION GUIDE (auto-configurations/models/spring-ai-autoconfigure-model-google-genai/MIGRATION_GUIDE.md)
Migration Guide: Spring AI Google GenAI Autoconfiguration
Overview
This guide helps you migrate from the old Vertex AI-based autoconfiguration to the new Google GenAI SDK-based autoconfiguration.
Starter Dependencies
Spring AI provides separate starters for Google GenAI functionality:
Chat Functionality
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-google-genai</artifactId>
<version>1.1.0-SNAPSHOT</version>
</dependency>Embedding Functionality
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-google-genai-embedding</artifactId>
<version>1.1.0-SNAPSHOT</version>
</dependency>Note: If you need both chat and embedding capabilities, include both starters in your project. The starters are designed to be used independently or together based on your requirements.
Key Changes
1. Property Namespace Changes
Old properties:
spring.ai.vertex.ai.gemini.project-id=my-project
spring.ai.vertex.ai.gemini.location=us-central1
spring.ai.vertex.ai.gemini.chat.options.model=gemini-pro
spring.ai.vertex.ai.embedding.text.options.model=textembedding-geckoNew properties:
# For Vertex AI mode
spring.ai.google.genai.project-id=my-project
spring.ai.google.genai.location=us-central1
spring.ai.google.genai.chat.model=gemini-2.0-flash
# For Gemini Developer API mode (new!)
spring.ai.google.genai.api-key=your-api-key
spring.ai.google.genai.chat.model=gemini-2.0-flash
# Embedding properties
spring.ai.google.genai.embedding.project-id=my-project
spring.ai.google.genai.embedding.location=us-central1
spring.ai.google.genai.embedding.text.options.model=text-embedding-0042. New Authentication Options
The new SDK supports both:
- Vertex AI mode: Using Google Cloud credentials (same as before)
- Gemini Developer API mode: Using API keys (new!)
3. Removed Features
transportproperty is no longer needed- Multimodal embedding autoconfiguration has been removed (pending support in new SDK)
4. Bean Name Changes
If you were autowiring beans by name:
vertexAi→googleGenAiClientvertexAiGeminiChat→googleGenAiChatModeltextEmbedding→googleGenAiTextEmbedding
5. Class Changes
If you were importing classes directly:
com.google.cloud.vertexai.VertexAI→com.google.genai.Clientorg.springframework.ai.vertexai.gemini.→org.springframework.ai.google.genai.
Migration Steps
- Update your application properties:
- Replace spring.ai.vertex.ai. with spring.ai.google.genai.
- Remove any transport configuration
- If using API key authentication:
- Set spring.ai.google.genai.api-key property
- Remove project-id and location for chat (not needed with API key)
- Update any custom configurations or bean references
- Test your application thoroughly
Environment Variables
export GOOGLE_CLOUD_PROJECT=my-project
export GOOGLE_CLOUD_LOCATION=us-central1New (additional option):
export GOOGLE_API_KEY=your-api-keyBackward Compatibility
The old autoconfiguration module is still available but deprecated. We recommend migrating to the new module as soon as possible.
Auto Configurations/Models/Spring Ai Autoconfigure Model Google Genai/Src/Test/Resources/Fake Credentials.Json (auto-configurations/models/spring-ai-autoconfigure-model-google-genai/src/test/resources/fake-credentials.json)
{
"type": "authorized_user",
"client_id": "test-client-id.apps.googleusercontent.com",
"client_secret": "test-client-secret",
"refresh_token": "test-refresh-token"
}
Auto Configurations/Models/Spring Ai Autoconfigure Model Mistral Ai/Src/Main/Resources/META INF/Additional Spring Configuration Metadata.Json (auto-configurations/models/spring-ai-autoconfigure-model-mistral-ai/src/main/resources/META-INF/additional-spring-configuration-metadata.json)
{
"groups": [
{
"name": "spring.ai.mistralai.chat.tool-choice",
"type": "org.springframework.ai.mistralai.api.MistralAiApi$ChatCompletionRequest$ToolChoice",
"sourceType": "org.springframework.ai.model.mistralai.autoconfigure.MistralAiChatProperties"
}
],
"properties": [],
"hints": []
}
Auto Configurations/Models/Spring Ai Autoconfigure Model Openai/Src/Main/Resources/META INF/Additional Spring Configuration Metadata.Json (auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/resources/META-INF/additional-spring-configuration-metadata.json)
{
"groups": [
{
"name": "spring.ai.openai.chat.output-audio",
"type": "org.springframework.ai.openai.OpenAiChatOptions$AudioParameters",
"sourceType": "org.springframework.ai.openai.OpenAiChatOptions"
}
],
"properties": [
{
"name": "spring.ai.openai.chat.output-audio.voice",
"type": "org.springframework.ai.openai.OpenAiChatOptions$AudioParameters$Voice",
"sourceType": "org.springframework.ai.openai.OpenAiChatOptions$AudioParameters"
},
{
"name": "spring.ai.openai.chat.output-audio.format",
"type": "org.springframework.ai.openai.OpenAiChatOptions$AudioParameters$AudioResponseFormat",
"sourceType": "org.springframework.ai.openai.OpenAiChatOptions$AudioParameters"
}
],
"hints": []
}
Document Readers/Spring Ai Jsoup Document Reader/ README (document-readers/spring-ai-jsoup-document-reader/ README.md)
Spring AI JSoup Document Reader
This module provides an HTML document reader for the Spring AI project. It leverages the JSoup library to parse HTML content and extract text and metadata, making it suitable for use in AI applications.
Features
- Flexible Text Extraction:
* Extract all text from the `` of an HTML document.
* Extract text from specific elements using CSS selectors.
* Group text by element, creating a separate document for each selected element.
* Combine text from multiple selected elements using a configurable separator.
- Metadata Extraction:
* Extract the document title.
* Extract content from <meta> tags (e.g., description, keywords). You can specify which meta tags to extract.
* Extract a list of all absolute URLs of links (<a href="...">) within the document.
- Configurable:
* Specify the character encoding (defaults to UTF-8).
* Customize the CSS selector for element selection.
* Configure the separator string for joining text from multiple elements.
* Choose whether to extract all text or use element-based extraction.
* Enable/disable link URL extraction.
* Add additional metadata using configuration.
- Resource-Based: Works with Spring's
Resourceabstraction, allowing you to read HTML from files, classpath resources, URLs, and even in-memory byte arrays.
How to Build:
./mvnw -pl document-readers/jsoup-reader clean installDocument Readers/Spring Ai Markdown Document Reader/Src/Test/Resources/Blockquote (document-readers/spring-ai-markdown-document-reader/src/test/resources/blockquote.md)
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur diam eros, laoreet sit amet cursus vitae, varius sed
nisi. Cras sit amet quam quis velit commodo porta consectetur id nisi. Phasellus tincidunt pulvinar augue.
Proin vel laoreet leo, sed luctus augue. Sed et ligula commodo, commodo lacus at, consequat turpis. Maecenas eget
sapien odio. Maecenas urna lectus, pellentesque in accumsan aliquam, congue eu libero. Ut rhoncus nec justo a
porttitor. Pellentesque auctor pharetra eros, viverra sodales lorem aliquet id. Curabitur semper nisi vel sem interdum
suscipit.
Document Readers/Spring Ai Markdown Document Reader/Src/Test/Resources/Code (document-readers/spring-ai-markdown-document-reader/src/test/resources/code.md)
This is a Java sample application:
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}Markdown also provides the possibility to use inline code formatting throughout the entire sentence.
Another possibility is to set block code without specific highlighting:
./mvnw spring-javaformat:applyDocument Readers/Spring Ai Markdown Document Reader/Src/Test/Resources/Horizontal Rules (document-readers/spring-ai-markdown-document-reader/src/test/resources/horizontal-rules.md)
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec tincidunt velit non bibendum gravida.
Cras accumsan tincidunt ornare. Donec hendrerit consequat tellus blandit accumsan. Aenean aliquam metus at arcu
elementum dignissim.
Nullam nisi dui, egestas nec sem nec, interdum lobortis enim. Pellentesque odio orci, faucibus eu luctus nec, venenatis
et magna.
Vestibulum nec eros non felis fermentum posuere eget ac risus. Curabitur et fringilla massa. Cras facilisis nec nisl sit
amet sagittis.
*
Aenean eu leo eu nibh tristique posuere quis quis massa. Nullam lacinia luctus sem ut vehicula.
---------------------------------------
Aenean quis vulputate mi. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Nam tincidunt nunc a tortor tincidunt, nec lobortis diam rhoncus.
- - -
Nulla facilisi. Phasellus eget tellus sed nibh ornare interdum eu eu mi.
Document Readers/Spring Ai Markdown Document Reader/Src/Test/Resources/Lists (document-readers/spring-ai-markdown-document-reader/src/test/resources/lists.md)
Ordered list
- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur diam eros, laoreet sit _amet_ cursus vitae,
varius sed nisi.
- Cras sit amet quam quis velit commodo porta consectetur id nisi. Phasellus tincidunt pulvinar augue.
- Proin vel laoreet leo, sed luctus augue. Sed et ligula commodo, commodo lacus at, consequat turpis. Maecenas eget
sapien odio.
1. Pellentesque auctor pharetra eros, viverra sodales lorem aliquet id. Curabitur semper nisi vel sem interdum
suscipit.
2. Maecenas urna lectus, pellentesque in accumsan aliquam, congue eu libero. Ut rhoncus nec justo a porttitor.
Unordered list
- Aenean eu leo eu nibh tristique posuere quis quis massa.
- Aenean imperdiet libero dui, nec malesuada dui maximus vel. Vestibulum sed dui condimentum, cursus libero in, dapibus
tortor.
* Etiam facilisis enim in egestas dictum.
Document Readers/Spring Ai Markdown Document Reader/Src/Test/Resources/Only Headers (document-readers/spring-ai-markdown-document-reader/src/test/resources/only-headers.md)
Header 1a
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur diam eros, laoreet sit amet cursus vitae, varius sed
nisi. Cras sit amet quam quis velit commodo porta consectetur id nisi. Phasellus tincidunt pulvinar augue.
Header 1b
Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Etiam lobortis risus libero, sed
sollicitudin risus cursus in. Morbi enim metus, ornare vel lacinia eget, venenatis vel nibh.
Header 2b
Proin vel laoreet leo, sed luctus augue. Sed et ligula commodo, commodo lacus at, consequat turpis. Maecenas eget sapien
odio. Maecenas urna lectus, pellentesque in accumsan aliquam, congue eu libero.
Header 1c
Header 2c
Ut rhoncus nec justo a porttitor. Pellentesque auctor pharetra eros, viverra sodales lorem aliquet id. Curabitur semper nisi vel sem interdum suscipit.
Document Readers/Spring Ai Markdown Document Reader/Src/Test/Resources/Simple (document-readers/spring-ai-markdown-document-reader/src/test/resources/simple.md)
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec tincidunt velit non bibendum gravida. Cras accumsan
tincidunt ornare. Donec hendrerit consequat tellus blandit accumsan. Aenean aliquam metus at arcu elementum dignissim.
Nullam nisi dui, egestas nec sem nec, interdum lobortis enim. Pellentesque odio orci, faucibus eu luctus nec, venenatis et magna. Vestibulum nec eros non felis fermentum posuere eget ac risus.
Aenean eu leo eu nibh tristique posuere quis quis massa.\
Nullam lacinia luctus sem ut vehicula.
Document Readers/Spring Ai Markdown Document Reader/Src/Test/Resources/With Formatting (document-readers/spring-ai-markdown-document-reader/src/test/resources/with-formatting.md)
This is a fancy header name
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec tincidunt velit non bibendum gravida. Cras accumsan
tincidunt ornare. Donec hendrerit consequat tellus blandit accumsan. Aenean aliquam metus at arcu elementum
dignissim.
Header 3
Aenean eu leo eu nibh tristique _posuere quis quis massa_.
Document Readers/Spring Ai Markdown Document Reader/Src/Test/Resources/Dir Test 1/Blockquote (document-readers/spring-ai-markdown-document-reader/src/test/resources/dir-test-1/blockquote.md)
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur diam eros, laoreet sit amet cursus vitae, varius sed
nisi. Cras sit amet quam quis velit commodo porta consectetur id nisi. Phasellus tincidunt pulvinar augue.
Proin vel laoreet leo, sed luctus augue. Sed et ligula commodo, commodo lacus at, consequat turpis. Maecenas eget
sapien odio. Maecenas urna lectus, pellentesque in accumsan aliquam, congue eu libero. Ut rhoncus nec justo a
porttitor. Pellentesque auctor pharetra eros, viverra sodales lorem aliquet id. Curabitur semper nisi vel sem interdum
suscipit.
Document Readers/Spring Ai Markdown Document Reader/Src/Test/Resources/Dir Test 1/Blockquote (document-readers/spring-ai-markdown-document-reader/src/test/resources/dir-test-1/blockquote.txt)
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur diam eros, laoreet sit amet cursus vitae, varius sed
nisi. Cras sit amet quam quis velit commodo porta consectetur id nisi. Phasellus tincidunt pulvinar augue.
Proin vel laoreet leo, sed luctus augue. Sed et ligula commodo, commodo lacus at, consequat turpis. Maecenas eget
sapien odio. Maecenas urna lectus, pellentesque in accumsan aliquam, congue eu libero. Ut rhoncus nec justo a
porttitor. Pellentesque auctor pharetra eros, viverra sodales lorem aliquet id. Curabitur semper nisi vel sem interdum
suscipit.
Document Readers/Spring Ai Markdown Document Reader/Src/Test/Resources/Dir Test 2/Only Headers (document-readers/spring-ai-markdown-document-reader/src/test/resources/dir-test-2/only-headers.md)
Header 1a
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur diam eros, laoreet sit amet cursus vitae, varius sed
nisi. Cras sit amet quam quis velit commodo porta consectetur id nisi. Phasellus tincidunt pulvinar augue.
Header 1b
Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Etiam lobortis risus libero, sed
sollicitudin risus cursus in. Morbi enim metus, ornare vel lacinia eget, venenatis vel nibh.
Header 2b
Proin vel laoreet leo, sed luctus augue. Sed et ligula commodo, commodo lacus at, consequat turpis. Maecenas eget sapien
odio. Maecenas urna lectus, pellentesque in accumsan aliquam, congue eu libero.
Header 1c
Header 2c
Ut rhoncus nec justo a porttitor. Pellentesque auctor pharetra eros, viverra sodales lorem aliquet id. Curabitur semper nisi vel sem interdum suscipit.
Document Readers/Spring Ai Markdown Document Reader/Src/Test/Resources/Dir Test 2/With Formatting (document-readers/spring-ai-markdown-document-reader/src/test/resources/dir-test-2/with-formatting.md)
This is a fancy header name
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec tincidunt velit non bibendum gravida. Cras accumsan
tincidunt ornare. Donec hendrerit consequat tellus blandit accumsan. Aenean aliquam metus at arcu elementum
dignissim.
Header 3
Aenean eu leo eu nibh tristique _posuere quis quis massa_.
Memory Repositories/Spring Ai Model Chat Memory Repository Jdbc/README (memory-repositories/spring-ai-model-chat-memory-repository-jdbc/README.md)
Memory Repositories/Spring Ai Model Chat Memory Repository Mongodb/README (memory-repositories/spring-ai-model-chat-memory-repository-mongodb/README.md)
Memory Repositories/Spring Ai Model Chat Memory Repository Redis/Src/Test/Resources/Application Metadata Schema.Yml (memory-repositories/spring-ai-model-chat-memory-repository-redis/src/test/resources/application-metadata-schema.yml)
spring:
ai:
chat:
memory:
redis:
host: localhost
port: 6379
index-name: chat-memory-with-schema
# Define metadata fields with their types for proper indexing
# This is compatible with RedisVL schema format
metadata-fields:
- name: priority
type: tag # For exact match searches (high, medium, low)
- name: category
type: tag # For exact match searches
- name: score
type: numeric # For numeric range queries
- name: confidence
type: numeric # For numeric comparisons
- name: model
type: tag # For exact match on model names
- name: description
type: text # For full-text search
Models/Spring Ai Anthropic/README (models/spring-ai-anthropic/README.md)
Anthropic Java SDK Integration
This module integrates the official Anthropic Java SDK with Spring AI, providing access to Claude models through Anthropic's API.
Anthropic Java SDK GitHub repository
Authentication
Configure your Anthropic API key either programmatically or via environment variable:
AnthropicChatOptions options = AnthropicChatOptions.builder()
.apiKey("<your-api-key>")
.build();Or using the environment variable (automatically detected):
export ANTHROPIC_API_KEY=<your-api-key>Features
This module supports:
- Chat Completions - Synchronous and streaming responses
- Tool Calling - Function calling with automatic tool execution
- Streaming Tool Calling - Tool calls in streaming mode with partial JSON accumulation
- Multi-Modal - Images and PDF documents
- Extended Thinking - Claude's thinking/reasoning feature with full streaming support
- Citations - Document-grounded responses with source attribution
- Prompt Caching - Reduce costs for repeated context with configurable strategies
- Structured Output - JSON schema-constrained responses with effort control
- Per-Request HTTP Headers - Custom headers per API call for tracking, beta features, and routing
- Observability - Micrometer-based metrics and tracing
Planned Features
- Amazon Bedrock - Access Claude through AWS Bedrock
- Google Vertex AI - Access Claude through Google Cloud
Basic Usage
// Create chat model with default options
AnthropicChatModel chatModel = new AnthropicChatModel(
AnthropicChatOptions.builder()
.model("claude-sonnet-4-20250514")
.maxTokens(1024)
.build()
);
// Synchronous call
ChatResponse response = chatModel.call(new Prompt("Hello, Claude!"));
// Streaming call
Flux<ChatResponse> stream = chatModel.stream(new Prompt("Tell me a story"));Tool Calling
var options = AnthropicChatOptions.builder()
.model("claude-sonnet-4-20250514")
.toolCallbacks(FunctionToolCallback.builder("getWeather", new WeatherService())
.description("Get the current weather for a location")
.inputType(WeatherRequest.class)
.build())
.build();
ChatResponse response = chatModel.call(new Prompt("What's the weather in Paris?", options));Extended Thinking
Enable Claude's reasoning feature to see step-by-step thinking before the final answer:
var options = AnthropicChatOptions.builder()
.model("claude-sonnet-4-20250514")
.temperature(1.0) // required when thinking is enabled
.maxTokens(16000)
.thinkingEnabled(10000L) // budget must be >= 1024 and < maxTokens
.build();
ChatResponse response = chatModel.call(new Prompt("Solve this step by step...", options));Three thinking modes are available via convenience builders:
thinkingEnabled(budgetTokens)- Enable with a specific token budgetthinkingAdaptive()- Let Claude decide whether to thinkthinkingDisabled()- Explicitly disable thinking
Thinking is fully supported in both synchronous and streaming modes, including signature capture for thinking block verification.
Citations
Anthropic's Citations API allows Claude to reference specific parts of provided documents when generating responses. Three document types are supported: plain text, PDF, and custom content blocks.
// Create a citation document
AnthropicCitationDocument document = AnthropicCitationDocument.builder()
.plainText("The Eiffel Tower was completed in 1889 in Paris, France. " +
"It stands 330 meters tall and was designed by Gustave Eiffel.")
.title("Eiffel Tower Facts")
.citationsEnabled(true)
.build();
// Call the model with the document
ChatResponse response = chatModel.call(
new Prompt(
"When was the Eiffel Tower built?",
AnthropicChatOptions.builder()
.model("claude-sonnet-4-20250514")
.maxTokens(1024)
.citationDocuments(document)
.build()
)
);
// Access citations from response metadata
List<Citation> citations = (List<Citation>) response.getMetadata().get("citations");
for (Citation citation : citations) {
System.out.println("Document: " + citation.getDocumentTitle());
System.out.println("Cited text: " + citation.getCitedText());
}PDF and custom content block documents are also supported via pdfFile(), pdf(), and customContent() builders.
Prompt Caching
Prompt caching reduces costs and latency by caching repeated context (system prompts, tool definitions, conversation history) across API calls. Five caching strategies are available:
| Strategy | Description |
|---|---|
NONE |
No caching (default) |
| SYSTEM_ONLY | Cache system message content |
| TOOLS_ONLY | Cache tool definitions |
| SYSTEM_AND_TOOLS | Cache both system messages and tool definitions |
| CONVERSATION_HISTORY | Cache system messages, tools, and conversation messages |
// Cache system messages to reduce costs for repeated prompts
var options = AnthropicChatOptions.builder()
.model("claude-sonnet-4-20250514")
.maxTokens(1024)
.cacheOptions(AnthropicCacheOptions.builder()
.strategy(AnthropicCacheStrategy.SYSTEM_AND_TOOLS)
.build())
.build();
ChatResponse response = chatModel.call(
new Prompt(List.of(
new SystemMessage("You are an expert assistant with deep domain knowledge..."),
new UserMessage("What is the capital of France?")),
options));
// Access cache token usage via native SDK usage
com.anthropic.models.messages.Usage sdkUsage =
(com.anthropic.models.messages.Usage) response.getMetadata().getUsage().getNativeUsage();
long cacheCreation = sdkUsage.cacheCreationInputTokens().orElse(0L);
long cacheRead = sdkUsage.cacheReadInputTokens().orElse(0L);You can also configure TTL (5 minutes or 1 hour), minimum content length thresholds, and multi-block system caching for static vs. dynamic system message segments:
var options = AnthropicCacheOptions.builder()
.strategy(AnthropicCacheStrategy.SYSTEM_ONLY)
.messageTypeTtl(MessageType.SYSTEM, AnthropicCacheTtl.ONE_HOUR)
.messageTypeMinContentLength(MessageType.SYSTEM, 100)
.multiBlockSystemCaching(true)
.build();Structured Output
Structured output constrains Claude to produce responses conforming to a JSON schema. The SDK module also supports Anthropic's effort control for tuning response quality vs speed.
Model Requirement: Structured output and effort control require
claude-sonnet-4-6or newer. Older models likeclaude-sonnet-4-20250514do not support these features.
JSON Schema Output
var options = AnthropicChatOptions.builder()
.model("claude-sonnet-4-6")
.outputSchema("""
{
"type": "object",
"properties": {
"name": {"type": "string"},
"capital": {"type": "string"},
"population": {"type": "integer"}
},
"required": ["name", "capital"],
"additionalProperties": false
}
""")
.build();
ChatResponse response = chatModel.call(new Prompt("Tell me about France.", options));
// Response text will be valid JSON conforming to the schemaEffort Control
Control how much compute Claude spends on its response. Lower effort means faster, cheaper responses; higher effort means more thorough reasoning.
var options = AnthropicChatOptions.builder()
.model("claude-sonnet-4-6")
.effort(OutputConfig.Effort.LOW) // LOW, MEDIUM, HIGH, or MAX
.build();Combined Schema + Effort
var options = AnthropicChatOptions.builder()
.model("claude-sonnet-4-6")
.outputSchema("{\"type\":\"object\",\"properties\":{\"answer\":{\"type\":\"integer\"}},\"required\":[\"answer\"],\"additionalProperties\":false}")
.effort(OutputConfig.Effort.HIGH)
.build();Direct OutputConfig
For full control, use the SDK's OutputConfig directly:
import com.anthropic.models.messages.OutputConfig;
import com.anthropic.models.messages.JsonOutputFormat;
import com.anthropic.core.JsonValue;
var outputConfig = OutputConfig.builder()
.effort(OutputConfig.Effort.HIGH)
.format(JsonOutputFormat.builder()
.schema(JsonOutputFormat.Schema.builder()
.putAdditionalProperty("type", JsonValue.from("object"))
.putAdditionalProperty("properties", JsonValue.from(Map.of(
"name", Map.of("type", "string"))))
.putAdditionalProperty("additionalProperties", JsonValue.from(false))
.build())
.build())
.build();
var options = AnthropicChatOptions.builder()
.model("claude-sonnet-4-6")
.outputConfig(outputConfig)
.build();Per-Request HTTP Headers
Add custom HTTP headers to individual API calls. Unlike customHeaders (which apply to all requests at the client level), httpHeaders are set per request.
var options = AnthropicChatOptions.builder()
.httpHeaders(Map.of(
"X-Request-Id", "req-12345",
"X-Custom-Tracking", "my-value"))
.build();
ChatResponse response = chatModel.call(new Prompt("Hello", options));Logging
Enable SDK logging by setting the environment variable:
export ANTHROPIC_LOG=debugDocumentation
For comprehensive documentation, see:
- Spring AI Anthropic Reference Documentation
- Anthropic API Documentation
- Anthropic Java SDK Documentation
Models/Spring Ai Anthropic/Src/Test/Resources/Prompts/Conversation History Cache Prompt (models/spring-ai-anthropic/src/test/resources/prompts/conversation-history-cache-prompt.txt)
You are an experienced career counselor and professional development expert with over 15 years of experience
helping technology professionals advance their careers in software engineering, data science, and emerging tech fields.
Your expertise spans career transitions, skill development, industry trends, and strategic career planning.
When providing career guidance, always consider these essential dimensions:
- Current market trends and emerging technologies affecting career trajectories
- Skills gap analysis and strategic upskilling recommendations for competitive advantage
- Industry-specific compensation benchmarks and negotiation strategies
- Professional networking approaches and personal brand development
- Leadership development pathways and technical career progression options
- Work-life balance considerations and remote work best practices
- Interview preparation strategies and portfolio development guidance
- Career transition planning including timing, risk mitigation, and bridge strategies
- Performance evaluation optimization and promotion pathway planning
- Entrepreneurial opportunities and freelancing vs full-time employment trade-offs
Career Development Framework for Conversation History Caching
Technical Skills Assessment and Development
Provide comprehensive technical skill evaluation:
- Current technology stack assessment with market relevance analysis
- Emerging technology identification and learning prioritization strategies
- Certification and formal education recommendations with ROI calculations
- Hands-on project suggestions to demonstrate competency and build portfolios
- Open source contribution strategies for visibility and community engagement
- Technical writing and speaking opportunities for thought leadership development
- Mentorship and reverse mentoring opportunities for skill exchange
Career Progression Strategy Planning
Develop strategic career advancement plans:
- Individual contributor vs management track decision frameworks
- Technical leadership roles and architectural responsibility progression
- Cross-functional collaboration skills for broader organizational impact
- Product management and business strategy understanding for technical leaders
- Agile and project management methodologies for delivery excellence
- Stakeholder communication and executive presentation skills development
- International and remote work opportunities for global career expansion
Industry and Market Analysis
Analyze technology industry trends comprehensively:
- Startup vs enterprise career path comparisons with risk-reward analysis
- Industry sector analysis including fintech, healthcare, education, and government
- Geographic market opportunities and cost of living considerations
- Remote work impact on career opportunities and compensation structures
- Freelancing and consulting market dynamics with rate optimization
- Technology adoption cycles and their impact on career longevity
- Economic factors affecting technology hiring and investment patterns
Professional Development and Networking
Guide strategic professional relationship building:
- Conference attendance and speaking engagement strategies for visibility
- Professional association participation and leadership opportunities
- Alumni network activation and industry meetup engagement tactics
- Social media presence optimization for professional brand building
- Mentorship relationship development both as mentor and mentee
- Cross-industry networking for diverse perspective and opportunity access
- International professional relationships for global career opportunities
Performance and Compensation Optimization
Optimize career advancement and compensation:
- Performance review preparation and goal-setting strategies for maximum impact
- Compensation negotiation tactics with market research and timing considerations
- Equity and stock option evaluation for startup and growth company positions
- Benefits package optimization including health, retirement, and professional development
- Professional development budget utilization for strategic skill building
- Side project and passive income development for financial diversification
- Career pivoting strategies with income protection and transition planning
Always provide personalized, actionable advice based on individual circumstances and career goals.
Consider market conditions, personal constraints, and long-term career sustainability.
Focus on building transferable skills and maintaining adaptability in a rapidly changing technology landscape.
This system prompt is specifically designed for testing conversation history caching strategies and contains sufficient tokens
to trigger Anthropic's prompt caching mechanism with Claude Sonnet 4 (1024+ token threshold).
Models/Spring Ai Anthropic/Src/Test/Resources/Prompts/Extended Ttl Cache Prompt (models/spring-ai-anthropic/src/test/resources/prompts/extended-ttl-cache-prompt.txt)
You are a comprehensive mathematical assistant specializing in arithmetic, algebra, calculus, statistics, and advanced mathematical concepts.
Your expertise spans elementary mathematics through graduate-level topics, with particular strength in problem-solving methodologies.
When addressing mathematical problems, always consider these fundamental aspects:
- Problem comprehension and identification of given information and unknowns
- Selection of appropriate mathematical methods and solution strategies
- Step-by-step solution development with clear logical progression
- Verification of results through alternative methods or sanity checks
- Interpretation of solutions in context with practical applications
- Common error identification and prevention strategies
- Conceptual understanding reinforcement through analogies and examples
- Connections to broader mathematical principles and theorems
- Computational accuracy and precision considerations
- Communication of mathematical reasoning in accessible language
Mathematical Problem-Solving Framework for Extended TTL Caching
Arithmetic and Number Theory
Provide comprehensive arithmetic analysis:
- Basic operations with integers, fractions, and decimal number systems
- Prime factorization and greatest common divisor calculations
- Modular arithmetic applications in cryptography and computer science
- Number base conversions between binary, octal, decimal, and hexadecimal systems
- Rational and irrational number properties with proof techniques
- Complex number operations including polar and rectangular forms
- Mathematical induction proofs for number theory propositions
Algebraic Problem Solving
Develop algebraic solution strategies:
- Linear equation systems using substitution, elimination, and matrix methods
- Quadratic equation solutions with discriminant analysis and graphical interpretation
- Polynomial factorization techniques including synthetic division and rational root theorem
- Exponential and logarithmic equation solving with change of base formulas
- Inequality solving with graphical representation and interval notation
- Function composition and inverse function determination
- Abstract algebra concepts including groups, rings, and fields
Calculus and Analysis
Analyze calculus problems comprehensively:
- Limit evaluation using algebraic manipulation and L'Hôpital's rule
- Derivative calculations with chain rule, product rule, and quotient rule applications
- Integration techniques including substitution, parts, and partial fractions
- Applications of derivatives in optimization and related rate problems
- Definite integral applications in area, volume, and physics problems
- Series convergence analysis with ratio, root, and integral tests
- Multivariable calculus including partial derivatives and multiple integrals
Statistical Analysis and Probability
Examine statistical methods thoroughly:
- Descriptive statistics including measures of central tendency and dispersion
- Probability distributions with normal, binomial, and Poisson applications
- Hypothesis testing with Type I and Type II error analysis
- Confidence interval construction and interpretation
- Regression analysis with correlation coefficient interpretation
- Analysis of variance (ANOVA) for comparing multiple groups
- Bayesian inference and conditional probability applications
Applied Mathematics and Modeling
Model real-world problems mathematically:
- Linear programming with simplex method and graphical solutions
- Differential equation modeling for population growth and decay
- Game theory applications in economics and strategic decision making
- Graph theory for network analysis and optimization problems
- Numerical analysis methods for approximation and error estimation
- Operations research techniques for resource allocation and scheduling
- Financial mathematics including compound interest and annuity calculations
Always provide clear explanations with multiple solution approaches where applicable.
Include graphical representations and real-world applications to enhance understanding.
Emphasize mathematical reasoning and proof techniques to develop analytical thinking skills.
Additional Mathematical Problem-Solving Strategies for Extended TTL Testing
Advanced Topics and Specialized Areas
Explore comprehensive mathematical domains:
- Abstract Algebra: Group theory, ring theory, field theory applications
- Real Analysis: Measure theory, functional analysis, topology concepts
- Complex Analysis: Analytic functions, contour integration, residue theory
- Discrete Mathematics: Graph theory, combinatorics, number theory applications
- Linear Algebra: Matrix decompositions, eigenvalue problems, vector spaces
- Differential Geometry: Manifolds, curvature, tensor calculus applications
- Optimization Theory: Linear programming, nonlinear optimization, convex analysis
- Probability Theory: Stochastic processes, measure-theoretic probability, limit theorems
- Mathematical Logic: Set theory, model theory, proof theory foundations
Computational Mathematics and Numerical Methods
Address computational aspects thoroughly:
- Numerical Linear Algebra: LU decomposition, QR factorization, singular value decomposition
- Numerical Integration: Gaussian quadrature, adaptive quadrature methods, Monte Carlo integration
- Ordinary Differential Equations: Runge-Kutta methods, multistep methods, boundary value problems
- Partial Differential Equations: Finite difference methods, finite element analysis, spectral methods
- Interpolation and Approximation: Spline interpolation, Chebyshev polynomials, least squares approximation
- Root Finding: Newton-Raphson method, bisection method, secant method applications
- Optimization Algorithms: Gradient descent, Newton's method, simplex algorithm implementations
Mathematical Modeling and Real-World Applications
Connect theory to practical implementations:
- Engineering Mathematics: Fourier analysis, Laplace transforms, control theory applications
- Mathematical Biology: Population dynamics, epidemic modeling, biochemical reaction networks
- Mathematical Physics: Quantum mechanics, relativity theory, statistical mechanics principles
- Mathematical Economics: Game theory, optimization in economics, financial mathematics modeling
- Actuarial Mathematics: Life insurance, annuities, pension fund calculations, risk assessment
- Cryptography: Number theory applications, elliptic curve cryptography, hash functions
- Signal Processing: Digital signal processing, wavelets, time-frequency analysis techniques
This system prompt is specifically designed for testing extended TTL caching strategies and contains sufficient tokens
to trigger Anthropic's prompt caching mechanism with Claude Sonnet 4 (1024+ token threshold). The expanded content
ensures we exceed the minimum token requirement significantly to guarantee cache creation rather than relying on
borderline token counts that might fail cache threshold requirements.
Models/Spring Ai Anthropic/Src/Test/Resources/Prompts/System And Tools Cache Prompt (models/spring-ai-anthropic/src/test/resources/prompts/system-and-tools-cache-prompt.txt)
You are a comprehensive weather analysis assistant specializing in meteorological data interpretation and outdoor activity recommendations.
Your expertise encompasses understanding complex weather patterns, atmospheric conditions, and their impact on various outdoor activities.
When analyzing weather data, always consider these critical factors:
- Temperature variations throughout the day and their impact on comfort levels
- Precipitation probability, intensity, and duration affecting outdoor plans
- Wind speed and direction influencing perceived temperature and activity safety
- Humidity levels affecting comfort and heat index calculations
- UV index and sun exposure recommendations for health and safety
- Atmospheric pressure changes indicating weather pattern shifts
- Visibility conditions for driving and outdoor navigation
- Air quality indices for respiratory health considerations
- Seasonal patterns and historical weather trends for context
- Local microclimate effects in urban vs rural environments
Weather Analysis Framework for System and Tools Caching
Temperature Analysis
Provide detailed temperature assessments:
- Current temperature readings with heat index or wind chill calculations
- Daily temperature ranges including minimum and maximum predictions
- Comfort zone analysis for different age groups and activity levels
- Thermal comfort indices considering humidity, wind, and solar radiation
- Clothing recommendations based on effective temperature measurements
- Risk assessments for heat-related illnesses or cold exposure
- Optimal timing recommendations for temperature-sensitive activities
Precipitation Assessment
Analyze precipitation patterns comprehensively:
- Current precipitation type, intensity, and accumulation rates
- Probability forecasts with confidence intervals and timing predictions
- Impact assessments on outdoor activities, transportation, and infrastructure
- Flood risk evaluations for low-lying areas and drainage systems
- Snow and ice formation potential with safety implications
- Seasonal precipitation trends and drought or flood pattern analysis
- Agricultural and ecological impacts of current and forecast precipitation
Wind Conditions Evaluation
Assess wind impacts thoroughly:
- Current wind speed, direction, and gust measurements
- Wind chill calculations and perceived temperature effects
- Safety considerations for high-wind activities and structural concerns
- Maritime and aviation wind impact assessments
- Dust and pollen dispersion patterns affected by wind conditions
- Energy generation potential for wind-powered systems
- Fire weather conditions and wildfire risk assessments
Atmospheric Monitoring
Monitor comprehensive atmospheric conditions:
- Barometric pressure trends indicating weather system movements
- Humidity levels with comfort and health impact assessments
- Air quality measurements including particulate matter and pollutants
- UV radiation levels with skin protection recommendations
- Visibility assessments for transportation and outdoor activities
- Lightning detection and severe weather warning systems
- Climate change indicators and long-term trend analysis
Activity Recommendations
Provide specific outdoor activity guidance:
- Walking, hiking, and running condition assessments with safety protocols
- Sports and recreational activity suitability ratings
- Gardening and agricultural work timing recommendations
- Construction and outdoor work safety guidelines
- Travel and transportation condition evaluations
- Photography and outdoor event planning considerations
- Emergency preparedness and severe weather response protocols
Severe Weather Protocols
Apply rigorous severe weather analysis procedures:
- Thunderstorm development tracking with lightning frequency and storm cell motion
- Tornado watch and warning interpretation with shelter-in-place guidance
- Hurricane and tropical storm trajectory analysis with evacuation timing windows
- Flash flood potential based on rainfall rates, soil saturation, and terrain
- Winter storm classification covering snowfall accumulation, ice loading, and blizzard criteria
- Heat wave and cold snap duration forecasting with public health advisory thresholds
- Coastal storm surge estimation and tidal interaction effects on low-lying areas
Data Quality and Confidence
Communicate forecast reliability transparently:
- Distinguish observed measurements from model-derived predictions
- Report confidence intervals and forecast uncertainty for each variable
- Note model disagreement between major numerical weather prediction systems
- Flag data gaps from sensor outages or sparse observation networks
- Explain how forecast skill degrades with lead time for each parameter
- Reconcile conflicting indicators rather than averaging them uncritically
- Provide ranges rather than single point estimates when uncertainty is high
Regional and Seasonal Context
Ground every assessment in local context:
- Adjust thresholds for regional climate norms and acclimatization
- Account for elevation, proximity to large bodies of water, and urban heat islands
- Incorporate seasonal baselines so anomalies are interpreted correctly
- Reference historical analogs for comparable weather setups
- Consider prevailing wind regimes and orographic effects on precipitation
- Factor in diurnal patterns specific to the location and time of year
Communication and Response Structure
Structure every response for clarity and usefulness:
- Lead with the single most decision-relevant takeaway for the user's question
- Follow with supporting detail organized from highest to lowest impact
- Use concrete numbers with units rather than vague qualitative descriptions
- Separate what is known now from what is forecast and how far out
- Call out any safety-critical condition explicitly and early in the response
- Offer a clear recommended action, not just a description of conditions
- Close with the most relevant caveat or condition that would change the advice
Outdoor Activity Risk Tiers
Classify recommendations into consistent risk tiers:
- Favorable conditions where the activity can proceed without special precautions
- Marginal conditions requiring specific mitigations such as timing or equipment
- Hazardous conditions where the activity should be postponed or relocated
- Dangerous conditions where outdoor exposure itself is the primary risk
- For each tier, name the dominant limiting factor driving the classification
- Re-evaluate the tier whenever a key variable crosses a documented threshold
Always provide specific, actionable recommendations with safety considerations paramount.
Include quantitative data where available and explain the reasoning behind recommendations.
Consider vulnerable populations including children, elderly, and individuals with health conditions.
This system prompt is specifically designed for testing system and tools caching strategies and contains sufficient tokens
to trigger Anthropic's prompt caching mechanism with current Claude Sonnet models (1024+ token threshold).
Models/Spring Ai Anthropic/Src/Test/Resources/Prompts/System Only Cache Prompt (models/spring-ai-anthropic/src/test/resources/prompts/system-only-cache-prompt.txt)
You are an expert software architect specializing in distributed systems and cloud-native applications.
Your responses should be detailed, technically accurate, and include comprehensive best practices
for scalability, reliability, maintainability, and cost-effectiveness in modern software systems.
When discussing architecture patterns, always consider these critical aspects:
- Scalability implications and potential bottlenecks across multiple dimensions including compute, storage, network, and database resources
- Fault tolerance and error handling strategies including circuit breakers, bulkheads, timeouts, retries, and graceful degradation
- Data consistency and transaction management including eventual consistency patterns, saga patterns, and distributed transaction challenges
- Security considerations and access patterns including authentication, authorization, encryption at rest and in transit, and zero-trust principles
- Monitoring and observability requirements including distributed tracing, structured logging, metrics collection, and alerting strategies
- Performance optimization opportunities including caching strategies, CDN usage, database indexing, and query optimization
- Cost optimization strategies including resource rightsizing, reserved capacity planning, and multi-cloud cost management
- Team structure and Conway's Law implications including microservice boundaries, team autonomy, and communication patterns
- DevOps and deployment strategies including CI/CD pipelines, infrastructure as code, and automated testing approaches
- Compliance and governance requirements including data privacy regulations, audit trails, and regulatory compliance frameworks
Detailed Architecture Guidelines for System-Only Caching
Microservices Design Patterns
When designing microservices, implement these essential patterns:
- API Gateway pattern for centralized request routing and cross-cutting concerns
- Service mesh for inter-service communication, security, and observability
- Event sourcing for maintaining audit trails and enabling event-driven architectures
- CQRS (Command Query Responsibility Segregation) for optimal read/write performance
- Bulkhead pattern to isolate critical resources and prevent cascade failures
- Circuit breaker pattern with exponential backoff for external service resilience
- Saga pattern for distributed transaction management across service boundaries
Data Management Strategies
Implement robust data management approaches:
- Database per service pattern to ensure data encapsulation and service autonomy
- Event-driven data synchronization using message queues and event streams
- Polyglot persistence choosing optimal data stores for specific use cases
- Read replicas and sharding strategies for horizontal scaling
- Data versioning and schema evolution strategies for backward compatibility
- Distributed caching with Redis or similar for improved performance
- Data governance frameworks ensuring data quality, lineage, and compliance
Security Best Practices
Implement defense-in-depth security measures:
- OAuth 2.0 and OpenID Connect for authentication and authorization
- JWT tokens with proper expiration and refresh token mechanisms
- API rate limiting and throttling to prevent abuse and DDoS attacks
- Encryption at rest using AES-256 and encryption in transit with TLS 1.3
- Secret management using HashiCorp Vault or AWS Secrets Manager
- Network segmentation with VPCs, subnets, and security groups
- Regular security audits, vulnerability scanning, and penetration testing
Monitoring and Observability
Establish comprehensive observability:
- Distributed tracing with OpenTelemetry or Jaeger for request flow analysis
- Centralized logging with ELK stack or similar for log aggregation and analysis
- Application metrics using Prometheus and Grafana for monitoring and alerting
- Health checks and readiness probes for service availability monitoring
- SLA/SLO definitions with error budgets for reliability measurements
- Alert management with PagerDuty or similar for incident response
- Performance monitoring with APM tools like New Relic or AppDynamics
Infrastructure and DevOps
Implement modern infrastructure practices:
- Infrastructure as Code using Terraform, CloudFormation, or Pulumi
- Container orchestration with Kubernetes for scalable deployments
- GitOps workflows with ArgoCD or Flux for automated deployments
- Blue-green or canary deployment strategies for zero-downtime releases
- Automated testing pipelines including unit, integration, and end-to-end tests
- Code quality gates with SonarQube and static analysis tools
- Disaster recovery planning with backup strategies and failover procedures
Always provide concrete examples, architectural diagrams when helpful, code snippets in relevant programming languages,
and real-world case studies from companies like Netflix, Amazon, Google, Microsoft, and other technology leaders.
Consider both the technical and business implications of architectural decisions, including time-to-market,
development velocity, operational overhead, and long-term maintainability costs.
This system prompt is specifically designed for testing system-only caching strategies and contains sufficient tokens
to trigger Anthropic's prompt caching mechanism with Claude Sonnet 4 (1024+ token threshold).
Models/Spring Ai Bedrock/README (models/spring-ai-bedrock/README.md)
- Anthropic3 Chat Documentation
- Anthropic2 Chat Documentation
- Cohere Chat Documentation
- Cohere Embedding Documentation
- Llama Chat Documentation
- Titan Chat Documentation
- Titan Embedding Documentation
- Jurassic2 Chat Documentation
Models/Spring Ai Deepseek/README (models/spring-ai-deepseek/README.md)
Models/Spring Ai Elevenlabs/README (models/spring-ai-elevenlabs/README.md)
Spring AI - ElevenLabs Text-to-Speech
ElevenLabs Text-to-Speech Documentation
Models/Spring Ai Elevenlabs/Src/Test/Resources/Voices.Json (models/spring-ai-elevenlabs/src/test/resources/voices.json)
{
"voices": [
{
"voice_id": "9BWtsMINqrJLrRacOk9x",
"name": "Aria",
"samples": null,
"category": "premade",
"fine_tuning": {
"is_allowed_to_fine_tune": true,
"state": {
"eleven_multilingual_v2": "fine_tuned",
"eleven_turbo_v2_5": "fine_tuned",
"eleven_flash_v2_5": "fine_tuned",
"eleven_v2_flash": "fine_tuned",
"eleven_v2_5_flash": "fine_tuned",
"eleven_turbo_v2": "fine_tuned",
"eleven_flash_v2": "fine_tuned"
},
"verification_failures": [],
"verification_attempts_count": 0,
"manual_verification_requested": false,
"language": "en",
"progress": {
"eleven_flash_v2_5": 1,
"eleven_v2_flash": 1,
"eleven_flash_v2": 1,
"eleven_v2_5_flash": 1
},
"message": {
"eleven_flash_v2_5": "Done!",
"eleven_v2_flash": "Done!",
"eleven_flash_v2": "Done!",
"eleven_v2_5_flash": "Done!"
},
"dataset_duration_seconds": null,
"verification_attempts": null,
"slice_ids": null,
"manual_verification": null,
"max_verification_attempts": 5,
"next_max_verification_attempts_reset_unix_ms": 1700000000000
},
"labels": {
"accent": "American",
"description": "expressive",
"age": "middle-aged",
"gender": "female",
"use_case": "social media"
},
"description": null,
"preview_url": "https://storage.googleapis.com/eleven-public-prod/premade/voices/9BWtsMINqrJLrRacOk9x/405766b8-1f4e-4d3c-aba1-6f25333823ec.mp3",
"available_for_tiers": [],
"settings": null,
"sharing": null,
"high_quality_base_model_ids": [
"eleven_v2_flash",
"eleven_flash_v2",
"eleven_turbo_v2_5",
"eleven_multilingual_v2",
"eleven_v2_5_flash",
"eleven_flash_v2_5",
"eleven_turbo_v2"
],
"verified_languages": [],
"safety_control": null,
"voice_verification": {
"requires_verification": false,
"is_verified": false,
"verification_failures": [],
"verification_attempts_count": 0,
"language": null,
"verification_attempts": null
},
"permission_on_resource": null,
"is_owner": false,
"is_legacy": false,
"is_mixed": false,
"created_at_unix": null
},
{
"voice_id": "CwhRBWXzGAHq8TQ4Fs17",
"name": "Roger",
"samples": null,
"category": "premade",
"fine_tuning": {
"is_allowed_to_fine_tune": true,
"state": {
"eleven_multilingual_v2": "fine_tuned",
"eleven_turbo_v2_5": "failed",
"eleven_flash_v2_5": "fine_tuned",
"eleven_v2_flash": "fine_tuned",
"eleven_v2_5_flash": "fine_tuned",
"eleven_turbo_v2": "fine_tuned",
"eleven_flash_v2": "fine_tuned"
},
"verification_failures": [],
"verification_attempts_count": 0,
"manual_verification_requested": false,
"language": "en",
"progress": {
"eleven_flash_v2_5": 1,
"eleven_v2_flash": 1,
"eleven_flash_v2": 1,
"eleven_v2_5_flash": 1
},
"message": {
"eleven_flash_v2_5": "Done!",
"eleven_v2_flash": "Done!",
"eleven_flash_v2": "Done!",
"eleven_v2_5_flash": "Done!"
},
"dataset_duration_seconds": null,
"verification_attempts": null,
"slice_ids": null,
"manual_verification": null,
"max_verification_attempts": 5,
"next_max_verification_attempts_reset_unix_ms": 1700000000000
},
"labels": {
"accent": "American",
"description": "confident",
"age": "middle-aged",
"gender": "male",
"use_case": "social media"
},
"description": null,
"preview_url": "https://storage.googleapis.com/eleven-public-prod/premade/voices/CwhRBWXzGAHq8TQ4Fs17/58ee3ff5-f6f2-4628-93b8-e38eb31806b0.mp3",
"available_for_tiers": [],
"settings": null,
"sharing": null,
"high_quality_base_model_ids": [
"eleven_v2_flash",
"eleven_flash_v2",
"eleven_turbo_v2_5",
"eleven_multilingual_v2",
"eleven_v2_5_flash",
"eleven_flash_v2_5",
"eleven_turbo_v2"
],
"verified_languages": [],
"safety_control": null,
"voice_verification": {
"requires_verification": false,
"is_verified": false,
"verification_failures": [],
"verification_attempts_count": 0,
"language": null,
"verification_attempts": null
},
"permission_on_resource": null,
"is_owner": false,
"is_legacy": false,
"is_mixed": false,
"created_at_unix": null
},
{
"voice_id": "EXAVITQu4vr4xnSDxMaL",
"name": "Sarah",
"samples": null,
"category": "premade",
"fine_tuning": {
"is_allowed_to_fine_tune": true,
"state": {},
"verification_failures": [],
"verification_attempts_count": 0,
"manual_verification_requested": false,
"language": "en",
"progress": {},
"message": {},
"dataset_duration_seconds": null,
"verification_attempts": null,
"slice_ids": null,
"manual_verification": null,
"max_verification_attempts": 5,
"next_max_verification_attempts_reset_unix_ms": 1700000000000
},
"labels": {
"accent": "american",
"description": "soft",
"age": "young",
"gender": "female",
"use_case": "news"
},
"description": null,
"preview_url": "https://storage.googleapis.com/eleven-public-prod/premade/voices/EXAVITQu4vr4xnSDxMaL/01a3e33c-6e99-4ee7-8543-ff2216a32186.mp3",
"available_for_tiers": [],
"settings": null,
"sharing": null,
"high_quality_base_model_ids": [
"eleven_turbo_v2",
"eleven_multilingual_v2",
"eleven_turbo_v2_5"
],
"verified_languages": [],
"safety_control": null,
"voice_verification": {
"requires_verification": false,
"is_verified": false,
"verification_failures": [],
"verification_attempts_count": 0,
"language": null,
"verification_attempts": null
},
"permission_on_resource": null,
"is_owner": false,
"is_legacy": false,
"is_mixed": false,
"created_at_unix": null
},
{
"voice_id": "FGY2WhTYpPnrIDTdsKH5",
"name": "Laura",
"samples": null,
"category": "premade",
"fine_tuning": {
"is_allowed_to_fine_tune": true,
"state": {
"eleven_multilingual_v2": "fine_tuned",
"eleven_turbo_v2_5": "fine_tuned",
"eleven_flash_v2_5": "fine_tuned",
"eleven_v2_flash": "fine_tuned",
"eleven_v2_5_flash": "fine_tuned",
"eleven_turbo_v2": "fine_tuned",
"eleven_flash_v2": "fine_tuned"
},
"verification_failures": [],
"verification_attempts_count": 0,
"manual_verification_requested": false,
"language": "en",
"progress": {
"eleven_flash_v2_5": 1,
"eleven_v2_flash": 1,
"eleven_flash_v2": 1,
"eleven_v2_5_flash": 1
},
"message": {
"eleven_flash_v2_5": "Done!",
"eleven_v2_flash": "Done!",
"eleven_flash_v2": "Done!",
"eleven_v2_5_flash": "Done!"
},
"dataset_duration_seconds": null,
"verification_attempts": null,
"slice_ids": null,
"manual_verification": null,
"max_verification_attempts": 5,
"next_max_verification_attempts_reset_unix_ms": 1700000000000
},
"labels": {
"accent": "American",
"description": "upbeat",
"age": "young",
"gender": "female",
"use_case": "social media"
},
"description": null,
"preview_url": "https://storage.googleapis.com/eleven-public-prod/premade/voices/FGY2WhTYpPnrIDTdsKH5/67341759-ad08-41a5-be6e-de12fe448618.mp3",
"available_for_tiers": [],
"settings": null,
"sharing": null,
"high_quality_base_model_ids": [
"eleven_v2_flash",
"eleven_flash_v2",
"eleven_turbo_v2_5",
"eleven_multilingual_v2",
"eleven_v2_5_flash",
"eleven_flash_v2_5",
"eleven_turbo_v2"
],
"verified_languages": [],
"safety_control": null,
"voice_verification": {
"requires_verification": false,
"is_verified": false,
"verification_failures": [],
"verification_attempts_count": 0,
"language": null,
"verification_attempts": null
},
"permission_on_resource": null,
"is_owner": false,
"is_legacy": false,
"is_mixed": false,
"created_at_unix": null
},
{
"voice_id": "IKne3meq5aSn9XLyUdCD",
"name": "Charlie",
"samples": null,
"category": "premade",
"fine_tuning": {
"is_allowed_to_fine_tune": true,
"state": {
"eleven_flash_v2_5": "fine_tuned",
"eleven_turbo_v2": "fine_tuned",
"eleven_flash_v2": "fine_tuned",
"eleven_v2_flash": "fine_tuned",
"eleven_v2_5_flash": "fine_tuned"
},
"verification_failures": [],
"verification_attempts_count": 0,
"manual_verification_requested": false,
"language": "en",
"progress": {
"eleven_flash_v2_5": 1,
"eleven_v2_flash": 1,
"eleven_flash_v2": 1,
"eleven_v2_5_flash": 1
},
"message": {
"eleven_flash_v2_5": "Done!",
"eleven_turbo_v2": "",
"eleven_flash_v2": "Done!",
"eleven_v2_flash": "Done!",
"eleven_v2_5_flash": "Done!"
},
"dataset_duration_seconds": null,
"verification_attempts": null,
"slice_ids": null,
"manual_verification": null,
"max_verification_attempts": 5,
"next_max_verification_attempts_reset_unix_ms": 1700000000000
},
"labels": {
"accent": "Australian",
"description": "natural",
"age": "middle aged",
"gender": "male",
"use_case": "conversational"
},
"description": null,
"preview_url": "https://storage.googleapis.com/eleven-public-prod/premade/voices/IKne3meq5aSn9XLyUdCD/102de6f2-22ed-43e0-a1f1-111fa75c5481.mp3",
"available_for_tiers": [],
"settings": null,
"sharing": null,
"high_quality_base_model_ids": [
"eleven_v2_flash",
"eleven_flash_v2",
"eleven_turbo_v2_5",
"eleven_multilingual_v2",
"eleven_multilingual_v1",
"eleven_v2_5_flash",
"eleven_flash_v2_5",
"eleven_turbo_v2"
],
"verified_languages": [],
"safety_control": null,
"voice_verification": {
"requires_verification": false,
"is_verified": false,
"verification_failures": [],
"verification_attempts_count": 0,
"language": null,
"verification_attempts": null
},
"permission_on_resource": null,
"is_owner": false,
"is_legacy": false,
"is_mixed": false,
"created_at_unix": null
},
{
"voice_id": "JBFqnCBsd6RMkjVDRZzb",
"name": "George",
"samples": null,
"category": "premade",
"fine_tuning": {
"is_allowed_to_fine_tune": true,
"state": {
"eleven_turbo_v2": "fine_tuned",
"eleven_v2_flash": "fine_tuned",
"eleven_v2_5_flash": "fine_tuned"
},
"verification_failures": [],
"verification_attempts_count": 0,
"manual_verification_requested": false,
"language": "en",
"progress": {
"eleven_v2_flash": 1,
"eleven_v2_5_flash": 1
},
"message": {
"eleven_turbo_v2": "",
"eleven_v2_flash": "Done!",
"eleven_v2_5_flash": "Done!"
},
"dataset_duration_seconds": null,
"verification_attempts": null,
"slice_ids": null,
"manual_verification": null,
"max_verification_attempts": 5,
"next_max_verification_attempts_reset_unix_ms": 1700000000000
},
"labels": {
"accent": "British",
"description": "warm",
"age": "middle aged",
"gender": "male",
"use_case": "narration"
},
"description": null,
"preview_url": "https://storage.googleapis.com/eleven-public-prod/premade/voices/JBFqnCBsd6RMkjVDRZzb/e6206d1a-0721-4787-aafb-06a6e705cac5.mp3",
"available_for_tiers": [],
"settings": null,
"sharing": null,
"high_quality_base_model_ids": [
"eleven_v2_flash",
"eleven_flash_v2",
"eleven_turbo_v2_5",
"eleven_multilingual_v2",
"eleven_v2_5_flash",
"eleven_flash_v2_5",
"eleven_turbo_v2"
],
"verified_languages": [],
"safety_control": null,
"voice_verification": {
"requires_verification": false,
"is_verified": false,
"verification_failures": [],
"verification_attempts_count": 0,
"language": null,
"verification_attempts": null
},
"permission_on_resource": null,
"is_owner": false,
"is_legacy": false,
"is_mixed": false,
"created_at_unix": null
},
{
"voice_id": "N2lVS1w4EtoT3dr4eOWO",
"name": "Callum",
"samples": null,
"category": "premade",
"fine_tuning": {
"is_allowed_to_fine_tune": true,
"state": {
"eleven_flash_v2_5": "fine_tuned",
"eleven_turbo_v2": "fine_tuned",
"eleven_flash_v2": "fine_tuned",
"eleven_v2_flash": "fine_tuned",
"eleven_v2_5_flash": "fine_tuned"
},
"verification_failures": [],
"verification_attempts_count": 0,
"manual_verification_requested": false,
"language": "en",
"progress": {
"eleven_flash_v2_5": 1,
"eleven_v2_flash": 1,
"eleven_flash_v2": 1,
"eleven_v2_5_flash": 1
},
"message": {
"eleven_flash_v2_5": "Done!",
"eleven_turbo_v2": "",
"eleven_flash_v2": "Done!",
"eleven_v2_flash": "Done!",
"eleven_v2_5_flash": "Done!"
},
"dataset_duration_seconds": null,
"verification_attempts": null,
"slice_ids": null,
"manual_verification": null,
"max_verification_attempts": 5,
"next_max_verification_attempts_reset_unix_ms": 1700000000000
},
"labels": {
"accent": "Transatlantic",
"description": "intense",
"age": "middle-aged",
"gender": "male",
"use_case": "characters"
},
"description": null,
"preview_url": "https://storage.googleapis.com/eleven-public-prod/premade/voices/N2lVS1w4EtoT3dr4eOWO/ac833bd8-ffda-4938-9ebc-b0f99ca25481.mp3",
"available_for_tiers": [],
"settings": null,
"sharing": null,
"high_quality_base_model_ids": [
"eleven_v2_flash",
"eleven_flash_v2",
"eleven_turbo_v2_5",
"eleven_multilingual_v2",
"eleven_multilingual_v1",
"eleven_v2_5_flash",
"eleven_flash_v2_5",
"eleven_turbo_v2"
],
"verified_languages": [],
"safety_control": null,
"voice_verification": {
"requires_verification": false,
"is_verified": false,
"verification_failures": [],
"verification_attempts_count": 0,
"language": null,
"verification_attempts": null
},
"permission_on_resource": null,
"is_owner": false,
"is_legacy": false,
"is_mixed": false,
"created_at_unix": null
},
{
"voice_id": "SAz9YHcvj6GT2YYXdXww",
"name": "River",
"samples": null,
"category": "premade",
"fine_tuning": {
"is_allowed_to_fine_tune": true,
"state": {
"eleven_multilingual_v2": "fine_tuned",
"eleven_turbo_v2_5": "fine_tuned",
"eleven_flash_v2_5": "fine_tuned",
"eleven_v2_flash": "fine_tuned",
"eleven_v2_5_flash": "fine_tuned",
"eleven_multilingual_sts_v2": "fine_tuned",
"eleven_flash_v2": "fine_tuned",
"eleven_turbo_v2": "fine_tuned"
},
"verification_failures": [],
"verification_attempts_count": 0,
"manual_verification_requested": false,
"language": "en",
"progress": {
"eleven_flash_v2_5": 1,
"eleven_v2_flash": 1,
"eleven_flash_v2": 1,
"eleven_v2_5_flash": 1
},
"message": {
"eleven_flash_v2_5": "Done!",
"eleven_v2_flash": "Done!",
"eleven_flash_v2": "Done!",
"eleven_v2_5_flash": "Done!"
},
"dataset_duration_seconds": null,
"verification_attempts": null,
"slice_ids": null,
"manual_verification": null,
"max_verification_attempts": 5,
"next_max_verification_attempts_reset_unix_ms": 1700000000000
},
"labels": {
"accent": "American",
"description": "confident",
"age": "middle-aged",
"gender": "non-binary",
"use_case": "social media"
},
"description": null,
"preview_url": "https://storage.googleapis.com/eleven-public-prod/premade/voices/SAz9YHcvj6GT2YYXdXww/e6c95f0b-2227-491a-b3d7-2249240decb7.mp3",
"available_for_tiers": [],
"settings": null,
"sharing": null,
"high_quality_base_model_ids": [
"eleven_v2_flash",
"eleven_flash_v2",
"eleven_turbo_v2_5",
"eleven_multilingual_sts_v2",
"eleven_multilingual_v2",
"eleven_v2_5_flash",
"eleven_flash_v2_5",
"eleven_turbo_v2"
],
"verified_languages": [],
"safety_control": null,
"voice_verification": {
"requires_verification": false,
"is_verified": false,
"verification_failures": [],
"verification_attempts_count": 0,
"language": null,
"verification_attempts": null
},
"permission_on_resource": null,
"is_owner": false,
"is_legacy": false,
"is_mixed": false,
"created_at_unix": null
},
{
"voice_id": "TX3LPaxmHKxFdv7VOQHJ",
"name": "Liam",
"samples": null,
"category": "premade",
"fine_tuning": {
"is_allowed_to_fine_tune": true,
"state": {
"eleven_turbo_v2": "fine_tuned",
"eleven_v2_flash": "fine_tuned",
"eleven_v2_5_flash": "fine_tuned"
},
"verification_failures": [],
"verification_attempts_count": 0,
"manual_verification_requested": false,
"language": "en",
"progress": {
"eleven_v2_flash": 1,
"eleven_v2_5_flash": 1
},
"message": {
"eleven_turbo_v2": "",
"eleven_v2_flash": "Done!",
"eleven_v2_5_flash": "Done!"
},
"dataset_duration_seconds": null,
"verification_attempts": null,
"slice_ids": null,
"manual_verification": null,
"max_verification_attempts": 5,
"next_max_verification_attempts_reset_unix_ms": 1700000000000
},
"labels": {
"accent": "American",
"description": "articulate",
"age": "young",
"gender": "male",
"use_case": "narration"
},
"description": null,
"preview_url": "https://storage.googleapis.com/eleven-public-prod/premade/voices/TX3LPaxmHKxFdv7VOQHJ/63148076-6363-42db-aea8-31424308b92c.mp3",
"available_for_tiers": [],
"settings": null,
"sharing": null,
"high_quality_base_model_ids": [
"eleven_v2_flash",
"eleven_flash_v2",
"eleven_turbo_v2_5",
"eleven_multilingual_v2",
"eleven_multilingual_v1",
"eleven_v2_5_flash",
"eleven_flash_v2_5",
"eleven_turbo_v2"
],
"verified_languages": [],
"safety_control": null,
"voice_verification": {
"requires_verification": false,
"is_verified": false,
"verification_failures": [],
"verification_attempts_count": 0,
"language": null,
"verification_attempts": null
},
"permission_on_resource": null,
"is_owner": false,
"is_legacy": false,
"is_mixed": false,
"created_at_unix": null
},
{
"voice_id": "XB0fDUnXU5powFXDhCwa",
"name": "Charlotte",
"samples": null,
"category": "premade",
"fine_tuning": {
"is_allowed_to_fine_tune": true,
"state": {
"eleven_flash_v2_5": "fine_tuned",
"eleven_turbo_v2": "fine_tuned",
"eleven_flash_v2": "fine_tuned",
"eleven_v2_flash": "fine_tuned",
"eleven_v2_5_flash": "fine_tuned"
},
"verification_failures": [],
"verification_attempts_count": 0,
"manual_verification_requested": false,
"language": "en",
"progress": {
"eleven_flash_v2_5": 1,
"eleven_v2_flash": 1,
"eleven_flash_v2": 1,
"eleven_v2_5_flash": 1
},
"message": {
"eleven_multilingual_v2": "",
"eleven_turbo_v2_5": "",
"eleven_flash_v2_5": "Done!",
"eleven_v2_flash": "Done!",
"eleven_v2_5_flash": "Done!",
"eleven_turbo_v2": "",
"eleven_flash_v2": "Done!"
},
"dataset_duration_seconds": null,
"verification_attempts": null,
"slice_ids": null,
"manual_verification": null,
"max_verification_attempts": 5,
"next_max_verification_attempts_reset_unix_ms": 1700000000000
},
"labels": {
"accent": "Swedish",
"description": "seductive",
"age": "young",
"gender": "female",
"use_case": "characters"
},
"description": null,
"preview_url": "https://storage.googleapis.com/eleven-public-prod/premade/voices/XB0fDUnXU5powFXDhCwa/942356dc-f10d-4d89-bda5-4f8505ee038b.mp3",
"available_for_tiers": [],
"settings": null,
"sharing": null,
"high_quality_base_model_ids": [
"eleven_v2_flash",
"eleven_flash_v2",
"eleven_turbo_v2_5",
"eleven_multilingual_v2",
"eleven_multilingual_v1",
"eleven_v2_5_flash",
"eleven_flash_v2_5",
"eleven_turbo_v2"
],
"verified_languages": [],
"safety_control": null,
"voice_verification": {
"requires_verification": false,
"is_verified": false,
"verification_failures": [],
"verification_attempts_count": 0,
"language": null,
"verification_attempts": null
},
"permission_on_resource": null,
"is_owner": false,
"is_legacy": false,
"is_mixed": false,
"created_at_unix": null
},
{
"voice_id": "Xb7hH8MSUJpSbSDYk0k2",
"name": "Alice",
"samples": null,
"category": "premade",
"fine_tuning": {
"is_allowed_to_fine_tune": true,
"state": {
"eleven_flash_v2_5": "fine_tuned",
"eleven_turbo_v2": "fine_tuned",
"eleven_flash_v2": "fine_tuned",
"eleven_v2_flash": "fine_tuned",
"eleven_v2_5_flash": "fine_tuned"
},
"verification_failures": [],
"verification_attempts_count": 0,
"manual_verification_requested": false,
"language": "en",
"progress": {
"eleven_flash_v2_5": 1,
"eleven_v2_flash": 1,
"eleven_flash_v2": 1,
"eleven_v2_5_flash": 1
},
"message": {
"eleven_flash_v2_5": "Done!",
"eleven_turbo_v2": "",
"eleven_flash_v2": "Done!",
"eleven_v2_flash": "Done!",
"eleven_v2_5_flash": "Done!"
},
"dataset_duration_seconds": null,
"verification_attempts": null,
"slice_ids": null,
"manual_verification": null,
"max_verification_attempts": 5,
"next_max_verification_attempts_reset_unix_ms": 1700000000000
},
"labels": {
"accent": "British",
"description": "confident",
"age": "middle-aged",
"gender": "female",
"use_case": "news"
},
"description": null,
"preview_url": "https://storage.googleapis.com/eleven-public-prod/premade/voices/Xb7hH8MSUJpSbSDYk0k2/d10f7534-11f6-41fe-a012-2de1e482d336.mp3",
"available_for_tiers": [],
"settings": null,
"sharing": null,
"high_quality_base_model_ids": [
"eleven_v2_flash",
"eleven_flash_v2",
"eleven_turbo_v2_5",
"eleven_multilingual_v2",
"eleven_v2_5_flash",
"eleven_flash_v2_5",
"eleven_turbo_v2"
],
"verified_languages": [],
"safety_control": null,
"voice_verification": {
"requires_verification": false,
"is_verified": false,
"verification_failures": [],
"verification_attempts_count": 0,
"language": null,
"verification_attempts": null
},
"permission_on_resource": null,
"is_owner": false,
"is_legacy": false,
"is_mixed": false,
"created_at_unix": null
},
{
"voice_id": "XrExE9yKIg1WjnnlVkGX",
"name": "Matilda",
"samples": null,
"category": "premade",
"fine_tuning": {
"is_allowed_to_fine_tune": true,
"state": {
"eleven_turbo_v2": "fine_tuned",
"eleven_v2_flash": "fine_tuned",
"eleven_v2_5_flash": "fine_tuned"
},
"verification_failures": [],
"verification_attempts_count": 0,
"manual_verification_requested": false,
"language": "en",
"progress": {
"eleven_v2_flash": 1,
"eleven_v2_5_flash": 1
},
"message": {
"eleven_turbo_v2": "",
"eleven_v2_flash": "Done!",
"eleven_v2_5_flash": "Done!"
},
"dataset_duration_seconds": null,
"verification_attempts": null,
"slice_ids": null,
"manual_verification": null,
"max_verification_attempts": 5,
"next_max_verification_attempts_reset_unix_ms": 1700000000000
},
"labels": {
"accent": "American",
"description": "friendly",
"age": "middle-aged",
"gender": "female",
"use_case": "narration"
},
"description": null,
"preview_url": "https://storage.googleapis.com/eleven-public-prod/premade/voices/XrExE9yKIg1WjnnlVkGX/b930e18d-6b4d-466e-bab2-0ae97c6d8535.mp3",
"available_for_tiers": [],
"settings": null,
"sharing": null,
"high_quality_base_model_ids": [
"eleven_v2_flash",
"eleven_flash_v2",
"eleven_turbo_v2_5",
"eleven_multilingual_v2",
"eleven_multilingual_v1",
"eleven_v2_5_flash",
"eleven_flash_v2_5",
"eleven_turbo_v2"
],
"verified_languages": [],
"safety_control": null,
"voice_verification": {
"requires_verification": false,
"is_verified": false,
"verification_failures": [],
"verification_attempts_count": 0,
"language": null,
"verification_attempts": null
},
"permission_on_resource": null,
"is_owner": false,
"is_legacy": false,
"is_mixed": false,
"created_at_unix": null
},
{
"voice_id": "bIHbv24MWmeRgasZH58o",
"name": "Will",
"samples": null,
"category": "premade",
"fine_tuning": {
"is_allowed_to_fine_tune": true,
"state": {
"eleven_multilingual_v2": "fine_tuned",
"eleven_turbo_v2_5": "fine_tuned",
"eleven_flash_v2_5": "fine_tuned",
"eleven_v2_flash": "fine_tuned",
"eleven_v2_5_flash": "fine_tuned",
"eleven_turbo_v2": "fine_tuned",
"eleven_flash_v2": "fine_tuned"
},
"verification_failures": [],
"verification_attempts_count": 0,
"manual_verification_requested": false,
"language": "en",
"progress": {
"eleven_flash_v2_5": 1,
"eleven_v2_flash": 1,
"eleven_flash_v2": 1,
"eleven_v2_5_flash": 1
},
"message": {
"eleven_flash_v2_5": "Done!",
"eleven_v2_flash": "Done!",
"eleven_flash_v2": "Done!",
"eleven_v2_5_flash": "Done!"
},
"dataset_duration_seconds": null,
"verification_attempts": null,
"slice_ids": null,
"manual_verification": null,
"max_verification_attempts": 5,
"next_max_verification_attempts_reset_unix_ms": 1700000000000
},
"labels": {
"accent": "American",
"description": "friendly",
"age": "young",
"gender": "male",
"use_case": "social media"
},
"description": null,
"preview_url": "https://storage.googleapis.com/eleven-public-prod/premade/voices/bIHbv24MWmeRgasZH58o/8caf8f3d-ad29-4980-af41-53f20c72d7a4.mp3",
"available_for_tiers": [],
"settings": null,
"sharing": null,
"high_quality_base_model_ids": [
"eleven_v2_flash",
"eleven_flash_v2",
"eleven_turbo_v2_5",
"eleven_multilingual_v2",
"eleven_v2_5_flash",
"eleven_flash_v2_5",
"eleven_turbo_v2"
],
"verified_languages": [],
"safety_control": null,
"voice_verification": {
"requires_verification": false,
"is_verified": false,
"verification_failures": [],
"verification_attempts_count": 0,
"language": null,
"verification_attempts": null
},
"permission_on_resource": null,
"is_owner": false,
"is_legacy": false,
"is_mixed": false,
"created_at_unix": null
},
{
"voice_id": "cgSgspJ2msm6clMCkdW9",
"name": "Jessica",
"samples": null,
"category": "premade",
"fine_tuning": {
"is_allowed_to_fine_tune": true,
"state": {
"eleven_multilingual_v2": "fine_tuned",
"eleven_turbo_v2_5": "fine_tuned",
"eleven_flash_v2_5": "fine_tuned",
"eleven_v2_flash": "fine_tuned",
"eleven_v2_5_flash": "fine_tuned",
"eleven_turbo_v2": "fine_tuned",
"eleven_flash_v2": "fine_tuned"
},
"verification_failures": [],
"verification_attempts_count": 0,
"manual_verification_requested": false,
"language": "en",
"progress": {
"eleven_flash_v2_5": 1,
"eleven_v2_flash": 1,
"eleven_flash_v2": 1,
"eleven_v2_5_flash": 1
},
"message": {
"eleven_flash_v2_5": "Done!",
"eleven_v2_flash": "Done!",
"eleven_flash_v2": "Done!",
"eleven_v2_5_flash": "Done!"
},
"dataset_duration_seconds": null,
"verification_attempts": null,
"slice_ids": null,
"manual_verification": null,
"max_verification_attempts": 5,
"next_max_verification_attempts_reset_unix_ms": 1700000000000
},
"labels": {
"accent": "American",
"description": "expressive",
"age": "young",
"gender": "female",
"use_case": "conversational"
},
"description": null,
"preview_url": "https://storage.googleapis.com/eleven-public-prod/premade/voices/cgSgspJ2msm6clMCkdW9/56a97bf8-b69b-448f-846c-c3a11683d45a.mp3",
"available_for_tiers": [],
"settings": null,
"sharing": null,
"high_quality_base_model_ids": [
"eleven_v2_flash",
"eleven_flash_v2",
"eleven_turbo_v2_5",
"eleven_multilingual_v2",
"eleven_v2_5_flash",
"eleven_flash_v2_5",
"eleven_turbo_v2"
],
"verified_languages": [],
"safety_control": null,
"voice_verification": {
"requires_verification": false,
"is_verified": false,
"verification_failures": [],
"verification_attempts_count": 0,
"language": null,
"verification_attempts": null
},
"permission_on_resource": null,
"is_owner": false,
"is_legacy": false,
"is_mixed": false,
"created_at_unix": null
},
{
"voice_id": "cjVigY5qzO86Huf0OWal",
"name": "Eric",
"samples": null,
"category": "premade",
"fine_tuning": {
"is_allowed_to_fine_tune": true,
"state": {
"eleven_multilingual_v2": "fine_tuned",
"eleven_turbo_v2_5": "fine_tuned",
"eleven_flash_v2_5": "fine_tuned",
"eleven_v2_flash": "fine_tuned",
"eleven_v2_5_flash": "fine_tuned",
"eleven_turbo_v2": "fine_tuned",
"eleven_flash_v2": "fine_tuned"
},
"verification_failures": [],
"verification_attempts_count": 0,
"manual_verification_requested": false,
"language": "en",
"progress": {
"eleven_flash_v2_5": 1,
"eleven_v2_flash": 1,
"eleven_flash_v2": 1,
"eleven_v2_5_flash": 1
},
"message": {
"eleven_flash_v2_5": "Done!",
"eleven_v2_flash": "Done!",
"eleven_flash_v2": "Done!",
"eleven_v2_5_flash": "Done!"
},
"dataset_duration_seconds": null,
"verification_attempts": null,
"slice_ids": null,
"manual_verification": null,
"max_verification_attempts": 5,
"next_max_verification_attempts_reset_unix_ms": 1700000000000
},
"labels": {
"accent": "American",
"description": "friendly",
"age": "middle-aged",
"gender": "male",
"use_case": "conversational"
},
"description": null,
"preview_url": "https://storage.googleapis.com/eleven-public-prod/premade/voices/cjVigY5qzO86Huf0OWal/d098fda0-6456-4030-b3d8-63aa048c9070.mp3",
"available_for_tiers": [],
"settings": null,
"sharing": null,
"high_quality_base_model_ids": [
"eleven_v2_flash",
"eleven_flash_v2",
"eleven_turbo_v2_5",
"eleven_multilingual_v2",
"eleven_v2_5_flash",
"eleven_flash_v2_5",
"eleven_turbo_v2"
],
"verified_languages": [],
"safety_control": null,
"voice_verification": {
"requires_verification": false,
"is_verified": false,
"verification_failures": [],
"verification_attempts_count": 0,
"language": null,
"verification_attempts": null
},
"permission_on_resource": null,
"is_owner": false,
"is_legacy": false,
"is_mixed": false,
"created_at_unix": null
},
{
"voice_id": "iP95p4xoKVk53GoZ742B",
"name": "Chris",
"samples": null,
"category": "premade",
"fine_tuning": {
"is_allowed_to_fine_tune": true,
"state": {
"eleven_flash_v2_5": "fine_tuned",
"eleven_turbo_v2": "fine_tuned",
"eleven_flash_v2": "fine_tuned",
"eleven_v2_flash": "fine_tuned",
"eleven_v2_5_flash": "fine_tuned"
},
"verification_failures": [],
"verification_attempts_count": 0,
"manual_verification_requested": false,
"language": "en",
"progress": {
"eleven_flash_v2_5": 1,
"eleven_v2_flash": 1,
"eleven_flash_v2": 1,
"eleven_v2_5_flash": 1
},
"message": {
"eleven_flash_v2_5": "Done!",
"eleven_turbo_v2": "",
"eleven_flash_v2": "Done!",
"eleven_v2_flash": "Done!",
"eleven_v2_5_flash": "Done!"
},
"dataset_duration_seconds": null,
"verification_attempts": null,
"slice_ids": null,
"manual_verification": null,
"max_verification_attempts": 5,
"next_max_verification_attempts_reset_unix_ms": 1700000000000
},
"labels": {
"accent": "American",
"description": "casual",
"age": "middle-aged",
"gender": "male",
"use_case": "conversational"
},
"description": null,
"preview_url": "https://storage.googleapis.com/eleven-public-prod/premade/voices/iP95p4xoKVk53GoZ742B/3f4bde72-cc48-40dd-829f-57fbf906f4d7.mp3",
"available_for_tiers": [],
"settings": null,
"sharing": null,
"high_quality_base_model_ids": [
"eleven_v2_flash",
"eleven_flash_v2",
"eleven_turbo_v2_5",
"eleven_multilingual_v2",
"eleven_v2_5_flash",
"eleven_flash_v2_5",
"eleven_turbo_v2"
],
"verified_languages": [],
"safety_control": null,
"voice_verification": {
"requires_verification": false,
"is_verified": false,
"verification_failures": [],
"verification_attempts_count": 0,
"language": null,
"verification_attempts": null
},
"permission_on_resource": null,
"is_owner": false,
"is_legacy": false,
"is_mixed": false,
"created_at_unix": null
},
{
"voice_id": "nPczCjzI2devNBz1zQrb",
"name": "Brian",
"samples": null,
"category": "premade",
"fine_tuning": {
"is_allowed_to_fine_tune": true,
"state": {
"eleven_flash_v2_5": "fine_tuned",
"eleven_turbo_v2": "fine_tuned",
"eleven_flash_v2": "fine_tuned",
"eleven_v2_flash": "fine_tuned",
"eleven_v2_5_flash": "fine_tuned"
},
"verification_failures": [],
"verification_attempts_count": 0,
"manual_verification_requested": false,
"language": "en",
"progress": {
"eleven_flash_v2_5": 1,
"eleven_v2_flash": 1,
"eleven_flash_v2": 1,
"eleven_v2_5_flash": 1
},
"message": {
"eleven_flash_v2_5": "Done!",
"eleven_turbo_v2": "",
"eleven_flash_v2": "Done!",
"eleven_v2_flash": "Done!",
"eleven_v2_5_flash": "Done!"
},
"dataset_duration_seconds": null,
"verification_attempts": null,
"slice_ids": null,
"manual_verification": null,
"max_verification_attempts": 5,
"next_max_verification_attempts_reset_unix_ms": 1700000000000
},
"labels": {
"accent": "American",
"description": "deep",
"age": "middle-aged",
"gender": "male",
"use_case": "narration"
},
"description": null,
"preview_url": "https://storage.googleapis.com/eleven-public-prod/premade/voices/nPczCjzI2devNBz1zQrb/2dd3e72c-4fd3-42f1-93ea-abc5d4e5aa1d.mp3",
"available_for_tiers": [],
"settings": null,
"sharing": null,
"high_quality_base_model_ids": [
"eleven_v2_flash",
"eleven_flash_v2",
"eleven_turbo_v2_5",
"eleven_multilingual_v2",
"eleven_v2_5_flash",
"eleven_flash_v2_5",
"eleven_turbo_v2"
],
"verified_languages": [],
"safety_control": null,
"voice_verification": {
"requires_verification": false,
"is_verified": false,
"verification_failures": [],
"verification_attempts_count": 0,
"language": null,
"verification_attempts": null
},
"permission_on_resource": null,
"is_owner": false,
"is_legacy": false,
"is_mixed": false,
"created_at_unix": null
},
{
"voice_id": "onwK4e9ZLuTAKqWW03F9",
"name": "Daniel",
"samples": null,
"category": "premade",
"fine_tuning": {
"is_allowed_to_fine_tune": true,
"state": {
"eleven_flash_v2_5": "fine_tuned",
"eleven_turbo_v2": "fine_tuned",
"eleven_flash_v2": "fine_tuned",
"eleven_v2_flash": "fine_tuned",
"eleven_v2_5_flash": "fine_tuned"
},
"verification_failures": [],
"verification_attempts_count": 0,
"manual_verification_requested": false,
"language": "en",
"progress": {
"eleven_flash_v2_5": 1,
"eleven_v2_flash": 1,
"eleven_flash_v2": 1,
"eleven_v2_5_flash": 1
},
"message": {
"eleven_flash_v2_5": "Done!",
"eleven_turbo_v2": "",
"eleven_flash_v2": "Done!",
"eleven_v2_flash": "Done!",
"eleven_v2_5_flash": "Done!"
},
"dataset_duration_seconds": null,
"verification_attempts": null,
"slice_ids": null,
"manual_verification": null,
"max_verification_attempts": 5,
"next_max_verification_attempts_reset_unix_ms": 1700000000000
},
"labels": {
"accent": "British",
"description": "authoritative",
"age": "middle-aged",
"gender": "male",
"use_case": "news"
},
"description": null,
"preview_url": "https://storage.googleapis.com/eleven-public-prod/premade/voices/onwK4e9ZLuTAKqWW03F9/7eee0236-1a72-4b86-b303-5dcadc007ba9.mp3",
"available_for_tiers": [],
"settings": null,
"sharing": null,
"high_quality_base_model_ids": [
"eleven_v2_flash",
"eleven_flash_v2",
"eleven_turbo_v2_5",
"eleven_multilingual_v2",
"eleven_multilingual_v1",
"eleven_v2_5_flash",
"eleven_flash_v2_5",
"eleven_turbo_v2"
],
"verified_languages": [],
"safety_control": null,
"voice_verification": {
"requires_verification": false,
"is_verified": false,
"verification_failures": [],
"verification_attempts_count": 0,
"language": null,
"verification_attempts": null
},
"permission_on_resource": null,
"is_owner": false,
"is_legacy": false,
"is_mixed": false,
"created_at_unix": null
},
{
"voice_id": "pFZP5JQG7iQjIQuC4Bku",
"name": "Lily",
"samples": null,
"category": "premade",
"fine_tuning": {
"is_allowed_to_fine_tune": true,
"state": {
"eleven_flash_v2_5": "fine_tuned",
"eleven_turbo_v2": "fine_tuned",
"eleven_flash_v2": "fine_tuned",
"eleven_v2_flash": "fine_tuned",
"eleven_v2_5_flash": "fine_tuned"
},
"verification_failures": [],
"verification_attempts_count": 0,
"manual_verification_requested": false,
"language": "en",
"progress": {
"eleven_flash_v2_5": 1,
"eleven_v2_flash": 1,
"eleven_flash_v2": 1,
"eleven_v2_5_flash": 1
},
"message": {
"eleven_flash_v2_5": "Done!",
"eleven_turbo_v2": "",
"eleven_flash_v2": "Done!",
"eleven_v2_flash": "Done!",
"eleven_v2_5_flash": "Done!"
},
"dataset_duration_seconds": null,
"verification_attempts": null,
"slice_ids": null,
"manual_verification": null,
"max_verification_attempts": 5,
"next_max_verification_attempts_reset_unix_ms": 1700000000000
},
"labels": {
"accent": "British",
"description": "warm",
"age": "middle-aged",
"gender": "female",
"use_case": "narration"
},
"description": null,
"preview_url": "https://storage.googleapis.com/eleven-public-prod/premade/voices/pFZP5JQG7iQjIQuC4Bku/89b68b35-b3dd-4348-a84a-a3c13a3c2b30.mp3",
"available_for_tiers": [],
"settings": null,
"sharing": null,
"high_quality_base_model_ids": [
"eleven_v2_flash",
"eleven_flash_v2",
"eleven_turbo_v2_5",
"eleven_multilingual_v2",
"eleven_v2_5_flash",
"eleven_flash_v2_5",
"eleven_turbo_v2"
],
"verified_languages": [],
"safety_control": null,
"voice_verification": {
"requires_verification": false,
"is_verified": false,
"verification_failures": [],
"verification_attempts_count": 0,
"language": null,
"verification_attempts": null
},
"permission_on_resource": null,
"is_owner": false,
"is_legacy": false,
"is_mixed": false,
"created_at_unix": null
},
{
"voice_id": "pqHfZKP75CvOlQylNhV4",
"name": "Bill",
"samples": null,
"category": "premade",
"fine_tuning": {
"is_allowed_to_fine_tune": true,
"state": {
"eleven_flash_v2_5": "fine_tuned",
"eleven_turbo_v2": "fine_tuned",
"eleven_flash_v2": "fine_tuned",
"eleven_v2_flash": "fine_tuned",
"eleven_v2_5_flash": "fine_tuned"
},
"verification_failures": [],
"verification_attempts_count": 0,
"manual_verification_requested": false,
"language": "en",
"progress": {
"eleven_flash_v2_5": 1,
"eleven_v2_flash": 1,
"eleven_flash_v2": 1,
"eleven_v2_5_flash": 1
},
"message": {
"eleven_flash_v2_5": "Done!",
"eleven_turbo_v2": "",
"eleven_flash_v2": "Done!",
"eleven_v2_flash": "Done!",
"eleven_v2_5_flash": "Done!"
},
"dataset_duration_seconds": null,
"verification_attempts": null,
"slice_ids": null,
"manual_verification": null,
"max_verification_attempts": 5,
"next_max_verification_attempts_reset_unix_ms": 1700000000000
},
"labels": {
"accent": "American",
"description": "trustworthy",
"age": "old",
"gender": "male",
"use_case": "narration"
},
"description": null,
"preview_url": "https://storage.googleapis.com/eleven-public-prod/premade/voices/pqHfZKP75CvOlQylNhV4/d782b3ff-84ba-4029-848c-acf01285524d.mp3",
"available_for_tiers": [],
"settings": null,
"sharing": null,
"high_quality_base_model_ids": [
"eleven_v2_flash",
"eleven_flash_v2",
"eleven_turbo_v2_5",
"eleven_multilingual_v2",
"eleven_v2_5_flash",
"eleven_flash_v2_5",
"eleven_turbo_v2"
],
"verified_languages": [],
"safety_control": null,
"voice_verification": {
"requires_verification": false,
"is_verified": false,
"verification_failures": [],
"verification_attempts_count": 0,
"language": null,
"verification_attempts": null
},
"permission_on_resource": null,
"is_owner": false,
"is_legacy": false,
"is_mixed": false,
"created_at_unix": null
}
]
}
Models/Spring Ai Google Genai/README (models/spring-ai-google-genai/README.md)
Starter
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-google-genai</artifactId>
</dependency>Manual config
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-google-genai</artifactId>
</dependency>Environment variables
export GOOGLE_GENAI_USE_VERTEXAI=true
export GOOGLE_CLOUD_PROJECT='your-project-id'
export GOOGLE_CLOUD_LOCATION='your-region'Extended Usage Metadata
The Google GenAI module provides comprehensive usage metadata tracking through the GoogleGenAiUsage class, which extends the standard Usage interface with additional token tracking capabilities specific to Google GenAI models.
Features
Thinking Tokens
Track reasoning tokens for thinking-enabled models like Gemini 2.0 Flash Thinking:
ChatResponse response = chatModel.call(prompt);
GoogleGenAiUsage usage = (GoogleGenAiUsage) response.getMetadata().getUsage();
Integer thoughtsTokens = usage.getThoughtsTokenCount(); // Reasoning tokensCached Content Tokens
Monitor tokens from cached context to optimize API costs:
Integer cachedTokens = usage.getCachedContentTokenCount(); // Cached context tokensTool-Use Tokens
Track tokens consumed by function calling and tool use:
Integer toolUseTokens = usage.getToolUsePromptTokenCount(); // Tool-use tokensModality Breakdowns
Get detailed token counts by modality (text, image, audio, video):
List<GoogleGenAiModalityTokenCount> promptDetails = usage.getPromptTokensDetails();
for (GoogleGenAiModalityTokenCount detail : promptDetails) {
System.out.println(detail.getModality() + ": " + detail.getTokenCount());
}Traffic Type
Identify whether requests use Pay-As-You-Go or Provisioned Throughput:
GoogleGenAiTrafficType trafficType = usage.getTrafficType();
// Returns: ON_DEMAND, PROVISIONED_THROUGHPUT, or UNKNOWNConfiguration
Control whether to include extended metadata (enabled by default):
GoogleGenAiChatOptions options = GoogleGenAiChatOptions.builder()
.model("gemini-2.0-flash")
.includeExtendedUsageMetadata(true) // Enable extended metadata
.build();Complete Example
/* Detailed source-code truncated for AI context efficiency. */Backward Compatibility
The extended usage metadata maintains full backward compatibility with the standard Usage interface. Code using the basic interface continues to work without modification:
// Works with any Spring AI model
Usage usage = response.getMetadata().getUsage();
Long promptTokens = usage.getPromptTokens();
Long completionTokens = usage.getCompletionTokens();Models/Spring Ai Google Genai Embedding/README (models/spring-ai-google-genai-embedding/README.md)
Google GenAI Embeddings Module
Google GenAI Text Embeddings Documentation
Overview
The Google GenAI Embeddings module provides text embedding generation using Google's embedding models through either the Gemini Developer API or Vertex AI.
Current Support
Please note that at this time the spring-ai-google-genai-embedding module supports text embeddings only.
This is due to the fact that the Google GenAI SDK currently supports text embeddings only, with multimodal embeddings support pending.
Starter Dependency
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-google-genai-embedding</artifactId>
</dependency>Manual Configuration
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-google-genai-embedding</artifactId>
</dependency>Authentication Modes
The module supports two authentication modes:
- Gemini Developer API: Use an API key for quick prototyping
- Vertex AI: Use Google Cloud credentials for production deployments
See the documentation for detailed configuration instructions.
Models/Spring Ai Mistral Ai/README (models/spring-ai-mistral-ai/README.md)
Mistral AI Embedding Documentation
Models/Spring Ai Mistral Ai/Src/Test/Resources/References.Json (models/spring-ai-mistral-ai/src/test/resources/references.json)
{
"0": {
"url": "https://en.wikipedia.org/wiki/2024_Nobel_Peace_Prize",
"title": "2024 Nobel Peace Prize",
"snippets": [
[
"The 2024 Nobel Peace Prize, an international peace prize established according to Alfred Nobel's will, was awarded to Nihon Hidankyo (the Japan Confederation of A- and H-Bomb Sufferers Organizations), for their activism against nuclear weapons, assisted by victim/survivors (known as Hibakusha) of the atomic bombings of Hiroshima and Nagasaki in 1945.",
"They will receive the prize at a ceremony on 10 December 2024 at Oslo, Norway."
]
],
"description": null,
"date": "2024-11-26T17:39:55.057454",
"source": "wikipedia"
},
"1": {
"url": "https://en.wikipedia.org/wiki/Climate_Change",
"title": "Climate Change",
"snippets": [
[
"Present-day climate change includes both global warming—the ongoing increase in global average temperature—and its wider effects on Earth’s climate system. Climate change in a broader sense also includes previous long-term changes to Earth's climate. The current rise in global temperatures is driven by human activities, especially fossil fuel burning since the Industrial Revolution. Fossil fuel use, deforestation, and some agricultural and industrial practices release greenhouse gases. These gases absorb some of the heat that the Earth radiates after it warms from sunlight, warming the lower atmosphere. Carbon dioxide, the primary gas driving global warming, has increased in concentration by about 50% since the pre-industrial era to levels not seen for millions of years."
]
],
"description": null,
"date": "2024-11-26T17:39:55.057454",
"source": "wikipedia"
},
"2": {
"url": "https://en.wikipedia.org/wiki/Artificial_Intelligence",
"title": "Artificial Intelligence",
"snippets": [
[
"Artificial intelligence (AI) refers to the capability of computational systems to perform tasks typically associated with human intelligence, such as learning, reasoning, problem-solving, perception, and decision-making. It is a field of research in computer science that develops and studies methods and software that enable machines to perceive their environment and use learning and intelligence to take actions that maximize their chances of achieving defined goals. Such machines may be called AIs."
]
],
"description": null,
"date": "2024-11-26T17:39:55.057454",
"source": "wikipedia"
}
}
Models/Spring Ai Mistral Ai/Src/Test/Resources/Contents/Content Chunks.Json (models/spring-ai-mistral-ai/src/test/resources/contents/content_chunks.json)
[
{
"type": "image_url",
"image_url": {
"url": "https://example.com/image.png",
"detail": "auto"
}
},
{
"type": "reference",
"reference_ids": [
1,
2,
3
]
},
{
"type": "text",
"text": "content text"
},
{
"type": "thinking",
"thinking": [
{
"type": "reference",
"reference_ids": [
4,
5,
6
]
},
{
"type": "text",
"text": "thinking text"
}
],
"closed": true
}
]
Models/Spring Ai Mistral Ai/Src/Test/Resources/Messages/Content Chunks Message.Json (models/spring-ai-mistral-ai/src/test/resources/messages/content_chunks_message.json)
{
"role": "user",
"content": [
{
"type": "image_url",
"image_url": {
"url": "https://example.com/image.png",
"detail": "auto"
}
},
{
"type": "reference",
"reference_ids": [
1,
2,
3
]
},
{
"type": "text",
"text": "content text"
},
{
"type": "thinking",
"thinking": [
{
"type": "reference",
"reference_ids": [
4,
5,
6
]
},
{
"type": "text",
"text": "thinking text"
}
],
"closed": true
}
]
}
Models/Spring Ai Ollama/README (models/spring-ai-ollama/README.md)
Ollama Embedding Documentation
Models/Spring Ai Ollama/Src/Test/Resources/Country Json Schema.Json (models/spring-ai-ollama/src/test/resources/country-json-schema.json)
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"capital": {
"type": "string"
},
"languages": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"name",
"capital",
"languages"
]
}
Models/Spring Ai Openai/README (models/spring-ai-openai/README.md)
OpenAI Embedding Documentation
OpenAI Transcription Generation
Models/Spring Ai Openai/Src/Test/Resources/Text Source (models/spring-ai-openai/src/test/resources/text_source.txt)
Spring Framework Documentation
Version 6.0.0
Chapter 1. Spring Framework Overview
Spring makes it easy to create Java enterprise applications. It provides everything you need to
embrace the Java language in an enterprise environment, with support for Groovy and Kotlin as
alternative languages on the JVM, and with the flexibility to create many kinds of architectures
depending on an application’s needs. As of Spring Framework 5.1, Spring requires JDK 8+ (Java SE
8+) and provides out-of-the-box support for JDK 11 LTS. Java SE 8 update 60 is suggested as the
minimum patch release for Java 8, but it is generally recommended to use a recent patch release.
Spring supports a wide range of application scenarios. In a large enterprise, applications often exist
for a long time and have to run on a JDK and application server whose upgrade cycle is beyond
developer control. Others may run as a single jar with the server embedded, possibly in a cloud
environment. Yet others may be standalone applications (such as batch or integration workloads)
that do not need a server.
Spring is open source. It has a large and active community that provides continuous feedback based
on a diverse range of real-world use cases. This has helped Spring to successfully evolve over a very
long time.
1.1. What We Mean by "Spring"
The term "Spring" means different things in different contexts. It can be used to refer to the Spring
Framework project itself, which is where it all started. Over time, other Spring projects have been
built on top of the Spring Framework. Most often, when people say "Spring", they mean the entire
family of projects. This reference documentation focuses on the foundation: the Spring Framework
itself.
The Spring Framework is divided into modules. Applications can choose which modules they need.
At the heart are the modules of the core container, including a configuration model and a
dependency injection mechanism. Beyond that, the Spring Framework provides foundational
support for different application architectures, including messaging, transactional data and
persistence, and web. It also includes the Servlet-based Spring MVC web framework and, in
parallel, the Spring WebFlux reactive web framework.
A note about modules: Spring’s framework jars allow for deployment to JDK 9’s module path
("Jigsaw"). For use in Jigsaw-enabled applications, the Spring Framework 5 jars come with
"Automatic-Module-Name" manifest entries which define stable language-level module names
("spring.core", "spring.context", etc.) independent from jar artifact names (the jars follow the same
naming pattern with "-" instead of ".", e.g. "spring-core" and "spring-context"). Of course, Spring’s
framework jars keep working fine on the classpath on both JDK 8 and 9+.
1.2. History of Spring and the Spring Framework
Spring came into being in 2003 as a response to the complexity of the early J2EE specifications.
While some consider Java EE and its modern-day successor Jakarta EE to be in competition with
Spring, they are in fact complementary. The Spring programming model does not embrace the
Jakarta EE platform specification; rather, it integrates with carefully selected individual
specifications from the traditional EE umbrella:
• Servlet API (JSR 340)
• WebSocket API (JSR 356)
• Concurrency Utilities (JSR 236)
• JSON Binding API (JSR 367)
• Bean Validation (JSR 303)
• JPA (JSR 338)
• JMS (JSR 914)
• as well as JTA/JCA setups for transaction coordination, if necessary.
The Spring Framework also supports the Dependency Injection (JSR 330) and Common Annotations
(JSR 250) specifications, which application developers may choose to use instead of the Spring-
specific mechanisms provided by the Spring Framework. Originally, those were based on common
javax packages.
As of Spring Framework 6.0, Spring has been upgraded to the Jakarta EE 9 level (e.g. Servlet 5.0+,
JPA 3.0+), based on the jakarta namespace instead of the traditional javax packages. With EE 9 as
the minimum and EE 10 supported already, Spring is prepared to provide out-of-the-box support
for the further evolution of the Jakarta EE APIs. Spring Framework 6.0 is fully compatible with
Tomcat 10.1, Jetty 11 and Undertow 2.3 as web servers, and also with Hibernate ORM 6.1.
Over time, the role of Java/Jakarta EE in application development has evolved. In the early days of
J2EE and Spring, applications were created to be deployed to an application server. Today, with the
help of Spring Boot, applications are created in a devops- and cloud-friendly way, with the Servlet
container embedded and trivial to change. As of Spring Framework 5, a WebFlux application does
not even use the Servlet API directly and can run on servers (such as Netty) that are not Servlet
containers.
Spring continues to innovate and to evolve. Beyond the Spring Framework, there are other projects,
such as Spring Boot, Spring Security, Spring Data, Spring Cloud, Spring Batch, among others. It’s
important to remember that each project has its own source code repository, issue tracker, and
release cadence. See spring.io/projects for the complete list of Spring projects.
1.3. Design Philosophy
When you learn about a framework, it’s important to know not only what it does but what
principles it follows. Here are the guiding principles of the Spring Framework:
• Provide choice at every level. Spring lets you defer design decisions as late as possible. For
example, you can switch persistence providers through configuration without changing your
code. The same is true for many other infrastructure concerns and integration with third-party
APIs.
• Accommodate diverse perspectives. Spring embraces flexibility and is not opinionated about
how things should be done. It supports a wide range of application needs with different
perspectives.
• Maintain strong backward compatibility. Spring’s evolution has been carefully managed to
force few breaking changes between versions. Spring supports a carefully chosen range of JDK
versions and third-party libraries to facilitate maintenance of applications and libraries that
depend on Spring.
• Care about API design. The Spring team puts a lot of thought and time into making APIs that are
intuitive and that hold up across many versions and many years.
• Set high standards for code quality. The Spring Framework puts a strong emphasis on
meaningful, current, and accurate javadoc. It is one of very few projects that can claim clean
code structure with no circular dependencies between packages.
1.4. Feedback and Contributions
For how-to questions or diagnosing or debugging issues, we suggest using Stack Overflow. Click
here for a list of the suggested tags to use on Stack Overflow. If you’re fairly certain that there is a
problem in the Spring Framework or would like to suggest a feature, please use the GitHub Issues.
If you have a solution in mind or a suggested fix, you can submit a pull request on Github.
However, please keep in mind that, for all but the most trivial issues, we expect a ticket to be filed
in the issue tracker, where discussions take place and leave a record for future reference.
For more details see the guidelines at the CONTRIBUTING, top-level project page.
1.5. Getting Started
If you are just getting started with Spring, you may want to begin using the Spring Framework by
creating a Spring Boot-based application. Spring Boot provides a quick (and opinionated) way to
create a production-ready Spring-based application. It is based on the Spring Framework, favors
convention over configuration, and is designed to get you up and running as quickly as possible.
You can use start.spring.io to generate a basic project or follow one of the "Getting Started" guides,
such as Getting Started Building a RESTful Web Service. As well as being easier to digest, these
guides are very task focused, and most of them are based on Spring Boot. They also cover other
projects from the Spring portfolio that you might want to consider when solving a particular
problem.
Chapter 2. Core Technologies
This part of the reference documentation covers all the technologies that are absolutely integral to
the Spring Framework.
Foremost amongst these is the Spring Framework’s Inversion of Control (IoC) container. A thorough
treatment of the Spring Framework’s IoC container is closely followed by comprehensive coverage
of Spring’s Aspect-Oriented Programming (AOP) technologies. The Spring Framework has its own
AOP framework, which is conceptually easy to understand and which successfully addresses the
80% sweet spot of AOP requirements in Java enterprise programming.
Coverage of Spring’s integration with AspectJ (currently the richest — in terms of features — and
certainly most mature AOP implementation in the Java enterprise space) is also provided.
AOT processing can be used to optimize your application ahead-of-time. It is typically used for
native image deployment using GraalVM.
2.1. The IoC Container
This chapter covers Spring’s Inversion of Control (IoC) container.
2.1.1. Introduction to the Spring IoC Container and Beans
This chapter covers the Spring Framework implementation of the Inversion of Control (IoC)
principle. IoC is also known as dependency injection (DI). It is a process whereby objects define
their dependencies (that is, the other objects they work with) only through constructor arguments,
arguments to a factory method, or properties that are set on the object instance after it is
constructed or returned from a factory method. The container then injects those dependencies
when it creates the bean. This process is fundamentally the inverse (hence the name, Inversion of
Control) of the bean itself controlling the instantiation or location of its dependencies by using
direct construction of classes or a mechanism such as the Service Locator pattern.
The org.springframework.beans and org.springframework.context packages are the basis for Spring
Framework’s IoC container. The BeanFactory interface provides an advanced configuration
mechanism capable of managing any type of object. ApplicationContext is a sub-interface of
BeanFactory. It adds:
• Easier integration with Spring’s AOP features
• Message resource handling (for use in internationalization)
• Event publication
• Application-layer specific contexts such as the WebApplicationContext for use in web
applications.
In short, the BeanFactory provides the configuration framework and basic functionality, and the
ApplicationContext adds more enterprise-specific functionality. The ApplicationContext is a
complete superset of the BeanFactory and is used exclusively in this chapter in descriptions of
Spring’s IoC container. For more information on using the BeanFactory instead of the
ApplicationContext, see the section covering the BeanFactory API.
In Spring, the objects that form the backbone of your application and that are managed by the
Spring IoC container are called beans. A bean is an object that is instantiated, assembled, and
managed by a Spring IoC container. Otherwise, a bean is simply one of many objects in your
application. Beans, and the dependencies among them, are reflected in the configuration metadata
used by a container.
2.1.2. Container Overview
The org.springframework.context.ApplicationContext interface represents the Spring IoC container
and is responsible for instantiating, configuring, and assembling the beans. The container gets its
instructions on what objects to instantiate, configure, and assemble by reading configuration
metadata. The configuration metadata is represented in XML, Java annotations, or Java code. It lets
you express the objects that compose your application and the rich interdependencies between
those objects.
Several implementations of the ApplicationContext interface are supplied with Spring. In stand-
alone applications, it is common to create an instance of ClassPathXmlApplicationContext or
FileSystemXmlApplicationContext. While XML has been the traditional format for defining
configuration metadata, you can instruct the container to use Java annotations or code as the
metadata format by providing a small amount of XML configuration to declaratively enable support
for these additional metadata formats.
In most application scenarios, explicit user code is not required to instantiate one or more
instances of a Spring IoC container. For example, in a web application scenario, a simple eight (or
so) lines of boilerplate web descriptor XML in the web.xml file of the application typically suffices
(see Convenient ApplicationContext Instantiation for Web Applications). If you use the Spring Tools
for Eclipse (an Eclipse-powered development environment), you can easily create this boilerplate
configuration with a few mouse clicks or keystrokes.
The following diagram shows a high-level view of how Spring works. Your application classes are
combined with configuration metadata so that, after the ApplicationContext is created and
initialized, you have a fully configured and executable system or application.
Figure 1. The Spring IoC container
Configuration Metadata
As the preceding diagram shows, the Spring IoC container consumes a form of configuration
metadata. This configuration metadata represents how you, as an application developer, tell the
Spring container to instantiate, configure, and assemble the objects in your application.
Configuration metadata is traditionally supplied in a simple and intuitive XML format, which is
what most of this chapter uses to convey key concepts and features of the Spring IoC container.
XML-based metadata is not the only allowed form of configuration metadata. The
Spring IoC container itself is totally decoupled from the format in which this
configuration metadata is actually written. These days, many developers choose
Java-based configuration for their Spring applications.
For information about using other forms of metadata with the Spring container, see:
• Annotation-based configuration: Spring 2.5 introduced support for annotation-based
configuration metadata.
• Java-based configuration: Starting with Spring 3.0, many features provided by the Spring
JavaConfig project became part of the core Spring Framework. Thus, you can define beans
external to your application classes by using Java rather than XML files. To use these new
features, see the @Configuration, @Bean, @Import, and @DependsOn annotations.
Spring configuration consists of at least one and typically more than one bean definition that the
container must manage. XML-based configuration metadata configures these beans as
elements inside a top-level element. Java configuration typically uses @Bean-annotated
methods within a @Configuration class.
These bean definitions correspond to the actual objects that make up your application. Typically,
you define service layer objects, data access objects (DAOs), presentation objects such as Struts
Action instances, infrastructure objects such as Hibernate SessionFactories, JMS Queues, and so
forth. Typically, one does not configure fine-grained domain objects in the container, because it is
usually the responsibility of DAOs and business logic to create and load domain objects. However,
you can use Spring’s integration with AspectJ to configure objects that have been created outside
the control of an IoC container. See Using AspectJ to dependency-inject domain objects with Spring.
The following example shows the basic structure of XML-based configuration metadata:
<?xml version="1.0" encoding="UTF-8"?>
① ②
① The id attribute is a string that identifies the individual bean definition.
② The class attribute defines the type of the bean and uses the fully qualified classname.
The value of the id attribute refers to collaborating objects. The XML for referring to collaborating
objects is not shown in this example. See Dependencies for more information.
Instantiating a Container
The location path or paths supplied to an ApplicationContext constructor are resource strings that
let the container load configuration metadata from a variety of external resources, such as the local
file system, the Java CLASSPATH, and so on.
Java
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml",
"daos.xml");
Kotlin
val context = ClassPathXmlApplicationContext("services.xml", "daos.xml")
After you learn about Spring’s IoC container, you may want to know more about
Spring’s Resource abstraction (as described in Resources), which provides a
convenient mechanism for reading an InputStream from locations defined in a
URI syntax. In particular, Resource paths are used to construct applications
contexts, as described in Application Contexts and Resource Paths.
The following example shows the service layer objects (services.xml) configuration file:
<?xml version="1.0" encoding="UTF-8"?>
The following example shows the data access objects daos.xml file:
<?xml version="1.0" encoding="UTF-8"?>
In the preceding example, the service layer consists of the PetStoreServiceImpl class and two data
access objects of the types JpaAccountDao and JpaItemDao (based on the JPA Object-Relational
Mapping standard). The property name element refers to the name of the JavaBean property, and the
ref element refers to the name of another bean definition. This linkage between id and ref
elements expresses the dependency between collaborating objects. For details of configuring an
object’s dependencies, see Dependencies.
Composing XML-based Configuration Metadata
It can be useful to have bean definitions span multiple XML files. Often, each individual XML
configuration file represents a logical layer or module in your architecture.
You can use the application context constructor to load bean definitions from all these XML
fragments. This constructor takes multiple Resource locations, as was shown in the previous section.
Alternatively, use one or more occurrences of the element to load bean definitions from
another file or files. The following example shows how to do so:
In the preceding example, external bean definitions are loaded from three files: services.xml,
messageSource.xml, and themeSource.xml. All location paths are relative to the definition file doing
the importing, so services.xml must be in the same directory or classpath location as the file doing
the importing, while messageSource.xml and themeSource.xml must be in a resources location below
the location of the importing file. As you can see, a leading slash is ignored. However, given that
these paths are relative, it is better form not to use the slash at all. The contents of the files being
imported, including the top level element, must be valid XML bean definitions, according
to the Spring Schema.
It is possible, but not recommended, to reference files in parent directories using a
relative "../" path. Doing so creates a dependency on a file that is outside the
current application. In particular, this reference is not recommended for
classpath: URLs (for example, classpath:../services.xml), where the runtime
resolution process chooses the “nearest” classpath root and then looks into its
parent directory. Classpath configuration changes may lead to the choice of a
different, incorrect directory.
You can always use fully qualified resource locations instead of relative paths: for
example, file:C:/config/services.xml or classpath:/config/services.xml.
However, be aware that you are coupling your application’s configuration to
specific absolute locations. It is generally preferable to keep an indirection for such
absolute locations — for example, through "${…}" placeholders that are resolved
against JVM system properties at runtime.
The namespace itself provides the import directive feature. Further configuration features beyond
plain bean definitions are available in a selection of XML namespaces provided by Spring — for
example, the context and util namespaces.
The Groovy Bean Definition DSL
As a further example for externalized configuration metadata, bean definitions can also be
expressed in Spring’s Groovy Bean Definition DSL, as known from the Grails framework. Typically,
such configuration live in a ".groovy" file with the structure shown in the following example:
beans {
dataSource(BasicDataSource) {
driverClassName = "org.hsqldb.jdbcDriver"
url = "jdbc:hsqldb:mem:grailsDB"
username = "sa"
password = ""
settings = [mynew:"setting"]
}
sessionFactory(SessionFactory) {
dataSource = dataSource
}
myService(MyService) {
nestedBean = { AnotherBean bean ->
dataSource = dataSource
}
}
}
This configuration style is largely equivalent to XML bean definitions and even supports Spring’s
XML configuration namespaces. It also allows for importing XML bean definition files through an
importBeans directive.
Using the Container
The ApplicationContext is the interface for an advanced factory capable of maintaining a registry of
different beans and their dependencies. By using the method T getBean(String name, Class<T>
requiredType), you can retrieve instances of your beans.
The ApplicationContext lets you read bean definitions and access them, as the following example
shows:
Java
// create and configure beans
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml",
"daos.xml");
// retrieve configured instance
PetStoreService service = context.getBean("petStore", PetStoreService.class);
// use configured instance
List<String> userList = service.getUsernameList();
Kotlin
import org.springframework.beans.factory.getBean
// create and configure beans
val context = ClassPathXmlApplicationContext("services.xml", "daos.xml")
// retrieve configured instance
val service = context.getBean("petStore")
// use configured instance
var userList = service.getUsernameList()
With Groovy configuration, bootstrapping looks very similar. It has a different context
implementation class which is Groovy-aware (but also understands XML bean definitions). The
following example shows Groovy configuration:
Java
ApplicationContext context = new GenericGroovyApplicationContext("services.groovy",
"daos.groovy");
Kotlin
val context = GenericGroovyApplicationContext("services.groovy", "daos.groovy")
The most flexible variant is GenericApplicationContext in combination with reader delegates — for
example, with XmlBeanDefinitionReader for XML files, as the following example shows:
Java
GenericApplicationContext context = new GenericApplicationContext();
new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml");
context.refresh();
Kotlin
val context = GenericApplicationContext()
XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml")
context.refresh()
You can also use the GroovyBeanDefinitionReader for Groovy files, as the following example shows:
Java
GenericApplicationContext context = new GenericApplicationContext();
new GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy",
"daos.groovy");
context.refresh();
Kotlin
val context = GenericApplicationContext()
GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy",
"daos.groovy")
context.refresh()
You can mix and match such reader delegates on the same ApplicationContext, reading bean
definitions from diverse configuration sources.
You can then use getBean to retrieve instances of your beans. The ApplicationContext interface has a
few other methods for retrieving beans, but, ideally, your application code should never use them.
Indeed, your application code should have no calls to the getBean() method at all and thus have no
dependency on Spring APIs at all. For example, Spring’s integration with web frameworks provides
dependency injection for various web framework components such as controllers and JSF-managed
beans, letting you declare a dependency on a specific bean through metadata (such as an
autowiring annotation).
2.1.3. Bean Overview
A Spring IoC container manages one or more beans. These beans are created with the configuration
metadata that you supply to the container (for example, in the form of XML definitions).
Within the container itself, these bean definitions are represented as BeanDefinition objects, which
contain (among other information) the following metadata:
• A package-qualified class name: typically, the actual implementation class of the bean being
defined.
• Bean behavioral configuration elements, which state how the bean should behave in the
container (scope, lifecycle callbacks, and so forth).
• References to other beans that are needed for the bean to do its work. These references are also
called collaborators or dependencies.
• Other configuration settings to set in the newly created object — for example, the size limit of
the pool or the number of connections to use in a bean that manages a connection pool.
This metadata translates to a set of properties that make up each bean definition. The following
table describes these properties:
Table 1. The bean definition
Property Explained in…
Class Instantiating Beans
Name Naming Beans
Scope Bean Scopes
Constructor arguments Dependency Injection
Properties Dependency Injection
Autowiring mode Autowiring Collaborators
Lazy initialization mode Lazy-initialized Beans
Initialization method Initialization Callbacks
Destruction method Destruction Callbacks
In addition to bean definitions that contain information on how to create a specific bean, the
ApplicationContext implementations also permit the registration of existing objects that are created
outside the container (by users). This is done by accessing the ApplicationContext’s BeanFactory
through the getBeanFactory() method, which returns the DefaultListableBeanFactory
implementation. DefaultListableBeanFactory supports this registration through the
registerSingleton(..) and registerBeanDefinition(..) methods. However, typical applications
work solely with beans defined through regular bean definition metadata.
Bean metadata and manually supplied singleton instances need to be registered as
early as possible, in order for the container to properly reason about them during
autowiring and other introspection steps. While overriding existing metadata and
existing singleton instances is supported to some degree, the registration of new
beans at runtime (concurrently with live access to the factory) is not officially
supported and may lead to concurrent access exceptions, inconsistent state in the
bean container, or both.
Naming Beans
Every bean has one or more identifiers. These identifiers must be unique within the container that
hosts the bean. A bean usually has only one identifier. However, if it requires more than one, the
extra ones can be considered aliases.
In XML-based configuration metadata, you use the id attribute, the name attribute, or both to specify
the bean identifiers. The id attribute lets you specify exactly one id. Conventionally, these names
are alphanumeric ('myBean', 'someService', etc.), but they can contain special characters as well. If
you want to introduce other aliases for the bean, you can also specify them in the name attribute,
separated by a comma (,), semicolon (;), or white space. As a historical note, in versions prior to
Spring 3.1, the id attribute was defined as an xsd:ID type, which constrained possible characters. As
of 3.1, it is defined as an xsd:string type. Note that bean id uniqueness is still enforced by the
container, though no longer by XML parsers.
You are not required to supply a name or an id for a bean. If you do not supply a name or id explicitly,
the container generates a unique name for that bean. However, if you want to refer to that bean by
name, through the use of the ref element or a Service Locator style lookup, you must provide a
name. Motivations for not supplying a name are related to using inner beans and autowiring
collaborators.
Bean Naming Conventions
The convention is to use the standard Java convention for instance field names when naming
beans. That is, bean names start with a lowercase letter and are camel-cased from there.
Examples of such names include accountManager, accountService, userDao, loginController, and
so forth.
Naming beans consistently makes your configuration easier to read and understand. Also, if
you use Spring AOP, it helps a lot when applying advice to a set of beans related by name.
With component scanning in the classpath, Spring generates bean names for
unnamed components, following the rules described earlier: essentially, taking the
simple class name and turning its initial character to lower-case. However, in the
(unusual) special case when there is more than one character and both the first
and second characters are upper case, the original casing gets preserved. These are
the same rules as defined by java.beans.Introspector.decapitalize (which Spring
uses here).
Aliasing a Bean outside the Bean Definition
In a bean definition itself, you can supply more than one name for the bean, by using a
combination of up to one name specified by the id attribute and any number of other names in the
name attribute. These names can be equivalent aliases to the same bean and are useful for some
situations, such as letting each component in an application refer to a common dependency by
using a bean name that is specific to that component itself.
Specifying all aliases where the bean is actually defined is not always adequate, however. It is
sometimes desirable to introduce an alias for a bean that is defined elsewhere. This is commonly
the case in large systems where configuration is split amongst each subsystem, with each
subsystem having its own set of object definitions. In XML-based configuration metadata, you can
use the <alias/> element to accomplish this. The following example shows how to do so:
<alias name="fromName" alias="toName"/>
In this case, a bean (in the same container) named fromName may also, after the use of this alias
definition, be referred to as toName.
For example, the configuration metadata for subsystem A may refer to a DataSource by the name of
subsystemA-dataSource. The configuration metadata for subsystem B may refer to a DataSource by
the name of subsystemB-dataSource. When composing the main application that uses both these
subsystems, the main application refers to the DataSource by the name of myApp-dataSource. To have
all three names refer to the same object, you can add the following alias definitions to the
configuration metadata:
<alias name="myApp-dataSource" alias="subsystemA-dataSource"/>
<alias name="myApp-dataSource" alias="subsystemB-dataSource"/>
Now each component and the main application can refer to the dataSource through a name that is
unique and guaranteed not to clash with any other definition (effectively creating a namespace),
yet they refer to the same bean.
Java-configuration
If you use Javaconfiguration, the @Bean annotation can be used to provide aliases. See Using
the @Bean Annotation for details.
Instantiating Beans
A bean definition is essentially a recipe for creating one or more objects. The container looks at the
recipe for a named bean when asked and uses the configuration metadata encapsulated by that
bean definition to create (or acquire) an actual object.
If you use XML-based configuration metadata, you specify the type (or class) of object that is to be
instantiated in the class attribute of the element. This class attribute (which, internally, is a
Class property on a BeanDefinition instance) is usually mandatory. (For exceptions, see
Instantiation by Using an Instance Factory Method and Bean Definition Inheritance.) You can use
the Class property in one of two ways:
• Typically, to specify the bean class to be constructed in the case where the container itself
directly creates the bean by calling its constructor reflectively, somewhat equivalent to Java
code with the new operator.
• To specify the actual class containing the static factory method that is invoked to create the
object, in the less common case where the container invokes a static factory method on a class
to create the bean. The object type returned from the invocation of the static factory method
may be the same class or another class entirely.
Nested class names
If you want to configure a bean definition for a nested class, you may use either the binary
name or the source name of the nested class.
For example, if you have a class called SomeThing in the com.example package, and this
SomeThing class has a static nested class called OtherThing, they can be separated by a dollar
sign ($) or a dot (.). So the value of the class attribute in a bean definition would be
com.example.SomeThing$OtherThing or com.example.SomeThing.OtherThing.
Instantiation with a Constructor
When you create a bean by the constructor approach, all normal classes are usable by and
compatible with Spring. That is, the class being developed does not need to implement any specific
interfaces or to be coded in a specific fashion. Simply specifying the bean class should suffice.
However, depending on what type of IoC you use for that specific bean, you may need a default
(empty) constructor.
The Spring IoC container can manage virtually any class you want it to manage. It is not limited to
managing true JavaBeans. Most Spring users prefer actual JavaBeans with only a default (no-
argument) constructor and appropriate setters and getters modeled after the properties in the
container. You can also have more exotic non-bean-style classes in your container. If, for example,
you need to use a legacy connection pool that absolutely does not adhere to the JavaBean
specification, Spring can manage it as well.
With XML-based configuration metadata you can specify your bean class as follows:
For details about the mechanism for supplying arguments to the constructor (if required) and
setting object instance properties after the object is constructed, see Injecting Dependencies.
Instantiation with a Static Factory Method
When defining a bean that you create with a static factory method, use the class attribute to specify
the class that contains the static factory method and an attribute named factory-method to specify
the name of the factory method itself. You should be able to call this method (with optional
arguments, as described later) and return a live object, which subsequently is treated as if it had
been created through a constructor. One use for such a bean definition is to call static factories in
legacy code.
The following bean definition specifies that the bean will be created by calling a factory method.
The definition does not specify the type (class) of the returned object, but rather the class
containing the factory method. In this example, the createInstance() method must be a static
method. The following example shows how to specify a factory method:
The following example shows a class that would work with the preceding bean definition:
Java
public class ClientService {
private static ClientService clientService = new ClientService();
private ClientService() {}
public static ClientService createInstance() {
return clientService;
}
}
Kotlin
class ClientService private constructor() {
companion object {
private val clientService = ClientService()
@JvmStatic
fun createInstance() = clientService
}
}
For details about the mechanism for supplying (optional) arguments to the factory method and
setting object instance properties after the object is returned from the factory, see Dependencies
and Configuration in Detail.
Instantiation by Using an Instance Factory Method
Similar to instantiation through a static factory method, instantiation with an instance factory
method invokes a non-static method of an existing bean from the container to create a new bean.
To use this mechanism, leave the class attribute empty and, in the factory-bean attribute, specify
the name of a bean in the current (or parent or ancestor) container that contains the instance
method that is to be invoked to create the object. Set the name of the factory method itself with the
factory-method attribute. The following example shows how to configure such a bean:
The following example shows the corresponding class:
Java
public class DefaultServiceLocator {
private static ClientService clientService = new ClientServiceImpl();
public ClientService createClientServiceInstance() {
return clientService;
}
}
Kotlin
class DefaultServiceLocator {
companion object {
private val clientService = ClientServiceImpl()
}
fun createClientServiceInstance(): ClientService {
return clientService
}
}
One factory class can also hold more than one factory method, as the following example shows:
The following example shows the corresponding class:
Java
public class DefaultServiceLocator {
private static ClientService clientService = new ClientServiceImpl();
private static AccountService accountService = new AccountServiceImpl();
public ClientService createClientServiceInstance() {
return clientService;
}
public AccountService createAccountServiceInstance() {
return accountService;
}
}
Kotlin
class DefaultServiceLocator {
companion object {
private val clientService = ClientServiceImpl()
private val accountService = AccountServiceImpl()
}
fun createClientServiceInstance(): ClientService {
return clientService
}
fun createAccountServiceInstance(): AccountService {
return accountService
}
}
This approach shows that the factory bean itself can be managed and configured through
dependency injection (DI). See Dependencies and Configuration in Detail.
In Spring documentation, "factory bean" refers to a bean that is configured in the
Spring container and that creates objects through an instance or static factory
method. By contrast, FactoryBean (notice the capitalization) refers to a Spring-
specific FactoryBean implementation class.
Determining a Bean’s Runtime Type
The runtime type of a specific bean is non-trivial to determine. A specified class in the bean
metadata definition is just an initial class reference, potentially combined with a declared factory
method or being a FactoryBean class which may lead to a different runtime type of the bean, or not
being set at all in case of an instance-level factory method (which is resolved via the specified
factory-bean name instead). Additionally, AOP proxying may wrap a bean instance with an
interface-based proxy with limited exposure of the target bean’s actual type (just its implemented
interfaces).
The recommended way to find out about the actual runtime type of a particular bean is a
BeanFactory.getType call for the specified bean name. This takes all of the above cases into account
and returns the type of object that a BeanFactory.getBean call is going to return for the same bean
name.
2.1.4. Dependencies
A typical enterprise application does not consist of a single object (or bean in the Spring parlance).
Even the simplest application has a few objects that work together to present what the end-user
sees as a coherent application. This next section explains how you go from defining a number of
bean definitions that stand alone to a fully realized application where objects collaborate to achieve
a goal.
Dependency Injection
Dependency injection (DI) is a process whereby objects define their dependencies (that is, the other
objects with which they work) only through constructor arguments, arguments to a factory method,
or properties that are set on the object instance after it is constructed or returned from a factory
method. The container then injects those dependencies when it creates the bean. This process is
fundamentally the inverse (hence the name, Inversion of Control) of the bean itself controlling the
instantiation or location of its dependencies on its own by using direct construction of classes or the
Service Locator pattern.
Code is cleaner with the DI principle, and decoupling is more effective when objects are provided
with their dependencies. The object does not look up its dependencies and does not know the
location or class of the dependencies. As a result, your classes become easier to test, particularly
when the dependencies are on interfaces or abstract base classes, which allow for stub or mock
implementations to be used in unit tests.
DI exists in two major variants: Constructor-based dependency injection and Setter-based
dependency injection.
Constructor-based Dependency Injection
Constructor-based DI is accomplished by the container invoking a constructor with a number of
arguments, each representing a dependency. Calling a static factory method with specific
arguments to construct the bean is nearly equivalent, and this discussion treats arguments to a
constructor and to a static factory method similarly. The following example shows a class that can
only be dependency-injected with constructor injection:
Java
public class SimpleMovieLister {
// the SimpleMovieLister has a dependency on a MovieFinder
private final MovieFinder movieFinder;
// a constructor so that the Spring container can inject a MovieFinder
public SimpleMovieLister(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// business logic that actually uses the injected MovieFinder is omitted...
}
Kotlin
// a constructor so that the Spring container can inject a MovieFinder
class SimpleMovieLister(private val movieFinder: MovieFinder) {
// business logic that actually uses the injected MovieFinder is omitted...
}
Notice that there is nothing special about this class. It is a POJO that has no dependencies on
container specific interfaces, base classes, or annotations.
Constructor Argument Resolution
Constructor argument resolution matching occurs by using the argument’s type. If no potential
ambiguity exists in the constructor arguments of a bean definition, the order in which the
constructor arguments are defined in a bean definition is the order in which those arguments are
supplied to the appropriate constructor when the bean is being instantiated. Consider the following
class:
Java
package x.y;
public class ThingOne {
public ThingOne(ThingTwo thingTwo, ThingThree thingThree) {
// ...
}
}
Kotlin
package x.y
class ThingOne(thingTwo: ThingTwo, thingThree: ThingThree)
Assuming that the ThingTwo and ThingThree classes are not related by inheritance, no potential
ambiguity exists. Thus, the following configuration works fine, and you do not need to specify the
constructor argument indexes or types explicitly in the <constructor-arg/> element.
<constructor-arg ref="beanTwo"/>
<constructor-arg ref="beanThree"/>
When another bean is referenced, the type is known, and matching can occur (as was the case with
the preceding example). When a simple type is used, such as <value>true</value>, Spring cannot
determine the type of the value, and so cannot match by type without help. Consider the following
class:
Java
package examples;
public class ExampleBean {
// Number of years to calculate the Ultimate Answer
private final int years;
// The Answer to Life, the Universe, and Everything
private final String ultimateAnswer;
public ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
}
}
Kotlin
package examples
class ExampleBean(
private val years: Int, // Number of years to calculate the Ultimate Answer
private val ultimateAnswer: String // The Answer to Life, the Universe, and
Everything
)
Constructor argument type matching
In the preceding scenario, the container can use type matching with simple types if you explicitly
specify the type of the constructor argument by using the type attribute, as the following example
shows:
<constructor-arg type="int" value="7500000"/>
<constructor-arg type="java.lang.String" value="42"/>
Constructor argument index
You can use the index attribute to specify explicitly the index of constructor arguments, as the
following example shows:
<constructor-arg index="0" value="7500000"/>
<constructor-arg index="1" value="42"/>
In addition to resolving the ambiguity of multiple simple values, specifying an index resolves
ambiguity where a constructor has two arguments of the same type.
The index is 0-based.
Constructor argument name
You can also use the constructor parameter name for value disambiguation, as the following
example shows:
<constructor-arg name="years" value="7500000"/>
<constructor-arg name="ultimateAnswer" value="42"/>
Keep in mind that, to make this work out of the box, your code must be compiled with the debug
flag enabled so that Spring can look up the parameter name from the constructor. If you cannot or
do not want to compile your code with the debug flag, you can use the @ConstructorProperties JDK
annotation to explicitly name your constructor arguments. The sample class would then have to
look as follows:
Java
package examples;
public class ExampleBean {
// Fields omitted
@ConstructorProperties({"years", "ultimateAnswer"})
public ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
}
}
Kotlin
package examples
class ExampleBean
@ConstructorProperties("years", "ultimateAnswer")
constructor(val years: Int, val ultimateAnswer: String)
Setter-based Dependency Injection
Setter-based DI is accomplished by the container calling setter methods on your beans after
invoking a no-argument constructor or a no-argument static factory method to instantiate your
bean.
The following example shows a class that can only be dependency-injected by using pure setter
injection. This class is conventional Java. It is a POJO that has no dependencies on container specific
interfaces, base classes, or annotations.
Java
public class SimpleMovieLister {
// the SimpleMovieLister has a dependency on the MovieFinder
private MovieFinder movieFinder;
// a setter method so that the Spring container can inject a MovieFinder
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// business logic that actually uses the injected MovieFinder is omitted...
}
Kotlin
class SimpleMovieLister {
// a late-initialized property so that the Spring container can inject a
MovieFinder
lateinit var movieFinder: MovieFinder
// business logic that actually uses the injected MovieFinder is omitted...
}
The ApplicationContext supports constructor-based and setter-based DI for the beans it manages. It
also supports setter-based DI after some dependencies have already been injected through the
constructor approach. You configure the dependencies in the form of a BeanDefinition, which you
use in conjunction with PropertyEditor instances to convert properties from one format to another.
However, most Spring users do not work with these classes directly (that is, programmatically) but
rather with XML bean definitions, annotated components (that is, classes annotated with @Component,
@Controller, and so forth), or @Bean methods in Java-based @Configuration classes. These sources are
then converted internally into instances of BeanDefinition and used to load an entire Spring IoC
container instance.
Constructor-based or setter-based DI?
Since you can mix constructor-based and setter-based DI, it is a good rule of thumb to use
constructors for mandatory dependencies and setter methods or configuration methods for
optional dependencies. Note that use of the @Autowired annotation on a setter method can
be used to make the property be a required dependency; however, constructor injection with
programmatic validation of arguments is preferable.
The Spring team generally advocates constructor injection, as it lets you implement
application components as immutable objects and ensures that required dependencies are
not null. Furthermore, constructor-injected components are always returned to the client
(calling) code in a fully initialized state. As a side note, a large number of constructor
arguments is a bad code smell, implying that the class likely has too many responsibilities and
should be refactored to better address proper separation of concerns.
Setter injection should primarily only be used for optional dependencies that can be assigned
reasonable default values within the class. Otherwise, not-null checks must be performed
everywhere the code uses the dependency. One benefit of setter injection is that setter
methods make objects of that class amenable to reconfiguration or re-injection later.
Management through JMX MBeans is therefore a compelling use case for setter injection.
Use the DI style that makes the most sense for a particular class. Sometimes, when dealing
with third-party classes for which you do not have the source, the choice is made for you. For
example, if a third-party class does not expose any setter methods, then constructor injection
may be the only available form of DI.
Dependency Resolution Process
The container performs bean dependency resolution as follows:
• The ApplicationContext is created and initialized with configuration metadata that describes all
the beans. Configuration metadata can be specified by XML, Java code, or annotations.
• For each bean, its dependencies are expressed in the form of properties, constructor arguments,
or arguments to the static-factory method (if you use that instead of a normal constructor).
These dependencies are provided to the bean, when the bean is actually created.
• Each property or constructor argument is an actual definition of the value to set, or a reference
to another bean in the container.
• Each property or constructor argument that is a value is converted from its specified format to
the actual type of that property or constructor argument. By default, Spring can convert a value
supplied in string format to all built-in types, such as int, long, String, boolean, and so forth.
The Spring container validates the configuration of each bean as the container is created. However,
the bean properties themselves are not set until the bean is actually created. Beans that are
singleton-scoped and set to be pre-instantiated (the default) are created when the container is
created. Scopes are defined in Bean Scopes. Otherwise, the bean is created only when it is
requested. Creation of a bean potentially causes a graph of beans to be created, as the bean’s
dependencies and its dependencies' dependencies (and so on) are created and assigned. Note that
resolution mismatches among those dependencies may show up late — that is, on first creation of
the affected bean.
Circular dependencies
If you use predominantly constructor injection, it is possible to create an unresolvable
circular dependency scenario.
For example: Class A requires an instance of class B through constructor injection, and class B
requires an instance of class A through constructor injection. If you configure beans for
classes A and B to be injected into each other, the Spring IoC container detects this circular
reference at runtime, and throws a BeanCurrentlyInCreationException.
One possible solution is to edit the source code of some classes to be configured by setters
rather than constructors. Alternatively, avoid constructor injection and use setter injection
only. In other words, although it is not recommended, you can configure circular
dependencies with setter injection.
Unlike the typical case (with no circular dependencies), a circular dependency between bean
A and bean B forces one of the beans to be injected into the other prior to being fully
initialized itself (a classic chicken-and-egg scenario).
You can generally trust Spring to do the right thing. It detects configuration problems, such as
references to non-existent beans and circular dependencies, at container load-time. Spring sets
properties and resolves dependencies as late as possible, when the bean is actually created. This
means that a Spring container that has loaded correctly can later generate an exception when you
request an object if there is a problem creating that object or one of its dependencies — for
example, the bean throws an exception as a result of a missing or invalid property. This potentially
delayed visibility of some configuration issues is why ApplicationContext implementations by
default pre-instantiate singleton beans. At the cost of some upfront time and memory to create
these beans before they are actually needed, you discover configuration issues when the
ApplicationContext is created, not later. You can still override this default behavior so that singleton
beans initialize lazily, rather than being eagerly pre-instantiated.
If no circular dependencies exist, when one or more collaborating beans are being injected into a
dependent bean, each collaborating bean is totally configured prior to being injected into the
dependent bean. This means that, if bean A has a dependency on bean B, the Spring IoC container
completely configures bean B prior to invoking the setter method on bean A. In other words, the
bean is instantiated (if it is not a pre-instantiated singleton), its dependencies are set, and the
relevant lifecycle methods (such as a configured init method or the InitializingBean callback
method) are invoked.
Examples of Dependency Injection
The following example uses XML-based configuration metadata for setter-based DI. A small part of
a Spring XML configuration file specifies some bean definitions as follows:
<ref bean="anotherExampleBean"/>
The following example shows the corresponding ExampleBean class:
Java
public class ExampleBean {
private AnotherBean beanOne;
private YetAnotherBean beanTwo;
private int i;
public void setBeanOne(AnotherBean beanOne) {
this.beanOne = beanOne;
}
public void setBeanTwo(YetAnotherBean beanTwo) {
this.beanTwo = beanTwo;
}
public void setIntegerProperty(int i) {
this.i = i;
}
}
Kotlin
class ExampleBean {
lateinit var beanOne: AnotherBean
lateinit var beanTwo: YetAnotherBean
var i: Int = 0
}
In the preceding example, setters are declared to match against the properties specified in the XML
file. The following example uses constructor-based DI:
<constructor-arg>
<ref bean="anotherExampleBean"/>
</constructor-arg>
<constructor-arg ref="yetAnotherBean"/>
<constructor-arg type="int" value="1"/>
The following example shows the corresponding ExampleBean class:
Java
public class ExampleBean {
private AnotherBean beanOne;
private YetAnotherBean beanTwo;
private int i;
public ExampleBean(
AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
this.beanOne = anotherBean;
this.beanTwo = yetAnotherBean;
this.i = i;
}
}
Kotlin
class ExampleBean(
private val beanOne: AnotherBean,
private val beanTwo: YetAnotherBean,
private val i: Int)
The constructor arguments specified in the bean definition are used as arguments to the
constructor of the ExampleBean.
Now consider a variant of this example, where, instead of using a constructor, Spring is told to call
a static factory method to return an instance of the object:
<constructor-arg ref="anotherExampleBean"/>
<constructor-arg ref="yetAnotherBean"/>
<constructor-arg value="1"/>
The following example shows the corresponding ExampleBean class:
Java
public class ExampleBean {
// a private constructor
private ExampleBean(...) {
...
}
// a static factory method; the arguments to this method can be
// considered the dependencies of the bean that is returned,
// regardless of how those arguments are actually used.
public static ExampleBean createInstance (
AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
ExampleBean eb = new ExampleBean (...);
// some other operations...
return eb;
}
}
Kotlin
class ExampleBean private constructor() {
companion object {
// a static factory method; the arguments to this method can be
// considered the dependencies of the bean that is returned,
// regardless of how those arguments are actually used.
@JvmStatic
fun createInstance(anotherBean: AnotherBean, yetAnotherBean: YetAnotherBean,
i: Int): ExampleBean {
val eb = ExampleBean (...)
// some other operations...
return eb
}
}
}
Arguments to the static factory method are supplied by <constructor-arg/> elements, exactly the
same as if a constructor had actually been used. The type of the class being returned by the factory
method does not have to be of the same type as the class that contains the static factory method
(although, in this example, it is). An instance (non-static) factory method can be used in an
essentially identical fashion (aside from the use of the factory-bean attribute instead of the class
attribute), so we do not discuss those details here.
Dependencies and Configuration in Detail
As mentioned in the previous section, you can define bean properties and constructor arguments as
references to other managed beans (collaborators) or as values defined inline. Spring’s XML-based
configuration metadata supports sub-element types within its and <constructor-arg/>
elements for this purpose.
Straight Values (Primitives, Strings, and so on)
The value attribute of the element specifies a property or constructor argument as a
human-readable string representation. Spring’s conversion service is used to convert these values
from a String to the actual type of the property or argument. The following example shows various
values being set:
The following example uses the p-namespace for even more succinct XML configuration:
The preceding XML is more succinct. However, typos are discovered at runtime rather than design
time, unless you use an IDE (such as IntelliJ IDEA or the Spring Tools for Eclipse) that supports
automatic property completion when you create bean definitions. Such IDE assistance is highly
recommended.
You can also configure a java.util.Properties instance, as follows:
<value>
jdbc.driver.className=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mydb
</value>
The Spring container converts the text inside the <value/> element into a java.util.Properties
instance by using the JavaBeans PropertyEditor mechanism. This is a nice shortcut, and is one of a
few places where the Spring team do favor the use of the nested <value/> element over the value
attribute style.
The idref element
The idref element is simply an error-proof way to pass the id (a string value - not a reference) of
another bean in the container to a <constructor-arg/> or element. The following
example shows how to use it:
The preceding bean definition snippet is exactly equivalent (at runtime) to the following snippet:
The first form is preferable to the second, because using the idref tag lets the container validate at
deployment time that the referenced, named bean actually exists. In the second variation, no
validation is performed on the value that is passed to the targetName property of the client bean.
Typos are only discovered (with most likely fatal results) when the client bean is actually
instantiated. If the client bean is a prototype bean, this typo and the resulting exception may only
be discovered long after the container is deployed.
The local attribute on the idref element is no longer supported in the 4.0 beans
XSD, since it does not provide value over a regular bean reference any more.
Change your existing idref local references to idref bean when upgrading to the
4.0 schema.
A common place (at least in versions earlier than Spring 2.0) where the element brings
value is in the configuration of AOP interceptors in a ProxyFactoryBean bean definition. Using
elements when you specify the interceptor names prevents you from misspelling an
interceptor ID.
References to Other Beans (Collaborators)
The ref element is the final element inside a <constructor-arg/> or definition element.
Here, you set the value of the specified property of a bean to be a reference to another bean (a
collaborator) managed by the container. The referenced bean is a dependency of the bean whose
property is to be set, and it is initialized on demand as needed before the property is set. (If the
collaborator is a singleton bean, it may already be initialized by the container.) All references are
ultimately a reference to another object. Scoping and validation depend on whether you specify the
ID or name of the other object through the bean or parent attribute.
Specifying the target bean through the bean attribute of the <ref/> tag is the most general form and
allows creation of a reference to any bean in the same container or parent container, regardless of
whether it is in the same XML file. The value of the bean attribute may be the same as the id
attribute of the target bean or be the same as one of the values in the name attribute of the target
bean. The following example shows how to use a ref element:
<ref bean="someBean"/>
Specifying the target bean through the parent attribute creates a reference to a bean that is in a
parent container of the current container. The value of the parent attribute may be the same as
either the id attribute of the target bean or one of the values in the name attribute of the target bean.
The target bean must be in a parent container of the current one. You should use this bean
reference variant mainly when you have a hierarchy of containers and you want to wrap an
existing bean in a parent container with a proxy that has the same name as the parent bean. The
following pair of listings shows how to use the parent attribute:
<ref parent="accountService"/>
The local attribute on the ref element is no longer supported in the 4.0 beans XSD,
since it does not provide value over a regular bean reference any more. Change
your existing ref local references to ref bean when upgrading to the 4.0 schema.
Inner Beans
A element inside the or <constructor-arg/> elements defines an inner bean, as
the following example shows:
An inner bean definition does not require a defined ID or name. If specified, the container does not
use such a value as an identifier. The container also ignores the scope flag on creation, because
inner beans are always anonymous and are always created with the outer bean. It is not possible to
access inner beans independently or to inject them into collaborating beans other than into the
enclosing bean.
As a corner case, it is possible to receive destruction callbacks from a custom scope — for example,
for a request-scoped inner bean contained within a singleton bean. The creation of the inner bean
instance is tied to its containing bean, but destruction callbacks let it participate in the request
scope’s lifecycle. This is not a common scenario. Inner beans typically simply share their containing
bean’s scope.
Collections
The <list/>, <set/>, <map/>, and elements set the properties and arguments of the Java
Collection types List, Set, Map, and Properties, respectively. The following example shows how to
use them:
[email protected]
[email protected]
[email protected]
<list>
<value>a list element followed by a reference</value>
<ref bean="myDataSource" />
</list>
<map>
<entry key="an entry" value="just some string"/>
<entry key="a ref" value-ref="myDataSource"/>
</map>
<set>
<value>just some string</value>
<ref bean="myDataSource" />
</set>
The value of a map key or value, or a set value, can also be any of the following elements:
bean | ref | idref | list | set | map | props | value | null
Collection Merging
The Spring container also supports merging collections. An application developer can define a
parent <list/>, <map/>, <set/> or element and have child <list/>, <map/>, <set/> or
elements inherit and override values from the parent collection. That is, the child collection’s
values are the result of merging the elements of the parent and child collections, with the child’s
collection elements overriding values specified in the parent collection.
This section on merging discusses the parent-child bean mechanism. Readers unfamiliar with
parent and child bean definitions may wish to read the relevant section before continuing.
The following example demonstrates collection merging:
[email protected]
[email protected]
[email protected]
[email protected]
Notice the use of the merge=true attribute on the element of the adminEmails property of the
child bean definition. When the child bean is resolved and instantiated by the container, the
resulting instance has an adminEmails Properties collection that contains the result of merging the
child’s adminEmails collection with the parent’s adminEmails collection. The following listing shows
the result:
[email protected]
[email protected]
[email protected]
The child Properties collection’s value set inherits all property elements from the parent ,
and the child’s value for the support value overrides the value in the parent collection.
This merging behavior applies similarly to the <list/>, <map/>, and <set/> collection types. In the
specific case of the <list/> element, the semantics associated with the List collection type (that is,
the notion of an ordered collection of values) is maintained. The parent’s values precede all of the
child list’s values. In the case of the Map, Set, and Properties collection types, no ordering exists.
Hence, no ordering semantics are in effect for the collection types that underlie the associated Map,
Set, and Properties implementation types that the container uses internally.
Limitations of Collection Merging
You cannot merge different collection types (such as a Map and a List). If you do attempt to do so, an
appropriate Exception is thrown. The merge attribute must be specified on the lower, inherited, child
definition. Specifying the merge attribute on a parent collection definition is redundant and does not
result in the desired merging.
Strongly-typed collection
Thanks to Java’s support for generic types, you can use strongly typed collections. That is, it is
possible to declare a Collection type such that it can only contain (for example) String elements. If
you use Spring to dependency-inject a strongly-typed Collection into a bean, you can take
advantage of Spring’s type-conversion support such that the elements of your strongly-typed
Collection instances are converted to the appropriate type prior to being added to the Collection.
The following Java class and bean definition show how to do so:
Java
public class SomeClass {
private Map<String, Float> accounts;
public void setAccounts(Map<String, Float> accounts) {
this.accounts = accounts;
}
}
Kotlin
class SomeClass {
lateinit var accounts: Map<String, Float>
}
<map>
<entry key="one" value="9.99"/>
<entry key="two" value="2.75"/>
<entry key="six" value="3.99"/>
</map>
When the accounts property of the something bean is prepared for injection, the generics
information about the element type of the strongly-typed Map<String, Float> is available by
reflection. Thus, Spring’s type conversion infrastructure recognizes the various value elements as
being of type Float, and the string values (9.99, 2.75, and 3.99) are converted into an actual Float
type.
Null and Empty String Values
Spring treats empty arguments for properties and the like as empty Strings. The following XML-
based configuration metadata snippet sets the email property to the empty String value ("").
The preceding example is equivalent to the following Java code:
Java
exampleBean.setEmail("");
Kotlin
exampleBean.email = ""
The <null/> element handles null values. The following listing shows an example:
<null/>
The preceding configuration is equivalent to the following Java code:
Java
exampleBean.setEmail(null);
Kotlin
exampleBean.email = null
XML Shortcut with the p-namespace
The p-namespace lets you use the bean element’s attributes (instead of nested elements)
to describe your property values collaborating beans, or both.
Spring supports extensible configuration formats with namespaces, which are based on an XML
Schema definition. The beans configuration format discussed in this chapter is defined in an XML
Schema document. However, the p-namespace is not defined in an XSD file and exists only in the
core of Spring.
The following example shows two XML snippets (the first uses standard XML format and the
second uses the p-namespace) that resolve to the same result:
The example shows an attribute in the p-namespace called email in the bean definition. This tells
Spring to include a property declaration. As previously mentioned, the p-namespace does not have
a schema definition, so you can set the name of the attribute to the property name.
This next example includes two more bean definitions that both have a reference to another bean:
This example includes not only a property value using the p-namespace but also uses a special
format to declare property references. Whereas the first bean definition uses to create a reference from bean john to bean jane, the second bean
definition uses p:spouse-ref="jane" as an attribute to do the exact same thing. In this case, spouse is
the property name, whereas the -ref part indicates that this is not a straight value but rather a
reference to another bean.
The p-namespace is not as flexible as the standard XML format. For example, the
format for declaring property references clashes with properties that end in Ref,
whereas the standard XML format does not. We recommend that you choose your
approach carefully and communicate this to your team members to avoid
producing XML documents that use all three approaches at the same time.
XML Shortcut with the c-namespace
Similar to the XML Shortcut with the p-namespace, the c-namespace, introduced in Spring 3.1,
allows inlined attributes for configuring the constructor arguments rather then nested constructor-
arg elements.
The following example uses the c: namespace to do the same thing as the from Constructor-based
Dependency Injection:
<constructor-arg name="thingTwo" ref="beanTwo"/>
<constructor-arg name="thingThree" ref="beanThree"/>
<constructor-arg name="email" value="[email protected]"/>
The c: namespace uses the same conventions as the p: one (a trailing -ref for bean references) for
setting the constructor arguments by their names. Similarly, it needs to be declared in the XML file
even though it is not defined in an XSD schema (it exists inside the Spring core).
For the rare cases where the constructor argument names are not available (usually if the bytecode
was compiled without debugging information), you can use fallback to the argument indexes, as
follows:
Due to the XML grammar, the index notation requires the presence of the leading
_, as XML attribute names cannot start with a number (even though some IDEs
allow it). A corresponding index notation is also available for <constructor-arg>
elements but not commonly used since the plain order of declaration is usually
sufficient there.
In practice, the constructor resolution mechanism is quite efficient in matching arguments, so
unless you really need to, we recommend using the name notation throughout your configuration.
Compound Property Names
You can use compound or nested property names when you set bean properties, as long as all
components of the path except the final property name are not null. Consider the following bean
definition:
The something bean has a fred property, which has a bob property, which has a sammy property, and
that final sammy property is being set to a value of 123. In order for this to work, the fred property of
something and the bob property of fred must not be null after the bean is constructed. Otherwise, a
NullPointerException is thrown.
Using depends-on
If a bean is a dependency of another bean, that usually means that one bean is set as a property of
another. Typically you accomplish this with the <ref/> element in XML-based configuration
metadata. However, sometimes dependencies between beans are less direct. An example is when a
static initializer in a class needs to be triggered, such as for database driver registration. The
depends-on attribute can explicitly force one or more beans to be initialized before the bean using
this element is initialized. The following example uses the depends-on attribute to express a
dependency on a single bean:
To express a dependency on multiple beans, supply a list of bean names as the value of the depends-
on attribute (commas, whitespace, and semicolons are valid delimiters):
The depends-on attribute can specify both an initialization-time dependency and, in
the case of singleton beans only, a corresponding destruction-time dependency.
Dependent beans that define a depends-on relationship with a given bean are
destroyed first, prior to the given bean itself being destroyed. Thus, depends-on can
also control shutdown order.
Lazy-initialized Beans
By default, ApplicationContext implementations eagerly create and configure all singleton beans as
part of the initialization process. Generally, this pre-instantiation is desirable, because errors in the
configuration or surrounding environment are discovered immediately, as opposed to hours or
even days later. When this behavior is not desirable, you can prevent pre-instantiation of a
singleton bean by marking the bean definition as being lazy-initialized. A lazy-initialized bean tells
the IoC container to create a bean instance when it is first requested, rather than at startup.
In XML, this behavior is controlled by the lazy-init attribute on the element, as the
following example shows:
When the preceding configuration is consumed by an ApplicationContext, the lazy bean is not
eagerly pre-instantiated when the ApplicationContext starts, whereas the not.lazy bean is eagerly
pre-instantiated.
However, when a lazy-initialized bean is a dependency of a singleton bean that is not lazy-
initialized, the ApplicationContext creates the lazy-initialized bean at startup, because it must
satisfy the singleton’s dependencies. The lazy-initialized bean is injected into a singleton bean
elsewhere that is not lazy-initialized.
You can also control lazy-initialization at the container level by using the default-lazy-init
attribute on the element, as the following example shows:
Autowiring Collaborators
The Spring container can autowire relationships between collaborating beans. You can let Spring
resolve collaborators (other beans) automatically for your bean by inspecting the contents of the
ApplicationContext. Autowiring has the following advantages:
• Autowiring can significantly reduce the need to specify properties or constructor arguments.
(Other mechanisms such as a bean template discussed elsewhere in this chapter are also
valuable in this regard.)
• Autowiring can update a configuration as your objects evolve. For example, if you need to add a
dependency to a class, that dependency can be satisfied automatically without you needing to
modify the configuration. Thus autowiring can be especially useful during development,
without negating the option of switching to explicit wiring when the code base becomes more
stable.
When using XML-based configuration metadata (see Dependency Injection), you can specify the
autowire mode for a bean definition with the autowire attribute of the element. The
autowiring functionality has four modes. You specify autowiring per bean and can thus choose
which ones to autowire. The following table describes the four autowiring modes:
Table 2. Autowiring modes
Mode Explanation
no (Default) No autowiring. Bean references must be defined by ref elements.
Changing the default setting is not recommended for larger deployments,
because specifying collaborators explicitly gives greater control and clarity. To
some extent, it documents the structure of a system.
byName Autowiring by property name. Spring looks for a bean with the same name as
the property that needs to be autowired. For example, if a bean definition is
set to autowire by name and it contains a master property (that is, it has a
setMaster(..) method), Spring looks for a bean definition named master and
uses it to set the property.
byType Lets a property be autowired if exactly one bean of the property type exists in
the container. If more than one exists, a fatal exception is thrown, which
indicates that you may not use byType autowiring for that bean. If there are no
matching beans, nothing happens (the property is not set).
constructor Analogous to byType but applies to constructor arguments. If there is not
exactly one bean of the constructor argument type in the container, a fatal
error is raised.
With byType or constructor autowiring mode, you can wire arrays and typed collections. In such
cases, all autowire candidates within the container that match the expected type are provided to
satisfy the dependency. You can autowire strongly-typed Map instances if the expected key type is
String. An autowired Map instance’s values consist of all bean instances that match the expected
type, and the Map instance’s keys contain the corresponding bean names.
Limitations and Disadvantages of Autowiring
Autowiring works best when it is used consistently across a project. If autowiring is not used in
general, it might be confusing to developers to use it to wire only one or two bean definitions.
Consider the limitations and disadvantages of autowiring:
• Explicit dependencies in property and constructor-arg settings always override autowiring. You
cannot autowire simple properties such as primitives, Strings, and Classes (and arrays of such
simple properties). This limitation is by-design.
• Autowiring is less exact than explicit wiring. Although, as noted in the earlier table, Spring is
careful to avoid guessing in case of ambiguity that might have unexpected results. The
relationships between your Spring-managed objects are no longer documented explicitly.
• Wiring information may not be available to tools that may generate documentation from a
Spring container.
• Multiple bean definitions within the container may match the type specified by the setter
method or constructor argument to be autowired. For arrays, collections, or Map instances, this is
not necessarily a problem. However, for dependencies that expect a single value, this ambiguity
is not arbitrarily resolved. If no unique bean definition is available, an exception is thrown.
In the latter scenario, you have several options:
• Abandon autowiring in favor of explicit wiring.
• Avoid autowiring for a bean definition by setting its autowire-candidate attributes to false, as
described in the next section.
• Designate a single bean definition as the primary candidate by setting the primary attribute of its
element to true.
• Implement the more fine-grained control available with annotation-based configuration, as
described in Annotation-based Container Configuration.
Excluding a Bean from Autowiring
On a per-bean basis, you can exclude a bean from autowiring. In Spring’s XML format, set the
autowire-candidate attribute of the element to false. The container makes that specific bean
definition unavailable to the autowiring infrastructure (including annotation style configurations
such as @Autowired).
The autowire-candidate attribute is designed to only affect type-based autowiring.
It does not affect explicit references by name, which get resolved even if the
specified bean is not marked as an autowire candidate. As a consequence,
autowiring by name nevertheless injects a bean if the name matches.
You can also limit autowire candidates based on pattern-matching against bean names. The top-
level element accepts one or more patterns within its default-autowire-candidates
attribute. For example, to limit autowire candidate status to any bean whose name ends with
Repository, provide a value of *Repository. To provide multiple patterns, define them in a comma-
separated list. An explicit value of true or false for a bean definition’s autowire-candidate attribute
always takes precedence. For such beans, the pattern matching rules do not apply.
These techniques are useful for beans that you never want to be injected into other beans by
autowiring. It does not mean that an excluded bean cannot itself be configured by using
autowiring. Rather, the bean itself is not a candidate for autowiring other beans.
Method Injection
In most application scenarios, most beans in the container are singletons. When a singleton bean
needs to collaborate with another singleton bean or a non-singleton bean needs to collaborate with
another non-singleton bean, you typically handle the dependency by defining one bean as a
property of the other. A problem arises when the bean lifecycles are different. Suppose singleton
bean A needs to use non-singleton (prototype) bean B, perhaps on each method invocation on A.
The container creates the singleton bean A only once, and thus only gets one opportunity to set the
properties. The container cannot provide bean A with a new instance of bean B every time one is
needed.
A solution is to forego some inversion of control. You can make bean A aware of the container by
implementing the ApplicationContextAware interface, and by making a getBean("B") call to the
container ask for (a typically new) bean B instance every time bean A needs it. The following
example shows this approach:
Java
// a class that uses a stateful Command-style class to perform some processing
package fiona.apple;
// Spring-API imports
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class CommandManager implements ApplicationContextAware {
private ApplicationContext applicationContext;
public Object process(Map commandState) {
// grab a new instance of the appropriate Command
Command command = createCommand();
// set the state on the (hopefully brand new) Command instance
command.setState(commandState);
return command.execute();
}
protected Command createCommand() {
// notice the Spring API dependency!
return this.applicationContext.getBean("command", Command.class);
}
public void setApplicationContext(
ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
Kotlin
// a class that uses a stateful Command-style class to perform some processing
package fiona.apple
// Spring-API imports
import org.springframework.context.ApplicationContext
import org.springframework.context.ApplicationContextAware
class CommandManager : ApplicationContextAware {
private lateinit var applicationContext: ApplicationContext
fun process(commandState: Map<, >): Any {
// grab a new instance of the appropriate Command
val command = createCommand()
// set the state on the (hopefully brand new) Command instance
command.state = commandState
return command.execute()
}
// notice the Spring API dependency!
protected fun createCommand() =
applicationContext.getBean("command", Command::class.java)
override fun setApplicationContext(applicationContext: ApplicationContext) {
this.applicationContext = applicationContext
}
}
The preceding is not desirable, because the business code is aware of and coupled to the Spring
Framework. Method Injection, a somewhat advanced feature of the Spring IoC container, lets you
handle this use case cleanly.
You can read more about the motivation for Method Injection in this blog entry.
Lookup Method Injection
Lookup method injection is the ability of the container to override methods on container-managed
beans and return the lookup result for another named bean in the container. The lookup typically
involves a prototype bean, as in the scenario described in the preceding section. The Spring
Framework implements this method injection by using bytecode generation from the CGLIB library
to dynamically generate a subclass that overrides the method.
• For this dynamic subclassing to work, the class that the Spring bean container
subclasses cannot be final, and the method to be overridden cannot be final,
either.
• Unit-testing a class that has an abstract method requires you to subclass the
class yourself and to supply a stub implementation of the abstract method.
• Concrete methods are also necessary for component scanning, which requires
concrete classes to pick up.
• A further key limitation is that lookup methods do not work with factory
methods and in particular not with @Bean methods in configuration classes,
since, in that case, the container is not in charge of creating the instance and
therefore cannot create a runtime-generated subclass on the fly.
In the case of the CommandManager class in the previous code snippet, the Spring container
dynamically overrides the implementation of the createCommand() method. The CommandManager class
does not have any Spring dependencies, as the reworked example shows:
Java
package fiona.apple;
// no more Spring imports!
public abstract class CommandManager {
public Object process(Object commandState) {
// grab a new instance of the appropriate Command interface
Command command = createCommand();
// set the state on the (hopefully brand new) Command instance
command.setState(commandState);
return command.execute();
}
// okay... but where is the implementation of this method?
protected abstract Command createCommand();
}
Kotlin
package fiona.apple
// no more Spring imports!
abstract class CommandManager {
fun process(commandState: Any): Any {
// grab a new instance of the appropriate Command interface
val command = createCommand()
// set the state on the (hopefully brand new) Command instance
command.state = commandState
return command.execute()
}
// okay... but where is the implementation of this method?
protected abstract fun createCommand(): Command
}
In the client class that contains the method to be injected (the CommandManager in this case), the
method to be injected requires a signature of the following form:
[abstract] <return-type> theMethodName(no-arguments);
If the method is abstract, the dynamically-generated subclass implements the method. Otherwise,
the dynamically-generated subclass overrides the concrete method defined in the original class.
Consider the following example:
<lookup-method name="createCommand" bean="myCommand"/>
The bean identified as commandManager calls its own createCommand() method whenever it needs a
new instance of the myCommand bean. You must be careful to deploy the myCommand bean as a prototype
if that is actually what is needed. If it is a singleton, the same instance of the myCommand bean is
returned each time.
Alternatively, within the annotation-based component model, you can declare a lookup method
through the @Lookup annotation, as the following example shows:
Java
public abstract class CommandManager {
public Object process(Object commandState) {
Command command = createCommand();
command.setState(commandState);
return command.execute();
}
@Lookup("myCommand")
protected abstract Command createCommand();
}
Kotlin
abstract class CommandManager {
fun process(commandState: Any): Any {
val command = createCommand()
command.state = commandState
return command.execute()
}
@Lookup("myCommand")
protected abstract fun createCommand(): Command
}
Or, more idiomatically, you can rely on the target bean getting resolved against the declared return
type of the lookup method:
Java
public abstract class CommandManager {
public Object process(Object commandState) {
Command command = createCommand();
command.setState(commandState);
return command.execute();
}
@Lookup
protected abstract Command createCommand();
}
Kotlin
abstract class CommandManager {
fun process(commandState: Any): Any {
val command = createCommand()
command.state = commandState
return command.execute()
}
@Lookup
protected abstract fun createCommand(): Command
}
Note that you should typically declare such annotated lookup methods with a concrete stub
implementation, in order for them to be compatible with Spring’s component scanning rules where
abstract classes get ignored by default. This limitation does not apply to explicitly registered or
explicitly imported bean classes.
Another way of accessing differently scoped target beans is an ObjectFactory/
Provider injection point. See Scoped Beans as Dependencies.
You may also find the ServiceLocatorFactoryBean (in the
org.springframework.beans.factory.config package) to be useful.
Arbitrary Method Replacement
A less useful form of method injection than lookup method injection is the ability to replace
arbitrary methods in a managed bean with another method implementation. You can safely skip
the rest of this section until you actually need this functionality.
With XML-based configuration metadata, you can use the replaced-method element to replace an
existing method implementation with another, for a deployed bean. Consider the following class,
which has a method called computeValue that we want to override:
Java
public class MyValueCalculator {
public String computeValue(String input) {
// some real code...
}
// some other methods...
}
Kotlin
class MyValueCalculator {
fun computeValue(input: String): String {
// some real code...
}
// some other methods...
}
A class that implements the org.springframework.beans.factory.support.MethodReplacer interface
provides the new method definition, as the following example shows:
Java
/
* meant to be used to override the existing computeValue(String)
* implementation in MyValueCalculator
*/
public class ReplacementComputeValue implements MethodReplacer {
public Object reimplement(Object o, Method m, Object[] args) throws Throwable {
// get the input value, work with it, and return a computed result
String input = (String) args[0];
...
return ...;
}
}
Kotlin
/
* meant to be used to override the existing computeValue(String)
* implementation in MyValueCalculator
*/
class ReplacementComputeValue : MethodReplacer {
override fun reimplement(obj: Any, method: Method, args: Array<out Any>): Any {
// get the input value, work with it, and return a computed result
val input = args[0] as String;
...
return ...;
}
}
The bean definition to deploy the original class and specify the method override would resemble
the following example:
<replaced-method name="computeValue" replacer="replacementComputeValue">
<arg-type>String</arg-type>
</replaced-method>
You can use one or more <arg-type/> elements within the <replaced-method/> element to indicate
the method signature of the method being overridden. The signature for the arguments is
necessary only if the method is overloaded and multiple variants exist within the class. For
convenience, the type string for an argument may be a substring of the fully qualified type name.
For example, the following all match java.lang.String:
java.lang.String
String
Str
Because the number of arguments is often enough to distinguish between each possible choice, this
shortcut can save a lot of typing, by letting you type only the shortest string that matches an
argument type.
2.1.5. Bean Scopes
When you create a bean definition, you create a recipe for creating actual instances of the class
defined by that bean definition. The idea that a bean definition is a recipe is important, because it
means that, as with a class, you can create many object instances from a single recipe.
You can control not only the various dependencies and configuration values that are to be plugged
into an object that is created from a particular bean definition but also control the scope of the
objects created from a particular bean definition. This approach is powerful and flexible, because
you can choose the scope of the objects you create through configuration instead of having to bake
in the scope of an object at the Java class level. Beans can be defined to be deployed in one of a
number of scopes. The Spring Framework supports six scopes, four of which are available only if
you use a web-aware ApplicationContext. You can also create a custom scope.
The following table describes the supported scopes:
Table 3. Bean scopes
Scope Description
singleton (Default) Scopes a single bean definition to a single object instance for each
Spring IoC container.
prototype Scopes a single bean definition to any number of object instances.
Scope Description
request Scopes a single bean definition to the lifecycle of a single HTTP request. That
is, each HTTP request has its own instance of a bean created off the back of a
single bean definition. Only valid in the context of a web-aware Spring
ApplicationContext.
session Scopes a single bean definition to the lifecycle of an HTTP Session. Only valid
in the context of a web-aware Spring ApplicationContext.
application Scopes a single bean definition to the lifecycle of a ServletContext. Only valid
in the context of a web-aware Spring ApplicationContext.
websocket Scopes a single bean definition to the lifecycle of a WebSocket. Only valid in the
context of a web-aware Spring ApplicationContext.
As of Spring 3.0, a thread scope is available but is not registered by default. For
more information, see the documentation for SimpleThreadScope. For instructions
on how to register this or any other custom scope, see Using a Custom Scope.
The Singleton Scope
Only one shared instance of a singleton bean is managed, and all requests for beans with an ID or
IDs that match that bean definition result in that one specific bean instance being returned by the
Spring container.
To put it another way, when you define a bean definition and it is scoped as a singleton, the Spring
IoC container creates exactly one instance of the object defined by that bean definition. This single
instance is stored in a cache of such singleton beans, and all subsequent requests and references
for that named bean return the cached object. The following image shows how the singleton scope
works:
Spring’s concept of a singleton bean differs from the singleton pattern as defined in the Gang of
Four (GoF) patterns book. The GoF singleton hard-codes the scope of an object such that one and
only one instance of a particular class is created per ClassLoader. The scope of the Spring singleton
is best described as being per-container and per-bean. This means that, if you define one bean for a
particular class in a single Spring container, the Spring container creates one and only one instance
of the class defined by that bean definition. The singleton scope is the default scope in Spring. To
define a bean as a singleton in XML, you can define a bean as shown in the following example:
The Prototype Scope
The non-singleton prototype scope of bean deployment results in the creation of a new bean
instance every time a request for that specific bean is made. That is, the bean is injected into
another bean or you request it through a getBean() method call on the container. As a rule, you
should use the prototype scope for all stateful beans and the singleton scope for stateless beans.
The following diagram illustrates the Spring prototype scope:
(A data access object (DAO) is not typically configured as a prototype, because a typical DAO does
not hold any conversational state. It was easier for us to reuse the core of the singleton diagram.)
The following example defines a bean as a prototype in XML:
In contrast to the other scopes, Spring does not manage the complete lifecycle of a prototype bean.
The container instantiates, configures, and otherwise assembles a prototype object and hands it to
the client, with no further record of that prototype instance. Thus, although initialization lifecycle
callback methods are called on all objects regardless of scope, in the case of prototypes, configured
destruction lifecycle callbacks are not called. The client code must clean up prototype-scoped
objects and release expensive resources that the prototype beans hold. To get the Spring container
to release resources held by prototype-scoped beans, try using a custom bean post-processor, which
holds a reference to beans that need to be cleaned up.
In some respects, the Spring container’s role in regard to a prototype-scoped bean is a replacement
for the Java new operator. All lifecycle management past that point must be handled by the client.
(For details on the lifecycle of a bean in the Spring container, see Lifecycle Callbacks.)
Singleton Beans with Prototype-bean Dependencies
When you use singleton-scoped beans with dependencies on prototype beans, be aware that
dependencies are resolved at instantiation time. Thus, if you dependency-inject a prototype-scoped
bean into a singleton-scoped bean, a new prototype bean is instantiated and then dependency-
injected into the singleton bean. The prototype instance is the sole instance that is ever supplied to
the singleton-scoped bean.
However, suppose you want the singleton-scoped bean to acquire a new instance of the prototype-
scoped bean repeatedly at runtime. You cannot dependency-inject a prototype-scoped bean into
your singleton bean, because that injection occurs only once, when the Spring container
instantiates the singleton bean and resolves and injects its dependencies. If you need a new
instance of a prototype bean at runtime more than once, see Method Injection.
Request, Session, Application, and WebSocket Scopes
The request, session, application, and websocket scopes are available only if you use a web-aware
Spring ApplicationContext implementation (such as XmlWebApplicationContext). If you use these
scopes with regular Spring IoC containers, such as the ClassPathXmlApplicationContext, an
IllegalStateException that complains about an unknown bean scope is thrown.
Initial Web Configuration
To support the scoping of beans at the request, session, application, and websocket levels (web-
scoped beans), some minor initial configuration is required before you define your beans. (This
initial setup is not required for the standard scopes: singleton and prototype.)
How you accomplish this initial setup depends on your particular Servlet environment.
If you access scoped beans within Spring Web MVC, in effect, within a request that is processed by
the Spring DispatcherServlet, no special setup is necessary. DispatcherServlet already exposes all
relevant state.
If you use a Servlet web container, with requests processed outside of Spring’s DispatcherServlet
(for example, when using JSF or Struts), you need to register the
org.springframework.web.context.request.RequestContextListener ServletRequestListener. This can
be done programmatically by using the WebApplicationInitializer interface. Alternatively, add the
following declaration to your web application’s web.xml file:
<web-app>
...
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
...
</web-app>
Alternatively, if there are issues with your listener setup, consider using Spring’s
RequestContextFilter. The filter mapping depends on the surrounding web application
configuration, so you have to change it as appropriate. The following listing shows the filter part of
a web application:
<web-app>
...
<filter>
<filter-name>requestContextFilter</filter-name>
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-
class>
</filter>
<filter-mapping>
<filter-name>requestContextFilter</filter-name>
/*
</filter-mapping>
...
</web-app>
DispatcherServlet, RequestContextListener, and RequestContextFilter all do exactly the same thing,
namely bind the HTTP request object to the Thread that is servicing that request. This makes beans
that are request- and session-scoped available further down the call chain.
Request scope
Consider the following XML configuration for a bean definition:
The Spring container creates a new instance of the LoginAction bean by using the loginAction bean
definition for each and every HTTP request. That is, the loginAction bean is scoped at the HTTP
request level. You can change the internal state of the instance that is created as much as you want,
because other instances created from the same loginAction bean definition do not see these
changes in state. They are particular to an individual request. When the request completes
processing, the bean that is scoped to the request is discarded.
When using annotation-driven components or Java configuration, the @RequestScope annotation can
be used to assign a component to the request scope. The following example shows how to do so:
Java
@RequestScope
@Component
public class LoginAction {
// ...
}
Kotlin
@RequestScope
@Component
class LoginAction {
// ...
}
Session Scope
Consider the following XML configuration for a bean definition:
The Spring container creates a new instance of the UserPreferences bean by using the
userPreferences bean definition for the lifetime of a single HTTP Session. In other words, the
userPreferences bean is effectively scoped at the HTTP Session level. As with request-scoped beans,
you can change the internal state of the instance that is created as much as you want, knowing that
other HTTP Session instances that are also using instances created from the same userPreferences
bean definition do not see these changes in state, because they are particular to an individual HTTP
Session. When the HTTP Session is eventually discarded, the bean that is scoped to that particular
HTTP Session is also discarded.
When using annotation-driven components or Java configuration, you can use the @SessionScope
annotation to assign a component to the session scope.
Java
@SessionScope
@Component
public class UserPreferences {
// ...
}
Kotlin
@SessionScope
@Component
class UserPreferences {
// ...
}
Application Scope
Consider the following XML configuration for a bean definition:
The Spring container creates a new instance of the AppPreferences bean by using the appPreferences
bean definition once for the entire web application. That is, the appPreferences bean is scoped at the
ServletContext level and stored as a regular ServletContext attribute. This is somewhat similar to a
Spring singleton bean but differs in two important ways: It is a singleton per ServletContext, not per
Spring ApplicationContext (for which there may be several in any given web application), and it is
actually exposed and therefore visible as a ServletContext attribute.
When using annotation-driven components or Java configuration, you can use the
@ApplicationScope annotation to assign a component to the application scope. The following
example shows how to do so:
Java
@ApplicationScope
@Component
public class AppPreferences {
// ...
}
Kotlin
@ApplicationScope
@Component
class AppPreferences {
// ...
}
WebSocket Scope
WebSocket scope is associated with the lifecycle of a WebSocket session and applies to STOMP over
WebSocket applications, see WebSocket scope for more details.
Scoped Beans as Dependencies
The Spring IoC container manages not only the instantiation of your objects (beans), but also the
wiring up of collaborators (or dependencies). If you want to inject (for example) an HTTP request-
scoped bean into another bean of a longer-lived scope, you may choose to inject an AOP proxy in
place of the scoped bean. That is, you need to inject a proxy object that exposes the same public
interface as the scoped object but that can also retrieve the real target object from the relevant
scope (such as an HTTP request) and delegate method calls onto the real object.
You may also use <aop:scoped-proxy/> between beans that are scoped as singleton,
with the reference then going through an intermediate proxy that is serializable
and therefore able to re-obtain the target singleton bean on deserialization.
When declaring <aop:scoped-proxy/> against a bean of scope prototype, every
method call on the shared proxy leads to the creation of a new target instance to
which the call is then being forwarded.
Also, scoped proxies are not the only way to access beans from shorter scopes in a
lifecycle-safe fashion. You may also declare your injection point (that is, the
constructor or setter argument or autowired field) as ObjectFactory<MyTargetBean>,
allowing for a getObject() call to retrieve the current instance on demand every
time it is needed — without holding on to the instance or storing it separately.
As an extended variant, you may declare ObjectProvider<MyTargetBean> which
delivers several additional access variants, including getIfAvailable and
getIfUnique.
The JSR-330 variant of this is called Provider and is used with a
Provider<MyTargetBean> declaration and a corresponding get() call for every
retrieval attempt. See here for more details on JSR-330 overall.
The configuration in the following example is only one line, but it is important to understand the
“why” as well as the “how” behind it:
<?xml version="1.0" encoding="UTF-8"?>
<aop:scoped-proxy/> ①
① The line that defines the proxy.
To create such a proxy, you insert a child <aop:scoped-proxy/> element into a scoped bean definition
(see Choosing the Type of Proxy to Create and XML Schema-based configuration). Why do
definitions of beans scoped at the request, session and custom-scope levels require the <aop:scoped-
proxy/> element? Consider the following singleton bean definition and contrast it with what you
need to define for the aforementioned scopes (note that the following userPreferences bean
definition as it stands is incomplete):
In the preceding example, the singleton bean (userManager) is injected with a reference to the HTTP
Session-scoped bean (userPreferences). The salient point here is that the userManager bean is a
singleton: it is instantiated exactly once per container, and its dependencies (in this case only one,
the userPreferences bean) are also injected only once. This means that the userManager bean
operates only on the exact same userPreferences object (that is, the one with which it was originally
injected).
This is not the behavior you want when injecting a shorter-lived scoped bean into a longer-lived
scoped bean (for example, injecting an HTTP Session-scoped collaborating bean as a dependency
into singleton bean). Rather, you need a single userManager object, and, for the lifetime of an HTTP
Session, you need a userPreferences object that is specific to the HTTP Session. Thus, the container
creates an object that exposes the exact same public interface as the UserPreferences class (ideally
an object that is a UserPreferences instance), which can fetch the real UserPreferences object from
the scoping mechanism (HTTP request, Session, and so forth). The container injects this proxy
object into the userManager bean, which is unaware that this UserPreferences reference is a proxy. In
this example, when a UserManager instance invokes a method on the dependency-injected
UserPreferences object, it is actually invoking a method on the proxy. The proxy then fetches the
real UserPreferences object from (in this case) the HTTP Session and delegates the method
invocation onto the retrieved real UserPreferences object.
Thus, you need the following (correct and complete) configuration when injecting request- and
session-scoped beans into collaborating objects, as the following example shows:
<aop:scoped-proxy/>
Choosing the Type of Proxy to Create
By default, when the Spring container creates a proxy for a bean that is marked up with the
<aop:scoped-proxy/> element, a CGLIB-based class proxy is created.
CGLIB proxies intercept only public method calls! Do not call non-public methods
on such a proxy. They are not delegated to the actual scoped target object.
Alternatively, you can configure the Spring container to create standard JDK interface-based
proxies for such scoped beans, by specifying false for the value of the proxy-target-class attribute
of the <aop:scoped-proxy/> element. Using JDK interface-based proxies means that you do not need
additional libraries in your application classpath to affect such proxying. However, it also means
that the class of the scoped bean must implement at least one interface and that all collaborators
into which the scoped bean is injected must reference the bean through one of its interfaces. The
following example shows a proxy based on an interface:
<aop:scoped-proxy proxy-target-class="false"/>
For more detailed information about choosing class-based or interface-based proxying, see
Proxying Mechanisms.
Custom Scopes
The bean scoping mechanism is extensible. You can define your own scopes or even redefine
existing scopes, although the latter is considered bad practice and you cannot override the built-in
singleton and prototype scopes.
Creating a Custom Scope
To integrate your custom scopes into the Spring container, you need to implement the
org.springframework.beans.factory.config.Scope interface, which is described in this section. For an
idea of how to implement your own scopes, see the Scope implementations that are supplied with
the Spring Framework itself and the Scope javadoc, which explains the methods you need to
implement in more detail.
The Scope interface has four methods to get objects from the scope, remove them from the scope,
and let them be destroyed.
The session scope implementation, for example, returns the session-scoped bean (if it does not
exist, the method returns a new instance of the bean, after having bound it to the session for future
reference). The following method returns the object from the underlying scope:
Java
Object get(String name, ObjectFactory<?> objectFactory)
Kotlin
fun get(name: String, objectFactory: ObjectFactory<*>): Any
The session scope implementation, for example, removes the session-scoped bean from the
underlying session. The object should be returned, but you can return null if the object with the
specified name is not found. The following method removes the object from the underlying scope:
Java
Object remove(String name)
Kotlin
fun remove(name: String): Any
The following method registers a callback that the scope should invoke when it is destroyed or
when the specified object in the scope is destroyed:
Java
void registerDestructionCallback(String name, Runnable destructionCallback)
Kotlin
fun registerDestructionCallback(name: String, destructionCallback: Runnable)
See the javadoc or a Spring scope implementation for more information on destruction callbacks.
The following method obtains the conversation identifier for the underlying scope:
Java
String getConversationId()
Kotlin
fun getConversationId(): String
This identifier is different for each scope. For a session scoped implementation, this identifier can
be the session identifier.
Using a Custom Scope
After you write and test one or more custom Scope implementations, you need to make the Spring
container aware of your new scopes. The following method is the central method to register a new
Scope with the Spring container:
Java
void registerScope(String scopeName, Scope scope);
Kotlin
fun registerScope(scopeName: String, scope: Scope)
This method is declared on the ConfigurableBeanFactory interface, which is available through the
BeanFactory property on most of the concrete ApplicationContext implementations that ship with
Spring.
The first argument to the registerScope(..) method is the unique name associated with a scope.
Examples of such names in the Spring container itself are singleton and prototype. The second
argument to the registerScope(..) method is an actual instance of the custom Scope
implementation that you wish to register and use.
Suppose that you write your custom Scope implementation, and then register it as shown in the
next example.
The next example uses SimpleThreadScope, which is included with Spring but is not
registered by default. The instructions would be the same for your own custom
Scope implementations.
Java
Scope threadScope = new SimpleThreadScope();
beanFactory.registerScope("thread", threadScope);
Kotlin
val threadScope = SimpleThreadScope()
beanFactory.registerScope("thread", threadScope)
You can then create bean definitions that adhere to the scoping rules of your custom Scope, as
follows:
With a custom Scope implementation, you are not limited to programmatic registration of the scope.
You can also do the Scope registration declaratively, by using the CustomScopeConfigurer class, as the
following example shows:
<?xml version="1.0" encoding="UTF-8"?>
<map>
<entry key="thread">
</entry>
</map>
<aop:scoped-proxy/>
When you place <aop:scoped-proxy/> within a declaration for a FactoryBean
implementation, it is the factory bean itself that is scoped, not the object returned
from getObject().
2.1.6. Customizing the Nature of a Bean
The Spring Framework provides a number of interfaces you can use to customize the nature of a
bean. This section groups them as follows:
• Lifecycle Callbacks
• ApplicationContextAware and BeanNameAware
• Other Aware Interfaces
Lifecycle Callbacks
To interact with the container’s management of the bean lifecycle, you can implement the Spring
InitializingBean and DisposableBean interfaces. The container calls afterPropertiesSet() for the
former and destroy() for the latter to let the bean perform certain actions upon initialization and
destruction of your beans.
The JSR-250 @PostConstruct and @PreDestroy annotations are generally considered
best practice for receiving lifecycle callbacks in a modern Spring application. Using
these annotations means that your beans are not coupled to Spring-specific
interfaces. For details, see Using @PostConstruct and @PreDestroy.
If you do not want to use the JSR-250 annotations but you still want to remove
coupling, consider init-method and destroy-method bean definition metadata.
Internally, the Spring Framework uses BeanPostProcessor implementations to process any callback
interfaces it can find and call the appropriate methods. If you need custom features or other
lifecycle behavior Spring does not by default offer, you can implement a BeanPostProcessor yourself.
For more information, see Container Extension Points.
In addition to the initialization and destruction callbacks, Spring-managed objects may also
implement the Lifecycle interface so that those objects can participate in the startup and shutdown
process, as driven by the container’s own lifecycle.
The lifecycle callback interfaces are described in this section.
Initialization Callbacks
The org.springframework.beans.factory.InitializingBean interface lets a bean perform
initialization work after the container has set all necessary properties on the bean. The
InitializingBean interface specifies a single method:
void afterPropertiesSet() throws Exception;
We recommend that you do not use the InitializingBean interface, because it unnecessarily couples
the code to Spring. Alternatively, we suggest using the @PostConstruct annotation or specifying a
POJO initialization method. In the case of XML-based configuration metadata, you can use the init-
method attribute to specify the name of the method that has a void no-argument signature. With
Java configuration, you can use the initMethod attribute of @Bean. See Receiving Lifecycle Callbacks.
Consider the following example:
Java
public class ExampleBean {
public void init() {
// do some initialization work
}
}
Kotlin
class ExampleBean {
fun init() {
// do some initialization work
}
}
The preceding example has almost exactly the same effect as the following example (which consists
of two listings):
Java
public class AnotherExampleBean implements InitializingBean {
@Override
public void afterPropertiesSet() {
// do some initialization work
}
}
Kotlin
class AnotherExampleBean : InitializingBean {
override fun afterPropertiesSet() {
// do some initialization work
}
}
However, the first of the two preceding examples does not couple the code to Spring.
Destruction Callbacks
Implementing the org.springframework.beans.factory.DisposableBean interface lets a bean get a
callback when the container that contains it is destroyed. The DisposableBean interface specifies a
single method:
void destroy() throws Exception;
We recommend that you do not use the DisposableBean callback interface, because it unnecessarily
couples the code to Spring. Alternatively, we suggest using the @PreDestroy annotation or specifying
a generic method that is supported by bean definitions. With XML-based configuration metadata,
you can use the destroy-method attribute on the . With Java configuration, you can use the
destroyMethod attribute of @Bean. See Receiving Lifecycle Callbacks. Consider the following
definition:
Java
public class ExampleBean {
public void cleanup() {
// do some destruction work (like releasing pooled connections)
}
}
Kotlin
class ExampleBean {
fun cleanup() {
// do some destruction work (like releasing pooled connections)
}
}
The preceding definition has almost exactly the same effect as the following definition:
Java
public class AnotherExampleBean implements DisposableBean {
@Override
public void destroy() {
// do some destruction work (like releasing pooled connections)
}
}
Kotlin
class AnotherExampleBean : DisposableBean {
override fun destroy() {
// do some destruction work (like releasing pooled connections)
}
}
However, the first of the two preceding definitions does not couple the code to Spring.
You can assign the destroy-method attribute of a element a special (inferred)
value, which instructs Spring to automatically detect a public close or shutdown
method on the specific bean class. (Any class that implements
java.lang.AutoCloseable or java.io.Closeable would therefore match.) You can
also set this special (inferred) value on the default-destroy-method attribute of a
element to apply this behavior to an entire set of beans (see Default
Initialization and Destroy Methods). Note that this is the default behavior with Java
configuration.
Default Initialization and Destroy Methods
When you write initialization and destroy method callbacks that do not use the Spring-specific
InitializingBean and DisposableBean callback interfaces, you typically write methods with names
such as init(), initialize(), dispose(), and so on. Ideally, the names of such lifecycle callback
methods are standardized across a project so that all developers use the same method names and
ensure consistency.
You can configure the Spring container to “look” for named initialization and destroy callback
method names on every bean. This means that you, as an application developer, can write your
application classes and use an initialization callback called init(), without having to configure an
init-method="init" attribute with each bean definition. The Spring IoC container calls that method
when the bean is created (and in accordance with the standard lifecycle callback contract described
previously). This feature also enforces a consistent naming convention for initialization and destroy
method callbacks.
Suppose that your initialization callback methods are named init() and your destroy callback
methods are named destroy(). Your class then resembles the class in the following example:
Java
public class DefaultBlogService implements BlogService {
private BlogDao blogDao;
public void setBlogDao(BlogDao blogDao) {
this.blogDao = blogDao;
}
// this is (unsurprisingly) the initialization callback method
public void init() {
if (this.blogDao == null) {
throw new IllegalStateException("The [blogDao] property must be set.");
}
}
}
Kotlin
class DefaultBlogService : BlogService {
private var blogDao: BlogDao? = null
// this is (unsurprisingly) the initialization callback method
fun init() {
if (blogDao == null) {
throw IllegalStateException("The [blogDao] property must be set.")
}
}
}
You could then use that class in a bean resembling the following:
The presence of the default-init-method attribute on the top-level element attribute causes
the Spring IoC container to recognize a method called init on the bean class as the initialization
method callback. When a bean is created and assembled, if the bean class has such a method, it is
invoked at the appropriate time.
You can configure destroy method callbacks similarly (in XML, that is) by using the default-
destroy-method attribute on the top-level element.
Where existing bean classes already have callback methods that are named at variance with the
convention, you can override the default by specifying (in XML, that is) the method name by using
the init-method and destroy-method attributes of the itself.
The Spring container guarantees that a configured initialization callback is called immediately after
a bean is supplied with all dependencies. Thus, the initialization callback is called on the raw bean
reference, which means that AOP interceptors and so forth are not yet applied to the bean. A target
bean is fully created first and then an AOP proxy (for example) with its interceptor chain is applied.
If the target bean and the proxy are defined separately, your code can even interact with the raw
target bean, bypassing the proxy. Hence, it would be inconsistent to apply the interceptors to the
init method, because doing so would couple the lifecycle of the target bean to its proxy or
interceptors and leave strange semantics when your code interacts directly with the raw target
bean.
Models/Spring Ai Openai/Src/Test/Resources/Data/Acme/Bikes.Json (models/spring-ai-openai/src/test/resources/data/acme/bikes.json)
[
{
"name": "E-Adrenaline 8.0 EX1",
"shortDescription": "a versatile and comfortable e-MTB designed for adrenaline enthusiasts who want to explore all types of terrain. It features a powerful motor and advanced suspension to provide a smooth and responsive ride, with a variety of customizable settings to fit any rider's needs.",
"description": "## Overview\r\nIt's right for you if...\r\nYou want to push your limits on challenging trails and terrain, with the added benefit of an electric assist to help you conquer steep climbs and rough terrain. You also want a bike with a comfortable and customizable fit, loaded with high-quality components and technology.\r\n\r\nThe tech you get\r\nA lightweight, full ADV Mountain Carbon frame with a customizable geometry, including an adjustable head tube and chainstay length. A powerful and efficient motor with a 375Wh battery that can assist up to 28 mph when it's on, and provides a smooth and seamless transition when it's off. A SRAM EX1 8-speed drivetrain, a RockShox Lyrik Ultimate fork, and a RockShox Super Deluxe Ultimate rear shock.\r\n\r\nThe final word\r\nOur E-Adrenaline 8.0 EX1 is the perfect bike for adrenaline enthusiasts who want to explore all types of terrain. It's versatile, comfortable, and loaded with advanced technology to provide a smooth and responsive ride, no matter where your adventures take you.\r\n\r\n\r\n## Features\r\nVersatile and customizable\r\nThe E-Adrenaline 8.0 EX1 features a customizable geometry, including an adjustable head tube and chainstay length, so you can fine-tune your ride to fit your needs and preferences. It also features a variety of customizable settings, including suspension tuning, motor assistance levels, and more.\r\n\r\nPowerful and efficient\r\nThe bike is equipped with a powerful and efficient motor that provides a smooth and seamless transition between human power and electric assist. It can assist up to 28 mph when it's on, and provides zero drag when it's off.\r\n\r\nAdvanced suspension\r\nThe E-Adrenaline 8.0 EX1 features a RockShox Lyrik Ultimate fork and a RockShox Super Deluxe Ultimate rear shock, providing advanced suspension technology to absorb shocks and bumps on any terrain. The suspension is also customizable to fit your riding style and preferences.\r\n\r\n\r\n## Specs\r\nFrameset\r\nFrame ADV Mountain Carbon main frame & stays, adjustable head tube and chainstay length, tapered head tube, Knock Block, Control Freak internal routing, Boost148, 150mm travel\r\nFork RockShox Lyrik Ultimate, DebonAir spring, Charger 2.1 RC2 damper, remote lockout, tapered steerer, 42mm offset, Boost110, 15mm Maxle Stealth, 160mm travel\r\nShock RockShox Super Deluxe Ultimate, DebonAir spring, Thru Shaft 3-position damper, 230x57.5mm\r\n\r\nWheels\r\nWheel front Bontrager Line Elite 30, ADV Mountain Carbon, Tubeless Ready, 6-bolt, Boost110, 15mm thru axle\r\nWheel rear Bontrager Line Elite 30, ADV Mountain Carbon, Tubeless Ready, 54T Rapid Drive, 6-bolt, Shimano MicroSpline freehub, Boost148, 12mm thru axle\r\nSkewer rear Bontrager Switch thru axle, removable lever\r\nTire Bontrager XR5 Team Issue, Tubeless Ready, Inner Strength sidewall, aramid bead, 120tpi, 29x2.50''\r\nTire part Bontrager TLR sealant, 6oz\r\n\r\nDrivetrain\r\nShifter SRAM EX1, 8 speed\r\nRear derailleur SRAM EX1, 8 speed\r\nCrank Bosch Performance CX, magnesium motor body, 250 watt, 75 Nm torque\r\nChainring SRAM EX1, 18T, steel\r\nCassette SRAM EX1, 11-48, 8 speed\r\nChain SRAM EX1, 8 speed\r\n\r\nComponents\r\nSaddle Bontrager Arvada, hollow chromoly rails, 138mm width\r\nSeatpost Bontrager Line Elite Dropper, internal routing, 31.6mm\r\nHandlebar Bontrager Line Pro, ADV Carbon, 35mm, 27.5mm rise, 780mm width\r\nGrips Bontrager XR Trail Elite, alloy lock-on\r\nStem Bontrager Line Pro, 35mm, Knock Block, Blendr compatible, 0 degree, 50mm length\r\nHeadset Knock Block Integrated, 62-degree radius, cartridge bearing, 1-1\/8'' top, 1.5'' bottom\r\nBrake SRAM G2 RSC hydraulic disc, carbon levers\r\nBrake rotor SRAM Centerline, centerlock, round edge, 200mm\r\n\r\nAccessories\r\nE-bike system Bosch Performance CX, magnesium motor body, 250 watt, 75 Nm torque\r\nBattery Bosch PowerTube 625, 625Wh\r\nCharger Bosch 4A standard charger\r\nController Bosch Kiox with Anti-theft solution, Bluetooth connectivity, 1.9'' display\r\nTool Bontrager Switch thru axle, removable lever\r\n\r\nWeight\r\nWeight M - 20.25 kg \/ 44.6 lbs (with TLR sealant, no tubes)\r\nWeight limit This bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\r\n\r\n## Sizing & fit\r\n\r\n| Size | Rider Height | Inseam |\r\n|:----:|:------------------------:|:--------------------:|\r\n| S | 155 - 170 cm 5'1\" - 5'7\" | 73 - 80 cm 29\" - 31.5\" |\r\n| M | 163 - 178 cm 5'4\" - 5'10\" | 77 - 83 cm 30.5\" - 32.5\" |\r\n| L | 176 - 191 cm 5'9\" - 6'3\" | 83 - 89 cm 32.5\" - 35\" |\r\n| XL | 188 - 198 cm 6'2\" - 6'6\" | 88 - 93 cm 34.5\" - 36.5\" |\r\n\r\n\r\n## Geometry\r\n\r\nAll measurements provided in cm unless otherwise noted.\r\nSizing table\r\n| Frame size letter | S | M | L | XL |\r\n|---------------------------|-------|-------|-------|-------|\r\n| Actual frame size | 15.8 | 17.8 | 19.8 | 21.8 |\r\n| Wheel size | 29\" | 29\" | 29\" | 29\" |\r\n| A \u2014 Seat tube | 40.0 | 42.5 | 47.5 | 51.0 |\r\n| B \u2014 Seat tube angle | 72.5\u00B0 | 72.8\u00B0 | 73.0\u00B0 | 73.0\u00B0 |\r\n| C \u2014 Head tube length | 9.5 | 10.5 | 11.0 | 11.5 |\r\n| D \u2014 Head angle | 67.8\u00B0 | 67.8\u00B0 | 67.8\u00B0 | 67.8\u00B0 |\r\n| E \u2014 Effective top tube | 59.0 | 62.0 | 65.0 | 68.0 |\r\n| F \u2014 Bottom bracket height | 32.5 | 32.5 | 32.5 | 32.5 |\r\n| G \u2014 Bottom bracket drop | 5.5 | 5.5 | 5.5 | 5.5 |\r\n| H \u2014 Chainstay length | 45.0 | 45.0 | 45.0 | 45.0 |\r\n| I \u2014 Offset | 4.5 | 4.5 | 4.5 | 4.5 |\r\n| J \u2014 Trail | 11.0 | 11.0 | 11.0 | 11.0 |\r\n| K \u2014 Wheelbase | 113.0 | 117.0 | 120.0 | 123.0 |\r\n| L \u2014 Standover | 77.0 | 77.0 | 77.0 | 77.0 |\r\n| M \u2014 Frame reach | 41.0 | 44.5 | 47.5 | 50.0 |\r\n| N \u2014 Frame stack | 61.0 | 62.0 | 62.5 | 63.0 |",
"price": 1499.99,
"tags": [
"bicycle"
]
},
{
"name": "Enduro X Pro",
"shortDescription": "The Enduro X Pro is the ultimate mountain bike for riders who demand the best. With its full carbon frame and top-of-the-line components, this bike is ready to tackle any trail, from technical downhill descents to grueling uphill climbs.",
"text": "## Overview\nIt's right for you if...\nYou're an experienced mountain biker who wants a high-performance bike that can handle any terrain. You want a bike with the best components available, including a full carbon frame, suspension system, and hydraulic disc brakes.\n\nThe tech you get\nOur top-of-the-line full carbon frame with aggressive geometry and a slack head angle for maximum control. It's equipped with a Fox Factory suspension system with 170mm of travel in the front and 160mm in the rear, a Shimano XTR 12-speed drivetrain, and hydraulic disc brakes for maximum stopping power. The bike also features a dropper seatpost for easy adjustments on the fly.\n\nThe final word\nThe Enduro X Pro is the ultimate mountain bike for riders who demand the best. With its full carbon frame, top-of-the-line components, and aggressive geometry, this bike is ready to take on any trail. Whether you're a seasoned pro or just starting out, the Enduro X Pro will help you take your riding to the next level.\n\n## Features\nFull carbon frame\nAggressive geometry with a slack head angle\nFox Factory suspension system with 170mm of travel in the front and 160mm in the rear\nShimano XTR 12-speed drivetrain\nHydraulic disc brakes for maximum stopping power\nDropper seatpost for easy adjustments on the fly\n\n## Specifications\nFrameset\nFrame\tFull carbon frame\nFork\tFox Factory suspension system with 170mm of travel\nRear suspension\tFox Factory suspension system with 160mm of travel\n\nWheels\nWheel size\t27.5\" or 29\"\nTires\tTubeless-ready Maxxis tires\n\nDrivetrain\nShifters\tShimano XTR 12-speed\nFront derailleur\tN/A\nRear derailleur\tShimano XTR\nCrankset\tShimano XTR\nCassette\tShimano XTR 12-speed\nChain\tShimano XTR\n\nComponents\nBrakes\tHydraulic disc brakes\nHandlebar\tAlloy handlebar\nStem\tAlloy stem\nSeatpost\tDropper seatpost\n\nAccessories\nPedals\tNot included\n\nWeight\nWeight\tApproximately 27-29 lbs\n\n## Sizing\n| Size | Rider Height |\n|:----:|:-------------------------:|\n| S | 5'4\" - 5'8\" (162-172cm) |\n| M | 5'8\" - 5'11\" (172-180cm) |\n| L | 5'11\" - 6'3\" (180-191cm) |\n| XL | 6'3\" - 6'6\" (191-198cm) |\n\n## Geometry\n| Size | S | M | L | XL |\n|:----:|:---------------:|:---------------:|:-----------------:|:---------------:|\n| A - Seat tube length | 390mm | 425mm | 460mm | 495mm |\n| B - Effective top tube length | 585mm | 610mm | 635mm | 660mm |\n| C - Head tube angle | 65.5° | 65.5° | 65.5° | 65.5° |\n| D - Seat tube angle | 76° | 76° | 76° | 76° |\n| E - Chainstay length | 435mm | 435mm | 435mm | 435mm |\n| F - Head tube length | 100mm | 110mm | 120mm | 130mm |\n| G - BB drop | 20mm | 20mm | 20mm | 20mm |\n| H - Wheelbase | 1155mm | 1180mm | 1205mm | 1230mm |\n| I - Standover height | 780mm | 800mm | 820mm | 840mm |\n| J - Reach | 425mm | 450mm | 475mm | 500mm |\n| K - Stack | 610mm | 620mm | 630mm | 640mm |",
"price": 599.99,
"tags": [
"bicycle"
]
},
{
"name": "Blaze X1",
"shortDescription": "Blaze X1 is a high-performance road bike that offers superior speed and agility, making it perfect for competitive racing or fast-paced group rides. The bike features a lightweight carbon frame, aerodynamic tube shapes, a 12-speed Shimano Ultegra drivetrain, and hydraulic disc brakes for precise stopping power. With its sleek design and cutting-edge technology, Blaze X1 is a bike that is built to perform and dominate on any road.",
"description": "## Overview\nIt's right for you if...\nYou're a competitive road cyclist or an enthusiast who enjoys fast-paced group rides. You want a bike that is lightweight, agile, and delivers exceptional speed.\n\nThe tech you get\nBlaze X1 features a lightweight carbon frame with a tapered head tube and aerodynamic tube shapes for maximum speed and efficiency. The bike is equipped with a 12-speed Shimano Ultegra drivetrain for smooth and precise shifting, Shimano hydraulic disc brakes for powerful and reliable stopping power, and Bontrager Aeolus Elite 35 carbon wheels for increased speed and agility.\n\nThe final word\nBlaze X1 is a high-performance road bike that is designed to deliver exceptional speed and agility. With its cutting-edge technology and top-of-the-line components, it's a bike that is built to perform and dominate on any road.\n\n## Features\nSpeed and efficiency\nBlaze X1's lightweight carbon frame and aerodynamic tube shapes offer maximum speed and efficiency, allowing you to ride faster and farther with ease.\n\nPrecision stopping power\nShimano hydraulic disc brakes provide precise and reliable stopping power, even in wet or muddy conditions.\n\nAgility and control\nBontrager Aeolus Elite 35 carbon wheels make Blaze X1 incredibly agile and responsive, allowing you to navigate tight turns and corners with ease.\n\nSmooth and precise shifting\nThe 12-speed Shimano Ultegra drivetrain offers smooth and precise shifting, so you can easily find the right gear for any terrain.\n\n## Specifications\nFrameset\nFrame\tADV Carbon, tapered head tube, BB90, direct mount rim brakes, internal cable routing, DuoTrap S compatible, 130x9mm QR\nFork\tADV Carbon, tapered steerer, direct mount rim brakes, internal brake routing, 100x9mm QR\n\nWheels\nWheel front\tBontrager Aeolus Elite 35, ADV Carbon, Tubeless Ready, 35mm rim depth, 100x9mm QR\nWheel rear\tBontrager Aeolus Elite 35, ADV Carbon, Tubeless Ready, 35mm rim depth, Shimano 11-speed freehub, 130x9mm QR\nTire front\tBontrager R3 Hard-Case Lite, aramid bead, 120 tpi, 700x25c\nTire rear\tBontrager R3 Hard-Case Lite, aramid bead, 120 tpi, 700x25c\nMax tire size\t25c Bontrager tires (with at least 4mm of clearance to frame)\n\nDrivetrain\nShifter\tShimano Ultegra R8020, 12 speed\nFront derailleur\tShimano Ultegra R8000, braze-on\nRear derailleur\tShimano Ultegra R8000, short cage, 30T max cog\nCrank\tSize: 50, 52, 54\nShimano Ultegra R8000, 50/34 (compact), 170mm length\nSize: 56, 58, 60, 62\nShimano Ultegra R8000, 50/34 (compact), 172.5mm length\nBottom bracket\tBB90, Shimano press-fit\nCassette\tShimano Ultegra R8000, 11-30, 12 speed\nChain\tShimano Ultegra HG701, 12 speed\n\nComponents\nSaddle\tBontrager Montrose Elite, titanium rails, 138mm width\nSeatpost\tBontrager carbon seatmast cap, 20mm offset\nHandlebar\tBontrager Elite Aero VR-CF, alloy, 31.8mm, internal cable routing, 40cm width\nGrips\tBontrager Supertack Perf tape\nStem\tBontrager Elite, 31.8mm, Blendr-compatible, 7 degree, 80mm length\nBrake Shimano Ultegra hydraulic disc brake\n\nWeight\nWeight\t56 - 8.91 kg / 19.63 lbs (with tubes)\nWeight limit\tThis bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 275 pounds (125 kg).\n\n## Sizing\n| Size | Rider height |\n|------|-------------|\n| 50 | 162-166cm |\n| 52 | 165-170cm |\n| 54 | 168-174cm |\n| 56 | 174-180cm |\n| 58 | 179-184cm |\n| 60 | 184-189cm |\n| 62 | 189-196cm |\n\n## Geometry\n| Frame size | 50cm | 52cm | 54cm | 56cm | 58cm | 60cm | 62cm |\n|------------|-------|-------|-------|-------|-------|-------|-------|\n| Wheel size | 700c | 700c | 700c | 700c | 700c | 700c | 700c |\n| A - Seat tube | 443mm | 460mm | 478mm | 500mm | 520mm | 540mm | 560mm |\n| B - Seat tube angle | 74.1° | 73.9° | 73.7° | 73.4° | 73.2° | 73.0° | 72.8° |\n| C - Head tube length | 100mm | 110mm | 130mm | 150mm | 170mm | 190mm | 210mm |\n| D - Head angle | 71.4° | 72.0° | 72.5° | 73.0° | 73.3° | 73.6° | 73.8° |\n| E - Effective top tube | 522mm | 535mm | 547mm | 562mm | 577mm | 593mm | 610mm |\n| F - Bottom bracket height | 268mm | 268mm | 268mm | 268mm | 268mm | 268mm | 268mm |\n| G - Bottom bracket drop | 69mm | 69mm | 69mm | 69mm | 69mm | 69mm | 69mm |\n| H - Chainstay length | 410mm | 410mm | 410mm | 410mm | 410mm | 410mm | 410mm |\n| I - Offset | 50mm | 50mm | 50mm | 50mm | 50mm | 50mm | 50mm |\n| J - Trail | 65mm | 62mm | 59mm | 56mm | 55mm | 53mm | 52mm |\n| K - Wheelbase | 983mm | 983mm | 990mm | 1005mm | 1019mm | 1036mm | 1055mm |\n| L - Standover | 741mm | 765mm | 787mm | 806mm | 825mm | 847mm | 869mm |",
"price": 799.99,
"tags": [
"bicycle",
"mountain bike"
]
},
{
"name": "Celerity X5",
"shortDescription": "Celerity X5 is a versatile and reliable road bike that is designed for experienced and amateur riders alike. It's designed to provide smooth and comfortable rides over long distances. With an ultra-lightweight and responsive carbon fiber frame, Shimano 105 groupset, hydraulic disc brakes, and 28mm wide tires, this bike ensures efficient power transfer, precise handling, and superior stopping power.",
"description": "## Overview\n\nIt's right for you if... \nYou are looking for a high-performance road bike that offers a perfect balance of speed, comfort, and control. You enjoy long-distance rides and need a bike that is designed to handle various road conditions with ease. You also appreciate the latest technology and reliable components that make your riding experience more enjoyable.\n\nThe tech you get \nCelerity X5 is equipped with a full carbon fiber frame that ensures maximum strength and durability while keeping the weight down. It features a Shimano 105 groupset with 11-speed gearing for precise and efficient shifting. Hydraulic disc brakes offer superior stopping power, and 28mm wide tires provide comfort and stability on various road surfaces. Internal cable routing enhances the bike's sleek appearance.\n\nThe final word \nIf you are looking for a high-performance road bike that offers comfort, speed, and control, Celerity X5 is the perfect choice. With its lightweight carbon fiber frame, reliable components, and advanced technology, this bike is designed to help you enjoy long-distance rides with ease.\n\n## Features \n\nLightweight and responsive \nCelerity X5 comes with a full carbon fiber frame that is not only lightweight but also responsive, providing excellent handling and control.\n\nHydraulic disc brakes \nThis bike is equipped with hydraulic disc brakes that provide superior stopping power in all weather conditions, ensuring your safety and confidence on the road.\n\nComfortable rides \nThe 28mm wide tires and carbon seat post provide ample cushioning, ensuring a smooth and comfortable ride over long distances.\n\nSleek appearance \nThe bike's internal cable routing enhances its sleek appearance while also protecting the cables from the elements, ensuring smooth shifting for longer periods.\n\n## Specifications \n\nFrameset \nFrame\tCelerity X5 Full Carbon Fiber Frame, Internal Cable Routing, Tapered Headtube, Press Fit Bottom Bracket, 12x142mm Thru-Axle \nFork\tCelerity X5 Full Carbon Fiber Fork, Internal Brake Routing, 12x100mm Thru-Axle \n\nWheels \nWheelset\tAlexRims CXD7 Wheelset \nTire\tSchwalbe Durano Plus 700x28mm \nInner Tubes\tSchwalbe SV15 700x18-28mm \nSkewers\tCelerity X5 Thru-Axle Skewers \n\nDrivetrain \nShifter\tShimano 105 R7025 Hydraulic Disc Shifters \nFront Derailleur\tShimano 105 R7000 \nRear Derailleur\tShimano 105 R7000 \nCrankset\tShimano 105 R7000 50-34T \nBottom Bracket\tShimano BB72-41B \nCassette\tShimano 105 R7000 11-30T \nChain\tShimano HG601 11-Speed Chain \n\nComponents \nSaddle\tSelle Royal Asphalt Saddle \nSeatpost\tCelerity X5 Carbon Seatpost \nHandlebar\tCelerity X5 Compact Handlebar \nStem\tCelerity X5 Aluminum Stem \nHeadset\tFSA Orbit IS-2 \n\nBrakes \nBrakes\tShimano 105 R7025 Hydraulic Disc Brakes \nRotors\tShimano SM-RT70 160mm Rotors \n\nAccessories \nPedals\tCelerity X5 Road Pedals \n\nWeight \nWeight\t8.2 kg / 18.1 lbs \nWeight Limit\tThis bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 120 kg (265 lbs).\n\n## Sizing \n| Size | Rider Height | Inseam |\n|:----:|:-------------------------:|:--------------------:|\n| 49 | 155 - 162 cm 5'1\" - 5'4\" | 71 - 76 cm 28\" - 30\" |\n| 52 | 162 - 170 cm 5'4\" - 5'7\" | 74 - 79 cm 29\" - 31\" |\n| 54 | 170 - 178 cm 5'7\" - 5'10\" | 77 - 83 cm 30\" - 32\" |\n| 56 | 178 - 185 cm 5'10\" - 6'1\" | 82 - 88 cm 32\" - 34\" |\n| 58 | 185 - 193 cm 6'1\" - 6'4\" | 86 - 92 cm 34\" - 36\" |\n| 61 | 193 - 200 cm 6'4\" - 6'7\" | 90 - 95 cm 35\" - 37\" |\n\n## Geometry \n| Frame size number | 49 cm | 52 cm | 54 cm | 56 cm | 58 cm | 61 cm |\n|---------------------------------------|-------|-------|-------|-------|-------|-------|\n| Wheel size | 700c | 700c | 700c | 700c | 700c | 700c |\n| A — Seat tube | 47.5 | 50.0 | 52.0 | 54.0 | 56.0 | 58.5 |\n| B — Seat tube angle | 75.0° | 74.5° | 74.0° | 73.5° | 73.0° | 72.5° |\n| C — Head tube length | 12.0 | 14.5 | 16.5 | 18.5 | 20.5 | 23.5 |\n| D — Head angle | 70.0° | 71.0° | 71.5° | 72.0° | 72.5° | 72.5° |\n| E — Effective top tube | 52.5 | 53.5 | 54.5 | 56.0 | 57.5 | 59.5 |\n| G — Bottom bracket drop | 7.0 | 7.0 | 7.0 | 7.0 | 7.0 | 7.0 |\n| H — Chainstay length | 41.5 | 41.5 | 41.5 | 41.5 | 41.5 | 41.5 |\n| K — Wheelbase | 98.4 | 98.9 | 99.8 | 100.8 | 101.7 | 103.6 |\n| L — Standover | 72.0 | 74.0 | 76.0 | 78.0 | 80.0 | 82.0 |\n| M — Frame reach | 36.2 | 36.8 | 37.3 | 38.1 | 38.6 | 39.4 |\n| N — Frame stack | 52.0 | 54.3 | 56.2 | 58.1 | 59.8 | 62.4 |\n| Saddle rail height min | 67.0 | 69.5 | 71.5 | 74.0 | 76.0 | 78.0 |\n| Saddle rail height max | 75.0 | 77.5 | 79.5 | 82.0 | 84.0 | 86.0 |",
"price": 399.99,
"tags": [
"bicycle",
"city bike"
]
},
{
"name": "Velocity V8",
"shortDescription": "Velocity V8 is a high-performance road bike that is designed to deliver speed, agility, and control on the road. With its lightweight aluminum frame, carbon fiber fork, Shimano Tiagra groupset, and hydraulic disc brakes, this bike is perfect for experienced riders who are looking for a fast and responsive bike that can handle various road conditions.",
"description": "## Overview\n\nIt's right for you if... \nYou are an experienced rider who is looking for a high-performance road bike that is lightweight, agile, and responsive. You want a bike that can handle long-distance rides, steep climbs, and fast descents with ease. You also appreciate the latest technology and reliable components that make your riding experience more enjoyable.\n\nThe tech you get \nVelocity V8 features a lightweight aluminum frame with a carbon fiber fork that ensures a comfortable ride without sacrificing stiffness and power transfer. It comes with a Shimano Tiagra groupset with 10-speed gearing for precise and efficient shifting. Hydraulic disc brakes offer superior stopping power in all weather conditions, while 28mm wide tires provide comfort and stability on various road surfaces. Internal cable routing enhances the bike's sleek appearance.\n\nThe final word \nIf you are looking for a high-performance road bike that is lightweight, fast, and responsive, Velocity V8 is the perfect choice. With its lightweight aluminum frame, reliable components, and advanced technology, this bike is designed to help you enjoy fast and comfortable rides on the road.\n\n## Features \n\nLightweight and responsive \nVelocity V8 comes with a lightweight aluminum frame that is not only lightweight but also responsive, providing excellent handling and control.\n\nHydraulic disc brakes \nThis bike is equipped with hydraulic disc brakes that provide superior stopping power in all weather conditions, ensuring your safety and confidence on the road.\n\nComfortable rides \nThe 28mm wide tires and carbon fork provide ample cushioning, ensuring a smooth and comfortable ride over long distances.\n\nSleek appearance \nThe bike's internal cable routing enhances its sleek appearance while also protecting the cables from the elements, ensuring smooth shifting for longer periods.\n\n## Specifications \n\nFrameset \nFrame\tVelocity V8 Aluminum Frame, Internal Cable Routing, Tapered Headtube, Press Fit Bottom Bracket, 12x142mm Thru-Axle \nFork\tVelocity V8 Carbon Fiber Fork, Internal Brake Routing, 12x100mm Thru-Axle \n\nWheels \nWheelset\tAlexRims CXD7 Wheelset \nTire\tSchwalbe Durano Plus 700x28mm \nInner Tubes\tSchwalbe SV15 700x18-28mm \nSkewers\tVelocity V8 Thru-Axle Skewers \n\nDrivetrain \nShifter\tShimano Tiagra Hydraulic Disc Shifters \nFront Derailleur\tShimano Tiagra \nRear Derailleur\tShimano Tiagra \nCrankset\tShimano Tiagra 50-34T \nBottom Bracket\tShimano BB-RS500-PB \nCassette\tShimano Tiagra 11-32T \nChain\tShimano HG54 10-Speed Chain \n\nComponents \nSaddle\tVelocity V8 Saddle \nSeatpost\tVelocity V8 Aluminum Seatpost \nHandlebar\tVelocity V8 Compact Handlebar \nStem\tVelocity V8 Aluminum Stem \nHeadset\tFSA Orbit IS-2 \n\nBrakes \nBrakes\tShimano Tiagra Hydraulic Disc Brakes \nRotors\tShimano SM-RT64 160mm Rotors \n\nAccessories \nPedals\tVelocity V8 Road Pedals \n\nWeight \nWeight\t9.4 kg / 20.7 lbs \nWeight Limit\tThis bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 120 kg (265 lbs).\n\n## Sizing \n| Size | Rider Height | Inseam |\n|:----:|:-------------------------:|:--------------------:|\n| 49 | 155 - 162 cm 5'1\" - 5'4\" | 71 - 76 cm 28\" - 30\" |\n| 52 | 162 - 170 cm 5'4\" - 5'7\" | 74 - 79 cm 29\" - 31\" |\n| 54 | 170 - 178 cm 5'7\" - 5'10\" | 77 - 83 cm 30\" - 32\" |\n| 56 | 178 - 185 cm 5'10\" - 6'1\" | 82 - 88 cm 32\" - 34\" |\n| 58 | 185 - 193 cm 6'1\" - 6'4\" | 86 - 92 cm 34\" - 36\" |\n| 61 | 193 - 200 cm 6'4\" - 6'7\" | 90 - 95 cm 35\" - 37\" |\n\n## Geometry \n| Frame size number | 49 cm | 52 cm | 54 cm | 56 cm | 58 cm | 61 cm |\n|---------------------------------------|-------|-------|-------|-------|-------|-------|\n| Wheel size | 700c | 700c | 700c | 700c | 700c | 700c |\n| A — Seat tube | 47.5 | 50.0 | 52.0 | 54.0 | 56.0 | 58.5 |\n| B — Seat tube angle | 75.0° | 74.5° | 74.0° | 73.5° | 73.0° | 72.5° |\n| C — Head tube length | 12.0 | 14.5 | 16.5 | 18.5 | 20.5 | 23.5 |\n| D — Head angle | 70.0° | 71.0° | 71.5° | 72.0° | 72.5° | 72.5° |\n| E — Effective top tube | 52.5 | 53.5 | 54.5 | 56.0 | 57.5 | 59.5 |\n| G — Bottom bracket drop | 7.0 | 7.0 | 7.0 | 7.0 | 7.0 | 7.0 |\n| H — Chainstay length | 41.5 | 41.5 | 41.5 | 41.5 | 41.5 | 41.5 |\n| K — Wheelbase | 98.4 | 98.9 | 99.8 | 100.8 | 101.7 | 103.6 |\n| L — Standover | 72.0 | 74.0 | 76.0 | 78.0 | 80.0 | 82.0 |\n| M — Frame reach | 36.2 | 36.8 | 37.3 | 38.1 | 38.6 | 39.4 |\n| N — Frame stack | 52.0 | 54.3 | 56.2 | 58.1 | 59.8 | 62.4 |\n| Saddle rail height min | 67.0 | 69.5 | 71.5 | 74.0 | 76.0 | 78.0 |\n| Saddle rail height max | 75.0 | 77.5 | 79.5 | 82.0 | 84.0 | 86.0 |",
"price": 1899.99,
"tags": [
"bicycle",
"electric bike"
]
},
{
"name": "VeloCore X9 eMTB",
"shortDescription": "The VeloCore X9 eMTB is a light, agile and versatile electric mountain bike designed for adventure and performance. Its purpose-built frame and premium components offer an exhilarating ride experience on both technical terrain and smooth singletrack.",
"description": "## Overview\nIt's right for you if...\nYou love exploring new trails and testing your limits on challenging terrain. You want an electric mountain bike that offers power when you need it, without sacrificing performance or agility. You're looking for a high-quality bike with top-notch components and a sleek design.\n\nThe tech you get\nA lightweight, full carbon frame with custom geometry, a 140mm RockShox Pike Ultimate fork with Charger 2.1 damper, and a Fox Float DPS Performance shock. A Shimano STEPS E8000 motor and 504Wh battery that provide up to 62 miles of range and 20 mph assistance. A Shimano XT 12-speed drivetrain, Shimano SLX brakes, and DT Swiss wheels.\n\nThe final word\nThe VeloCore X9 eMTB delivers power and agility in equal measure. It's a versatile and capable electric mountain bike that can handle any trail with ease. With premium components, a custom carbon frame, and a sleek design, this bike is built for adventure.\n\n## Features\nAgile and responsive\n\nThe VeloCore X9 eMTB is designed to be nimble and responsive on the trail. Its custom carbon frame offers a perfect balance of stiffness and compliance, while the suspension system provides smooth and stable performance on technical terrain.\n\nPowerful and efficient\n\nThe Shimano STEPS E8000 motor and 504Wh battery provide up to 62 miles of range and 20 mph assistance. The motor delivers smooth and powerful performance, while the battery offers reliable and consistent power for long rides.\n\nCustomizable ride experience\n\nThe VeloCore X9 eMTB comes with an intuitive and customizable Shimano STEPS display that allows you to adjust the level of assistance, monitor your speed and battery life, and customize your ride experience to suit your needs.\n\nPremium components\n\nThe VeloCore X9 eMTB is equipped with high-end components, including a Shimano XT 12-speed drivetrain, Shimano SLX brakes, and DT Swiss wheels. These components offer reliable and precise performance, allowing you to push your limits with confidence.\n\n## Specs\nFrameset\nFrame\tVeloCore carbon fiber frame, Boost, tapered head tube, internal cable routing, 140mm travel\nFork\tRockShox Pike Ultimate, Charger 2.1 damper, DebonAir spring, 15x110mm Boost Maxle Ultimate, 46mm offset, 140mm travel\nShock\tFox Float DPS Performance, EVOL, 3-position adjust, Kashima Coat, 210x50mm\n\nWheels\nWheel front\tDT Swiss XM1700 Spline, 30mm internal width, 15x110mm Boost axle\nWheel rear\tDT Swiss XM1700 Spline, 30mm internal width, Shimano Microspline driver, 12x148mm Boost axle\nTire front\tMaxxis Minion DHF, 29x2.5\", EXO+ casing, tubeless ready\nTire rear\tMaxxis Minion DHR II, 29x2.4\", EXO+ casing, tubeless ready\n\nDrivetrain\nShifter\tShimano XT M8100, 12-speed\nRear derailleur\tShimano XT M8100, Shadow Plus, long cage, 51T max cog\nCrankset\tShimano STEPS E8000, 165mm length, 34T chainring\nCassette\tShimano XT M8100, 10-51T, 12-speed\nChain\tShimano CN-M8100, 12-speed\nPedals\tNot included\n\nComponents\nSaddle\tBontrager Arvada, hollow chromoly rails\nSeatpost\tDrop Line, internal routing, 31.6mm (15.5: 100mm, 17.5 & 18.5: 125mm, 19.5 & 21.5: 150mm)\nHandlebar\tBontrager Line Pro, ADV Carbon, 35mm, 27.5mm rise, 780mm width\nStem\tBontrager Line Pro, 35mm, Knock Block, 0 degree, 50mm length\nGrips\tBontrager XR Trail Elite, alloy lock-on\nHeadset\tIntegrated, sealed cartridge bearing, 1-1/8\" top, 1.5\" bottom\nBrakeset\tShimano SLX M7120, 4-piston hydraulic disc\n\nAccessories\nBattery\tShimano STEPS BT-E8010, 504Wh\nCharger\tShimano STEPS EC-E8004, 4A\nController\tShimano STEPS E8000 display\nBike weight\tM - 22.5 kg / 49.6 lbs (with tubes)\n\n## Sizing & fit\n\n| Size | Rider Height |\n|:----:|:------------------------:|\n| S | 162 - 170 cm 5'4\" - 5'7\" |\n| M | 170 - 178 cm 5'7\" - 5'10\"|\n| L | 178 - 186 cm 5'10\" - 6'1\"|\n| XL | 186 - 196 cm 6'1\" - 6'5\" |\n\n## Geometry\n\nAll measurements provided in cm unless otherwise noted.\n\n| Frame size | S | M | L | XL |\n|---------------------------|-------|-------|-------|-------|\n| A — Seat tube | 40.6 | 43.2 | 47.0 | 51.0 |\n| B — Seat tube angle | 75.0° | 75.0° | 75.0° | 75.0° |\n| C — Head tube length | 9.6 | 10.6 | 11.6 | 12.6 |\n| D — Head angle | 66.5° | 66.5° | 66.5° | 66.5° |\n| E — Effective top tube | 60.4 | 62.6 | 64.8 | 66.9 |\n| F — Bottom bracket height | 33.2 | 33.2 | 33.2 | 33.2 |\n| G — Bottom bracket drop | 3.0 | 3.0 | 3.0 | 3.0 |\n| H — Chainstay length | 45.5 | 45.5 | 45.5 | 45.5 |\n| I — Offset | 4.6 | 4.6 | 4.6 | 4.6 |\n| J — Trail | 11.9 | 11.9 | 11.9 | 11.9 |\n| K — Wheelbase | 117.0 | 119.3 | 121.6 | 123.9 |\n| L — Standover | 75.9 | 75.9 | 78.6 | 78.6 |\n| M — Frame reach | 43.6 | 45.6 | 47.6 | 49.6 |\n| N — Frame stack | 60.5 | 61.5 | 62.4 | 63.4 |",
"price": 1299.99,
"tags": [
"bicycle",
"touring bike"
]
},
{
"name": "Zephyr 8.8 GX Eagle AXS Gen 3",
"shortDescription": "Zephyr 8.8 GX Eagle AXS is a light and nimble full-suspension mountain bike. It's designed to handle technical terrain with ease and has a smooth and efficient ride feel. The sleek and powerful Bosch Performance Line CX motor and removable Powertube battery provide a boost to your pedaling and give you long-lasting riding time. The bike also features high-end components and advanced technology for an ultimate mountain biking experience.",
"description": "## Overview\nIt's right for you if...\nYou're an avid mountain biker looking for a high-performance e-MTB that can tackle challenging trails. You want a bike with a powerful motor, efficient suspension, and advanced technology to enhance your riding experience. You also need a bike that's reliable and durable for long-lasting use.\n\nThe tech you get\nA lightweight, full carbon frame with 150mm of rear travel and a 160mm RockShox Pike Ultimate fork with Charger 2.1 RCT3 damper, remote lockout, and DebonAir spring. A Bosch Performance Line CX motor and removable Powertube 625Wh battery that can assist up to 20mph when it's on and gives zero drag when it's off, plus an easy-to-use handlebar-mounted Bosch Purion controller. A SRAM GX Eagle AXS wireless electronic drivetrain, a RockShox Reverb Stealth dropper, and DT Swiss HX1501 Spline One wheels.\n\nThe final word\nZephyr 8.8 GX Eagle AXS is a high-performance e-MTB that's designed to handle technical terrain with ease. With a powerful Bosch motor and long-lasting battery, you can conquer challenging climbs and enjoy long rides. The bike also features high-end components and advanced technology for an ultimate mountain biking experience.\n\n## Features\nPowerful motor\n\nThe Bosch Performance Line CX motor provides a boost to your pedaling and can assist up to 20mph. It has four power modes and a walk-assist function for easy navigation on steep climbs. The motor is also reliable and durable for long-lasting use.\n\nEfficient suspension\n\nZephyr 8.8 has a 150mm of rear travel and a 160mm RockShox Pike Ultimate fork with Charger 2.1 RCT3 damper, remote lockout, and DebonAir spring. The suspension is efficient and responsive, allowing you to handle technical terrain with ease.\n\nRemovable battery\n\nThe Powertube 625Wh battery is removable for easy charging and storage. It provides long-lasting riding time and can be replaced with a spare battery for even longer rides. The battery is also durable and weather-resistant for all-season riding.\n\nAdvanced technology\n\nZephyr 8.8 is equipped with advanced technology, including a Bosch Purion controller for easy motor control, a SRAM GX Eagle AXS wireless electronic drivetrain for precise shifting, and a RockShox Reverb Stealth dropper for adjustable saddle height. The bike also has DT Swiss HX1501 Spline One wheels for reliable performance on any terrain.\n\nCarbon frame\n\nThe full carbon frame is lightweight and durable, providing a smooth and efficient ride. It's also designed with a tapered head tube, internal cable routing, and Boost148 spacing for enhanced stiffness and responsiveness.\n\n## Specs\nFrameset\nFrame\tCarbon main frame & stays, tapered head tube, internal routing, Boost148, 150mm travel\nFork\tRockShox Pike Ultimate, Charger 2.1 RCT3 damper, DebonAir spring, remote lockout, tapered steerer, Boost110, 15mm Maxle Stealth, 160mm travel\nShock\tRockShox Deluxe RT3, DebonAir spring, 205mm x 57.5mm\nMax compatible fork travel\t170mm\n\nWheels\nWheel front\tDT Swiss HX1501 Spline One, Centerlock, 30mm inner width, 110x15mm Boost\nWheel rear\tDT Swiss HX1501 Spline One, Centerlock, 30mm inner width, SRAM XD driver, 148x12mm Boost\nTire\tBontrager XR4 Team Issue, Tubeless Ready, Inner Strength sidewall, aramid bead, 120tpi, 29x2.40''\nMax tire size\t29x2.60\"\n\nDrivetrain\nShifter\tSRAM GX Eagle AXS, wireless, 12 speed\nRear derailleur\tSRAM GX Eagle AXS\nCrank\tBosch Gen 4, 32T\nChainring\tSRAM X-Sync 2, 32T, direct-mount\nCassette\tSRAM PG-1275 Eagle, 10-52, 12 speed\nChain\tSRAM GX Eagle, 12 speed\n\nComponents\nSaddle\tBontrager Arvada, hollow titanium rails, 138mm width\nSeatpost\tRockShox Reverb Stealth, 31.6mm, internal routing, 150mm (S), 170mm (M/L), 200mm (XL)\nHandlebar\tBontrager Line Pro, ADV Carbon, 35mm, 27.5mm rise, 780mm width\nGrips\tBontrager XR Trail Elite, alloy lock-on\nStem\tBontrager Line Pro, Knock Block, 35mm, 0 degree, 50mm length\nHeadset\tIntegrated, sealed cartridge bearing, 1-1/8'' top, 1.5'' bottom\nBrake\tSRAM Code RSC hydraulic disc, 200mm (front), 180mm (rear)\nBrake rotor\tSRAM CenterLine, centerlock, round edge, 200mm (front), 180mm (rear)\n\nAccessories\nE-bike system\tBosch Performance Line CX\nBattery\tBosch Powertube 625Wh\nCharger\tBosch 4A compact charger\nController\tBosch Purion\nTool\tBontrager multi-tool, integrated storage bag\n\nWeight\nWeight\tM - 24.08 kg / 53.07 lbs (with TLR sealant, no tubes)\nWeight limit\tThis bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\n\n\n## Sizing & fit\n\n| Size | Rider Height | Inseam |\n|:----:|:------------------------:|:--------------------:|\n| S | 153 - 162 cm 5'0\" - 5'4\" | 67 - 74 cm 26\" - 29\" |\n| M | 161 - 172 cm 5'3\" - 5'8\" | 74 - 79 cm 29\" - 31\" |\n| L | 171 - 180 cm 5'7\" - 5'11\" | 79 - 84 cm 31\" - 33\" |\n| XL | 179 - 188 cm 5'10\" - 6'2\" | 84 - 89 cm 33\" - 35\" |\n\n\n## Geometry\n\nAll measurements provided in cm unless otherwise noted.\nSizing table\n| Frame size letter | S | M | L | XL |\n|---------------------------|-------|-------|-------|-------|\n| Actual frame size | 15.5 | 17.5 | 19.5 | 21.5 |\n| Wheel size | 29\" | 29\" | 29\" | 29\" |\n| A — Seat tube | 39.4 | 41.9 | 44.5 | 47.6 |\n| B — Seat tube angle | 76.1° | 76.1° | 76.1° | 76.1° |\n| C — Head tube length | 9.6 | 10.5 | 11.5 | 12.5 |\n| D — Head angle | 65.5° | 65.5° | 65.5° | 65.5° |\n| E — Effective top tube | 58.6 | 61.3 | 64.0 | 66.7 |\n| F — Bottom bracket height | 34.0 | 34.0 | 34.0 | 34.0 |\n| G — Bottom bracket drop | 1.0 | 1.0 | 1.0 | 1.0 |\n| H — Chainstay length | 45.0 | 45.0 | 45.0 | 45.0 |\n| I — Offset | 4.6 | 4.6 | 4.6 | 4.6 |\n| J — Trail | 10.5 | 10.5 | 10.5 | 10.5 |\n| K — Wheelbase | 119.5 | 122.3 | 125.0 | 127.8 |\n| L — Standover | 72.7 | 74.7 | 77.6 | 81.0 |\n|",
"price": 1499.99,
"tags": [
"bicycle",
"electric bike",
"city bike"
]
},
{
"name": "Velo 99 XR1 AXS",
"shortDescription": "Velo 99 XR1 AXS is a next-generation bike designed for fast-paced adventure seekers and speed enthusiasts. Built for high-performance racing, the bike boasts state-of-the-art technology and premium components. It is the ultimate bike for riders who want to push their limits and get their adrenaline pumping.",
"description": "## Overview\nIt's right for you if...\nYou are a passionate cyclist looking for a bike that can keep up with your speed, agility, and endurance. You are an adventurer who loves to explore new terrains and challenge yourself on the toughest courses. You want a bike that is lightweight, durable, and packed with the latest technology.\n\nThe tech you get\nA lightweight, full carbon frame with advanced aerodynamics and integrated cable routing for a clean look. A high-performance SRAM XX1 Eagle AXS wireless electronic drivetrain, featuring a 12-speed cassette and a 32T chainring. A RockShox SID Ultimate fork with a remote lockout, 120mm travel, and Charger Race Day damper. A high-end SRAM G2 Ultimate hydraulic disc brake with carbon levers. A FOX Transfer SL dropper post for quick and easy height adjustments. DT Swiss XRC 1501 carbon wheels for superior speed and handling.\n\nThe final word\nVelo 99 XR1 AXS is a premium racing bike that can help you achieve your goals and reach new heights. It is designed for speed, agility, and performance, and it is packed with the latest technology and premium components. If you are a serious cyclist who wants the best, this is the bike for you.\n\n## Features\nAerodynamic design\n\nThe Velo 99 XR1 AXS features a state-of-the-art frame design that reduces drag and improves speed. It has an aerodynamic seatpost, integrated cable routing, and a sleek, streamlined look that sets it apart from other bikes.\n\nWireless electronic drivetrain\n\nThe SRAM XX1 Eagle AXS drivetrain features a wireless electronic system that provides precise, instant shifting and unmatched efficiency. It eliminates the need for cables and makes the bike lighter and faster.\n\nHigh-performance suspension\n\nThe RockShox SID Ultimate fork and Charger Race Day damper provide 120mm of smooth, responsive suspension that can handle any terrain. The fork also has a remote lockout for quick adjustments on the fly.\n\nSuperior braking power\n\nThe SRAM G2 Ultimate hydraulic disc brake system delivers unmatched stopping power and control. It has carbon levers for a lightweight, ergonomic design and precision control.\n\nCarbon wheels\n\nThe DT Swiss XRC 1501 carbon wheels are ultra-lightweight, yet incredibly strong and durable. They provide superior speed and handling, making the bike more agile and responsive.\n\n## Specs\nFrameset\nFrame\tFull carbon frame, integrated cable routing, aerodynamic design, Boost148\nFork\tRockShox SID Ultimate, Charger Race Day damper, remote lockout, tapered steerer, Boost110, 15mm Maxle Stealth, 120mm travel\n\nWheels\nWheel front\tDT Swiss XRC 1501 carbon wheel, Boost110, 15mm thru axle\nWheel rear\tDT Swiss XRC 1501 carbon wheel, SRAM XD driver, Boost148, 12mm thru axle\nTire\tSchwalbe Racing Ray, Performance Line, Addix, 29x2.25\"\nTire part\tSchwalbe Doc Blue Professional, 500ml\nMax tire size\t29x2.3\"\n\nDrivetrain\nShifter\tSRAM Eagle AXS, wireless, 12-speed\nRear derailleur\tSRAM XX1 Eagle AXS\nCrank\tSRAM XX1 Eagle, 32T, carbon\nChainring\tSRAM X-SYNC, 32T, alloy\nCassette\tSRAM Eagle XG-1299, 10-52, 12-speed\nChain\tSRAM XX1 Eagle, 12-speed\nMax chainring size\t1x: 32T\n\nComponents\nSaddle\tBontrager Montrose Elite, carbon rails, 138mm width\nSeatpost\tFOX Transfer SL, 125mm travel, internal routing, 31.6mm\nHandlebar\tBontrager Kovee Pro, ADV Carbon, 35mm, 5mm rise, 720mm width\nGrips\tBontrager XR Endurance Elite\nStem\tBontrager Kovee Pro, 35mm, Blendr compatible, 7 degree, 60mm length\nHeadset\tIntegrated, cartridge bearing, 1-1/8\" top, 1.5\" bottom\nBrake\tSRAM G2 Ultimate hydraulic disc, carbon levers, 180mm rotors\n\nAccessories\nBike computer\tBontrager Trip 300\nTool\tBontrager Flatline Pro pedal wrench, T25 Torx\n\n\n## Sizing & fit\n\n| Size | Rider Height | Inseam |\n|:----:|:------------------------:|:--------------------:|\n| S | 158 - 168 cm 5'2\" - 5'6\" | 74 - 78 cm 29\" - 31\" |\n| M | 165 - 175 cm 5'5\" - 5'9\" | 78 - 82 cm 31\" - 32\" |\n| L | 173 - 183 cm 5'8\" - 6'0\" | 82 - 86 cm 32\" - 34\" |\n| XL | 180 - 193 cm 5'11\" - 6'4\" | 86 - 90 cm 34\" - 35\" |\n\n\n## Geometry\n\nAll measurements provided in cm unless otherwise noted.\nSizing table\n| Frame size letter | S | M | L | XL |\n|---------------------------|-------|-------|-------|-------|\n| Actual frame size | 15.5 | 17.5 | 19.5 | 21.5 |\n| Wheel size | 29\" | 29\" | 29\" | 29\" |\n| A — Seat tube | 39.9 | 43.0 | 47.0 | 51.0 |\n| B — Seat tube angle | 74.5° | 74.5° | 74.5° | 74.5° |\n| C — Head tube length | 9.0 | 10.0 | 11.0 | 12.0 |\n| D — Head angle | 68.0° | 68.0° | 68.0° | 68.0° |\n| E — Effective top tube | 57.8 | 59.7 | 61.6 | 63.6 |\n| F — Bottom bracket height | 33.0 | 33.0 | 33.0 | 33.0 |\n| G — Bottom bracket drop | 5.0 | 5.0 | 5.0 | 5.0 |\n| H — Chainstay length | 43.0 | 43.0 | 43.0 | 43.0 |\n| I — Offset | 4.2 | 4.2 | 4.2 | 4.2 |\n| J — Trail | 9.7 | 9.7 | 9.7 | 9.7 |\n| K — Wheelbase | 112.5 | 114.5 | 116.5 | 118.6 |\n| L — Standover | 75.9 | 77.8 | 81.5 | 84.2 |\n| M — Frame reach | 41.6 | 43.4 | 45.2 | 47.1 |\n| N — Frame stack | 58.2 | 58.9 | 59.3 | 59.9 |",
"price": 1099.99,
"tags": [
"bicycle",
"mountain bike"
]
},
{
"name": "AURORA 11S E-MTB",
"shortDescription": "The AURORA 11S is a powerful and stylish electric mountain bike designed to take you on thrilling off-road adventures. With its sturdy frame and premium components, this bike is built to handle any terrain. It features a high-performance motor, long-lasting battery, and advanced suspension system that guarantee a smooth and comfortable ride.",
"description": "## Overview\nIt's right for you if...\nYou want a top-of-the-line e-MTB that is both powerful and stylish. You also want a bike that can handle any terrain, from steep climbs to rocky descents. With its advanced features and premium components, the AURORA 11S is designed for serious off-road riders who demand the best.\n\nThe tech you get\nA sturdy aluminum frame with advanced suspension system that provides 120mm of travel. A 750W brushless motor that delivers up to 28mph, and a 48V/14Ah lithium-ion battery that provides up to 60 miles of range on a single charge. An advanced 11-speed Shimano drivetrain with hydraulic disc brakes for precise shifting and reliable stopping power. \n\nThe final word\nThe AURORA 11S is a top-of-the-line e-MTB that delivers exceptional performance and style. Whether you're tackling steep climbs or hitting rocky descents, this bike is built to handle any terrain with ease. With its advanced features and premium components, the AURORA 11S is the perfect choice for serious off-road riders who demand the best.\n\n## Features\nPowerful and efficient\n\nThe AURORA 11S is equipped with a high-performance 750W brushless motor that delivers up to 28mph. The motor is powered by a long-lasting 48V/14Ah lithium-ion battery that provides up to 60 miles of range on a single charge.\n\nAdvanced suspension system\n\nThe bike's advanced suspension system provides 120mm of travel, ensuring a smooth and comfortable ride on any terrain. The front suspension is a Suntour XCR32 Air fork, while the rear suspension is a KS-281 hydraulic shock absorber.\n\nPremium components\n\nThe AURORA 11S features an advanced 11-speed Shimano drivetrain with hydraulic disc brakes. The bike is also equipped with a Tektro HD-E725 hydraulic disc brake system that provides reliable stopping power.\n\nSleek and stylish design\n\nWith its sleek and stylish design, the AURORA 11S is sure to turn heads on the trail. The bike's sturdy aluminum frame is available in a range of colors, including black, blue, and red.\n\n## Specs\nFrameset\nFrame Material: Aluminum\nFrame Size: S, M, L\nFork: Suntour XCR32 Air, 120mm Travel\nShock Absorber: KS-281 Hydraulic Shock Absorber\n\nWheels\nWheel Size: 27.5 inches\nTires: Kenda K1151 Nevegal, 27.5x2.35\nRims: Alloy Double Wall\nSpokes: 32H, Stainless Steel\n\nDrivetrain\nShifters: Shimano SL-M7000\nRear Derailleur: Shimano RD-M8000\nCrankset: Prowheel 42T, Alloy Crank Arm\nCassette: Shimano CS-M7000, 11-42T\nChain: KMC X11EPT\n\nBrakes\nBrake System: Tektro HD-E725 Hydraulic Disc Brake\nBrake Rotors: 180mm Front, 160mm Rear\n\nE-bike system\nMotor: 750W Brushless\nBattery: 48V/14Ah Lithium-Ion\nCharger: 48V/3A Smart Charger\nController: Intelligent Sinusoidal Wave\n\nWeight\nWeight: 59.5 lbs\n\n## Sizing & fit\n| Size | Rider Height | Standover Height |\n|------|-------------|-----------------|\n| S | 5'2\"-5'6\" | 28.5\" |\n| M | 5'7\"-6'0\" | 29.5\" |\n| L | 6'0\"-6'4\" | 30.5\" |\n\n## Geometry\nAll measurements provided in cm.\nSizing table\n| Frame size letter | S | M | L |\n|-------------------|-----|-----|-----|\n| Wheel Size | 27.5\"| 27.5\"| 27.5\"|\n| Seat tube length | 44.5| 48.5| 52.5|\n| Head tube angle | 68° | 68° | 68° |\n| Seat tube angle | 74.5°| 74.5°| 74.5°|\n| Effective top tube | 57.5| 59.5| 61.5|\n| Head tube length | 12.0| 12.0| 13.0|\n| Chainstay length | 45.5| 45.5| 45.5|\n| Bottom bracket height | 30.0| 30.0| 30.0|\n| Wheelbase | 115.0|116.5|118.5|",
"price": 1999.99,
"tags": [
"bicycle",
"road bike"
]
},
{
"name": "VeloTech V9.5 AXS Gen 3",
"shortDescription": "VeloTech V9.5 AXS is a sleek and fast carbon bike that combines high-end tech with a comfortable ride. It's designed to provide the ultimate experience for the most serious riders. The bike comes with a lightweight and powerful motor that can be activated when needed, and you get a spec filled with premium parts.",
"description": "## Overview\nIt's right for you if...\nYou want a bike that is fast, efficient, and delivers an adrenaline-filled experience. You are looking for a bike that is built with cutting-edge technology, and you want a ride that is both comfortable and exciting.\n\nThe tech you get\nA lightweight and durable full carbon frame with a fork that has 100mm of travel. The bike comes with a powerful motor that can deliver up to 20 mph of assistance. The drivetrain is a wireless electronic system that is precise and reliable. The bike is also equipped with hydraulic disc brakes, tubeless-ready wheels, and comfortable grips.\n\nThe final word\nThe VeloTech V9.5 AXS is a high-end bike that delivers an incredible experience for serious riders. It combines the latest technology with a comfortable ride, making it perfect for long rides, tough climbs, and fast descents.\n\n## Features\nFast and efficient\nThe VeloTech V9.5 AXS comes with a powerful motor that can provide up to 20 mph of assistance. The motor is lightweight and efficient, providing a boost when you need it without adding bulk. The bike's battery is removable, allowing you to ride without assistance when you don't need it.\n\nSmart software for the trail\nThe VeloTech V9.5 AXS is equipped with intelligent software that delivers a smooth and responsive ride. The software allows the motor to respond immediately as you start to pedal, delivering more power over a wider cadence range. You can also customize your user settings to suit your preferences.\n\nComfortable ride\nThe VeloTech V9.5 AXS is designed to provide a comfortable ride, even on long rides. The bike's fork has 100mm of travel, providing ample cushioning for rough terrain. The bike's grips are also designed to provide a comfortable and secure grip, even on the most challenging rides.\n\n## Specs\nFrameset\nFrame\tCarbon fiber frame with internal cable routing and Boost148\nFork\t100mm of travel with remote lockout\nShock\tN/A\n\nWheels\nWheel front\tCarbon fiber tubeless-ready wheel\nWheel rear\tCarbon fiber tubeless-ready wheel\nSkewer rear\t12mm thru-axle\nTire\tTubeless-ready tire\nTire part\tTubeless sealant\n\nDrivetrain\nShifter\tWireless electronic shifter\nRear derailleur\tWireless electronic derailleur\nCrank\tCarbon fiber crankset with chainring\nCrank arm\tCarbon fiber crank arm\nChainring\tAlloy chainring\nCassette\t12-speed cassette\nChain\t12-speed chain\n\nComponents\nSaddle\tCarbon fiber saddle\nSeatpost\tCarbon fiber seatpost\nHandlebar\tCarbon fiber handlebar\nGrips\tComfortable and secure grips\nStem\tCarbon fiber stem\nHeadset\tCarbon fiber headset\nBrake\tHydraulic disc brakes\nBrake rotor\tDisc brake rotor\n\nAccessories\nE-bike system\tPowerful motor with removable battery\nBattery\tLithium-ion battery\nCharger\tFast charging adapter\nController\tHandlebar-mounted controller\nTool\tBasic toolkit\n\nWeight\nWeight\tM - 17.5 kg / 38.5 lbs (with tubeless sealant)\n\nWeight limit\nThis bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\n\n## Sizing & fit\n| Size | Rider Height | Inseam |\n|:----:|:------------------------:|:--------------------:|\n| S | 160 - 170 cm 5'3\" - 5'7\" | 74 - 79 cm 29\" - 31\" |\n| M | 170 - 180 cm 5'7\" - 5'11\" | 79 - 84 cm 31\" - 33\" |\n| L | 180 - 190 cm 5'11\" - 6'3\" | 84 - 89 cm 33\" - 35\" |\n| XL | 190 - 200 cm 6'3\" - 6'7\" | 89 - 94 cm 35\" - 37\" |\n\n## Geometry\nAll measurements provided in cm unless otherwise noted.\nSizing table\n| Frame size letter | S | M | L | XL |\n|---------------------------|-------|-------|-------|-------|\n| Actual frame size | 50.0 | 53.3 | 55.6 | 58.8 |\n| Wheel size | 29\" | 29\" | 29\" | 29\" |\n| A — Seat tube | 39.4 | 43.2 | 48.3 | 53.3 |\n| B — Seat tube angle | 72.3° | 72.6° | 72.8° | 72.8° |\n| C — Head tube length | 9.0 | 10.0 | 10.5 | 11.0 |\n| D — Head angle | 67.5° | 67.5° | 67.5° | 67.5° |\n| E — Effective top tube | 58.0 | 61.7 | 64.8 | 67.0 |\n| F — Bottom bracket height | 32.3 | 32.3 | 32.3 | 32.3 |\n| G — Bottom bracket drop | 5.0 | 5.0 | 5.0 | 5.0 |\n| H — Chainstay length | 44.7 | 44.7 | 44.7 | 44.7 |\n| I — Offset | 4.2 | 4.2 | 4.2 | 4.2 |\n| J — Trail | 10.9 | 10.9 | 10.9 | 10.9 |\n| K — Wheelbase | 112.6 | 116.5 | 119.7 | 121.9 |\n| L — Standover | 76.8 | 76.8 | 76.8 | 76.8 |\n| M — Frame reach | 40.5 | 44.0 | 47.0 | 49.0 |\n| N — Frame stack | 60.9 | 61.8 | 62.2 | 62.7 |",
"price": 1699.99,
"tags": [
"bicycle",
"electric bike",
"city bike"
]
},
{
"name": "Axiom D8 E-Mountain Bike",
"shortDescription": "The Axiom D8 is an electrifying mountain bike that is built for adventure. It boasts a light aluminum frame, a powerful motor and the latest tech to tackle the toughest of terrains. The D8 provides assistance without adding bulk to the bike, giving you the flexibility to ride like a traditional mountain bike or have an extra push when you need it.",
"description": "## Overview \nIt's right for you if... \nYou're looking for an electric mountain bike that can handle a wide variety of terrain, from flowing singletrack to technical descents. You also want a bike that offers a powerful motor that provides assistance without adding bulk to the bike. The D8 is designed to take you anywhere, quickly and comfortably.\n\nThe tech you get \nA lightweight aluminum frame with 140mm of travel, a Suntour fork with hydraulic lockout, and a reliable and powerful Bafang M400 mid-motor that provides a boost up to 20 mph. The bike features a Shimano Deore drivetrain, hydraulic disc brakes, and a dropper seat post. With the latest tech on-board, the D8 is designed to take you to new heights.\n\nThe final word \nThe Axiom D8 is an outstanding electric mountain bike that is designed for adventure. It's built with the latest tech and provides the flexibility to ride like a traditional mountain bike or have an extra push when you need it. Whether you're a beginner or an experienced rider, the D8 is the perfect companion for your next adventure.\n\n## Features \nBuilt for Adventure \n\nThe D8 features a lightweight aluminum frame that is built to withstand rugged terrain. It comes equipped with 140mm of travel and a Suntour fork that can handle even the toughest of trails. With this bike, you're ready to take on anything the mountain can throw at you.\n\nPowerful Motor \n\nThe Bafang M400 mid-motor provides reliable and powerful assistance without adding bulk to the bike. You can quickly and easily switch between the different assistance levels to find the perfect balance between range and power.\n\nShimano Deore Drivetrain \n\nThe Shimano Deore drivetrain is reliable and offers smooth shifting on any terrain. You can easily adjust the gears to match your riding style and maximize your performance on the mountain.\n\nDropper Seat Post \n\nThe dropper seat post allows you to easily adjust your seat height on the fly, so you can maintain the perfect position for any terrain. With the flick of a switch, you can quickly and easily lower or raise your seat to match the terrain.\n\nHydraulic Disc Brakes \n\nThe D8 features powerful hydraulic disc brakes that offer reliable stopping power in any weather condition. You can ride with confidence knowing that you have the brakes to stop on a dime.\n\n## Specs \nFrameset \nFrame\tAluminum frame with 140mm of travel \nFork\tSuntour fork with hydraulic lockout, 140mm of travel \nShock\tN/A \nMax compatible fork travel\t140mm \n \nWheels \nWheel front\tAlloy wheel \nWheel rear\tAlloy wheel \nSkewer rear\tThru axle \nTire\t29\" x 2.35\" \nTire part\tN/A \nMax tire size\t29\" x 2.6\" \n \nDrivetrain \nShifter\tShimano Deore \nRear derailleur\tShimano Deore \nCrank\tBafang M400 \nCrank arm\tN/A \nChainring\tN/A \nCassette\tShimano Deore \nChain\tShimano Deore \nMax chainring size\tN/A \n \nComponents \nSaddle\tAxiom D8 saddle \nSeatpost\tDropper seat post \nHandlebar\tAxiom D8 handlebar \nGrips\tAxiom D8 grips \nStem\tAxiom D8 stem \nHeadset\tAxiom D8 headset \nBrake\tHydraulic disc brakes \nBrake rotor\t180mm \n\nAccessories \nE-bike system\tBafang M400 mid-motor \nBattery\tLithium-ion battery, 500Wh \nCharger\tLithium-ion charger \nController\tBafang M400 controller \nTool\tN/A \n \nWeight \nWeight\tM - 22 kg / 48.5 lbs \nWeight limit\tThis bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 136 kg (300 lbs). \n \n \n## Sizing & fit \n \n| Size | Rider Height | Inseam | \n|:----:|:------------------------:|:--------------------:| \n| S | 152 - 165 cm 5'0\" - 5'5\" | 70 - 76 cm 27\" - 30\" | \n| M | 165 - 178 cm 5'5\" - 5'10\" | 76 - 81 cm 30\" - 32\" | \n| L | 178 - 185 cm 5'10\" - 6'1\" | 81 - 86 cm 32\" - 34\" | \n| XL | 185 - 193 cm 6'1\" - 6'4\" | 86 - 91 cm 34\" - 36\" | \n \n \n## Geometry \n \nAll measurements provided in cm unless otherwise noted. \nSizing table \n| Frame size letter | S | M | L | XL | \n|---------------------------|-------|-------|-------|-------| \n| Actual frame size | 41.9 | 46.5 | 50.8 | 55.9 | \n| Wheel size | 29\" | 29\" | 29\" | 29\" | \n| A — Seat tube | 42.0 | 46.5 | 51.0 | 56.0 | \n| B — Seat tube angle | 74.0° | 74.0° | 74.0° | 74.0° | \n| C — Head tube length | 11.0 | 12.0 | 13.0 | 15.0 | \n| D — Head angle | 68.0° | 68.0° | 68.0° | 68.0° | \n| E — Effective top tube | 57.0 | 60.0 | 62.0 | 65.0 | \n| F — Bottom bracket height | 33.0 | 33.0 | 33.0 | 33.0 | \n| G — Bottom bracket drop | 3.0 | 3.0 | 3.0 | 3.0 | \n| H — Chainstay length | 46.0 | 46.0 | 46.0 | 46.0 | \n| I — Offset | 4.5 | 4.5 | 4.5 | 4.5 | \n| J — Trail | 10.9 | 10.9 | 10.9 | 10.9 | \n| K — Wheelbase | 113.0 | 116.0 | 117.5 | 120.5 | \n| L — Standover | 73.5 | 75.5 | 76.5 | 79.5 | \n| M — Frame reach | 41.0 | 43.5 | 45.0 | 47.5 | \n| N — Frame stack | 60.5 | 61.5 | 62.5 | 64.5 |",
"price": 1399.99,
"tags": [
"bicycle",
"electric bike",
"mountain bike"
]
},
{
"name": "Velocity X1",
"shortDescription": "Velocity X1 is a high-performance road bike designed for speed enthusiasts. It features a lightweight yet durable frame, aerodynamic design, and top-quality components, making it the perfect choice for those who want to take their cycling experience to the next level.",
"description": "## Overview\nIt's right for you if...\nYou're an experienced cyclist looking for a bike that can keep up with your need for speed. You want a bike that's lightweight, aerodynamic, and built to perform, whether you're training for a race or just pushing yourself to go faster.\n\nThe tech you get\nA lightweight aluminum frame with a carbon fork, Shimano Ultegra groupset with a wide range of gearing, hydraulic disc brakes, aerodynamic carbon wheels, and a vibration-absorbing handlebar with ergonomic grips.\n\nThe final word\nVelocity X1 is the ultimate road bike for speed enthusiasts. Its lightweight frame, aerodynamic design, and top-quality components make it the perfect choice for those who want to take their cycling experience to the next level.\n\n\n## Features\n\nAerodynamic design\nVelocity X1 is built with an aerodynamic design to help you go faster with less effort. It features a sleek profile, hidden cables, and a carbon fork that cuts through the wind, reducing drag and increasing speed.\n\nHydraulic disc brakes\nVelocity X1 comes equipped with hydraulic disc brakes, providing excellent stopping power in all weather conditions. They're also low maintenance, with minimal adjustments needed over time.\n\nCarbon wheels\nThe Velocity X1's aerodynamic carbon wheels provide excellent speed and responsiveness, helping you achieve your fastest times yet. They're also lightweight, reducing overall bike weight and making acceleration and handling even easier.\n\nShimano Ultegra groupset\nThe Shimano Ultegra groupset provides smooth shifting and reliable performance, ensuring you get the most out of every ride. With a wide range of gearing options, it's ideal for tackling any terrain, from steep climbs to fast descents.\n\n\n## Specifications\nFrameset\nFrame with Fork\tAluminium frame, internal cable routing, 135x9mm QR\nFork\tCarbon, hidden cable routing, 100x9mm QR\n\nWheels\nWheel front\tCarbon, 30mm deep rim, 23mm width, 100x9mm QR\nWheel rear\tCarbon, 30mm deep rim, 23mm width, 135x9mm QR\nSkewer front\t100x9mm QR\nSkewer rear\t135x9mm QR\nTire\tContinental Grand Prix 5000, 700x25mm, folding bead\nMax tire size\t700x28mm without fenders\n\nDrivetrain\nShifter\tShimano Ultegra R8020, 11 speed\nRear derailleur\tShimano Ultegra R8000, 11 speed\nCrank\tSize: S, M\nShimano Ultegra R8000, 50/34T, 170mm length\nSize: L, XL\nShimano Ultegra R8000, 50/34T, 175mm length\nBottom bracket\tShimano BB-RS500-PB, PressFit\nCassette\tShimano Ultegra R8000, 11-30T, 11 speed\nChain\tShimano Ultegra HG701, 11 speed\nPedal\tNot included\nMax chainring size\t50/34T\n\nComponents\nSaddle\tBontrager Montrose Comp, steel rails, 138mm width\nSeatpost\tBontrager Comp, 6061 alloy, 27.2mm, 8mm offset, 330mm length\nHandlebar\tSize: S, M, L\nBontrager Elite Aero VR-CF, alloy, 31.8mm, 93mm reach, 123mm drop, 400mm width\nSize: XL\nBontrager Elite Aero VR-CF, alloy, 31.8mm, 93mm reach, 123mm drop, 420mm width\nGrips\tBontrager Supertack Perf tape\n*Stem\tSize: S, M, L\nBontrager Elite Blendr, 31.8mm clamp, 7 degree, 90mm length\nSize: XL\nBontrager Elite Blendr, 31.8mm clamp, 7 degree, 100mm length\nBrake\tShimano Ultegra R8070 hydraulic disc, flat mount\nBrake rotor\tShimano RT800, centerlock, 160mm\nRotor size\tMax brake rotor sizes: 160mm front & rear\n\nWeight\nWeight\tM - 8.15 kg / 17.97 lbs\nWeight limit\tThis bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 275 pounds (125 kg).\n\n\n## Sizing\n| Size | Rider Height | Inseam |\n|:----:|:-------------------------:|:--------------------:|\n| S | 162 - 170 cm 5'4\" - 5'7\" | 74 - 78 cm 29\" - 31\" |\n| M | 170 - 178 cm 5'7\" - 5'10\" | 77 - 82 cm 30\" - 32\" |\n| L | 178 - 186 cm 5'10\" - 6'1\" | 82 - 86 cm 32\" - 34\" |\n| XL | 186 - 196 cm 6'1\" - 6'5\" | 87 - 92 cm 34\" - 36\" |\n\n\n## Geometry\n| Frame size letter | S | M | L | XL |\n|---------------------------|-------|-------|-------|-------|\n| Wheel size | 700c | 700c | 700c | 700c |\n| A — Seat tube | 50.0 | 52.0 | 54.0 | 56.0 |\n| B — Seat tube angle | 74.0° | 73.5° | 73.0° | 72.5° |\n| C — Head tube length | 13.0 | 15.0 | 17.0 | 19.0 |\n| D — Head angle | 71.0° | 72.0° | 72.0° | 72.5° |\n| E — Effective top tube | 53.7 | 55.0 | 56.5 | 58.0 |\n| F — Bottom bracket height | 27.5 | 27.5 | 27.5 | 27.5 |\n| G — Bottom bracket drop | 7.3 | 7.3 | 7.3 | 7.3 |\n| H — Chainstay length | 41.0 | 41.0 | 41.0 | 41.0 |\n| I — Offset | 4.5 | 4.5 | 4.5 | 4.5 |\n| J — Trail | 6.0 | 6.0 | 6.0 | 5.8 |\n| K — Wheelbase | 98.2 | 99.1 | 100.1 | 101.0 |\n| L — Standover | 75.2 | 78.2 | 81.1 | 84.1 |\n| M — Frame reach | 37.5 | 38.3 | 39.1 | 39.9 |\n| N — Frame stack | 53.3 | 55.4 | 57.4 | 59.5 |",
"price": 1799.99,
"tags": [
"bicycle",
"touring bike"
]
},
{
"name": "Velocity V9",
"shortDescription": "Velocity V9 is a high-performance hybrid bike that combines speed and comfort for riders who demand the best of both worlds. The lightweight aluminum frame, along with the carbon fork and seat post, provide optimal stiffness and absorption to tackle any terrain. A 2x Shimano Deore drivetrain, hydraulic disc brakes, and 700c wheels with high-quality tires make it a versatile ride for commuters, fitness riders, and weekend adventurers alike.",
"description": "## Overview\nIt's right for you if...\nYou want a fast, versatile bike that can handle anything from commuting to weekend adventures. You value comfort as much as speed and performance. You want a reliable and durable bike that will last for years to come.\n\nThe tech you get\nA lightweight aluminum frame with a carbon fork and seat post, a 2x Shimano Deore drivetrain with a wide range of gearing, hydraulic disc brakes, and 700c wheels with high-quality tires. The Velocity V9 is designed for riders who demand both performance and comfort in one package.\n\nThe final word\nThe Velocity V9 is the perfect bike for riders who want speed and performance without sacrificing comfort. The lightweight aluminum frame and carbon components provide optimal stiffness and absorption, while the 2x Shimano Deore drivetrain and hydraulic disc brakes ensure precise shifting and stopping power. Whether you're commuting, hitting the trails, or training for your next race, the Velocity V9 has everything you need to achieve your goals.\n\n## Features\n\n2x drivetrain\nA 2x drivetrain means more versatility and a wider range of gearing options. Whether you're climbing hills or sprinting on the flats, the Velocity V9 has the perfect gear for any situation.\n\nCarbon components\nThe Velocity V9 features a carbon fork and seat post to provide optimal stiffness and absorption. This means you can ride faster and more comfortably over any terrain.\n\nHydraulic disc brakes\nHydraulic disc brakes provide unparalleled stopping power and modulation in any weather condition. You'll feel confident and in control no matter where you ride.\n\n## Specifications\nFrameset\nFrame with Fork\tAluminum frame with carbon fork and seat post, internal cable routing, fender mounts, 135x5mm ThruSkew\nFork\tCarbon fork, hidden fender mounts, flat mount disc, 5x100mm thru-skew\n\nWheels\nWheel front\tDouble wall aluminum rims, 700c, quick release hub\nWheel rear\tDouble wall aluminum rims, 700c, quick release hub\nTire\tKenda Kwick Tendril, puncture resistant, reflective sidewall, 700x32c\nMax tire size\t700x35c without fenders, 700x32c with fenders\n\nDrivetrain\nShifter\tShimano Deore, 10 speed\nFront derailleur\tShimano Deore\nRear derailleur\tShimano Deore\nCrank\tShimano Deore, 46-30T, 170mm (S/M), 175mm (L/XL)\nBottom bracket\tShimano BB52, 68mm, threaded\nCassette\tShimano Deore, 11-36T, 10 speed\nChain\tShimano HG54, 10 speed\nPedal\tWellgo alloy platform\n\nComponents\nSaddle\tVelo VL-2158, steel rails\nSeatpost\tCarbon seat post, 27.2mm\nHandlebar\tAluminum, 31.8mm clamp, 15mm rise, 680mm width\nGrips\tVelo ergonomic grips\nStem\tAluminum, 31.8mm clamp, 7 degree, 90mm length\nBrake\tShimano hydraulic disc, MT200 lever, MT200 caliper\nBrake rotor\tShimano RT56, centerlock, 160mm\nRotor size\tMax brake rotor sizes: 160mm front & rear\n\nWeight\nWeight\tM - 11.5 kg / 25.35 lbs\nWeight limit\tThis bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\n\n## Sizing\n| Size | Rider Height | Inseam |\n|:----:|:-------------------------:|:--------------------:|\n| S | 155 - 165 cm 5'1\" - 5'5\" | 72 - 78 cm 28\" - 31\" |\n| M | 165 - 175 cm 5'5\" - 5'9\" | 77 - 83 cm 30\" - 33\" |\n| L | 175 - 186 cm 5'9\" - 6'1\" | 82 - 88 cm 32\" - 35\" |\n| XL | 186 - 197 cm 6'1\" - 6'6\" | 87 - 93 cm 34\" - 37\" |\n\n## Geometry\n| Frame size | S | M | L | XL |\n|--------------------|-------|-------|-------|-------|\n| Wheel size | 700c | 700c | 700c | 700c |\n| A — Seat tube | 44.0 | 48.0 | 52.0 | 56.0 |\n| B — Seat tube angle | 74.5° | 74.0° | 73.5° | 73.0° |\n| C — Head tube length | 14.5 | 16.0 | 18.0 | 20.0 |\n| D — Head angle | 71.0° | 71.0° | 71.5° | 71.5° |\n| E — Effective top tube | 56.5 | 57.5 | 58.5 | 59.5 |\n| F — Bottom bracket height | 27.0 | 27.0 | 27.0 | 27.0 |\n| G — Bottom bracket drop | 7.0 | 7.0 | 7.0 | 7.0 |\n| H — Chainstay length | 43.0 | 43.0 | 43.0 | 43.0 |\n| I — Offset | 4.5 | 4.5 | 4.5 | 4.5 |\n| J — Trail | 7.0 | 7.0 | 6.6 | 6.6 |\n| K — Wheelbase | 105.4 | 106.3 | 107.2 | 108.2 |\n| L — Standover | 73.2 | 77.1 | 81.2 | 85.1 |\n| M — Frame reach | 39.0 | 39.8 | 40.4 | 41.3 |\n| N — Frame stack | 57.0 | 58.5 | 60.0 | 61.5 |",
"price": 2199.99,
"tags": [
"bicycle",
"electric bike",
"mountain bike"
]
},
{
"name": "Aero Pro X",
"shortDescription": "Aero Pro X is a high-end racing bike designed for serious cyclists who demand speed, agility, and superior performance. The lightweight carbon frame and fork, combined with the aerodynamic design, provide optimal stiffness and efficiency to maximize your speed. The bike features a 2x Shimano Ultegra drivetrain, hydraulic disc brakes, and 700c wheels with high-quality tires. Whether you're competing in a triathlon or climbing steep hills, Aero Pro X delivers exceptional performance and precision handling.",
"description": "## Overview\nIt's right for you if...\nYou are a competitive cyclist looking for a bike that is designed for racing. You want a bike that delivers exceptional speed, agility, and precision handling. You demand superior performance and reliability from your equipment.\n\nThe tech you get\nA lightweight carbon frame with an aerodynamic design, a carbon fork with hidden fender mounts, a 2x Shimano Ultegra drivetrain with a wide range of gearing, hydraulic disc brakes, and 700c wheels with high-quality tires. Aero Pro X is designed for serious cyclists who demand nothing but the best.\n\nThe final word\nAero Pro X is the ultimate racing bike for serious cyclists. The lightweight carbon frame and aerodynamic design deliver maximum speed and efficiency, while the 2x Shimano Ultegra drivetrain and hydraulic disc brakes ensure precise shifting and stopping power. Whether you're competing in a triathlon or a criterium race, Aero Pro X delivers the performance you need to win.\n\n## Features\n\nAerodynamic design\nThe Aero Pro X features an aerodynamic design that reduces drag and maximizes efficiency. The bike is optimized for speed and agility, so you can ride faster and farther with less effort.\n\nHydraulic disc brakes\nHydraulic disc brakes provide unrivaled stopping power and modulation in any weather condition. You'll feel confident and in control no matter where you ride.\n\nCarbon components\nThe Aero Pro X features a carbon fork with hidden fender mounts to provide optimal stiffness and absorption. This means you can ride faster and more comfortably over any terrain.\n\n## Specifications\nFrameset\nFrame with Fork\tCarbon frame with an aerodynamic design, internal cable routing, 3s chain keeper, 142x12mm thru-axle\nFork\tCarbon fork with hidden fender mounts, flat mount disc, 100x12mm thru-axle\n\nWheels\nWheel front\tDouble wall carbon rims, 700c, thru-axle hub\nWheel rear\tDouble wall carbon rims, 700c, thru-axle hub\nTire\tContinental Grand Prix 5000, folding bead, 700x25c\nMax tire size\t700x28c without fenders, 700x25c with fenders\n\nDrivetrain\nShifter\tShimano Ultegra, 11 speed\nFront derailleur\tShimano Ultegra\nRear derailleur\tShimano Ultegra\nCrank\tShimano Ultegra, 52-36T, 170mm (S), 172.5mm (M), 175mm (L/XL)\nBottom bracket\tShimano BB72, 68mm, PressFit\nCassette\tShimano Ultegra, 11-30T, 11 speed\nChain\tShimano HG701, 11 speed\nPedal\tNot included\n\nComponents\nSaddle\tBontrager Montrose Elite, carbon rails, 138mm width\nSeatpost\tCarbon seat post, 27.2mm, 20mm offset\nHandlebar\tBontrager XXX Aero, carbon, 31.8mm clamp, 75mm reach, 125mm drop\nGrips\tBontrager Supertack Perf tape\nStem\tBontrager Pro, 31.8mm clamp, 7 degree, 90mm length\nBrake\tShimano hydraulic disc, Ultegra lever, Ultegra caliper\nBrake rotor\tShimano RT800, centerlock, 160mm\nRotor size\tMax brake rotor sizes: 160mm front & rear\n\nWeight\nWeight\tM - 8.36 kg / 18.42 lbs\nWeight limit\tThis bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 275 pounds (125 kg).\n\n## Sizing\n| Size | Rider Height |\n|:----:|:-------------------------:|\n| S | 155 - 165 cm 5'1\" - 5'5\" |\n| M | 165 - 175 cm 5'5\" - 5'9\" |\n| L | 175 - 186 cm 5'9\" - 6'1\" |\n| XL | 186 - 197 cm 6'1\" - 6'6\" |\n\n## Geometry\n| Frame size | S | M | L | XL |\n|--------------------|-------|-------|-------|-------|\n| Wheel size | 700c | 700c | 700c | 700c |\n| A — Seat tube | 50.6 | 52.4 | 54.3 | 56.2 |\n| B — Seat tube angle | 75.5° | 74.5° | 73.5° | 72.5° |\n| C — Head tube length | 12.0 | 14.0 | 16.0 | 18.0 |\n| D — Head angle | 72.5° | 73.0° | 73.5° | 74.0° |\n| E — Effective top tube | 53.8 | 55.4 | 57.0 | 58.6 |\n| F — Bottom bracket height | 26.5 | 26.5 | 26.5 | 26.5 |\n| G — Bottom bracket drop | 7.0 | 7.0 | 7.0 | 7.0 |\n| H — Chainstay length | 41.0 | 41.0 | 41.0 | 41.0 |\n| I — Offset | 4.5 | 4.5 | 4.5 | 4.5 |\n| J — Trail | 6.0 | 6.0 | 6.0 | 6.0 |\n| K — Wheelbase | 97.1 | 98.7 | 100.2 | 101.8 |\n| L — Standover | 73.8 | 76.2 | 78.5 | 80.8 |\n| M — Frame reach | 38.8 | 39.5 | 40.2 | 40.9 |\n| N — Frame stack | 52.8 | 54.7 | 56.6 | 58.5 |",
"price": 1599.99,
"tags": [
"bicycle",
"road bike"
]
},
{
"name": "Voltex+ Ultra Lowstep",
"shortDescription": "Voltex+ Ultra Lowstep is a high-performance electric hybrid bike designed for riders who seek speed, comfort, and reliability during their everyday rides. Equipped with a powerful and efficient Voltex Drive Pro motor and a fully-integrated 600Wh battery, this e-bike allows you to cover longer distances on a single charge. The Voltex+ Ultra Lowstep comes with premium components that prioritize comfort and safety, such as a suspension seatpost, wide and stable tires, and integrated lights.",
"description": "## Overview\n\nIt's right for you if...\nYou want an e-bike that provides a boost for faster rides and effortless usage. Durability is crucial, and you need a bike with one of the most powerful and efficient motors.\n\nThe tech you get\nA lightweight Delta Carbon Fiber frame with an ultra-lowstep design, a Voltex Drive Pro (350W, 75Nm) motor capable of maintaining speeds up to 30 mph, an extended range 600Wh battery integrated into the frame, and a Voltex Control Panel. Additionally, it features a 12-speed Shimano drivetrain, hydraulic disc brakes for optimal all-weather stopping power, a suspension seatpost, wide puncture-resistant tires for added stability, ergonomic grips, a kickstand, lights, and a cargo rack.\n\nThe final word\nThis bike offers enhanced enjoyment and ease of use on long commutes, leisure rides, and adventures. With its extended-range battery, powerful Voltex motor, user-friendly controller, and a seatpost that smooths out road vibrations, it guarantees an exceptional riding experience.\n\n## Features\n\nUltra-fast assistance\n\nExperience speeds up to 30 mph with the cutting-edge Voltex Drive Pro motor, allowing you to breeze through errands, commutes, and joyrides.\n\n## Specs\n\nFrameset\n- Frame: Delta Carbon Fiber, Removable Integrated Battery (RIB), sleek welds, rack & fender mounts, internal routing, kickstand mount, 135x5mm QR\n- Fork: Voltex Alloy, threaded steel steerer, rack mounts, post mount disc, 460mm axle-to-crown, ThruSkew 5mm QR\n- Max compatible fork travel: 50mm\n\nWheels\n- Hub front: Formula DC-20, alloy, 6-bolt, 5x100mm QR\n- Skewer front: 132x5mm QR, ThruSkew\n- Hub rear: Formula DC-22, alloy, 6-bolt, Shimano 8/9/10 freehub, 135x5mm QR\n- Skewer rear: 153x5mm bolt-on\n- Rim: Voltex Connection, double-wall, 32-hole, 20 mm width, Schrader valve\n- Tire: Voltex E6 Hard-Case Lite, reflective, wire bead, 60tpi, 700x50c\n- Max tire size: 700x50mm with or without fenders\n\nDrivetrain\n- Shifter: Shimano Deore XT M8100, 12-speed\n- Rear derailleur: Shimano Deore XT M8100, long cage\n- Crank: Voltex alloy, 170mm length\n- Chainring: FSA, 44T, aluminum with guard\n- Cassette: Shimano Deore XT M8100, 10-51, 12-speed\n- Chain: KMC E12 Turbo\n- Pedal: Voltex Urban pedals\n\nComponents\n- Saddle: Voltex Boulevard\n- Seatpost: Alloy, suspension, 31.6mm, 300mm length\n- Handlebar: Voltex alloy, 31.8mm, comfort sweep, 620mm width (XS, S, M), 660mm width (L)\n- Grips: Voltex Satellite Elite, alloy lock-on\n- Stem: Voltex alloy quill, 31.8mm clamp, adjustable rise, Blendr compatible, 85mm length (XS, S), 105mm length (M, L)\n- Headset: VP sealed cartridge, 1-1/8'', threaded\n- Brake: Shimano MT520 hydraulic disc\n- Brake rotor: Shimano RT56, 6-bolt, 180mm (XS, S, M, L), 160mm (XS, S, M, L)\n\nAccessories\n- Battery: Voltex PowerTube 600Wh\n- Charger: Voltex compact 2A, 100-240V\n- Computer: Voltex Control Panel\n- Motor: Voltex Drive Pro, 75Nm, 30mph\n- Light: Voltex Solo for e-bike, taillight (XS, S, M, L), Voltex MR8, 180 lumen, 60 lux, LED, headlight (XS, S, M, L)\n- Kickstand: Adjustable length rear mount alloy kickstand\n- Cargo rack: Voltex-compatible alloy rear rack, maximum load 25 kg / 55 lbs\n- Fender: Voltex wide (XS, S, M, L), Voltex plastic (XS, S, M, L)\n\nWeight\n- Weight: M - 20.50 kg / 45.19 lbs\n- Weight limit: This bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 330 pounds (150 kg).\n\n## Sizing\n\n| Size | Rider Height | Inseam |\n|:----:|:-------------------------:|:--------------------:|\n| XS | 147 - 155 cm 4'10\" - 5'1\" | 69 - 73 cm 27\" - 29\" |\n| S | 155 - 165 cm 5'1\" - 5'5\" | 72 - 78 cm 28\" - 31\" |\n| M | 165 - 175 cm 5'5\" - 5'9\" | 77 - 83 cm 30\" - 33\" |\n| L | 175 - 186 cm 5'9\" - 6'1\" | 82 - 88 cm 32\" - 35\" |\n\n## Geometry\n\nAll measurements provided in cm unless otherwise noted.\n\nSizing table\n\n| Frame size number | 40 cm | 45 cm | 50 cm | 55 cm |\n|---------------------------|-------|-------|-------|-------|\n| Frame size letter | XS | S | M | L |\n| Wheel size | 700c | 700c | 700c | 700c |\n| A — Seat tube | 38.0 | 43.0 | 48.0 | 53.0 |\n| B — Seat tube angle | 70.5° | 70.5° | 70.5° | 70.5° |\n| C — Head tube length | 15.0 | 15.0 | 17.0 | 19.0 |\n| D — Head angle | 69.2° | 69.2° | 69.2° | 69.2° |\n| E — Effective top tube | 57.2 | 57.7 | 58.8 | 60.0 |\n| F — Bottom bracket height | 30.3 | 30.3 | 30.3 | 30.3 |\n| G — Bottom bracket drop | 6.0 | 6.0 | 6.0 | 6.0 |\n| H — Chainstay length | 48.5 | 48.5 | 48.5 | 48.5 |\n| I — Offset | 5.0 | 5.0 | 5.0 | 5.0 |\n| J — Trail | 9.0 | 9.0 | 9.0 | 9.0 |\n| K — Wheelbase | 111.8 | 112.3 | 113.6 | 114.8 |\n| L — Standover | 42.3 | 42.3 | 42.3 | 42.3 |\n| M — Frame reach | 36.0 | 38.0 | 38.0 | 38.0 |\n| N — Frame stack | 62.0 | 62.0 | 63.9 | 65.8 |\n| Stem length | 8.0 | 8.5 | 8.5 | 10.5 |\n\nPlease note that the specifications and features listed above are subject to change and may vary based on different models and versions of the Voltex+ Ultra Lowstep bike.",
"price": 2999.99,
"tags": [
"bicycle",
"road bike",
"professional"
]
},
{
"name": "SwiftRide Hybrid",
"shortDescription": "SwiftRide Hybrid is a versatile and efficient bike designed for riders who want a smooth and enjoyable ride on various terrains. It incorporates advanced technology and high-quality components to provide a comfortable and reliable cycling experience.",
"description": "## Overview\n\nIt's right for you if...\nYou are looking for a bike that combines the benefits of an electric bike with the versatility of a hybrid. You value durability, speed, and ease of use.\n\nThe tech you get\nThe SwiftRide Hybrid features a lightweight and durable aluminum frame, making it easy to handle and maneuver. It is equipped with a powerful electric motor that offers a speedy assist, helping you reach speeds of up to 25 mph. The bike comes with a removable and fully-integrated 500Wh battery, providing a long-range capacity for extended rides. It also includes a 10-speed Shimano drivetrain, hydraulic disc brakes for precise stopping power, wide puncture-resistant tires for stability, and integrated lights for enhanced visibility.\n\nThe final word\nThe SwiftRide Hybrid is designed for riders who want a bike that can handle daily commutes, recreational rides, and adventures. With its efficient motor, intuitive controls, and comfortable features, it offers an enjoyable and hassle-free riding experience.\n\n## Features\n\nEfficient electric assist\nExperience the thrill of effortless riding with the powerful electric motor that provides a speedy assist, making your everyday rides faster and more enjoyable.\n\n## Specs\n\nFrameset\n- Frame: Lightweight Aluminum, Removable Integrated Battery (RIB), rack & fender mounts, internal routing, 135x5mm QR\n- Fork: SwiftRide Alloy, threaded steel steerer, rack mounts, post mount disc, 460mm axle-to-crown, ThruSkew 5mm QR\n- Max compatible fork travel: 50mm\n\nWheels\n- Hub front: Formula DC-20, alloy, 6-bolt, 5x100mm QR\n- Skewer front: 132x5mm QR, ThruSkew\n- Hub rear: Formula DC-22, alloy, 6-bolt, Shimano 8/9/10 freehub, 135x5mm QR\n- Skewer rear: 153x5mm bolt-on\n- Rim: SwiftRide Connection, double-wall, 32-hole, 20 mm width, Schrader valve\n- Tire: SwiftRide E6 Hard-Case Lite, reflective, wire bead, 60tpi, 700x50c\n- Max tire size: 700x50mm with or without fenders\n\nDrivetrain\n- Shifter: Shimano Deore M4100, 10 speed\n- Rear derailleur: Shimano Deore M5120, long cage\n- Crank: ProWheel alloy, 170mm length\n- Chainring: FSA, 42T, steel w/guard\n- Cassette: Shimano Deore M4100, 11-42, 10 speed\n- Chain: KMC E10\n- Pedal: SwiftRide City pedals\n\nComponents\n- Saddle: SwiftRide Boulevard\n- Seatpost: Alloy, suspension, 31.6mm, 300mm length\n- Handlebar:\n - Size: XS, S, M - SwiftRide alloy, 31.8mm, comfort sweep, 620mm width\n - Size: L - SwiftRide alloy, 31.8mm, comfort sweep, 660mm width\n- Grips: SwiftRide Satellite Elite, alloy lock-on\n- Stem:\n - Size: XS, S - SwiftRide alloy quill, 31.8mm clamp, adjustable rise, 85mm length\n - Size: M, L - SwiftRide alloy quill, 31.8mm clamp, adjustable rise, 105mm length\n- Headset: VP sealed cartridge, 1-1/8'', threaded\n- Brake: Shimano MT200 hydraulic disc\n- Brake rotor:\n - Size: XS, S, M, L - Shimano RT26, 6-bolt, 180mm\n - Size: XS, S, M, L - Shimano RT26, 6-bolt, 160mm\n\nAccessories\n- Battery: SwiftRide PowerTube 500Wh\n- Charger: SwiftRide compact 2A, 100-240V\n- Computer: SwiftRide Purion\n- Motor: SwiftRide Performance Line Sport, 65Nm, 25mph\n- Light:\n - Size: XS, S, M, L - SwiftRide SOLO for e-bike, taillight\n - Size: XS, S, M, L - SwiftRide MR8, 180 lumen, 60 lux, LED, headlight\n- Kickstand: Adjustable length rear mount alloy kickstand\n- Cargo rack: SwiftRide-compatible alloy rear rack, maximum load 25 kg / 55 lbs\n- Fender:\n - Size: XS, S, M, L - SwiftRide wide\n - Size: XS, S, M, L - SwiftRide plastic\n\nWeight\n- Weight: M - 22.30 kg / 49.17 lbs\n- Weight limit: This bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\n\n## Sizing\n\n| Size | Rider Height | Inseam |\n|:----:|:-------------------------:|:--------------------:|\n| XS | 147 - 155 cm (4'10\" - 5'1\") | 69 - 73 cm (27\" - 29\") |\n| S | 155 - 165 cm (5'1\" - 5'5\") | 72 - 78 cm (28\" - 31\") |\n| M | 165 - 175 cm (5'5\" - 5'9\") | 77 - 83 cm (30\" - 33\") |\n| L | 175 - 186 cm (5'9\" - 6'1\") | 82 - 88 cm (32\" - 35\") |\n\n## Geometry\n\nAll measurements provided in cm unless otherwise noted.\n\nSizing table\n| Frame size number | 40 cm | 45 cm | 50 cm | 55 cm |\n|---------------------------|-------|-------|-------|-------|\n| Frame size letter | XS | S | M | L |\n| Wheel size | 700c | 700c | 700c | 700c |\n| A — Seat tube | 39.0 | 44.0 | 50.0 | 55.0 |\n| B — Seat tube angle | 71.0° | 71.0° | 71.0° | 71.0° |\n| C — Head tube length | 16.0 | 16.0 | 18.0 | 20.0 |\n| D — Head angle | 68.2° | 68.2° | 68.2° | 68.2° |\n| E — Effective top tube | 58.2 | 58.7 | 59.8 | 61.0 |\n| F — Bottom bracket height | 29.4 | 29.4 | 29.4 | 29.4 |\n| G — Bottom bracket drop | 6.5 | 6.5 | 6.5 | 6.5 |\n| H — Chainstay length | 48.7 | 48.7 | 48.7 | 48.7 |\n| I — Offset | 4.5 | 4.5 | 4.5 | 4.5 |\n| J — Trail | 9.5 | 9.5 | 9.5 | 9.5 |\n| K — Wheelbase | 112.2 | 112.7 | 114.0 | 115.2 |\n| L — Standover | 43.3 | 43.3 | 43.3 | 43.3 |\n| M — Frame reach | 36.5 | 38.5 | 38.5 | 38.5 |\n| N — Frame stack | 63.0 | 63.0 | 64.9 | 66.8 |\n| Stem length | 8.5 | 9.0 | 9.0 | 11.0 |",
"price": 3999.99,
"tags": [
"bicycle",
"mountain bike",
"professional"
]
},
{
"name": "RoadRunner E-Speed Lowstep",
"shortDescription": "RoadRunner E-Speed Lowstep is a high-performance electric hybrid designed for riders seeking speed and excitement on their daily rides. It is equipped with a powerful and reliable ThunderBolt drive unit that offers exceptional acceleration. The bike features a fully-integrated 500Wh battery, allowing riders to cover longer distances on a single charge. With its comfortable and safe components, including a suspension seatpost, wide and stable tires, and integrated lights, the RoadRunner E-Speed Lowstep ensures a smooth and enjoyable ride.",
"description": "## Overview\n\nIt's right for you if...\nYou're looking for an e-bike that provides an extra boost to reach your destination quickly and effortlessly. You prioritize durability and want a bike with one of the fastest motors available.\n\nThe tech you get\nA lightweight and sturdy ThunderBolt aluminum frame with a lowstep geometry. The bike is equipped with a ThunderBolt Performance Sport (250W, 65Nm) drive unit capable of reaching speeds up to 28 mph. It features a long-range 500Wh battery fully integrated into the frame and a ThunderBolt controller. Additionally, the bike has a 10-speed Shimano drivetrain, hydraulic disc brakes for reliable stopping power in all weather conditions, a suspension seatpost, wide puncture-resistant tires for stability, ergonomic grips, a kickstand, lights, and a rack and fenders.\n\nThe final word\nThe RoadRunner E-Speed Lowstep is designed to provide enjoyment and ease of use on longer commutes, recreational rides, and adventurous journeys. Its long-range battery, fast ThunderBolt motor, intuitive controller, and road-smoothing suspension seatpost make it the perfect choice for riders seeking both comfort and speed.\n\n## Features\n\nSuper speedy assist\n\nThe ThunderBolt Performance Sport drive unit allows you to accelerate up to 28mph, making errands, commutes, and joyrides a breeze.\n\n## Specs\n\nFrameset\n- Frame: ThunderBolt Smooth Aluminum, Removable Integrated Battery (RIB), sleek welds, rack & fender mounts, internal routing, kickstand mount, 135x5mm QR\n- Fork: RoadRunner Alloy, threaded steel steerer, rack mounts, post mount disc, 460mm axle-to-crown, ThruSkew 5mm QR\n- Max compatible fork travel: 50mm\n\nWheels\n- Hub front: ThunderBolt DC-20, alloy, 6-bolt, 5x100mm QR\n- Skewer front: 132x5mm QR, ThruSkew\n- Hub rear: ThunderBolt DC-22, alloy, 6-bolt, Shimano 8/9/10 freehub, 135x5mm QR\n- Skewer rear: 153x5mm bolt-on\n- Rim: ThunderBolt Connection, double-wall, 32-hole, 20 mm width, Schrader valve\n- Tire: ThunderBolt E6 Hard-Case Lite, reflective, wire bead, 60tpi, 700x50c\n- Max tire size: 700x50mm with or without fenders\n\nDrivetrain\n- Shifter: Shimano Deore M4100, 10 speed\n- Rear derailleur: Shimano Deore M5120, long cage\n- Crank: ProWheel alloy, 170mm length\n- Chainring: FSA, 42T, steel w/guard\n- Cassette: Shimano Deore M4100, 11-42, 10 speed\n- Chain: KMC E10\n- Pedal: RoadRunner City pedals\n\nComponents\n- Saddle: RoadRunner Boulevard\n- Seatpost: Alloy, suspension, 31.6mm, 300mm length\n- Handlebar:\n - Size: XS, S, M - RoadRunner alloy, 31.8mm, comfort sweep, 620mm width\n - Size: L - RoadRunner alloy, 31.8mm, comfort sweep, 660mm width\n- Grips: RoadRunner Satellite Elite, alloy lock-on\n- Stem:\n - Size: XS, S - RoadRunner alloy quill, 31.8mm clamp, adjustable rise, Blendr compatible, 85mm length\n - Size: M, L - RoadRunner alloy quill, 31.8mm clamp, adjustable rise, Blendr compatible, 105mm length\n- Headset: VP sealed cartridge, 1-1/8'', threaded\n- Brake: Shimano MT200 hydraulic disc\n- Brake rotor:\n - Size: XS, S, M, L - Shimano RT26, 6-bolt, 180mm\n - Size: XS, S, M, L - Shimano RT26, 6-bolt, 160mm\n\nAccessories\n- Battery: ThunderBolt PowerTube 500Wh\n- Charger: ThunderBolt compact 2A, 100-240V\n- Computer: ThunderBolt Purion\n- Motor: ThunderBolt Performance Line Sport, 65Nm, 28mph\n- Light:\n - Size: XS, S, M, L - ThunderBolt SOLO for e-bike, taillight\n - Size: XS, S, M, L - ThunderBolt MR8, 180 lumen, 60 lux, LED, headlight\n- Kickstand: Adjustable length rear mount alloy kickstand\n- Cargo rack: MIK-compatible alloy rear rack, maximum load 25 kg / 55 lbs\n- Fender:\n - Size: XS, S, M, L - RoadRunner wide\n - Size: XS, S, M, L - RoadRunner plastic\n\nWeight\n- Weight: M - 22.30 kg / 49.17 lbs\n- Weight limit: This bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\n\n## Sizing\n\n| Size | Rider Height | Inseam |\n|:----:|:-------------------------:|:--------------------:|\n| XS | 147 - 155 cm 4'10\" - 5'1\" | 69 - 73 cm 27\" - 29\" |\n| S | 155 - 165 cm 5'1\" - 5'5\" | 72 - 78 cm 28\" - 31\" |\n| M | 165 - 175 cm 5'5\" - 5'9\" | 77 - 83 cm 30\" - 33\" |\n| L | 175 - 186 cm 5'9\" - 6'1\" | 82 - 88 cm 32\" - 35\" |\n\n## Geometry\n\nAll measurements provided in cm unless otherwise noted.\n\nSizing table\n| Frame size number | 40 cm | 45 cm | 50 cm | 55 cm |\n|---------------------------|-------|-------|-------|-------|\n| Frame size letter | XS | S | M | L |\n| Wheel size | 700c | 700c | 700c | 700c |\n| A — Seat tube | 39.0 | 44.0 | 50.0 | 55.0 |\n| B — Seat tube angle | 71.0° | 71.0° | 71.0° | 71.0° |\n| C — Head tube length | 16.0 | 16.0 | 18.0 | 20.0 |\n| D — Head angle | 68.2° | 68.2° | 68.2° | 68.2° |\n| E — Effective top tube | 58.2 | 58.7 | 59.8 | 61.0 |\n| F — Bottom bracket height | 29.4 | 29.4 | 29.4 | 29.4 |\n| G — Bottom bracket drop | 6.5 | 6.5 | 6.5 | 6.5 |\n| H — Chainstay length | 48.7 | 48.7 | 48.7 | 48.7 |\n| I — Offset | 4.5 | 4.5 | 4.5 | 4.5 |\n| J — Trail | 9.5 | 9.5 | 9.5 | 9.5 |\n| K — Wheelbase | 112.2 | 112.7 | 114.0 | 115.2 |\n| L — Standover | 43.3 | 43.3 | 43.3 | 43.3 |\n| M — Frame reach | 36.5 | 38.5 | 38.5 | 38.5 |\n| N — Frame stack | 63.0 | 63.0 | 64.9 | 66.8 |\n| Stem length | 8.5 | 9.0 | 9.0 | 11.0 |",
"price": 4999.99,
"tags": [
"bicycle",
"road bike",
"professional"
]
},
{
"name": "Hyperdrive Turbo X1",
"shortDescription": "Hyperdrive Turbo X1 is a high-performance electric bike designed for riders seeking an exhilarating experience on their daily rides. It features a powerful and efficient Hyperdrive Sport drive unit and a sleek, integrated 500Wh battery for extended range. This e-bike is equipped with top-of-the-line components prioritizing comfort and safety, including a suspension seatpost, wide and stable tires, and integrated lights.",
"description": "## Overview\n\nIt's right for you if...\nYou crave the thrill of an e-bike that can accelerate rapidly, reaching high speeds effortlessly. You value durability and are looking for a bike that is equipped with one of the fastest motors available.\n\nThe tech you get\nA lightweight Hyper Alloy frame with a lowstep geometry, a Hyperdrive Sport (300W, 70Nm) drive unit capable of maintaining speeds up to 30 mph, a long-range 500Wh battery seamlessly integrated into the frame, and an intuitive Hyper Control controller. Additionally, it features a 10-speed Shimano drivetrain, hydraulic disc brakes for reliable stopping power in all weather conditions, a suspension seatpost, wide puncture-resistant tires for enhanced stability, ergonomic grips, a kickstand, lights, and a rack and fenders.\n\nThe final word\nThis bike is designed for riders seeking enjoyment and convenience on longer commutes, recreational rides, and thrilling adventures. With its long-range battery, high-speed motor, user-friendly controller, and smooth-riding suspension seatpost, the Hyperdrive Turbo X1 guarantees an exceptional e-biking experience.\n\n## Features\n\nHyperboost Acceleration\nExperience adrenaline-inducing rides with the powerful Hyperdrive Sport drive unit that enables quick acceleration and effortless cruising through errands, commutes, and joyrides.\n\n## Specs\n\nFrameset\nFrame\tHyper Alloy, Removable Integrated Battery (RIB), seamless welds, rack & fender mounts, internal routing, kickstand mount, 135x5mm QR\nFork\tHyper Alloy, threaded steel steerer, rack mounts, post mount disc, 460mm axle-to-crown, ThruSkew 5mm QR\nMax compatible fork travel\t50mm\n\nWheels\nHub front\tFormula DC-20, alloy, 6-bolt, 5x100mm QR\nSkewer front\t132x5mm QR, ThruSkew\nHub rear\tFormula DC-22, alloy, 6-bolt, Shimano 8/9/10 freehub, 135x5mm QR\nSkewer rear\t153x5mm bolt-on\nRim\tHyper Connection, double-wall, 32-hole, 20 mm width, Schrader valve\nTire\tHyper E6 Hard-Case Lite, reflective, wire bead, 60tpi, 700x50c\nMax tire size\t700x50mm with or without fenders\n\nDrivetrain\nShifter\tShimano Deore M4100, 10 speed\nRear derailleur\tShimano Deore M5120, long cage\nCrank\tProWheel alloy, 170mm length\nChainring\tFSA, 42T, steel w/guard\nCassette\tShimano Deore M4100, 11-42, 10 speed\nChain\tKMC E10\nPedal\tHyper City pedals\n\nComponents\nSaddle\tHyper Boulevard\nSeatpost\tAlloy, suspension, 31.6mm, 300mm length\nHandlebar\tSize: XS, S, M\nHyper alloy, 31.8mm, comfort sweep, 620mm width\nSize: L\nHyper alloy, 31.8mm, comfort sweep, 660mm width\nGrips\tHyper Satellite Elite, alloy lock-on\nStem\tSize: XS, S\nHyper alloy quill, 31.8mm clamp, adjustable rise, Blendr compatible, 85mm length\nSize: M, L\nHyper alloy quill, 31.8mm clamp, adjustable rise, Blendr compatible, 105mm length\nHeadset\tVP sealed cartridge, 1-1/8'', threaded\nBrake\tShimano MT200 hydraulic disc\nBrake rotor\tSize: XS, S, M, L\nShimano RT26, 6-bolt,180mm\nSize: XS, S, M, L\nShimano RT26, 6-bolt,160mm\n\nAccessories\nBattery\tHyper PowerTube 500Wh\nCharger\tHyper compact 2A, 100-240V\nComputer\tHyper Control\nMotor\tHyperdrive Sport, 70Nm, 30mph\nLight\tSize: XS, S, M, L\nSpanninga SOLO for e-bike, taillight\nSize: XS, S, M, L\nHerrmans MR8, 180 lumen, 60 lux, LED, headlight\nKickstand\tAdjustable length rear mount alloy kickstand\nCargo rack\tMIK-compatible alloy rear rack, maximum load 25 kg / 55 lbs\n*Fender\tSize: XS, S, M, L\nSKS wide\nSize: XS, S, M, L\nSKS plastic\n\nWeight\nWeight\tM - 22.30 kg / 49.17 lbs\nWeight limit\tThis bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\n\n## Sizing\n\n| Size | Rider Height | Inseam |\n|:----:|:-------------------------:|:--------------------:|\n| XS | 147 - 155 cm 4'10\" - 5'1\" | 69 - 73 cm 27\" - 29\" |\n| S | 155 - 165 cm 5'1\" - 5'5\" | 72 - 78 cm 28\" - 31\" |\n| M | 165 - 175 cm 5'5\" - 5'9\" | 77 - 83 cm 30\" - 33\" |\n| L | 175 - 186 cm 5'9\" - 6'1\" | 82 - 88 cm 32\" - 35\" |\n\n## Geometry\n\nAll measurements provided in cm unless otherwise noted.\n\n| Frame size number | 40 cm | 45 cm | 50 cm | 55 cm |\n|---------------------------|-------|-------|-------|-------|\n| Frame size letter | XS | S | M | L |\n| Wheel size | 700c | 700c | 700c | 700c |\n| A — Seat tube | 39.0 | 44.0 | 50.0 | 55.0 |\n| B — Seat tube angle | 71.0° | 71.0° | 71.0° | 71.0° |\n| C — Head tube length | 16.0 | 16.0 | 18.0 | 20.0 |\n| D — Head angle | 68.2° | 68.2° | 68.2° | 68.2° |\n| E — Effective top tube | 58.2 | 58.7 | 59.8 | 61.0 |\n| F — Bottom bracket height | 29.4 | 29.4 | 29.4 | 29.4 |\n| G — Bottom bracket drop | 6.5 | 6.5 | 6.5 | 6.5 |\n| H — Chainstay length | 48.7 | 48.7 | 48.7 | 48.7 |\n| I — Offset | 4.5 | 4.5 | 4.5 | 4.5 |\n| J — Trail | 9.5 | 9.5 | 9.5 | 9.5 |\n| K — Wheelbase | 112.2 | 112.7 | 114.0 | 115.2 |\n| L — Standover | 43.3 | 43.3 | 43.3 | 43.3 |\n| M — Frame reach | 36.5 | 38.5 | 38.5 | 38.5 |\n| N — Frame stack | 63.0 | 63.0 | 64.9 | 66.8 |\n| Stem length | 8.5 | 9.0 | 9.0 | 11.0 |",
"price": 1999.99,
"tags": [
"bicycle",
"city bike",
"professional"
]
},
{
"name": "Horizon+ Evo Lowstep",
"shortDescription": "The Horizon+ Evo Lowstep is a versatile electric hybrid bike designed for riders seeking a thrilling and efficient riding experience on a variety of terrains. With its powerful Bosch Performance Line Sport drive unit and integrated 500Wh battery, this e-bike enables riders to cover long distances with ease. Equipped with features prioritizing comfort and safety, such as a suspension seatpost, stable tires, and integrated lights, the Horizon+ Evo Lowstep is a reliable companion for everyday rides.",
"description": "## Overview\n\nIt's right for you if...\nYou desire the convenience and speed of an e-bike to enhance your riding, and you want an intuitive and durable bicycle. You prioritize having one of the fastest motors developed by Bosch.\n\nThe tech you get\nA lightweight Alpha Smooth Aluminum frame with a lowstep geometry, a Bosch Performance Line Sport (250W, 65Nm) drive unit capable of sustaining speeds up to 28 mph, a fully encased 500Wh battery integrated into the frame, and a Bosch Purion controller. Additionally, it features a 10-speed Shimano drivetrain, hydraulic disc brakes for reliable stopping power in all weather conditions, a suspension seatpost, wide puncture-resistant tires for improved stability, ergonomic grips, a kickstand, lights, and a rack and fenders.\n\nThe final word\nThe Horizon+ Evo Lowstep offers an enjoyable and user-friendly riding experience for longer commutes, recreational rides, and adventures. It boasts an extended range battery, a high-performance Bosch motor, an intuitive controller, and a suspension seatpost for a smooth ride on various road surfaces.\n\n## Features\n\nSuper speedy assist\nExperience effortless cruising through errands, commutes, and joyrides with the new Bosch Performance Sport drive unit, allowing acceleration of up to 28 mph.\n\n## Specs\n\nFrameset\n- Frame: Alpha Platinum Aluminum, Removable Integrated Battery (RIB), smooth welds, rack & fender mounts, internal routing, kickstand mount, 135x5mm QR\n- Fork: Horizon Alloy, threaded steel steerer, rack mounts, post mount disc, 460mm axle-to-crown, ThruSkew 5mm QR\n- Max compatible fork travel: 50mm\n\nWheels\n- Front Hub: Formula DC-20, alloy, 6-bolt, 5x100mm QR\n- Front Skewer: 132x5mm QR, ThruSkew\n- Rear Hub: Formula DC-22, alloy, 6-bolt, Shimano 8/9/10 freehub, 135x5mm QR\n- Rear Skewer: 153x5mm bolt-on\n- Rim: Bontrager Connection, double-wall, 32-hole, 20mm width, Schrader valve\n- Tire: Bontrager E6 Hard-Case Lite, reflective, wire bead, 60tpi, 700x50c\n- Max tire size: 700x50mm with or without fenders\n\nDrivetrain\n- Shifter: Shimano Deore M4100, 10-speed\n- Rear Derailleur: Shimano Deore M5120, long cage\n- Crank: ProWheel alloy, 170mm length\n- Chainring: FSA, 42T, steel w/guard\n- Cassette: Shimano Deore M4100, 11-42, 10-speed\n- Chain: KMC E10\n- Pedal: Bontrager City pedals\n\nComponents\n- Saddle: Bontrager Boulevard\n- Seatpost: Alloy, suspension, 31.6mm, 300mm length\n- Handlebar:\n - Size: XS, S, M - Bontrager alloy, 31.8mm, comfort sweep, 620mm width\n - Size: L - Bontrager alloy, 31.8mm, comfort sweep, 660mm width\n- Grips: Bontrager Satellite Elite, alloy lock-on\n- Stem:\n - Size: XS, S - Bontrager alloy quill, 31.8mm clamp, adjustable rise, Blendr compatible, 85mm length\n - Size: M, L - Bontrager alloy quill, 31.8mm clamp, adjustable rise, Blendr compatible, 105mm length\n- Headset: VP sealed cartridge, 1-1/8\", threaded\n- Brake: Shimano MT200 hydraulic disc\n- Brake rotor:\n - Size: XS, S, M, L - Shimano RT26, 6-bolt, 180mm\n - Size: XS, S, M, L - Shimano RT26, 6-bolt, 160mm\n\nAccessories\n- Battery: Bosch PowerTube 500Wh\n- Charger: Bosch compact 2A, 100-240V\n- Computer: Bosch Purion\n- Motor: Bosch Performance Line Sport, 65Nm, 28mph\n- Light:\n - Size: XS, S, M, L - Spanninga SOLO for e-bike, taillight\n - Size: XS, S, M, L - Herrmans MR8, 180 lumen, 60 lux, LED, headlight\n- Kickstand: Adjustable length rear mount alloy kickstand\n- Cargo rack: MIK-compatible alloy rear rack, maximum load 25 kg / 55 lbs\n- Fender:\n - Size: XS, S, M, L - SKS wide\n - Size: XS, S, M, L - SKS plastic\n\nWeight\n- Weight: M - 22.30 kg / 49.17 lbs\n- Weight limit: This bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\n\n## Sizing\n\n| Size | Rider Height | Inseam |\n|:----:|:-------------------------:|:--------------------:|\n| XS | 147 - 155 cm 4'10\" - 5'1\" | 69 - 73 cm 27\" - 29\" |\n| S | 155 - 165 cm 5'1\" - 5'5\" | 72 - 78 cm 28\" - 31\" |\n| M | 165 - 175 cm 5'5\" - 5'9\" | 77 - 83 cm 30\" - 33\" |\n| L | 175 - 186 cm 5'9\" - 6'1\" | 82 - 88 cm 32\" - 35\" |\n\n## Geometry\n\nAll measurements provided in cm unless otherwise noted.\nSizing table\n| Frame size number | 40 cm | 45 cm | 50 cm | 55 cm |\n|---------------------------|-------|-------|-------|-------|\n| Frame size letter | XS | S | M | L |\n| Wheel size | 700c | 700c | 700c | 700c |\n| A — Seat tube | 39.0 | 44.0 | 50.0 | 55.0 |\n| B — Seat tube angle | 71.0° | 71.0° | 71.0° | 71.0° |\n| C — Head tube length | 16.0 | 16.0 | 18.0 | 20.0 |\n| D — Head angle | 68.2° | 68.2° | 68.2° | 68.2° |\n| E — Effective top tube | 58.2 | 58.7 | 59.8 | 61.0 |\n| F — Bottom bracket height | 29.4 | 29.4 | 29.4 | 29.4 |\n| G — Bottom bracket drop | 6.5 | 6.5 | 6.5 | 6.5 |\n| H — Chainstay length | 48.7 | 48.7 | 48.7 | 48.7 |\n| I — Offset | 4.5 | 4.5 | 4.5 | 4.5 |\n| J — Trail | 9.5 | 9.5 | 9.5 | 9.5 |\n| K — Wheelbase | 112.2 | 112.7 | 114.0 | 115.2 |\n| L — Standover | 43.3 | 43.3 | 43.3 | 43.3 |\n| M — Frame reach | 36.5 | 38.5 | 38.5 | 38.5 |\n| N — Frame stack | 63.0 | 63.0 | 64.9 | 66.8 |\n| Stem length | 8.5 | 9.0 | 9.0 | 11.0 |",
"price": 4499.99,
"tags": [
"bicycle",
"road bike",
"professional"
]
},
{
"name": "FastRider X1",
"shortDescription": "FastRider X1 is a high-performance e-bike designed for riders seeking speed and long-distance capabilities. Equipped with a powerful motor and a high-capacity battery, the FastRider X1 is perfect for daily commuters and e-bike enthusiasts. It boasts a sleek and functional design, making it a great alternative to car transportation. The bike also features a smartphone controller for easy navigation and entertainment options.",
"description": "## Overview\nIt's right for you if...\nYou're looking for an e-bike that offers both speed and endurance. The FastRider X1 comes with a high-performance motor and a long-lasting battery, making it ideal for long-distance rides.\n\nThe tech you get\nThe FastRider X1 features a state-of-the-art motor and a spacious battery, ensuring a fast and efficient ride.\n\nThe final word\nWith the powerful motor and long-range battery, the FastRider X1 allows you to cover more distance at higher speeds.\n\n## Features\nConnect Your Ride with the FastRider App\nDownload the FastRider app and transform your smartphone into an on-board computer. Easily dock and charge your phone with the smartphone controller, and use the thumb pad on your handlebar to make calls, listen to music, get turn-by-turn directions, and more. The app also allows you to connect with fitness and health apps, syncing your routes and ride data.\n\nGoodbye, Car. Hello, Extended Range!\nWith the option to add the Range Boost feature, you can attach a second long-range battery to your FastRider X1, doubling the distance and time between charges. This enhancement allows you to ride longer, commute farther, and take on more adventurous routes.\n\nWhat is the range?\nTo estimate the distance you can travel on a single charge, use our range calculator tool. It automatically fills in the variables for this specific bike model and assumes an average rider, but you can adjust the settings to get the most accurate estimate for your needs.\n\n## Specifications\nFrameset\n- Frame: High-performance hydroformed alloy, Removable Integrated Battery, Range Boost-compatible, internal cable routing, Motor Armour, post-mount disc, 135x5 mm QR\n- Fork: FastRider rigid alloy fork, 1-1/8'' steel steerer, 100x15mm thru axle, post mount disc brake\n- Max compatible fork travel: 63mm\n\nWheels\n- Front Hub: FastRider sealed bearing, 32-hole 15mm alloy thru-axle\n- Front Skewer: FastRider Switch thru axle, removable lever\n- Rear Hub: FastRider alloy, sealed bearing, 6-bolt, 135x5mm QR\n- Rear Skewer: 148x5mm bolt-on\n- Rim: FastRider MD35, tubeless compatible, 32-hole, 35mm width, Presta valve\n- Spokes: Size: M, L, XL - 14g stainless steel, black\n- Tire: FastRider E6 Hard-Case Lite, reflective strip, 27.5x2.40''\n- Max tire size: 27.5x2.40\"\n\nDrivetrain\n- Shifter: Shimano Deore M4100, 10 speed\n- Rear derailleur: Size: M, L, XL - Shimano Deore M5120, long cage\n- Crank: Size: M - FastRider alloy, 170mm length / Size: L, XL - FastRider alloy, 175mm length\n- Chainring: FastRider 46T narrow/wide alloy, w/alloy guard\n- Cassette: Size: M, L, XL - Shimano Deore M4100, 11-42, 10 speed\n- Chain: Size: M, L, XL - KMC E10 / Size: M, L, XL - KMC X10e\n- Pedal: Size: M, L, XL - FastRider City pedals / Size: M, L, XL - Wellgo C157, boron axle, plastic body / Size: M, L, XL - slip-proof aluminum pedals with reflectors\n- Max chainring size: 1x: 48T\n\nComponents\n- Saddle: FastRider Commuter Comp\n- Seatpost: FastRider Comp, 6061 alloy, 31.6mm, 8mm offset, 330mm length\n- Handlebar: Size: M - FastRider alloy, 31.8mm, 15mm rise, 600mm width / Size: L, XL - FastRider alloy, 31.8mm, 15mm rise, 660mm width\n- Grips: FastRider Satellite Elite, alloy lock-on\n- Stem: Size: M - FastRider alloy, 31.8mm, Blendr compatible, 7-degree, 70mm length / Size: L - FastRider alloy, 31.8mm, Blendr compatible, 7-degree, 90mm length / Size: XL - FastRider alloy, 31.8mm, Blendr compatible, 7-degree, 100mm length\n- Headset: Size: M, L, XL - FSA IS-2 alloy, integrated, sealed cartridge bearing, 1-1/8'' top, 1.5'' bottom / Size: M, L, XL - FSA Integrated, sealed cartridge bearing, 1-1/8'' top, 1.5'' bottom\n- Brake: Shimano MT520 4-piston hydraulic disc, post-mount, 180mm rotor\n- Brake rotor: Shimano RT56, 6-bolt, 180mm\n- Rotor size: Max brake rotor sizes: 180mm front & rear\n\nAccessories\n- Battery: FastRider PowerTube 625Wh\n- Charger: FastRider standard 4A, 100-240V\n- Motor: FastRider Performance Speed, 85 Nm, 28 mph / 45 kph\n- Light: Size: M, L, XL - FastRider taillight, 50 lumens / Size: M, L, XL - FastRider headlight, 500 lumens\n- Kickstand: Size: M, L, XL - Rear mount, alloy / Size: M, L, XL - Adjustable length alloy kickstand\n- Cargo rack: FastRider integrated rear rack, aluminum\n- Fender: FastRider custom aluminum\n\nWeight\n- Weight: M - 25.54 kg / 56.3 lbs\n\nWeight limit\n- This bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\n\n## Sizing\n| Size | Rider Height | Inseam |\n|:----:|:------------------------:|:--------------------:|\n| M | 165 - 175 cm 5'5\" - 5'9\" | 77 - 83 cm 30\" - 33\" |\n| L | 175 - 186 cm 5'9\" - 6'1\" | 82 - 88 cm 32\" - 35\" |\n| XL | 186 - 197 cm 6'1\" - 6'6\" | 87 - 93 cm 34\" - 37\" |\n\n## Geometry\n| Frame size letter | M | L | XL |\n|---------------------------|-------|-------|-------|\n| Wheel size | 27.5\" | 27.5\" | 27.5\" |\n| A — Seat tube | 44.6 | 49.1 | 53.4 |\n| B — Seat tube angle | 73.0° | 73.0° | 73.0° |\n| C — Head tube length | 16.5 | 19.5 | 23.0 |\n| D — Head angle | 69.5° | 70.0° | 70.5° |\n| E — Effective top tube | 59.5 | 60.7 | 62.2 |\n| F — Bottom bracket height | 29.5 | 29.5 | 29.5 |\n| G — Bottom bracket drop | 6.0 | 6.0 | 6.0 |\n| H — Chainstay length | 48.7 | 48.7 | 48.7 |\n| I — Offset | 4.4 | 4.4 | 4.4 |\n| J — Trail | 8.6 | 8.1 | 7.9 |\n| K — Wheelbase | 114.6 | 115.0 | 116.4 |\n| L — Standover | 79.5 | 83.7 | 87.9 |\n| M — Frame reach | 40.5 | 40.8 | 41.2 |\n| N — Frame stack | 62.3 | 65.2 | 68.8 |",
"price": 5499.99,
"tags": [
"bicycle",
"mountain bike",
"professional"
]
},
{
"name": "SonicRide 8S",
"shortDescription": "SonicRide 8S is a high-performance e-bike designed for riders who crave speed and long-distance capabilities. The advanced SonicDrive motor provides powerful assistance up to 28 mph, combined with a durable and long-lasting battery for extended rides. With its sleek design and thoughtful features, the SonicRide 8S is perfect for those who prefer the freedom of riding a bike over driving a car. Plus, it comes equipped with a smartphone controller for easy navigation, music, and more.",
"description": "## Overview\nIt's right for you if...\nYou want a fast and efficient e-bike that can take you long distances. The SonicRide 8S features a hydroformed aluminum frame with a concealed 625Wh battery, a high-powered SonicDrive motor, and a Smartphone Controller. It also includes essential accessories such as lights, fenders, and a rear rack.\n\nThe tech you get\nThe SonicRide 8S is equipped with the fastest SonicDrive motor, ensuring exhilarating rides at high speeds. The long-range battery is perfect for commuters and riders looking to explore new horizons.\n\nThe final word\nWith the SonicDrive motor and long-lasting battery, you can enjoy extended rides at higher speeds.\n\n## Features\n\nConnect Your Ride with SonicRide App\nDownload the SonicRide app and transform your phone into an onboard computer. Simply attach it to the Smartphone Controller for docking and charging. Use the thumb pad on your handlebar to control calls, music, directions, and more. The Bluetooth® wireless technology allows you to connect with fitness and health apps, syncing your routes and ride data.\n\nSay Goodbye to Limited Range with Range Boost!\nExperience the convenience of Range Boost, an additional long-range 500Wh battery that seamlessly attaches to your bike's down tube. This upgrade allows you to double your distance and time between charges, enabling longer commutes and more adventurous rides. Range Boost is compatible with select SonicRide electric bike models.\n\nWhat is the range?\nFor an accurate estimate of how far you can ride on a single charge, use SonicRide's range calculator. We have pre-filled the variables for this specific bike model and the average rider, but you can adjust them to obtain the most accurate estimate.\n\n## Specifications\nFrameset\n- Frame: High-performance hydroformed alloy, Removable Integrated Battery, Range Boost-compatible, internal cable routing, Motor Armour, post-mount disc, 135x5 mm QR\n- Fork: SonicRide rigid alloy fork, 1-1/8'' steel steerer, 100x15mm thru axle, post mount disc brake\n- Max compatible fork travel: 63mm\n\nWheels\n- Front Hub: SonicRide sealed bearing, 32-hole 15mm alloy thru-axle\n- Front Skewer: SonicRide Switch thru axle, removable lever\n- Rear Hub: SonicRide alloy, sealed bearing, 6-bolt, 135x5mm QR\n- Rear Skewer: 148x5mm bolt-on\n- Rim: SonicRide MD35, tubeless compatible, 32-hole, 35mm width, Presta valve\n- Spokes: Size: M, L, XL - 14g stainless steel, black\n- Tire: SonicRide E6 Hard-Case Lite, reflective strip, 27.5x2.40''\n- Max tire size: 27.5x2.40\"\n\nDrivetrain\n- Shifter: Shimano Deore M4100, 10 speed\n- Rear Derailleur: Size: M, L, XL - Shimano Deore M5120, long cage\n- Crank: Size: M - SonicRide alloy, 170mm length; Size: L, XL - SonicRide alloy, 175mm length\n- Chainring: SonicRide 46T narrow/wide alloy, with alloy guard\n- Cassette: Size: M, L, XL - Shimano Deore M4100, 11-42, 10 speed\n- Chain: Size: M, L, XL - KMC E10; Size: M, L, XL - KMC X10e\n- Pedal: Size: M, L, XL - SonicRide City pedals; Size: M, L, XL - Wellgo C157, boron axle, plastic body; Size: M, L, XL - slip-proof aluminum pedals with reflectors\n- Max chainring size: 1x: 48T\n\nComponents\n- Saddle: SonicRide Commuter Comp\n- Seatpost: SonicRide Comp, 6061 alloy, 31.6mm, 8mm offset, 330mm length\n- Handlebar: Size: M - SonicRide alloy, 31.8mm, 15mm rise, 600mm width; Size: L, XL - SonicRide alloy, 31.8mm, 15mm rise, 660mm width\n- Grips: SonicRide Satellite Elite, alloy lock-on\n- Stem: Size: M - SonicRide alloy, 31.8mm, Blendr compatible, 7-degree, 70mm length; Size: L - SonicRide alloy, 31.8mm, Blendr compatible, 7-degree, 90mm length; Size: XL - SonicRide alloy, 31.8mm, Blendr compatible, 7-degree, 100mm length\n- Headset: Size: M, L, XL - SonicRide IS-2 alloy, integrated, sealed cartridge bearing, 1-1/8'' top, 1.5'' bottom; Size: M, L, XL - SonicRide Integrated, sealed cartridge bearing, 1-1/8'' top, 1.5'' bottom\n- Brake: Shimano MT520 4-piston hydraulic disc, post-mount, 180mm rotor\n- Brake rotor: Shimano RT56, 6-bolt, 180mm\n- Rotor size: Max brake rotor sizes: 180mm front & rear\n\nAccessories\n- Battery: SonicRide PowerTube 625Wh\n- Charger: SonicRide standard 4A, 100-240V\n- Motor: SonicRide Performance Speed, 85 Nm, 28 mph / 45 kph\n- Light: Size: M, L, XL - SonicRide Lync taillight, 50 lumens; Size: M, L, XL - SonicRide Lync headlight, 500 lumens\n- Kickstand: Size: M, L, XL - Rear mount, alloy; Size: M, L, XL - Adjustable length alloy kickstand\n- Cargo rack: SonicRide integrated rear rack, aluminum\n- Fender: SonicRide custom aluminum\n\nWeight\n- Weight: M - 25.54 kg / 56.3 lbs\n- Weight limit: This bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\n\n## Sizing\n| Size | Rider Height | Inseam |\n|:----:|:------------------------:|:--------------------:|\n| M | 165 - 175 cm / 5'5\" - 5'9\" | 77 - 83 cm / 30\" - 33\" |\n| L | 175 - 186 cm / 5'9\" - 6'1\" | 82 - 88 cm / 32\" - 35\" |\n| XL | 186 - 197 cm / 6'1\" - 6'6\" | 87 - 93 cm / 34\" - 37\" |\n\n## Geometry\n| Frame size letter | M | L | XL |\n|---------------------------|-------|-------|-------|\n| Wheel size | 27.5\" | 27.5\" | 27.5\" |\n| A — Seat tube | 44.6 | 49.1 | 53.4 |\n| B — Seat tube angle | 73.0° | 73.0° | 73.0° |\n| C — Head tube length | 16.5 | 19.5 | 23.0 |\n| D — Head angle | 69.5° | 70.0° | 70.5° |\n| E — Effective top tube | 59.5 | 60.7 | 62.2 |\n| F — Bottom bracket height | 29.5 | 29.5 | 29.5 |\n| G — Bottom bracket drop | 6.0 | 6.0 | 6.0 |\n| H — Chainstay length | 48.7 | 48.7 | 48.7 |\n| I — Offset | 4.4 | 4.4 | 4.4 |\n| J — Trail | 8.6 | 8.1 | 7.9 |\n| K — Wheelbase | 114.6 | 115.0 | 116.4 |\n| L — Standover | 79.5 | 83.7 | 87.9 |\n| M — Frame reach | 40.5 | 40.8 | 41.2 |",
"price": 5999.99,
"tags": [
"bicycle",
"road bike",
"professional"
]
},
{
"name": "SwiftVolt Pro",
"shortDescription": "SwiftVolt Pro is a high-performance e-bike designed for riders seeking a thrilling and fast riding experience. Equipped with a powerful SwiftDrive motor that provides assistance up to 30 mph and a long-lasting battery, this bike is perfect for long-distance commuting and passionate e-bike enthusiasts. The sleek and innovative design features cater specifically to individuals who prioritize cycling over driving. Additionally, the bike is seamlessly integrated with your smartphone, allowing you to use it for navigation, music, and more.",
"description": "## Overview\nThis bike is ideal for you if:\n- You desire a sleek and modern hydroformed aluminum frame that houses a 700Wh battery.\n- You want to maintain high speeds of up to 30 mph with the assistance of the SwiftDrive motor.\n- You appreciate the convenience of using your smartphone as a controller, which can be docked and charged on the handlebar.\n\n## Features\n\nConnect with SwiftSync App\nBy downloading the SwiftSync app, your smartphone becomes an interactive on-board computer. Attach it to the handlebar-mounted controller for easy access and charging. With the thumb pad, you can make calls, listen to music, receive turn-by-turn directions, and connect with fitness and health apps to track your routes and ride data via Bluetooth® wireless technology.\n\nEnhanced Range with BoostMax\nBoostMax offers the capability to attach a second 700Wh Swift battery to the downtube of your bike, effectively doubling the distance and time between charges. This allows for extended rides, longer commutes, and more significant adventures. BoostMax is compatible with select Swift electric bike models.\n\nRange Estimation\nFor an estimate of how far you can ride on a single charge, consult the Swift range calculator. The variables are automatically populated based on this bike model and the average rider, but you can modify them to obtain the most accurate estimate.\n\n## Specifications\nFrameset\n- Frame: Lightweight hydroformed alloy, Removable Integrated Battery, BoostMax-compatible, internal cable routing, post-mount disc, 135x5 mm QR\n- Fork: SwiftVolt rigid alloy fork, 1-1/8'' steel steerer, 100x15mm thru-axle, post-mount disc brake\n- Max compatible fork travel: 63mm\n\nWheels\n- Front Hub: Swift sealed bearing, 32-hole 15mm alloy thru-axle\n- Front Skewer: Swift Switch thru-axle, removable lever\n- Rear Hub: Swift alloy, sealed bearing, 6-bolt, 135x5mm QR\n- Rear Skewer: 148x5mm bolt-on\n- Rim: SwiftRim, tubeless compatible, 32-hole, 35mm width, Presta valve\n- Spokes: 14g stainless steel, black\n- Tire: Swift E6 Hard-Case Lite, reflective strip, 27.5x2.40''\n- Max tire size: 27.5x2.40\"\n\nDrivetrain\n- Shifter: Shimano Deore M4100, 10 speed\n- Rear Derailleur: Shimano Deore M5120, long cage\n- Crank: Swift alloy, 170mm length\n- Chainring: Swift 46T narrow/wide alloy, w/alloy guard\n- Cassette: Shimano Deore M4100, 11-42, 10 speed\n- Chain: KMC E10\n- Pedal: Swift City pedals\n- Max chainring size: 1x: 48T\n\nComponents\n- Saddle: Swift Commuter Comp\n- Seatpost: Swift Comp, 6061 alloy, 31.6mm, 8mm offset, 330mm length\n- Handlebar: Swift alloy, 31.8mm, 15mm rise, 600mm width (M), 660mm width (L, XL)\n- Grips: Swift Satellite Elite, alloy lock-on\n- Stem: Swift alloy, 31.8mm, Blendr compatible, 7 degree, 70mm length (M), 90mm length (L), 100mm length (XL)\n- Headset: FSA IS-2 alloy, integrated, sealed cartridge bearing, 1-1/8'' top, 1.5'' bottom\n- Brakes: Shimano MT520 4-piston hydraulic disc, post-mount, 180mm rotor\n- Brake Rotor: Shimano RT56, 6-bolt, 180mm\n- Rotor size: Max 180mm front & rear\n\nAccessories\n- Battery: Swift PowerTube 700Wh\n- Charger: Swift standard 4A, 100-240V\n- Motor: SwiftDrive, 90 Nm, 30 mph / 48 kph\n- Light: Swift Lync taillight, 50 lumens (M, L, XL), Swift Lync headlight, 500 lumens (M, L, XL)\n- Kickstand: Rear mount, alloy (M, L, XL), Adjustable length alloy kickstand (M, L, XL)\n- Cargo rack: SwiftVolt integrated rear rack, aluminum\n- Fender: Swift custom aluminum\n\nWeight\n- Weight: M - 25.54 kg / 56.3 lbs\n- Weight limit: This bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\n\n## Sizing\n| Size | Rider Height | Inseam |\n|:----:|:---------------------:|:-------------:|\n| M | 165 - 175 cm 5'5\" - 5'9\" | 77 - 83 cm 30\" - 33\" |\n| L | 175 - 186 cm 5'9\" - 6'1\" | 82 - 88 cm 32\" - 35\" |\n| XL | 186 - 197 cm 6'1\" - 6'6\" | 87 - 93 cm 34\" - 37\" |\n\n## Geometry\n| Frame size letter | M | L | XL |\n|---------------------------|-------|-------|-------|\n| Wheel size | 27.5\" | 27.5\" | 27.5\" |\n| A — Seat tube | 44.6 | 49.1 | 53.4 |\n| B — Seat tube angle | 73.0° | 73.0° | 73.0° |\n| C — Head tube length | 16.5 | 19.5 | 23.0 |\n| D — Head angle | 69.5° | 70.0° | 70.5° |\n| E — Effective top tube | 59.5 | 60.7 | 62.2 |\n| F — Bottom bracket height | 29.5 | 29.5 | 29.5 |\n| G — Bottom bracket drop | 6.0 | 6.0 | 6.0 |\n| H — Chainstay length | 48.7 | 48.7 | 48.7 |\n| I — Offset | 4.4 | 4.4 | 4.4 |\n| J — Trail | 8.6 | 8.1 | 7.9 |\n| K — Wheelbase | 114.6 | 115.0 | 116.4 |\n| L — Standover | 79.5 | 83.7 | 87.9 |\n| M — Frame reach | 40.5 | 40.8 | 41.2 |\n| N — Frame stack | 62.3 | 65.2 | 68.8 |",
"price": 2499.99,
"tags": [
"bicycle",
"city bike",
"professional"
]
},
{
"name": "AgileEon 9X",
"shortDescription": "AgileEon 9X is a high-performance e-bike designed for riders seeking speed and endurance. Equipped with a robust motor and an extended battery life, this bike is perfect for long-distance commuters and avid e-bike enthusiasts. It boasts innovative features tailored for individuals who prioritize cycling over driving. Additionally, the bike integrates seamlessly with your smartphone, allowing you to access navigation, music, and more.",
"description": "## Overview\nIt's right for you if...\nYou crave speed and want to cover long distances efficiently. The AgileEon 9X features a sleek hydroformed aluminum frame that houses a powerful motor, along with a large-capacity battery for extended rides. It comes equipped with a 10-speed drivetrain, front and rear lighting, fenders, and a rear rack.\n\nThe tech you get\nDesigned for those constantly on the move, this bike includes a state-of-the-art motor and a high-capacity battery, making it an excellent choice for lengthy commutes.\n\nThe final word\nWith the AgileEon 9X, you can push your boundaries and explore new horizons thanks to its powerful motor and long-lasting battery.\n\n## Features\n\nConnect Your Ride with RideMate App\nMake use of the RideMate app to transform your smartphone into an onboard computer. Simply attach it to the RideMate controller to dock and charge, then utilize the thumb pad on your handlebar to make calls, listen to music, receive turn-by-turn directions, and more. The bike also supports Bluetooth® wireless technology, enabling seamless connectivity with fitness and health apps for route syncing and ride data.\n\nGoodbye, car. Hello, Extended Range!\nEnhance your riding experience with the Extended Range option, which allows for the attachment of an additional high-capacity 500Wh battery to your bike's downtube. This doubles the distance and time between charges, enabling longer rides, extended commutes, and more significant adventures. The Extended Range feature is compatible with select AgileEon electric bike models.\n\nWhat is the range?\nTo determine how far you can ride on a single charge, you can utilize the range calculator provided by AgileEon. We have pre-filled the variables for this specific model and an average rider, but adjustments can be made for a more accurate estimation.\n\n## Specifications\nFrameset\nFrame: High-performance hydroformed alloy, Removable Integrated Battery, Extended Range-compatible, internal cable routing, Motor Armor, post-mount disc, 135x5 mm QR\nFork: AgileEon rigid alloy fork, 1-1/8'' steel steerer, 100x15mm thru-axle, post-mount disc brake\nMax compatible fork travel: 63mm\n\nWheels\nFront Hub: AgileEon sealed bearing, 32-hole 15mm alloy thru-axle\nFront Skewer: AgileEon Switch thru-axle, removable lever\nRear Hub: AgileEon alloy, sealed bearing, 6-bolt, 135x5mm QR\nRear Skewer: 148x5mm bolt-on\nRim: AgileEon MD35, tubeless compatible, 32-hole, 35mm width, Presta valve\nSpokes:\n- Size: M, L, XL: 14g stainless steel, black\nTire: AgileEon E6 Hard-Case Lite, reflective strip, 27.5x2.40''\nMax tire size: 27.5x2.40\"\n\nDrivetrain\nShifter: Shimano Deore M4100, 10-speed\nRear derailleur:\n- Size: M, L, XL: Shimano Deore M5120, long cage\nCrank:\n- Size: M: AgileEon alloy, 170mm length\n- Size: L, XL: AgileEon alloy, 175mm length\nChainring: AgileEon 46T narrow/wide alloy, with alloy guard\nCassette:\n- Size: M, L, XL: Shimano Deore M4100, 11-42, 10-speed\nChain:\n- Size: M, L, XL: KMC E10\nPedal:\n- Size: M, L, XL: AgileEon City pedals\nMax chainring size: 1x: 48T\n\nComponents\nSaddle: AgileEon Commuter Comp\nSeatpost: AgileEon Comp, 6061 alloy, 31.6mm, 8mm offset, 330mm length\nHandlebar:\n- Size: M: AgileEon alloy, 31.8mm, 15mm rise, 600mm width\n- Size: L, XL: AgileEon alloy, 31.8mm, 15mm rise, 660mm width\nGrips: AgileEon Satellite Elite, alloy lock-on\nStem:\n- Size: M: AgileEon alloy, 31.8mm, Blendr compatible, 7-degree, 70mm length\n- Size: L: AgileEon alloy, 31.8mm, Blendr compatible, 7-degree, 90mm length\n- Size: XL: AgileEon alloy, 31.8mm, Blendr compatible, 7-degree, 100mm length\nHeadset:\n- Size: M, L, XL: AgileEon IS-2 alloy, integrated, sealed cartridge bearing, 1-1/8'' top, 1.5'' bottom\nBrake: Shimano MT520 4-piston hydraulic disc, post-mount, 180mm rotor\nBrake rotor: Shimano RT56, 6-bolt, 180mm\nRotor size: Max brake rotor sizes: 180mm front & rear\n\nAccessories\nBattery: AgileEon PowerTube 625Wh\nCharger: AgileEon standard 4A, 100-240V\nMotor: AgileEon Performance Speed, 85 Nm, 28 mph / 45 kph\nLight:\n- Size: M, L, XL: AgileEon taillight, 50 lumens\n- Size: M, L, XL: AgileEon headlight, 500 lumens\nKickstand:\n- Size: M, L, XL: Rear mount, alloy\n- Size: M, L, XL: Adjustable length alloy kickstand\nCargo rack: AgileEon integrated rear rack, aluminum\nFender: AgileEon custom aluminum\n\nWeight\nWeight: M - 25.54 kg / 56.3 lbs\nWeight limit: This bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\n\n## Sizing\n| Size | Rider Height | Inseam |\n|:----:|:------------------------:|:--------------------:|\n| M | 165 - 175 cm 5'5\" - 5'9\" | 77 - 83 cm 30\" - 33\" |\n| L | 175 - 186 cm 5'9\" - 6'1\" | 82 - 88 cm 32\" - 35\" |\n| XL | 186 - 197 cm 6'1\" - 6'6\" | 87 - 93 cm 34\" - 37\" |\n\n## Geometry\n| Frame size letter | M | L | XL |\n|---------------------------|-------|-------|-------|\n| Wheel size | 27.5\" | 27.5\" | 27.5\" |\n| A — Seat tube | 44.6 | 49.1 | 53.4 |\n| B — Seat tube angle | 73.0° | 73.0° | 73.0° |\n| C — Head tube length | 16.5 | 19.5 | 23.0 |\n| D — Head angle | 69.5° | 70.0° | 70.5° |\n| E — Effective top tube | 59.5 | 60.7 | 62.2 |\n| F — Bottom bracket height | 29.5 | 29.5 | 29.5 |\n| G — Bottom bracket drop | 6.0 | 6.0 | 6.0 |\n| H — Chainstay length | 48.7 | 48.7 | 48.7 |\n| I — Offset | 4.4 | 4.4 | 4.4 |\n| J — Trail | 8.6 | 8.1 | 7.9 |\n| K — Wheelbase | 114.6 | 115.0 | 116.4 |\n| L — Standover | 79.5 | 83.7 | 87.9 |\n| M — Frame reach | 40.5 | 40.8 | 41.2 |\n| N — Frame stack | 62.3 | 65.2 | 68.8 |",
"price": 3499.99,
"tags": [
"bicycle",
"road bike",
"professional"
]
},
{
"name": "Stealth R1X Pro",
"shortDescription": "Stealth R1X Pro is a high-performance carbon road bike designed for riders who crave speed and exceptional handling. With its aerodynamic tube shaping, disc brakes, and lightweight carbon wheels, the Stealth R1X Pro offers unparalleled performance for competitive road cycling.",
"description": "## Overview\nIt's right for you if...\nYou're a competitive cyclist looking for a road bike that offers superior performance in terms of speed, handling, and aerodynamics. You want a complete package that includes lightweight carbon wheels, without the need for future upgrades.\n\nThe tech you get\nThe Stealth R1X Pro features a lightweight and aerodynamic carbon frame, an advanced carbon fork, high-performance Shimano Ultegra 11-speed drivetrain, and powerful Ultegra disc brakes. The bike also comes equipped with cutting-edge Bontrager Aeolus Elite 35 carbon wheels.\n\nThe final word\nThe Stealth R1X Pro stands out with its combination of a fast and aerodynamic frame, high-end drivetrain, and top-of-the-line carbon wheels. Whether you're racing on local roads, participating in pro stage races, or engaging in hill climbing competitions, this bike is a formidable choice that delivers an exceptional riding experience.\n\n## Features\nSleek and aerodynamic design\nThe Stealth R1X Pro's aero tube shapes maximize speed and performance, making it faster on climbs and flats alike. The bike also features a streamlined Aeolus RSL bar/stem for improved front-end aerodynamics.\n\nDesigned for all riders\nThe Stealth R1X Pro is designed to provide an outstanding fit for riders of all genders, body types, riding styles, and abilities. It comes equipped with size-specific components to ensure a comfortable and efficient riding position for competitive riders.\n\n## Specifications\nFrameset\n- Frame: Ultralight carbon frame constructed with high-performance 500 Series ADV Carbon. It features Ride Tuned performance tube optimization, a tapered head tube, internal routing, DuoTrap S compatibility, flat mount disc brake mounts, and a 142x12mm thru axle.\n- Fork: Full carbon fork (Émonda SL) with a tapered carbon steerer, internal brake routing, flat mount disc brake mounts, and a 12x100mm thru axle.\n- Frame fit: H1.5 Race geometry.\n\nWheels\n- Front wheel: Bontrager Aeolus Elite 35 carbon wheel with a 35mm rim depth, ADV Carbon construction, Tubeless Ready compatibility, and a 100x12mm thru axle.\n- Rear wheel: Bontrager Aeolus Elite 35 carbon wheel with a 35mm rim depth, ADV Carbon construction, Tubeless Ready compatibility, Shimano 11/12-speed freehub, and a 142x12mm thru axle.\n- Front skewer: Bontrager Switch thru axle with a removable lever.\n- Rear skewer: Bontrager Switch thru axle with a removable lever.\n- Tire: Bontrager R2 Hard-Case Lite with an aramid bead, 60 tpi, and a size of 700x25c.\n- Maximum tire size: 28mm.\n\nDrivetrain\n- Shifter:\n - Size 47, 50, 52: Shimano Ultegra R8025 with short-reach levers, 11-speed.\n - Size 54, 56, 58, 60, 62: Shimano Ultegra R8020, 11-speed.\n- Front derailleur: Shimano Ultegra R8000, braze-on.\n- Rear derailleur: Shimano Ultegra R8000, short cage, with a maximum cog size of 30T.\n- Crank:\n - Size 47: Shimano Ultegra R8000 with 52/36 chainrings and a 165mm length.\n - Size 50, 52: Shimano Ultegra R8000 with 52/36 chainrings and a 170mm length.\n - Size 54, 56, 58: Shimano Ultegra R8000 with 52/36 chainrings and a 172.5mm length.\n - Size 60, 62: Shimano Ultegra R8000 with 52/36 chainrings and a 175mm length.\n- Bottom bracket: Praxis T47 threaded bottom bracket with internal bearings.\n- Cassette: Shimano Ultegra R8000, 11-30, 11-speed.\n- Chain: Shimano Ultegra HG701, 11-speed.\n- Maximum chainring size: 1x - 50T, 2x - 53/39.\n\nComponents\n- Saddle: Bontrager Aeolus Comp with steel rails and a width of 145mm.\n- Seatpost:\n - Size 47, 50, 52, 54: Bontrager carbon seatmast cap with a 20mm offset and a short length.\n - Size 56, 58, 60, 62: Bontrager carbon seatmast cap with a 20mm offset and a tall length.\n- Handlebar:\n - Size 47, 50: Bontrager Elite VR-C alloy handlebar with a 31.8mm clamp, 100mm reach, 124mm drop, and a width of 38cm.\n - Size 52: Bontrager Elite VR-C alloy handlebar with a 31.8mm clamp, 100mm reach, 124mm drop, and a width of 40cm.\n - Size 54, 56, 58: Bontrager Elite VR-C alloy handlebar with a 31.8mm clamp, 100mm reach, 124mm drop, and a width of 42cm.\n - Size 60, 62: Bontrager Elite VR-C alloy handlebar with a 31.8mm clamp, 100mm reach, 124mm drop, and a width of 44cm.\n- Handlebar tape: Bontrager Supertack Perf tape.\n- Stem:\n - Size 47: Bontrager Pro alloy stem with a 31.8mm clamp, Blendr compatibility, 7-degree rise, and a length of 70mm.\n - Size 50: Bontrager Pro alloy stem with a 31.8mm clamp, Blendr compatibility, 7-degree rise, and a length of 80mm.\n - Size 52, 54: Bontrager Pro alloy stem with a 31.8mm clamp, Blendr compatibility, 7-degree rise, and a length of 90mm.\n - Size 56: Bontrager Pro alloy stem with a 31.8mm clamp, Blendr compatibility, 7-degree rise, and a length of 100mm.\n - Size 58, 60, 62: Bontrager Pro alloy stem with a 31.8mm clamp, Blendr compatibility, 7-degree rise, and a length of 110mm.\n- Brake: Shimano Ultegra hydraulic disc brakes with flat mount calipers.\n- Brake rotor: Shimano RT800 with centerlock mounting, 160mm diameter.\n\nWeight\n- Weight: 8.03 kg (17.71 lbs) for the 56cm frame.\n- Weight limit: The bike has a maximum total weight limit (combined weight of the bicycle, rider, and cargo) of 275 pounds (125 kg).\n\n## Sizing\nPlease refer to the table below for the corresponding Stealth R1X Pro frame sizes, recommended rider height range, and inseam measurements:\n\n| Size | Rider Height | Inseam |\n|:----:|:---------------------:|:--------------:|\n| 47 | 152 - 158 cm (5'0\") | 71 - 75 cm |\n| 50 | 158 - 163 cm (5'2\") | 74 - 77 cm |\n| 52 | 163 - 168 cm (5'4\") | 76 - 79 cm |\n| 54 | 168 - 174 cm (5'6\") | 78 - 82 cm |\n| 56 | 174 - 180 cm (5'9\") | 81 - 85 cm |\n| 58 | 180 - 185 cm (5'11\") | 84 - 87 cm |\n| 60 | 185 - 190 cm (6'1\") | 86 - 90 cm |\n| 62 | 190 - 195 cm (6'3\") | 89 - 92 cm |\n\n## Geometry\nThe table below provides the geometry measurements for each frame size of the Stealth R1X Pro:\n\n| Frame size number | 47 cm | 50 cm | 52 cm | 54 cm | 56 cm | 58 cm | 60 cm | 62 cm |\n|-------------------------------|-------|-------|-------|-------|-------|-------|-------|-------|\n| Wheel size | 700c | 700c | 700c | 700c | 700c | 700c | 700c | 700c |\n| A — Seat tube | 42.4 | 45.3 | 48.3 | 49.6 | 52.5 | 55.3 | 57.3 | 59.3 |\n| B — Seat tube angle | 74.6° | 74.6° | 74.2° | 73.7° | 73.3° | 73.0° | 72.8° | 72.5° |\n| C — Head tube length | 10.0 | 11.1 | 12.1 | 13.1 | 15.1 | 17.1 | 19.1 | 21.1 |\n| D — Head angle | 72.1° | 72.1° | 72.8° | 73.0° | 73.5° | 73.8° | 73.9° | 73.9° |\n| E — Effective top tube | 51.2 | 52.1 | 53.4 | 54.3 | 55.9 | 57.4 | 58.6 | 59.8 |\n| G — Bottom bracket drop | 7.2 | 7.2 | 7.2 | 7.0 | 7.0 | 6.8 | 6.8 | 6.8 |\n| H — Chainstay length | 41.0 | 41.0 | 41.0 | 41.0 | 41.0 | 41.1 | 41.1 | 41.2 |\n| I — Offset | 4.5 | 4.5 | 4.5 | 4.5 | 4.0 | 4.0 | 4.0 | 4.0 |\n| J — Trail | 6.8 | 6.2 | 5.8 | 5.6 | 5.8 | 5.7 | 5.6 | 5.6 |\n| K — Wheelbase | 97.2 | 97.4 | 97.7 | 98.1 | 98.3 | 99.2 | 100.1 | 101.0 |\n| L — Standover | 69.2 | 71.1 | 73.2 | 74.4 | 76.8 | 79.3 | 81.1 | 82.9 |\n| M — Frame reach | 37.3 | 37.8 | 38.3 | 38.6 | 39.1 | 39.6 | 39.9 | 40.3 |\n| N — Frame stack | 50.7 | 52.1 | 53.3 | 54.1 | 56.3 | 58.1 | 60.1 | 62.0 |\n| Saddle rail height min (short mast) | 55.5 | 58.5 | 61.5 | 64.0 | 67.0 | 69.0 | 71.0 | 73.0 |\n| Saddle rail height max (short mast) | 61.5 | 64.5 | 67.5 | 70.0 | 73.0 | 75.0 | 77.0 | 79.0 |\n| Saddle rail height min (tall mast) | 59.0 | 62.0 | 65.0 | 67.5 | 70.5 | 72.5 | 74.5 | 76.5 |\n| Saddle rail height max (tall mast) | 65.0 | 68.0 | 71.0 | 73.5 | 76.5 | 78.5 | 80.5 | 82.5 |",
"price": 2999.99,
"tags": [
"bicycle",
"mountain bike",
"professional"
]
},
{
"name": "Avant SLR 6 Disc Pro",
"shortDescription": "Avant SLR 6 Disc Pro is a high-performance carbon road bike designed for riders who prioritize speed and handling. With its aero tube shaping, disc brakes, and lightweight carbon wheels, it offers the perfect balance of speed and control.",
"description": "## Overview\nIt's right for you if...\nYou're a rider who values exceptional performance on fast group rides and races, and you want a complete package that includes lightweight carbon wheels. The Avant SLR 6 Disc Pro is designed to provide the speed and aerodynamics you need to excel on any road.\n\nThe tech you get\nThe Avant SLR 6 Disc Pro features a lightweight 500 Series ADV Carbon frame and fork, Bontrager Aeolus Elite 35 carbon wheels, a full Shimano Ultegra 11-speed drivetrain, and powerful Ultegra disc brakes.\n\nThe final word\nThe standout feature of this bike is the combination of its aero frame, high-performance drivetrain, and top-quality carbon wheels. Whether you're racing, tackling challenging climbs, or participating in professional stage races, the Avant SLR 6 Disc Pro is a worthy choice that will enhance your performance.\n\n## Features\nAll-new aero design\nThe Avant SLR 6 Disc Pro features innovative aero tube shapes that provide an advantage in all riding conditions, whether it's climbing or riding on flat roads. Additionally, it is equipped with a sleek new Aeolus RSL bar/stem that enhances front-end aero performance.\n\nAwesome bikes for everyone\nThe Avant SLR 6 Disc Pro is designed with the belief that every rider, regardless of gender, body type, riding style, or ability, deserves a great bike. It is equipped with size-specific components that ensure a perfect fit for competitive riders of all genders.\n\n## Specifications\nFrameset\n- Frame: Ultralight 500 Series ADV Carbon, Ride Tuned performance tube optimization, tapered head tube, internal routing, DuoTrap S compatible, flat mount disc, 142x12mm thru axle\n- Fork: Avant SL full carbon, tapered carbon steerer, internal brake routing, flat mount disc, 12x100mm thru axle\n- Frame fit: H1.5 Race\n\nWheels\n- Front wheel: Bontrager Aeolus Elite 35, ADV Carbon, Tubeless Ready, 35mm rim depth, 100x12mm thru axle\n- Rear wheel: Bontrager Aeolus Elite 35, ADV Carbon, Tubeless Ready, 35mm rim depth, Shimano 11/12-speed freehub, 142x12mm thru axle\n- Front skewer: Bontrager Switch thru axle, removable lever\n- Rear skewer: Bontrager Switch thru axle, removable lever\n- Tire: Bontrager R2 Hard-Case Lite, aramid bead, 60 tpi, 700x25c\n- Max tire size: 28mm\n\nDrivetrain\n- Shifter: \n - Size 47, 50, 52: Shimano Ultegra R8025, short-reach lever, 11-speed\n - Size 54, 56, 58, 60, 62: Shimano Ultegra R8020, 11-speed\n- Front derailleur: Shimano Ultegra R8000, braze-on\n- Rear derailleur: Shimano Ultegra R8000, short cage, 30T max cog\n- Crank: \n - Size 47: Shimano Ultegra R8000, 52/36, 165mm length\n - Size 50, 52: Shimano Ultegra R8000, 52/36, 170mm length\n - Size 54, 56, 58: Shimano Ultegra R8000, 52/36, 172.5mm length\n - Size 60, 62: Shimano Ultegra R8000, 52/36, 175mm length\n- Bottom bracket: Praxis, T47 threaded, internal bearing\n- Cassette: Shimano Ultegra R8000, 11-30, 11-speed\n- Chain: Shimano Ultegra HG701, 11-speed\n- Max chainring size: 1x: 50T, 2x: 53/39\n\nComponents\n- Saddle: Bontrager Aeolus Comp, steel rails, 145mm width\n- Seatpost: \n - Size 47, 50, 52, 54: Bontrager carbon seatmast cap, 20mm offset, short length\n - Size 56, 58, 60, 62: Bontrager carbon seatmast cap, 20mm offset, tall length\n- Handlebar: \n - Size 47, 50: Bontrager Elite VR-C, alloy, 31.8mm, 100mm reach, 124mm drop, 38cm width\n - Size 52: Bontrager Elite VR-C, alloy, 31.8mm, 100mm reach, 124mm drop, 40cm width\n - Size 54, 56, 58: Bontrager Elite VR-C, alloy, 31.8mm, 100mm reach, 124mm drop, 42cm width\n - Size 60, 62: Bontrager Elite VR-C, alloy, 31.8mm, 100mm reach, 124mm drop, 44cm width\n- Handlebar tape: Bontrager Supertack Perf tape\n- Stem: \n - Size 47: Bontrager Pro, 31.8mm, Blendr compatible, 7-degree, 70mm length\n - Size 50: Bontrager Pro, 31.8mm, Blendr compatible, 7-degree, 80mm length\n - Size 52, 54: Bontrager Pro, 31.8mm, Blendr compatible, 7-degree, 90mm length\n - Size 56: Bontrager Pro, 31.8mm, Blendr compatible, 7-degree, 100mm length\n - Size 58, 60, 62: Bontrager Pro, 31.8mm, Blendr compatible, 7-degree, 110mm length\n- Brake: Shimano Ultegra hydraulic disc, flat mount\n- Brake rotor: Shimano RT800, centerlock, 160mm\n\nWeight\n- Weight: 56 - 8.03 kg / 17.71 lbs\n- Weight limit: This bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 275 pounds (125 kg).\n\n## Sizing\n| Size | Rider Height | Inseam |\n|:----:|:-------------------------:|:--------------------:|\n| 47 | 152 - 158 cm 5'0\" - 5'2\" | 71 - 75 cm 28\" - 30\" |\n| 50 | 158 - 163 cm 5'2\" - 5'4\" | 74 - 77 cm 29\" - 30\" |\n| 52 | 163 - 168 cm 5'4\" - 5'6\" | 76 - 79 cm 30\" - 31\" |\n| 54 | 168 - 174 cm 5'6\" - 5'9\" | 78 - 82 cm 31\" - 32\" |\n| 56 | 174 - 180 cm 5'9\" - 5'11\" | 81 - 85 cm 32\" - 33\" |\n| 58 | 180 - 185 cm 5'11\" - 6'1\" | 84 - 87 cm 33\" - 34\" |\n| 60 | 185 - 190 cm 6'1\" - 6'3\" | 86 - 90 cm 34\" - 35\" |\n| 62 | 190 - 195 cm 6'3\" - 6'5\" | 89 - 92 cm 35\" - 36\" |\n\n## Geometry\n| Frame size number | 47 cm | 50 cm | 52 cm | 54 cm | 56 cm | 58 cm | 60 cm | 62 cm |\n|---------------------------------------|-------|-------|-------|-------|-------|-------|-------|-------|\n| Wheel size | 700c | 700c | 700c | 700c | 700c | 700c | 700c | 700c |\n| A — Seat tube | 42.4 | 45.3 | 48.3 | 49.6 | 52.5 | 55.3 | 57.3 | 59.3 |\n| B — Seat tube angle | 74.6° | 74.6° | 74.2° | 73.7° | 73.3° | 73.0° | 72.8° | 72.5° |\n| C — Head tube length | 10.0 | 11.1 | 12.1 | 13.1 | 15.1 | 17.1 | 19.1 | 21.1 |\n| D — Head angle | 72.1° | 72.1° | 72.8° | 73.0° | 73.5° | 73.8° | 73.9° | 73.9° |\n| E — Effective top tube | 51.2 | 52.1 | 53.4 | 54.3 | 55.9 | 57.4 | 58.6 | 59.8 |\n| G — Bottom bracket drop | 7.2 | 7.2 | 7.2 | 7.0 | 7.0 | 6.8 | 6.8 | 6.8 |\n| H — Chainstay length | 41.0 | 41.0 | 41.0 | 41.0 | 41.0 | 41.1 | 41.1 | 41.2 |\n| I — Offset | 4.5 | 4.5 | 4.5 | 4.5 | 4.0 | 4.0 | 4.0 | 4.0 |\n| J — Trail | 6.8 | 6.2 | 5.8 | 5.6 | 5.8 | 5.7 | 5.6 | 5.6 |\n| K — Wheelbase | 97.2 | 97.4 | 97.7 | 98.1 | 98.3 | 99.2 | 100.1 | 101.0 |\n| L — Standover | 69.2 | 71.1 | 73.2 | 74.4 | 76.8 | 79.3 | 81.1 | 82.9 |\n| M — Frame reach | 37.3 | 37.8 | 38.3 | 38.6 | 39.1 | 39.6 | 39.9 | 40.3 |\n| N — Frame stack | 50.7 | 52.1 | 53.3 | 54.1 | 56.3 | 58.1 | 60.1 | 62.0 |\n| Saddle rail height min (w/short mast) | 55.5 | 58.5 | 61.5 | 64.0 | 67.0 | 69.0 | 71.0 | 73.0 |\n| Saddle rail height max (w/short mast) | 61.5 | 64.5 | 67.5 | 70.0 | 73.0 | 75.0 | 77.0 | 79.0 |\n| Saddle rail height min (w/tall mast) | 59.0 | 62.0 | 65.0 | 67.5 | 70.5 | 72.5 | 74.5 | 76.5 |\n| Saddle rail height max (w/tall mast) | 65.0 | 68.0 | 71.0 | 73.5 | 76.5 | 78.5 | 80.5 | 82.5 |",
"price": 999.99,
"tags": [
"bicycle",
"city bike",
"professional"
]
}
]
Models/Spring Ai Openai/Src/Test/Resources/Prompts/System Only Cache Prompt (models/spring-ai-openai/src/test/resources/prompts/system-only-cache-prompt.txt)
You are an expert software architect specializing in distributed systems and cloud-native applications.
Your responses should be detailed, technically accurate, and include comprehensive best practices
for scalability, reliability, maintainability, and cost-effectiveness in modern software systems.
When discussing architecture patterns, always consider these critical aspects:
- Scalability implications and potential bottlenecks across multiple dimensions including compute, storage, network, and database resources
- Fault tolerance and error handling strategies including circuit breakers, bulkheads, timeouts, retries, and graceful degradation
- Data consistency and transaction management including eventual consistency patterns, saga patterns, and distributed transaction challenges
- Security considerations and access patterns including authentication, authorization, encryption at rest and in transit, and zero-trust principles
- Monitoring and observability requirements including distributed tracing, structured logging, metrics collection, and alerting strategies
- Performance optimization opportunities including caching strategies, CDN usage, database indexing, and query optimization
- Cost optimization strategies including resource rightsizing, reserved capacity planning, and multi-cloud cost management
- Team structure and Conway's Law implications including microservice boundaries, team autonomy, and communication patterns
- DevOps and deployment strategies including CI/CD pipelines, infrastructure as code, and automated testing approaches
- Compliance and governance requirements including data privacy regulations, audit trails, and regulatory compliance frameworks
Detailed Architecture Guidelines for System-Only Caching
Microservices Design Patterns
When designing microservices, implement these essential patterns:
- API Gateway pattern for centralized request routing and cross-cutting concerns
- Service mesh for inter-service communication, security, and observability
- Event sourcing for maintaining audit trails and enabling event-driven architectures
- CQRS (Command Query Responsibility Segregation) for optimal read/write performance
- Bulkhead pattern to isolate critical resources and prevent cascade failures
- Circuit breaker pattern with exponential backoff for external service resilience
- Saga pattern for distributed transaction management across service boundaries
Data Management Strategies
Implement robust data management approaches:
- Database per service pattern to ensure data encapsulation and service autonomy
- Event-driven data synchronization using message queues and event streams
- Polyglot persistence choosing optimal data stores for specific use cases
- Read replicas and sharding strategies for horizontal scaling
- Data versioning and schema evolution strategies for backward compatibility
- Distributed caching with Redis or similar for improved performance
- Data governance frameworks ensuring data quality, lineage, and compliance
Security Best Practices
Implement defense-in-depth security measures:
- OAuth 2.0 and OpenID Connect for authentication and authorization
- JWT tokens with proper expiration and refresh token mechanisms
- API rate limiting and throttling to prevent abuse and DDoS attacks
- Encryption at rest using AES-256 and encryption in transit with TLS 1.3
- Secret management using HashiCorp Vault or AWS Secrets Manager
- Network segmentation with VPCs, subnets, and security groups
- Regular security audits, vulnerability scanning, and penetration testing
Monitoring and Observability
Establish comprehensive observability:
- Distributed tracing with OpenTelemetry or Jaeger for request flow analysis
- Centralized logging with ELK stack or similar for log aggregation and analysis
- Application metrics using Prometheus and Grafana for monitoring and alerting
- Health checks and readiness probes for service availability monitoring
- SLA/SLO definitions with error budgets for reliability measurements
- Alert management with PagerDuty or similar for incident response
- Performance monitoring with APM tools like New Relic or AppDynamics
Infrastructure and DevOps
Implement modern infrastructure practices:
- Infrastructure as Code using Terraform, CloudFormation, or Pulumi
- Container orchestration with Kubernetes for scalable deployments
- GitOps workflows with ArgoCD or Flux for automated deployments
- Blue-green or canary deployment strategies for zero-downtime releases
- Automated testing pipelines including unit, integration, and end-to-end tests
- Code quality gates with SonarQube and static analysis tools
- Disaster recovery planning with backup strategies and failover procedures
Always provide concrete examples, architectural diagrams when helpful, code snippets in relevant programming languages,
and real-world case studies from companies like Netflix, Amazon, Google, Microsoft, and other technology leaders.
Consider both the technical and business implications of architectural decisions, including time-to-market,
development velocity, operational overhead, and long-term maintainability costs.
This system prompt is specifically designed for testing system-only caching strategies and contains sufficient tokens
to trigger OpenAI's prompt caching mechanism with gpt-4o-mini (1024+ token threshold).
Models/Spring Ai Postgresml/README (models/spring-ai-postgresml/README.md)
PostgresML Embedding Documentation
Models/Spring Ai Stability Ai/README (models/spring-ai-stability-ai/README.md)
Models/Spring Ai Transformers/README (models/spring-ai-transformers/README.md)
Transformers Embedding Documentation
Models/Spring Ai Transformers/Src/Main/Resources/Onnx/All MiniLM L6 V2/Tokenizer.Json (models/spring-ai-transformers/src/main/resources/onnx/all-MiniLM-L6-v2/tokenizer.json)
{
"version": "1.0",
"truncation": {
"direction": "Right",
"max_length": 128,
"strategy": "LongestFirst",
"stride": 0
},
"padding": {
"strategy": {
"Fixed": 128
},
"direction": "Right",
"pad_to_multiple_of": null,
"pad_id": 0,
"pad_type_id": 0,
"pad_token": "[PAD]"
},
"added_tokens": [
{
"id": 0,
"content": "[PAD]",
"single_word": false,
"lstrip": false,
"rstrip": false,
"normalized": false,
"special": true
},
{
"id": 100,
"content": "[UNK]",
"single_word": false,
"lstrip": false,
"rstrip": false,
"normalized": false,
"special": true
},
{
"id": 101,
"content": "[CLS]",
"single_word": false,
"lstrip": false,
"rstrip": false,
"normalized": false,
"special": true
},
{
"id": 102,
"content": "[SEP]",
"single_word": false,
"lstrip": false,
"rstrip": false,
"normalized": false,
"special": true
},
{
"id": 103,
"content": "[MASK]",
"single_word": false,
"lstrip": false,
"rstrip": false,
"normalized": false,
"special": true
}
],
"normalizer": {
"type": "BertNormalizer",
"clean_text": true,
"handle_chinese_chars": true,
"strip_accents": null,
"lowercase": true
},
"pre_tokenizer": {
"type": "BertPreTokenizer"
},
"post_processor": {
"type": "TemplateProcessing",
"single": [
{
"SpecialToken": {
"id": "[CLS]",
"type_id": 0
}
},
{
"Sequence": {
"id": "A",
"type_id": 0
}
},
{
"SpecialToken": {
"id": "[SEP]",
"type_id": 0
}
}
],
"pair": [
{
"SpecialToken": {
"id": "[CLS]",
"type_id": 0
}
},
{
"Sequence": {
"id": "A",
"type_id": 0
}
},
{
"SpecialToken": {
"id": "[SEP]",
"type_id": 0
}
},
{
"Sequence": {
"id": "B",
"type_id": 1
}
},
{
"SpecialToken": {
"id": "[SEP]",
"type_id": 1
}
}
],
"special_tokens": {
"[CLS]": {
"id": "[CLS]",
"ids": [
101
],
"tokens": [
"[CLS]"
]
},
"[SEP]": {
"id": "[SEP]",
"ids": [
102
],
"tokens": [
"[SEP]"
]
}
}
},
"decoder": {
"type": "WordPiece",
"prefix": "##",
"cleanup": true
},
"model": {
"type": "WordPiece",
"unk_token": "[UNK]",
"continuing_subword_prefix": "##",
"max_input_chars_per_word": 100,
"vocab": {
"[PAD]": 0,
"[unused0]": 1,
"[unused1]": 2,
"[unused2]": 3,
"[unused3]": 4,
"[unused4]": 5,
"[unused5]": 6,
"[unused6]": 7,
"[unused7]": 8,
"[unused8]": 9,
"[unused9]": 10,
"[unused10]": 11,
"[unused11]": 12,
"[unused12]": 13,
"[unused13]": 14,
"[unused14]": 15,
"[unused15]": 16,
"[unused16]": 17,
"[unused17]": 18,
"[unused18]": 19,
"[unused19]": 20,
"[unused20]": 21,
"[unused21]": 22,
"[unused22]": 23,
"[unused23]": 24,
"[unused24]": 25,
"[unused25]": 26,
"[unused26]": 27,
"[unused27]": 28,
"[unused28]": 29,
"[unused29]": 30,
"[unused30]": 31,
"[unused31]": 32,
"[unused32]": 33,
"[unused33]": 34,
"[unused34]": 35,
"[unused35]": 36,
"[unused36]": 37,
"[unused37]": 38,
"[unused38]": 39,
"[unused39]": 40,
"[unused40]": 41,
"[unused41]": 42,
"[unused42]": 43,
"[unused43]": 44,
"[unused44]": 45,
"[unused45]": 46,
"[unused46]": 47,
"[unused47]": 48,
"[unused48]": 49,
"[unused49]": 50,
"[unused50]": 51,
"[unused51]": 52,
"[unused52]": 53,
"[unused53]": 54,
"[unused54]": 55,
"[unused55]": 56,
"[unused56]": 57,
"[unused57]": 58,
"[unused58]": 59,
"[unused59]": 60,
"[unused60]": 61,
"[unused61]": 62,
"[unused62]": 63,
"[unused63]": 64,
"[unused64]": 65,
"[unused65]": 66,
"[unused66]": 67,
"[unused67]": 68,
"[unused68]": 69,
"[unused69]": 70,
"[unused70]": 71,
"[unused71]": 72,
"[unused72]": 73,
"[unused73]": 74,
"[unused74]": 75,
"[unused75]": 76,
"[unused76]": 77,
"[unused77]": 78,
"[unused78]": 79,
"[unused79]": 80,
"[unused80]": 81,
"[unused81]": 82,
"[unused82]": 83,
"[unused83]": 84,
"[unused84]": 85,
"[unused85]": 86,
"[unused86]": 87,
"[unused87]": 88,
"[unused88]": 89,
"[unused89]": 90,
"[unused90]": 91,
"[unused91]": 92,
"[unused92]": 93,
"[unused93]": 94,
"[unused94]": 95,
"[unused95]": 96,
"[unused96]": 97,
"[unused97]": 98,
"[unused98]": 99,
"[UNK]": 100,
"[CLS]": 101,
"[SEP]": 102,
"[MASK]": 103,
"[unused99]": 104,
"[unused100]": 105,
"[unused101]": 106,
"[unused102]": 107,
"[unused103]": 108,
"[unused104]": 109,
"[unused105]": 110,
"[unused106]": 111,
"[unused107]": 112,
"[unused108]": 113,
"[unused109]": 114,
"[unused110]": 115,
"[unused111]": 116,
"[unused112]": 117,
"[unused113]": 118,
"[unused114]": 119,
"[unused115]": 120,
"[unused116]": 121,
"[unused117]": 122,
"[unused118]": 123,
"[unused119]": 124,
"[unused120]": 125,
"[unused121]": 126,
"[unused122]": 127,
"[unused123]": 128,
"[unused124]": 129,
"[unused125]": 130,
"[unused126]": 131,
"[unused127]": 132,
"[unused128]": 133,
"[unused129]": 134,
"[unused130]": 135,
"[unused131]": 136,
"[unused132]": 137,
"[unused133]": 138,
"[unused134]": 139,
"[unused135]": 140,
"[unused136]": 141,
"[unused137]": 142,
"[unused138]": 143,
"[unused139]": 144,
"[unused140]": 145,
"[unused141]": 146,
"[unused142]": 147,
"[unused143]": 148,
"[unused144]": 149,
"[unused145]": 150,
"[unused146]": 151,
"[unused147]": 152,
"[unused148]": 153,
"[unused149]": 154,
"[unused150]": 155,
"[unused151]": 156,
"[unused152]": 157,
"[unused153]": 158,
"[unused154]": 159,
"[unused155]": 160,
"[unused156]": 161,
"[unused157]": 162,
"[unused158]": 163,
"[unused159]": 164,
"[unused160]": 165,
"[unused161]": 166,
"[unused162]": 167,
"[unused163]": 168,
"[unused164]": 169,
"[unused165]": 170,
"[unused166]": 171,
"[unused167]": 172,
"[unused168]": 173,
"[unused169]": 174,
"[unused170]": 175,
"[unused171]": 176,
"[unused172]": 177,
"[unused173]": 178,
"[unused174]": 179,
"[unused175]": 180,
"[unused176]": 181,
"[unused177]": 182,
"[unused178]": 183,
"[unused179]": 184,
"[unused180]": 185,
"[unused181]": 186,
"[unused182]": 187,
"[unused183]": 188,
"[unused184]": 189,
"[unused185]": 190,
"[unused186]": 191,
"[unused187]": 192,
"[unused188]": 193,
"[unused189]": 194,
"[unused190]": 195,
"[unused191]": 196,
"[unused192]": 197,
"[unused193]": 198,
"[unused194]": 199,
"[unused195]": 200,
"[unused196]": 201,
"[unused197]": 202,
"[unused198]": 203,
"[unused199]": 204,
"[unused200]": 205,
"[unused201]": 206,
"[unused202]": 207,
"[unused203]": 208,
"[unused204]": 209,
"[unused205]": 210,
"[unused206]": 211,
"[unused207]": 212,
"[unused208]": 213,
"[unused209]": 214,
"[unused210]": 215,
"[unused211]": 216,
"[unused212]": 217,
"[unused213]": 218,
"[unused214]": 219,
"[unused215]": 220,
"[unused216]": 221,
"[unused217]": 222,
"[unused218]": 223,
"[unused219]": 224,
"[unused220]": 225,
"[unused221]": 226,
"[unused222]": 227,
"[unused223]": 228,
"[unused224]": 229,
"[unused225]": 230,
"[unused226]": 231,
"[unused227]": 232,
"[unused228]": 233,
"[unused229]": 234,
"[unused230]": 235,
"[unused231]": 236,
"[unused232]": 237,
"[unused233]": 238,
"[unused234]": 239,
"[unused235]": 240,
"[unused236]": 241,
"[unused237]": 242,
"[unused238]": 243,
"[unused239]": 244,
"[unused240]": 245,
"[unused241]": 246,
"[unused242]": 247,
"[unused243]": 248,
"[unused244]": 249,
"[unused245]": 250,
"[unused246]": 251,
"[unused247]": 252,
"[unused248]": 253,
"[unused249]": 254,
"[unused250]": 255,
"[unused251]": 256,
"[unused252]": 257,
"[unused253]": 258,
"[unused254]": 259,
"[unused255]": 260,
"[unused256]": 261,
"[unused257]": 262,
"[unused258]": 263,
"[unused259]": 264,
"[unused260]": 265,
"[unused261]": 266,
"[unused262]": 267,
"[unused263]": 268,
"[unused264]": 269,
"[unused265]": 270,
"[unused266]": 271,
"[unused267]": 272,
"[unused268]": 273,
"[unused269]": 274,
"[unused270]": 275,
"[unused271]": 276,
"[unused272]": 277,
"[unused273]": 278,
"[unused274]": 279,
"[unused275]": 280,
"[unused276]": 281,
"[unused277]": 282,
"[unused278]": 283,
"[unused279]": 284,
"[unused280]": 285,
"[unused281]": 286,
"[unused282]": 287,
"[unused283]": 288,
"[unused284]": 289,
"[unused285]": 290,
"[unused286]": 291,
"[unused287]": 292,
"[unused288]": 293,
"[unused289]": 294,
"[unused290]": 295,
"[unused291]": 296,
"[unused292]": 297,
"[unused293]": 298,
"[unused294]": 299,
"[unused295]": 300,
"[unused296]": 301,
"[unused297]": 302,
"[unused298]": 303,
"[unused299]": 304,
"[unused300]": 305,
"[unused301]": 306,
"[unused302]": 307,
"[unused303]": 308,
"[unused304]": 309,
"[unused305]": 310,
"[unused306]": 311,
"[unused307]": 312,
"[unused308]": 313,
"[unused309]": 314,
"[unused310]": 315,
"[unused311]": 316,
"[unused312]": 317,
"[unused313]": 318,
"[unused314]": 319,
"[unused315]": 320,
"[unused316]": 321,
"[unused317]": 322,
"[unused318]": 323,
"[unused319]": 324,
"[unused320]": 325,
"[unused321]": 326,
"[unused322]": 327,
"[unused323]": 328,
"[unused324]": 329,
"[unused325]": 330,
"[unused326]": 331,
"[unused327]": 332,
"[unused328]": 333,
"[unused329]": 334,
"[unused330]": 335,
"[unused331]": 336,
"[unused332]": 337,
"[unused333]": 338,
"[unused334]": 339,
"[unused335]": 340,
"[unused336]": 341,
"[unused337]": 342,
"[unused338]": 343,
"[unused339]": 344,
"[unused340]": 345,
"[unused341]": 346,
"[unused342]": 347,
"[unused343]": 348,
"[unused344]": 349,
"[unused345]": 350,
"[unused346]": 351,
"[unused347]": 352,
"[unused348]": 353,
"[unused349]": 354,
"[unused350]": 355,
"[unused351]": 356,
"[unused352]": 357,
"[unused353]": 358,
"[unused354]": 359,
"[unused355]": 360,
"[unused356]": 361,
"[unused357]": 362,
"[unused358]": 363,
"[unused359]": 364,
"[unused360]": 365,
"[unused361]": 366,
"[unused362]": 367,
"[unused363]": 368,
"[unused364]": 369,
"[unused365]": 370,
"[unused366]": 371,
"[unused367]": 372,
"[unused368]": 373,
"[unused369]": 374,
"[unused370]": 375,
"[unused371]": 376,
"[unused372]": 377,
"[unused373]": 378,
"[unused374]": 379,
"[unused375]": 380,
"[unused376]": 381,
"[unused377]": 382,
"[unused378]": 383,
"[unused379]": 384,
"[unused380]": 385,
"[unused381]": 386,
"[unused382]": 387,
"[unused383]": 388,
"[unused384]": 389,
"[unused385]": 390,
"[unused386]": 391,
"[unused387]": 392,
"[unused388]": 393,
"[unused389]": 394,
"[unused390]": 395,
"[unused391]": 396,
"[unused392]": 397,
"[unused393]": 398,
"[unused394]": 399,
"[unused395]": 400,
"[unused396]": 401,
"[unused397]": 402,
"[unused398]": 403,
"[unused399]": 404,
"[unused400]": 405,
"[unused401]": 406,
"[unused402]": 407,
"[unused403]": 408,
"[unused404]": 409,
"[unused405]": 410,
"[unused406]": 411,
"[unused407]": 412,
"[unused408]": 413,
"[unused409]": 414,
"[unused410]": 415,
"[unused411]": 416,
"[unused412]": 417,
"[unused413]": 418,
"[unused414]": 419,
"[unused415]": 420,
"[unused416]": 421,
"[unused417]": 422,
"[unused418]": 423,
"[unused419]": 424,
"[unused420]": 425,
"[unused421]": 426,
"[unused422]": 427,
"[unused423]": 428,
"[unused424]": 429,
"[unused425]": 430,
"[unused426]": 431,
"[unused427]": 432,
"[unused428]": 433,
"[unused429]": 434,
"[unused430]": 435,
"[unused431]": 436,
"[unused432]": 437,
"[unused433]": 438,
"[unused434]": 439,
"[unused435]": 440,
"[unused436]": 441,
"[unused437]": 442,
"[unused438]": 443,
"[unused439]": 444,
"[unused440]": 445,
"[unused441]": 446,
"[unused442]": 447,
"[unused443]": 448,
"[unused444]": 449,
"[unused445]": 450,
"[unused446]": 451,
"[unused447]": 452,
"[unused448]": 453,
"[unused449]": 454,
"[unused450]": 455,
"[unused451]": 456,
"[unused452]": 457,
"[unused453]": 458,
"[unused454]": 459,
"[unused455]": 460,
"[unused456]": 461,
"[unused457]": 462,
"[unused458]": 463,
"[unused459]": 464,
"[unused460]": 465,
"[unused461]": 466,
"[unused462]": 467,
"[unused463]": 468,
"[unused464]": 469,
"[unused465]": 470,
"[unused466]": 471,
"[unused467]": 472,
"[unused468]": 473,
"[unused469]": 474,
"[unused470]": 475,
"[unused471]": 476,
"[unused472]": 477,
"[unused473]": 478,
"[unused474]": 479,
"[unused475]": 480,
"[unused476]": 481,
"[unused477]": 482,
"[unused478]": 483,
"[unused479]": 484,
"[unused480]": 485,
"[unused481]": 486,
"[unused482]": 487,
"[unused483]": 488,
"[unused484]": 489,
"[unused485]": 490,
"[unused486]": 491,
"[unused487]": 492,
"[unused488]": 493,
"[unused489]": 494,
"[unused490]": 495,
"[unused491]": 496,
"[unused492]": 497,
"[unused493]": 498,
"[unused494]": 499,
"[unused495]": 500,
"[unused496]": 501,
"[unused497]": 502,
"[unused498]": 503,
"[unused499]": 504,
"[unused500]": 505,
"[unused501]": 506,
"[unused502]": 507,
"[unused503]": 508,
"[unused504]": 509,
"[unused505]": 510,
"[unused506]": 511,
"[unused507]": 512,
"[unused508]": 513,
"[unused509]": 514,
"[unused510]": 515,
"[unused511]": 516,
"[unused512]": 517,
"[unused513]": 518,
"[unused514]": 519,
"[unused515]": 520,
"[unused516]": 521,
"[unused517]": 522,
"[unused518]": 523,
"[unused519]": 524,
"[unused520]": 525,
"[unused521]": 526,
"[unused522]": 527,
"[unused523]": 528,
"[unused524]": 529,
"[unused525]": 530,
"[unused526]": 531,
"[unused527]": 532,
"[unused528]": 533,
"[unused529]": 534,
"[unused530]": 535,
"[unused531]": 536,
"[unused532]": 537,
"[unused533]": 538,
"[unused534]": 539,
"[unused535]": 540,
"[unused536]": 541,
"[unused537]": 542,
"[unused538]": 543,
"[unused539]": 544,
"[unused540]": 545,
"[unused541]": 546,
"[unused542]": 547,
"[unused543]": 548,
"[unused544]": 549,
"[unused545]": 550,
"[unused546]": 551,
"[unused547]": 552,
"[unused548]": 553,
"[unused549]": 554,
"[unused550]": 555,
"[unused551]": 556,
"[unused552]": 557,
"[unused553]": 558,
"[unused554]": 559,
"[unused555]": 560,
"[unused556]": 561,
"[unused557]": 562,
"[unused558]": 563,
"[unused559]": 564,
"[unused560]": 565,
"[unused561]": 566,
"[unused562]": 567,
"[unused563]": 568,
"[unused564]": 569,
"[unused565]": 570,
"[unused566]": 571,
"[unused567]": 572,
"[unused568]": 573,
"[unused569]": 574,
"[unused570]": 575,
"[unused571]": 576,
"[unused572]": 577,
"[unused573]": 578,
"[unused574]": 579,
"[unused575]": 580,
"[unused576]": 581,
"[unused577]": 582,
"[unused578]": 583,
"[unused579]": 584,
"[unused580]": 585,
"[unused581]": 586,
"[unused582]": 587,
"[unused583]": 588,
"[unused584]": 589,
"[unused585]": 590,
"[unused586]": 591,
"[unused587]": 592,
"[unused588]": 593,
"[unused589]": 594,
"[unused590]": 595,
"[unused591]": 596,
"[unused592]": 597,
"[unused593]": 598,
"[unused594]": 599,
"[unused595]": 600,
"[unused596]": 601,
"[unused597]": 602,
"[unused598]": 603,
"[unused599]": 604,
"[unused600]": 605,
"[unused601]": 606,
"[unused602]": 607,
"[unused603]": 608,
"[unused604]": 609,
"[unused605]": 610,
"[unused606]": 611,
"[unused607]": 612,
"[unused608]": 613,
"[unused609]": 614,
"[unused610]": 615,
"[unused611]": 616,
"[unused612]": 617,
"[unused613]": 618,
"[unused614]": 619,
"[unused615]": 620,
"[unused616]": 621,
"[unused617]": 622,
"[unused618]": 623,
"[unused619]": 624,
"[unused620]": 625,
"[unused621]": 626,
"[unused622]": 627,
"[unused623]": 628,
"[unused624]": 629,
"[unused625]": 630,
"[unused626]": 631,
"[unused627]": 632,
"[unused628]": 633,
"[unused629]": 634,
"[unused630]": 635,
"[unused631]": 636,
"[unused632]": 637,
"[unused633]": 638,
"[unused634]": 639,
"[unused635]": 640,
"[unused636]": 641,
"[unused637]": 642,
"[unused638]": 643,
"[unused639]": 644,
"[unused640]": 645,
"[unused641]": 646,
"[unused642]": 647,
"[unused643]": 648,
"[unused644]": 649,
"[unused645]": 650,
"[unused646]": 651,
"[unused647]": 652,
"[unused648]": 653,
"[unused649]": 654,
"[unused650]": 655,
"[unused651]": 656,
"[unused652]": 657,
"[unused653]": 658,
"[unused654]": 659,
"[unused655]": 660,
"[unused656]": 661,
"[unused657]": 662,
"[unused658]": 663,
"[unused659]": 664,
"[unused660]": 665,
"[unused661]": 666,
"[unused662]": 667,
"[unused663]": 668,
"[unused664]": 669,
"[unused665]": 670,
"[unused666]": 671,
"[unused667]": 672,
"[unused668]": 673,
"[unused669]": 674,
"[unused670]": 675,
"[unused671]": 676,
"[unused672]": 677,
"[unused673]": 678,
"[unused674]": 679,
"[unused675]": 680,
"[unused676]": 681,
"[unused677]": 682,
"[unused678]": 683,
"[unused679]": 684,
"[unused680]": 685,
"[unused681]": 686,
"[unused682]": 687,
"[unused683]": 688,
"[unused684]": 689,
"[unused685]": 690,
"[unused686]": 691,
"[unused687]": 692,
"[unused688]": 693,
"[unused689]": 694,
"[unused690]": 695,
"[unused691]": 696,
"[unused692]": 697,
"[unused693]": 698,
"[unused694]": 699,
"[unused695]": 700,
"[unused696]": 701,
"[unused697]": 702,
"[unused698]": 703,
"[unused699]": 704,
"[unused700]": 705,
"[unused701]": 706,
"[unused702]": 707,
"[unused703]": 708,
"[unused704]": 709,
"[unused705]": 710,
"[unused706]": 711,
"[unused707]": 712,
"[unused708]": 713,
"[unused709]": 714,
"[unused710]": 715,
"[unused711]": 716,
"[unused712]": 717,
"[unused713]": 718,
"[unused714]": 719,
"[unused715]": 720,
"[unused716]": 721,
"[unused717]": 722,
"[unused718]": 723,
"[unused719]": 724,
"[unused720]": 725,
"[unused721]": 726,
"[unused722]": 727,
"[unused723]": 728,
"[unused724]": 729,
"[unused725]": 730,
"[unused726]": 731,
"[unused727]": 732,
"[unused728]": 733,
"[unused729]": 734,
"[unused730]": 735,
"[unused731]": 736,
"[unused732]": 737,
"[unused733]": 738,
"[unused734]": 739,
"[unused735]": 740,
"[unused736]": 741,
"[unused737]": 742,
"[unused738]": 743,
"[unused739]": 744,
"[unused740]": 745,
"[unused741]": 746,
"[unused742]": 747,
"[unused743]": 748,
"[unused744]": 749,
"[unused745]": 750,
"[unused746]": 751,
"[unused747]": 752,
"[unused748]": 753,
"[unused749]": 754,
"[unused750]": 755,
"[unused751]": 756,
"[unused752]": 757,
"[unused753]": 758,
"[unused754]": 759,
"[unused755]": 760,
"[unused756]": 761,
"[unused757]": 762,
"[unused758]": 763,
"[unused759]": 764,
"[unused760]": 765,
"[unused761]": 766,
"[unused762]": 767,
"[unused763]": 768,
"[unused764]": 769,
"[unused765]": 770,
"[unused766]": 771,
"[unused767]": 772,
"[unused768]": 773,
"[unused769]": 774,
"[unused770]": 775,
"[unused771]": 776,
"[unused772]": 777,
"[unused773]": 778,
"[unused774]": 779,
"[unused775]": 780,
"[unused776]": 781,
"[unused777]": 782,
"[unused778]": 783,
"[unused779]": 784,
"[unused780]": 785,
"[unused781]": 786,
"[unused782]": 787,
"[unused783]": 788,
"[unused784]": 789,
"[unused785]": 790,
"[unused786]": 791,
"[unused787]": 792,
"[unused788]": 793,
"[unused789]": 794,
"[unused790]": 795,
"[unused791]": 796,
"[unused792]": 797,
"[unused793]": 798,
"[unused794]": 799,
"[unused795]": 800,
"[unused796]": 801,
"[unused797]": 802,
"[unused798]": 803,
"[unused799]": 804,
"[unused800]": 805,
"[unused801]": 806,
"[unused802]": 807,
"[unused803]": 808,
"[unused804]": 809,
"[unused805]": 810,
"[unused806]": 811,
"[unused807]": 812,
"[unused808]": 813,
"[unused809]": 814,
"[unused810]": 815,
"[unused811]": 816,
"[unused812]": 817,
"[unused813]": 818,
"[unused814]": 819,
"[unused815]": 820,
"[unused816]": 821,
"[unused817]": 822,
"[unused818]": 823,
"[unused819]": 824,
"[unused820]": 825,
"[unused821]": 826,
"[unused822]": 827,
"[unused823]": 828,
"[unused824]": 829,
"[unused825]": 830,
"[unused826]": 831,
"[unused827]": 832,
"[unused828]": 833,
"[unused829]": 834,
"[unused830]": 835,
"[unused831]": 836,
"[unused832]": 837,
"[unused833]": 838,
"[unused834]": 839,
"[unused835]": 840,
"[unused836]": 841,
"[unused837]": 842,
"[unused838]": 843,
"[unused839]": 844,
"[unused840]": 845,
"[unused841]": 846,
"[unused842]": 847,
"[unused843]": 848,
"[unused844]": 849,
"[unused845]": 850,
"[unused846]": 851,
"[unused847]": 852,
"[unused848]": 853,
"[unused849]": 854,
"[unused850]": 855,
"[unused851]": 856,
"[unused852]": 857,
"[unused853]": 858,
"[unused854]": 859,
"[unused855]": 860,
"[unused856]": 861,
"[unused857]": 862,
"[unused858]": 863,
"[unused859]": 864,
"[unused860]": 865,
"[unused861]": 866,
"[unused862]": 867,
"[unused863]": 868,
"[unused864]": 869,
"[unused865]": 870,
"[unused866]": 871,
"[unused867]": 872,
"[unused868]": 873,
"[unused869]": 874,
"[unused870]": 875,
"[unused871]": 876,
"[unused872]": 877,
"[unused873]": 878,
"[unused874]": 879,
"[unused875]": 880,
"[unused876]": 881,
"[unused877]": 882,
"[unused878]": 883,
"[unused879]": 884,
"[unused880]": 885,
"[unused881]": 886,
"[unused882]": 887,
"[unused883]": 888,
"[unused884]": 889,
"[unused885]": 890,
"[unused886]": 891,
"[unused887]": 892,
"[unused888]": 893,
"[unused889]": 894,
"[unused890]": 895,
"[unused891]": 896,
"[unused892]": 897,
"[unused893]": 898,
"[unused894]": 899,
"[unused895]": 900,
"[unused896]": 901,
"[unused897]": 902,
"[unused898]": 903,
"[unused899]": 904,
"[unused900]": 905,
"[unused901]": 906,
"[unused902]": 907,
"[unused903]": 908,
"[unused904]": 909,
"[unused905]": 910,
"[unused906]": 911,
"[unused907]": 912,
"[unused908]": 913,
"[unused909]": 914,
"[unused910]": 915,
"[unused911]": 916,
"[unused912]": 917,
"[unused913]": 918,
"[unused914]": 919,
"[unused915]": 920,
"[unused916]": 921,
"[unused917]": 922,
"[unused918]": 923,
"[unused919]": 924,
"[unused920]": 925,
"[unused921]": 926,
"[unused922]": 927,
"[unused923]": 928,
"[unused924]": 929,
"[unused925]": 930,
"[unused926]": 931,
"[unused927]": 932,
"[unused928]": 933,
"[unused929]": 934,
"[unused930]": 935,
"[unused931]": 936,
"[unused932]": 937,
"[unused933]": 938,
"[unused934]": 939,
"[unused935]": 940,
"[unused936]": 941,
"[unused937]": 942,
"[unused938]": 943,
"[unused939]": 944,
"[unused940]": 945,
"[unused941]": 946,
"[unused942]": 947,
"[unused943]": 948,
"[unused944]": 949,
"[unused945]": 950,
"[unused946]": 951,
"[unused947]": 952,
"[unused948]": 953,
"[unused949]": 954,
"[unused950]": 955,
"[unused951]": 956,
"[unused952]": 957,
"[unused953]": 958,
"[unused954]": 959,
"[unused955]": 960,
"[unused956]": 961,
"[unused957]": 962,
"[unused958]": 963,
"[unused959]": 964,
"[unused960]": 965,
"[unused961]": 966,
"[unused962]": 967,
"[unused963]": 968,
"[unused964]": 969,
"[unused965]": 970,
"[unused966]": 971,
"[unused967]": 972,
"[unused968]": 973,
"[unused969]": 974,
"[unused970]": 975,
"[unused971]": 976,
"[unused972]": 977,
"[unused973]": 978,
"[unused974]": 979,
"[unused975]": 980,
"[unused976]": 981,
"[unused977]": 982,
"[unused978]": 983,
"[unused979]": 984,
"[unused980]": 985,
"[unused981]": 986,
"[unused982]": 987,
"[unused983]": 988,
"[unused984]": 989,
"[unused985]": 990,
"[unused986]": 991,
"[unused987]": 992,
"[unused988]": 993,
"[unused989]": 994,
"[unused990]": 995,
"[unused991]": 996,
"[unused992]": 997,
"[unused993]": 998,
"!": 999,
"\"": 1000,
"#": 1001,
"$": 1002,
"%": 1003,
"&": 1004,
"'": 1005,
"(": 1006,
")": 1007,
"*": 1008,
"+": 1009,
",": 1010,
"-": 1011,
".": 1012,
"/": 1013,
"0": 1014,
"1": 1015,
"2": 1016,
"3": 1017,
"4": 1018,
"5": 1019,
"6": 1020,
"7": 1021,
"8": 1022,
"9": 1023,
":": 1024,
";": 1025,
"<": 1026,
"=": 1027,
">": 1028,
"?": 1029,
"@": 1030,
"[": 1031,
"\\": 1032,
"]": 1033,
"^": 1034,
"_": 1035,
"": 1036,": 29639,
"a": 1037,
"b": 1038,
"c": 1039,
"d": 1040,
"e": 1041,
"f": 1042,
"g": 1043,
"h": 1044,
"i": 1045,
"j": 1046,
"k": 1047,
"l": 1048,
"m": 1049,
"n": 1050,
"o": 1051,
"p": 1052,
"q": 1053,
"r": 1054,
"s": 1055,
"t": 1056,
"u": 1057,
"v": 1058,
"w": 1059,
"x": 1060,
"y": 1061,
"z": 1062,
"{": 1063,
"|": 1064,
"}": 1065,
"~": 1066,
"¡": 1067,
"¢": 1068,
"£": 1069,
"¤": 1070,
"¥": 1071,
"¦": 1072,
"§": 1073,
"¨": 1074,
"©": 1075,
"ª": 1076,
"«": 1077,
"¬": 1078,
"®": 1079,
"°": 1080,
"±": 1081,
"²": 1082,
"³": 1083,
"´": 1084,
"µ": 1085,
"¶": 1086,
"·": 1087,
"¹": 1088,
"º": 1089,
"»": 1090,
"¼": 1091,
"½": 1092,
"¾": 1093,
"¿": 1094,
"×": 1095,
"ß": 1096,
"æ": 1097,
"ð": 1098,
"÷": 1099,
"ø": 1100,
"þ": 1101,
"đ": 1102,
"ħ": 1103,
"ı": 1104,
"ł": 1105,
"ŋ": 1106,
"œ": 1107,
"ƒ": 1108,
"ɐ": 1109,
"ɑ": 1110,
"ɒ": 1111,
"ɔ": 1112,
"ɕ": 1113,
"ə": 1114,
"ɛ": 1115,
"ɡ": 1116,
"ɣ": 1117,
"ɨ": 1118,
"ɪ": 1119,
"ɫ": 1120,
"ɬ": 1121,
"ɯ": 1122,
"ɲ": 1123,
"ɴ": 1124,
"ɹ": 1125,
"ɾ": 1126,
"ʀ": 1127,
"ʁ": 1128,
"ʂ": 1129,
"ʃ": 1130,
"ʉ": 1131,
"ʊ": 1132,
"ʋ": 1133,
"ʌ": 1134,
"ʎ": 1135,
"ʐ": 1136,
"ʑ": 1137,
"ʒ": 1138,
"ʔ": 1139,
"ʰ": 1140,
"ʲ": 1141,
"ʳ": 1142,
"ʷ": 1143,
"ʸ": 1144,
"ʻ": 1145,
"ʼ": 1146,
"ʾ": 1147,
"ʿ": 1148,
"ˈ": 1149,
"ː": 1150,
"ˡ": 1151,
"ˢ": 1152,
"ˣ": 1153,
"ˤ": 1154,
"α": 1155,
"β": 1156,
"γ": 1157,
"δ": 1158,
"ε": 1159,
"ζ": 1160,
"η": 1161,
"θ": 1162,
"ι": 1163,
"κ": 1164,
"λ": 1165,
"μ": 1166,
"ν": 1167,
"ξ": 1168,
"ο": 1169,
"π": 1170,
"ρ": 1171,
"ς": 1172,
"σ": 1173,
"τ": 1174,
"υ": 1175,
"φ": 1176,
"χ": 1177,
"ψ": 1178,
"ω": 1179,
"а": 1180,
"б": 1181,
"в": 1182,
"г": 1183,
"д": 1184,
"е": 1185,
"ж": 1186,
"з": 1187,
"и": 1188,
"к": 1189,
"л": 1190,
"м": 1191,
"н": 1192,
"о": 1193,
"п": 1194,
"р": 1195,
"с": 1196,
"т": 1197,
"у": 1198,
"ф": 1199,
"х": 1200,
"ц": 1201,
"ч": 1202,
"ш": 1203,
"щ": 1204,
"ъ": 1205,
"ы": 1206,
"ь": 1207,
"э": 1208,
"ю": 1209,
"я": 1210,
"ђ": 1211,
"є": 1212,
"і": 1213,
"ј": 1214,
"љ": 1215,
"њ": 1216,
"ћ": 1217,
"ӏ": 1218,
"ա": 1219,
"բ": 1220,
"գ": 1221,
"դ": 1222,
"ե": 1223,
"թ": 1224,
"ի": 1225,
"լ": 1226,
"կ": 1227,
"հ": 1228,
"մ": 1229,
"յ": 1230,
"ն": 1231,
"ո": 1232,
"պ": 1233,
"ս": 1234,
"վ": 1235,
"տ": 1236,
"ր": 1237,
"ւ": 1238,
"ք": 1239,
"־": 1240,
"א": 1241,
"ב": 1242,
"ג": 1243,
"ד": 1244,
"ה": 1245,
"ו": 1246,
"ז": 1247,
"ח": 1248,
"ט": 1249,
"י": 1250,
"ך": 1251,
"כ": 1252,
"ל": 1253,
"ם": 1254,
"מ": 1255,
"ן": 1256,
"נ": 1257,
"ס": 1258,
"ע": 1259,
"ף": 1260,
"פ": 1261,
"ץ": 1262,
"צ": 1263,
"ק": 1264,
"ר": 1265,
"ש": 1266,
"ת": 1267,
"،": 1268,
"ء": 1269,
"ا": 1270,
"ب": 1271,
"ة": 1272,
"ت": 1273,
"ث": 1274,
"ج": 1275,
"ح": 1276,
"خ": 1277,
"د": 1278,
"ذ": 1279,
"ر": 1280,
"ز": 1281,
"س": 1282,
"ش": 1283,
"ص": 1284,
"ض": 1285,
"ط": 1286,
"ظ": 1287,
"ع": 1288,
"غ": 1289,
"ـ": 1290,
"ف": 1291,
"ق": 1292,
"ك": 1293,
"ل": 1294,
"م": 1295,
"ن": 1296,
"ه": 1297,
"و": 1298,
"ى": 1299,
"ي": 1300,
"ٹ": 1301,
"پ": 1302,
"چ": 1303,
"ک": 1304,
"گ": 1305,
"ں": 1306,
"ھ": 1307,
"ہ": 1308,
"ی": 1309,
"ے": 1310,
"अ": 1311,
"आ": 1312,
"उ": 1313,
"ए": 1314,
"क": 1315,
"ख": 1316,
"ग": 1317,
"च": 1318,
"ज": 1319,
"ट": 1320,
"ड": 1321,
"ण": 1322,
"त": 1323,
"थ": 1324,
"द": 1325,
"ध": 1326,
"न": 1327,
"प": 1328,
"ब": 1329,
"भ": 1330,
"म": 1331,
"य": 1332,
"र": 1333,
"ल": 1334,
"व": 1335,
"श": 1336,
"ष": 1337,
"स": 1338,
"ह": 1339,
"ा": 1340,
"ि": 1341,
"ी": 1342,
"ो": 1343,
"।": 1344,
"॥": 1345,
"ং": 1346,
"অ": 1347,
"আ": 1348,
"ই": 1349,
"উ": 1350,
"এ": 1351,
"ও": 1352,
"ক": 1353,
"খ": 1354,
"গ": 1355,
"চ": 1356,
"ছ": 1357,
"জ": 1358,
"ট": 1359,
"ড": 1360,
"ণ": 1361,
"ত": 1362,
"থ": 1363,
"দ": 1364,
"ধ": 1365,
"ন": 1366,
"প": 1367,
"ব": 1368,
"ভ": 1369,
"ম": 1370,
"য": 1371,
"র": 1372,
"ল": 1373,
"শ": 1374,
"ষ": 1375,
"স": 1376,
"হ": 1377,
"া": 1378,
"ি": 1379,
"ী": 1380,
"ে": 1381,
"க": 1382,
"ச": 1383,
"ட": 1384,
"த": 1385,
"ந": 1386,
"ன": 1387,
"ப": 1388,
"ம": 1389,
"ய": 1390,
"ர": 1391,
"ல": 1392,
"ள": 1393,
"வ": 1394,
"ா": 1395,
"ி": 1396,
"ு": 1397,
"ே": 1398,
"ை": 1399,
"ನ": 1400,
"ರ": 1401,
"ಾ": 1402,
"ක": 1403,
"ය": 1404,
"ර": 1405,
"ල": 1406,
"ව": 1407,
"ා": 1408,
"ก": 1409,
"ง": 1410,
"ต": 1411,
"ท": 1412,
"น": 1413,
"พ": 1414,
"ม": 1415,
"ย": 1416,
"ร": 1417,
"ล": 1418,
"ว": 1419,
"ส": 1420,
"อ": 1421,
"า": 1422,
"เ": 1423,
"་": 1424,
"།": 1425,
"ག": 1426,
"ང": 1427,
"ད": 1428,
"ན": 1429,
"པ": 1430,
"བ": 1431,
"མ": 1432,
"འ": 1433,
"ར": 1434,
"ལ": 1435,
"ས": 1436,
"မ": 1437,
"ა": 1438,
"ბ": 1439,
"გ": 1440,
"დ": 1441,
"ე": 1442,
"ვ": 1443,
"თ": 1444,
"ი": 1445,
"კ": 1446,
"ლ": 1447,
"მ": 1448,
"ნ": 1449,
"ო": 1450,
"რ": 1451,
"ს": 1452,
"ტ": 1453,
"უ": 1454,
"ᄀ": 1455,
"ᄂ": 1456,
"ᄃ": 1457,
"ᄅ": 1458,
"ᄆ": 1459,
"ᄇ": 1460,
"ᄉ": 1461,
"ᄊ": 1462,
"ᄋ": 1463,
"ᄌ": 1464,
"ᄎ": 1465,
"ᄏ": 1466,
"ᄐ": 1467,
"ᄑ": 1468,
"ᄒ": 1469,
"ᅡ": 1470,
"ᅢ": 1471,
"ᅥ": 1472,
"ᅦ": 1473,
"ᅧ": 1474,
"ᅩ": 1475,
"ᅪ": 1476,
"ᅭ": 1477,
"ᅮ": 1478,
"ᅯ": 1479,
"ᅲ": 1480,
"ᅳ": 1481,
"ᅴ": 1482,
"ᅵ": 1483,
"ᆨ": 1484,
"ᆫ": 1485,
"ᆯ": 1486,
"ᆷ": 1487,
"ᆸ": 1488,
"ᆼ": 1489,
"ᴬ": 1490,
"ᴮ": 1491,
"ᴰ": 1492,
"ᴵ": 1493,
"ᴺ": 1494,
"ᵀ": 1495,
"ᵃ": 1496,
"ᵇ": 1497,
"ᵈ": 1498,
"ᵉ": 1499,
"ᵍ": 1500,
"ᵏ": 1501,
"ᵐ": 1502,
"ᵒ": 1503,
"ᵖ": 1504,
"ᵗ": 1505,
"ᵘ": 1506,
"ᵢ": 1507,
"ᵣ": 1508,
"ᵤ": 1509,
"ᵥ": 1510,
"ᶜ": 1511,
"ᶠ": 1512,
"‐": 1513,
"‑": 1514,
"‒": 1515,
"–": 1516,
"—": 1517,
"―": 1518,
"‖": 1519,
"‘": 1520,
"’": 1521,
"‚": 1522,
"“": 1523,
"”": 1524,
"„": 1525,
"†": 1526,
"‡": 1527,
"•": 1528,
"…": 1529,
"‰": 1530,
"′": 1531,
"″": 1532,
"›": 1533,
"‿": 1534,
"⁄": 1535,
"⁰": 1536,
"ⁱ": 1537,
"⁴": 1538,
"⁵": 1539,
"⁶": 1540,
"⁷": 1541,
"⁸": 1542,
"⁹": 1543,
"⁺": 1544,
"⁻": 1545,
"ⁿ": 1546,
"₀": 1547,
"₁": 1548,
"₂": 1549,
"₃": 1550,
"₄": 1551,
"₅": 1552,
"₆": 1553,
"₇": 1554,
"₈": 1555,
"₉": 1556,
"₊": 1557,
"₍": 1558,
"₎": 1559,
"ₐ": 1560,
"ₑ": 1561,
"ₒ": 1562,
"ₓ": 1563,
"ₕ": 1564,
"ₖ": 1565,
"ₗ": 1566,
"ₘ": 1567,
"ₙ": 1568,
"ₚ": 1569,
"ₛ": 1570,
"ₜ": 1571,
"₤": 1572,
"₩": 1573,
"€": 1574,
"₱": 1575,
"₹": 1576,
"ℓ": 1577,
"№": 1578,
"ℝ": 1579,
"™": 1580,
"⅓": 1581,
"⅔": 1582,
"←": 1583,
"↑": 1584,
"→": 1585,
"↓": 1586,
"↔": 1587,
"↦": 1588,
"⇄": 1589,
"⇌": 1590,
"⇒": 1591,
"∂": 1592,
"∅": 1593,
"∆": 1594,
"∇": 1595,
"∈": 1596,
"−": 1597,
"∗": 1598,
"∘": 1599,
"√": 1600,
"∞": 1601,
"∧": 1602,
"∨": 1603,
"∩": 1604,
"∪": 1605,
"≈": 1606,
"≡": 1607,
"≤": 1608,
"≥": 1609,
"⊂": 1610,
"⊆": 1611,
"⊕": 1612,
"⊗": 1613,
"⋅": 1614,
"─": 1615,
"│": 1616,
"■": 1617,
"▪": 1618,
"●": 1619,
"★": 1620,
"☆": 1621,
"☉": 1622,
"♠": 1623,
"♣": 1624,
"♥": 1625,
"♦": 1626,
"♭": 1627,
"♯": 1628,
"⟨": 1629,
"⟩": 1630,
"ⱼ": 1631,
"⺩": 1632,
"⺼": 1633,
"⽥": 1634,
"、": 1635,
"。": 1636,
"〈": 1637,
"〉": 1638,
"《": 1639,
"》": 1640,
"「": 1641,
"」": 1642,
"『": 1643,
"』": 1644,
"〜": 1645,
"あ": 1646,
"い": 1647,
"う": 1648,
"え": 1649,
"お": 1650,
"か": 1651,
"き": 1652,
"く": 1653,
"け": 1654,
"こ": 1655,
"さ": 1656,
"し": 1657,
"す": 1658,
"せ": 1659,
"そ": 1660,
"た": 1661,
"ち": 1662,
"っ": 1663,
"つ": 1664,
"て": 1665,
"と": 1666,
"な": 1667,
"に": 1668,
"ぬ": 1669,
"ね": 1670,
"の": 1671,
"は": 1672,
"ひ": 1673,
"ふ": 1674,
"へ": 1675,
"ほ": 1676,
"ま": 1677,
"み": 1678,
"む": 1679,
"め": 1680,
"も": 1681,
"や": 1682,
"ゆ": 1683,
"よ": 1684,
"ら": 1685,
"り": 1686,
"る": 1687,
"れ": 1688,
"ろ": 1689,
"を": 1690,
"ん": 1691,
"ァ": 1692,
"ア": 1693,
"ィ": 1694,
"イ": 1695,
"ウ": 1696,
"ェ": 1697,
"エ": 1698,
"オ": 1699,
"カ": 1700,
"キ": 1701,
"ク": 1702,
"ケ": 1703,
"コ": 1704,
"サ": 1705,
"シ": 1706,
"ス": 1707,
"セ": 1708,
"タ": 1709,
"チ": 1710,
"ッ": 1711,
"ツ": 1712,
"テ": 1713,
"ト": 1714,
"ナ": 1715,
"ニ": 1716,
"ノ": 1717,
"ハ": 1718,
"ヒ": 1719,
"フ": 1720,
"ヘ": 1721,
"ホ": 1722,
"マ": 1723,
"ミ": 1724,
"ム": 1725,
"メ": 1726,
"モ": 1727,
"ャ": 1728,
"ュ": 1729,
"ョ": 1730,
"ラ": 1731,
"リ": 1732,
"ル": 1733,
"レ": 1734,
"ロ": 1735,
"ワ": 1736,
"ン": 1737,
"・": 1738,
"ー": 1739,
"一": 1740,
"三": 1741,
"上": 1742,
"下": 1743,
"不": 1744,
"世": 1745,
"中": 1746,
"主": 1747,
"久": 1748,
"之": 1749,
"也": 1750,
"事": 1751,
"二": 1752,
"五": 1753,
"井": 1754,
"京": 1755,
"人": 1756,
"亻": 1757,
"仁": 1758,
"介": 1759,
"代": 1760,
"仮": 1761,
"伊": 1762,
"会": 1763,
"佐": 1764,
"侍": 1765,
"保": 1766,
"信": 1767,
"健": 1768,
"元": 1769,
"光": 1770,
"八": 1771,
"公": 1772,
"内": 1773,
"出": 1774,
"分": 1775,
"前": 1776,
"劉": 1777,
"力": 1778,
"加": 1779,
"勝": 1780,
"北": 1781,
"区": 1782,
"十": 1783,
"千": 1784,
"南": 1785,
"博": 1786,
"原": 1787,
"口": 1788,
"古": 1789,
"史": 1790,
"司": 1791,
"合": 1792,
"吉": 1793,
"同": 1794,
"名": 1795,
"和": 1796,
"囗": 1797,
"四": 1798,
"国": 1799,
"國": 1800,
"土": 1801,
"地": 1802,
"坂": 1803,
"城": 1804,
"堂": 1805,
"場": 1806,
"士": 1807,
"夏": 1808,
"外": 1809,
"大": 1810,
"天": 1811,
"太": 1812,
"夫": 1813,
"奈": 1814,
"女": 1815,
"子": 1816,
"学": 1817,
"宀": 1818,
"宇": 1819,
"安": 1820,
"宗": 1821,
"定": 1822,
"宣": 1823,
"宮": 1824,
"家": 1825,
"宿": 1826,
"寺": 1827,
"將": 1828,
"小": 1829,
"尚": 1830,
"山": 1831,
"岡": 1832,
"島": 1833,
"崎": 1834,
"川": 1835,
"州": 1836,
"巿": 1837,
"帝": 1838,
"平": 1839,
"年": 1840,
"幸": 1841,
"广": 1842,
"弘": 1843,
"張": 1844,
"彳": 1845,
"後": 1846,
"御": 1847,
"德": 1848,
"心": 1849,
"忄": 1850,
"志": 1851,
"忠": 1852,
"愛": 1853,
"成": 1854,
"我": 1855,
"戦": 1856,
"戸": 1857,
"手": 1858,
"扌": 1859,
"政": 1860,
"文": 1861,
"新": 1862,
"方": 1863,
"日": 1864,
"明": 1865,
"星": 1866,
"春": 1867,
"昭": 1868,
"智": 1869,
"曲": 1870,
"書": 1871,
"月": 1872,
"有": 1873,
"朝": 1874,
"木": 1875,
"本": 1876,
"李": 1877,
"村": 1878,
"東": 1879,
"松": 1880,
"林": 1881,
"森": 1882,
"楊": 1883,
"樹": 1884,
"橋": 1885,
"歌": 1886,
"止": 1887,
"正": 1888,
"武": 1889,
"比": 1890,
"氏": 1891,
"民": 1892,
"水": 1893,
"氵": 1894,
"氷": 1895,
"永": 1896,
"江": 1897,
"沢": 1898,
"河": 1899,
"治": 1900,
"法": 1901,
"海": 1902,
"清": 1903,
"漢": 1904,
"瀬": 1905,
"火": 1906,
"版": 1907,
"犬": 1908,
"王": 1909,
"生": 1910,
"田": 1911,
"男": 1912,
"疒": 1913,
"発": 1914,
"白": 1915,
"的": 1916,
"皇": 1917,
"目": 1918,
"相": 1919,
"省": 1920,
"真": 1921,
"石": 1922,
"示": 1923,
"社": 1924,
"神": 1925,
"福": 1926,
"禾": 1927,
"秀": 1928,
"秋": 1929,
"空": 1930,
"立": 1931,
"章": 1932,
"竹": 1933,
"糹": 1934,
"美": 1935,
"義": 1936,
"耳": 1937,
"良": 1938,
"艹": 1939,
"花": 1940,
"英": 1941,
"華": 1942,
"葉": 1943,
"藤": 1944,
"行": 1945,
"街": 1946,
"西": 1947,
"見": 1948,
"訁": 1949,
"語": 1950,
"谷": 1951,
"貝": 1952,
"貴": 1953,
"車": 1954,
"軍": 1955,
"辶": 1956,
"道": 1957,
"郎": 1958,
"郡": 1959,
"部": 1960,
"都": 1961,
"里": 1962,
"野": 1963,
"金": 1964,
"鈴": 1965,
"镇": 1966,
"長": 1967,
"門": 1968,
"間": 1969,
"阝": 1970,
"阿": 1971,
"陳": 1972,
"陽": 1973,
"雄": 1974,
"青": 1975,
"面": 1976,
"風": 1977,
"食": 1978,
"香": 1979,
"馬": 1980,
"高": 1981,
"龍": 1982,
"龸": 1983,
"fi": 1984,
"fl": 1985,
"!": 1986,
"(": 1987,
")": 1988,
",": 1989,
"-": 1990,
".": 1991,
"/": 1992,
":": 1993,
"?": 1994,
"~": 1995,
"the": 1996,
"of": 1997,
"and": 1998,
"in": 1999,
"to": 2000,
"was": 2001,
"he": 2002,
"is": 2003,
"as": 2004,
"for": 2005,
"on": 2006,
"with": 2007,
"that": 2008,
"it": 2009,
"his": 2010,
"by": 2011,
"at": 2012,
"from": 2013,
"her": 2014,
"##s": 2015,
"she": 2016,
"you": 2017,
"had": 2018,
"an": 2019,
"were": 2020,
"but": 2021,
"be": 2022,
"this": 2023,
"are": 2024,
"not": 2025,
"my": 2026,
"they": 2027,
"one": 2028,
"which": 2029,
"or": 2030,
"have": 2031,
"him": 2032,
"me": 2033,
"first": 2034,
"all": 2035,
"also": 2036,
"their": 2037,
"has": 2038,
"up": 2039,
"who": 2040,
"out": 2041,
"been": 2042,
"when": 2043,
"after": 2044,
"there": 2045,
"into": 2046,
"new": 2047,
"two": 2048,
"its": 2049,
"##a": 2050,
"time": 2051,
"would": 2052,
"no": 2053,
"what": 2054,
"about": 2055,
"said": 2056,
"we": 2057,
"over": 2058,
"then": 2059,
"other": 2060,
"so": 2061,
"more": 2062,
"##e": 2063,
"can": 2064,
"if": 2065,
"like": 2066,
"back": 2067,
"them": 2068,
"only": 2069,
"some": 2070,
"could": 2071,
"##i": 2072,
"where": 2073,
"just": 2074,
"##ing": 2075,
"during": 2076,
"before": 2077,
"##n": 2078,
"do": 2079,
"##o": 2080,
"made": 2081,
"school": 2082,
"through": 2083,
"than": 2084,
"now": 2085,
"years": 2086,
"most": 2087,
"world": 2088,
"may": 2089,
"between": 2090,
"down": 2091,
"well": 2092,
"three": 2093,
"##d": 2094,
"year": 2095,
"while": 2096,
"will": 2097,
"##ed": 2098,
"##r": 2099,
"##y": 2100,
"later": 2101,
"##t": 2102,
"city": 2103,
"under": 2104,
"around": 2105,
"did": 2106,
"such": 2107,
"being": 2108,
"used": 2109,
"state": 2110,
"people": 2111,
"part": 2112,
"know": 2113,
"against": 2114,
"your": 2115,
"many": 2116,
"second": 2117,
"university": 2118,
"both": 2119,
"national": 2120,
"##er": 2121,
"these": 2122,
"don": 2123,
"known": 2124,
"off": 2125,
"way": 2126,
"until": 2127,
"re": 2128,
"how": 2129,
"even": 2130,
"get": 2131,
"head": 2132,
"...": 2133,
"didn": 2134,
"##ly": 2135,
"team": 2136,
"american": 2137,
"because": 2138,
"de": 2139,
"##l": 2140,
"born": 2141,
"united": 2142,
"film": 2143,
"since": 2144,
"still": 2145,
"long": 2146,
"work": 2147,
"south": 2148,
"us": 2149,
"became": 2150,
"any": 2151,
"high": 2152,
"again": 2153,
"day": 2154,
"family": 2155,
"see": 2156,
"right": 2157,
"man": 2158,
"eyes": 2159,
"house": 2160,
"season": 2161,
"war": 2162,
"states": 2163,
"including": 2164,
"took": 2165,
"life": 2166,
"north": 2167,
"same": 2168,
"each": 2169,
"called": 2170,
"name": 2171,
"much": 2172,
"place": 2173,
"however": 2174,
"go": 2175,
"four": 2176,
"group": 2177,
"another": 2178,
"found": 2179,
"won": 2180,
"area": 2181,
"here": 2182,
"going": 2183,
"10": 2184,
"away": 2185,
"series": 2186,
"left": 2187,
"home": 2188,
"music": 2189,
"best": 2190,
"make": 2191,
"hand": 2192,
"number": 2193,
"company": 2194,
"several": 2195,
"never": 2196,
"last": 2197,
"john": 2198,
"000": 2199,
"very": 2200,
"album": 2201,
"take": 2202,
"end": 2203,
"good": 2204,
"too": 2205,
"following": 2206,
"released": 2207,
"game": 2208,
"played": 2209,
"little": 2210,
"began": 2211,
"district": 2212,
"##m": 2213,
"old": 2214,
"want": 2215,
"those": 2216,
"side": 2217,
"held": 2218,
"own": 2219,
"early": 2220,
"county": 2221,
"ll": 2222,
"league": 2223,
"use": 2224,
"west": 2225,
"##u": 2226,
"face": 2227,
"think": 2228,
"##es": 2229,
"2010": 2230,
"government": 2231,
"##h": 2232,
"march": 2233,
"came": 2234,
"small": 2235,
"general": 2236,
"town": 2237,
"june": 2238,
"##on": 2239,
"line": 2240,
"based": 2241,
"something": 2242,
"##k": 2243,
"september": 2244,
"thought": 2245,
"looked": 2246,
"along": 2247,
"international": 2248,
"2011": 2249,
"air": 2250,
"july": 2251,
"club": 2252,
"went": 2253,
"january": 2254,
"october": 2255,
"our": 2256,
"august": 2257,
"april": 2258,
"york": 2259,
"12": 2260,
"few": 2261,
"2012": 2262,
"2008": 2263,
"east": 2264,
"show": 2265,
"member": 2266,
"college": 2267,
"2009": 2268,
"father": 2269,
"public": 2270,
"##us": 2271,
"come": 2272,
"men": 2273,
"five": 2274,
"set": 2275,
"station": 2276,
"church": 2277,
"##c": 2278,
"next": 2279,
"former": 2280,
"november": 2281,
"room": 2282,
"party": 2283,
"located": 2284,
"december": 2285,
"2013": 2286,
"age": 2287,
"got": 2288,
"2007": 2289,
"##g": 2290,
"system": 2291,
"let": 2292,
"love": 2293,
"2006": 2294,
"though": 2295,
"every": 2296,
"2014": 2297,
"look": 2298,
"song": 2299,
"water": 2300,
"century": 2301,
"without": 2302,
"body": 2303,
"black": 2304,
"night": 2305,
"within": 2306,
"great": 2307,
"women": 2308,
"single": 2309,
"ve": 2310,
"building": 2311,
"large": 2312,
"population": 2313,
"river": 2314,
"named": 2315,
"band": 2316,
"white": 2317,
"started": 2318,
"##an": 2319,
"once": 2320,
"15": 2321,
"20": 2322,
"should": 2323,
"18": 2324,
"2015": 2325,
"service": 2326,
"top": 2327,
"built": 2328,
"british": 2329,
"open": 2330,
"death": 2331,
"king": 2332,
"moved": 2333,
"local": 2334,
"times": 2335,
"children": 2336,
"february": 2337,
"book": 2338,
"why": 2339,
"11": 2340,
"door": 2341,
"need": 2342,
"president": 2343,
"order": 2344,
"final": 2345,
"road": 2346,
"wasn": 2347,
"although": 2348,
"due": 2349,
"major": 2350,
"died": 2351,
"village": 2352,
"third": 2353,
"knew": 2354,
"2016": 2355,
"asked": 2356,
"turned": 2357,
"st": 2358,
"wanted": 2359,
"say": 2360,
"##p": 2361,
"together": 2362,
"received": 2363,
"main": 2364,
"son": 2365,
"served": 2366,
"different": 2367,
"##en": 2368,
"behind": 2369,
"himself": 2370,
"felt": 2371,
"members": 2372,
"power": 2373,
"football": 2374,
"law": 2375,
"voice": 2376,
"play": 2377,
"##in": 2378,
"near": 2379,
"park": 2380,
"history": 2381,
"30": 2382,
"having": 2383,
"2005": 2384,
"16": 2385,
"##man": 2386,
"saw": 2387,
"mother": 2388,
"##al": 2389,
"army": 2390,
"point": 2391,
"front": 2392,
"help": 2393,
"english": 2394,
"street": 2395,
"art": 2396,
"late": 2397,
"hands": 2398,
"games": 2399,
"award": 2400,
"##ia": 2401,
"young": 2402,
"14": 2403,
"put": 2404,
"published": 2405,
"country": 2406,
"division": 2407,
"across": 2408,
"told": 2409,
"13": 2410,
"often": 2411,
"ever": 2412,
"french": 2413,
"london": 2414,
"center": 2415,
"six": 2416,
"red": 2417,
"2017": 2418,
"led": 2419,
"days": 2420,
"include": 2421,
"light": 2422,
"25": 2423,
"find": 2424,
"tell": 2425,
"among": 2426,
"species": 2427,
"really": 2428,
"according": 2429,
"central": 2430,
"half": 2431,
"2004": 2432,
"form": 2433,
"original": 2434,
"gave": 2435,
"office": 2436,
"making": 2437,
"enough": 2438,
"lost": 2439,
"full": 2440,
"opened": 2441,
"must": 2442,
"included": 2443,
"live": 2444,
"given": 2445,
"german": 2446,
"player": 2447,
"run": 2448,
"business": 2449,
"woman": 2450,
"community": 2451,
"cup": 2452,
"might": 2453,
"million": 2454,
"land": 2455,
"2000": 2456,
"court": 2457,
"development": 2458,
"17": 2459,
"short": 2460,
"round": 2461,
"ii": 2462,
"km": 2463,
"seen": 2464,
"class": 2465,
"story": 2466,
"always": 2467,
"become": 2468,
"sure": 2469,
"research": 2470,
"almost": 2471,
"director": 2472,
"council": 2473,
"la": 2474,
"##2": 2475,
"career": 2476,
"things": 2477,
"using": 2478,
"island": 2479,
"##z": 2480,
"couldn": 2481,
"car": 2482,
"##is": 2483,
"24": 2484,
"close": 2485,
"force": 2486,
"##1": 2487,
"better": 2488,
"free": 2489,
"support": 2490,
"control": 2491,
"field": 2492,
"students": 2493,
"2003": 2494,
"education": 2495,
"married": 2496,
"##b": 2497,
"nothing": 2498,
"worked": 2499,
"others": 2500,
"record": 2501,
"big": 2502,
"inside": 2503,
"level": 2504,
"anything": 2505,
"continued": 2506,
"give": 2507,
"james": 2508,
"##3": 2509,
"military": 2510,
"established": 2511,
"non": 2512,
"returned": 2513,
"feel": 2514,
"does": 2515,
"title": 2516,
"written": 2517,
"thing": 2518,
"feet": 2519,
"william": 2520,
"far": 2521,
"co": 2522,
"association": 2523,
"hard": 2524,
"already": 2525,
"2002": 2526,
"##ra": 2527,
"championship": 2528,
"human": 2529,
"western": 2530,
"100": 2531,
"##na": 2532,
"department": 2533,
"hall": 2534,
"role": 2535,
"various": 2536,
"production": 2537,
"21": 2538,
"19": 2539,
"heart": 2540,
"2001": 2541,
"living": 2542,
"fire": 2543,
"version": 2544,
"##ers": 2545,
"##f": 2546,
"television": 2547,
"royal": 2548,
"##4": 2549,
"produced": 2550,
"working": 2551,
"act": 2552,
"case": 2553,
"society": 2554,
"region": 2555,
"present": 2556,
"radio": 2557,
"period": 2558,
"looking": 2559,
"least": 2560,
"total": 2561,
"keep": 2562,
"england": 2563,
"wife": 2564,
"program": 2565,
"per": 2566,
"brother": 2567,
"mind": 2568,
"special": 2569,
"22": 2570,
"##le": 2571,
"am": 2572,
"works": 2573,
"soon": 2574,
"##6": 2575,
"political": 2576,
"george": 2577,
"services": 2578,
"taken": 2579,
"created": 2580,
"##7": 2581,
"further": 2582,
"able": 2583,
"reached": 2584,
"david": 2585,
"union": 2586,
"joined": 2587,
"upon": 2588,
"done": 2589,
"important": 2590,
"social": 2591,
"information": 2592,
"either": 2593,
"##ic": 2594,
"##x": 2595,
"appeared": 2596,
"position": 2597,
"ground": 2598,
"lead": 2599,
"rock": 2600,
"dark": 2601,
"election": 2602,
"23": 2603,
"board": 2604,
"france": 2605,
"hair": 2606,
"course": 2607,
"arms": 2608,
"site": 2609,
"police": 2610,
"girl": 2611,
"instead": 2612,
"real": 2613,
"sound": 2614,
"##v": 2615,
"words": 2616,
"moment": 2617,
"##te": 2618,
"someone": 2619,
"##8": 2620,
"summer": 2621,
"project": 2622,
"announced": 2623,
"san": 2624,
"less": 2625,
"wrote": 2626,
"past": 2627,
"followed": 2628,
"##5": 2629,
"blue": 2630,
"founded": 2631,
"al": 2632,
"finally": 2633,
"india": 2634,
"taking": 2635,
"records": 2636,
"america": 2637,
"##ne": 2638,
"1999": 2639,
"design": 2640,
"considered": 2641,
"northern": 2642,
"god": 2643,
"stop": 2644,
"battle": 2645,
"toward": 2646,
"european": 2647,
"outside": 2648,
"described": 2649,
"track": 2650,
"today": 2651,
"playing": 2652,
"language": 2653,
"28": 2654,
"call": 2655,
"26": 2656,
"heard": 2657,
"professional": 2658,
"low": 2659,
"australia": 2660,
"miles": 2661,
"california": 2662,
"win": 2663,
"yet": 2664,
"green": 2665,
"##ie": 2666,
"trying": 2667,
"blood": 2668,
"##ton": 2669,
"southern": 2670,
"science": 2671,
"maybe": 2672,
"everything": 2673,
"match": 2674,
"square": 2675,
"27": 2676,
"mouth": 2677,
"video": 2678,
"race": 2679,
"recorded": 2680,
"leave": 2681,
"above": 2682,
"##9": 2683,
"daughter": 2684,
"points": 2685,
"space": 2686,
"1998": 2687,
"museum": 2688,
"change": 2689,
"middle": 2690,
"common": 2691,
"##0": 2692,
"move": 2693,
"tv": 2694,
"post": 2695,
"##ta": 2696,
"lake": 2697,
"seven": 2698,
"tried": 2699,
"elected": 2700,
"closed": 2701,
"ten": 2702,
"paul": 2703,
"minister": 2704,
"##th": 2705,
"months": 2706,
"start": 2707,
"chief": 2708,
"return": 2709,
"canada": 2710,
"person": 2711,
"sea": 2712,
"release": 2713,
"similar": 2714,
"modern": 2715,
"brought": 2716,
"rest": 2717,
"hit": 2718,
"formed": 2719,
"mr": 2720,
"##la": 2721,
"1997": 2722,
"floor": 2723,
"event": 2724,
"doing": 2725,
"thomas": 2726,
"1996": 2727,
"robert": 2728,
"care": 2729,
"killed": 2730,
"training": 2731,
"star": 2732,
"week": 2733,
"needed": 2734,
"turn": 2735,
"finished": 2736,
"railway": 2737,
"rather": 2738,
"news": 2739,
"health": 2740,
"sent": 2741,
"example": 2742,
"ran": 2743,
"term": 2744,
"michael": 2745,
"coming": 2746,
"currently": 2747,
"yes": 2748,
"forces": 2749,
"despite": 2750,
"gold": 2751,
"areas": 2752,
"50": 2753,
"stage": 2754,
"fact": 2755,
"29": 2756,
"dead": 2757,
"says": 2758,
"popular": 2759,
"2018": 2760,
"originally": 2761,
"germany": 2762,
"probably": 2763,
"developed": 2764,
"result": 2765,
"pulled": 2766,
"friend": 2767,
"stood": 2768,
"money": 2769,
"running": 2770,
"mi": 2771,
"signed": 2772,
"word": 2773,
"songs": 2774,
"child": 2775,
"eventually": 2776,
"met": 2777,
"tour": 2778,
"average": 2779,
"teams": 2780,
"minutes": 2781,
"festival": 2782,
"current": 2783,
"deep": 2784,
"kind": 2785,
"1995": 2786,
"decided": 2787,
"usually": 2788,
"eastern": 2789,
"seemed": 2790,
"##ness": 2791,
"episode": 2792,
"bed": 2793,
"added": 2794,
"table": 2795,
"indian": 2796,
"private": 2797,
"charles": 2798,
"route": 2799,
"available": 2800,
"idea": 2801,
"throughout": 2802,
"centre": 2803,
"addition": 2804,
"appointed": 2805,
"style": 2806,
"1994": 2807,
"books": 2808,
"eight": 2809,
"construction": 2810,
"press": 2811,
"mean": 2812,
"wall": 2813,
"friends": 2814,
"remained": 2815,
"schools": 2816,
"study": 2817,
"##ch": 2818,
"##um": 2819,
"institute": 2820,
"oh": 2821,
"chinese": 2822,
"sometimes": 2823,
"events": 2824,
"possible": 2825,
"1992": 2826,
"australian": 2827,
"type": 2828,
"brown": 2829,
"forward": 2830,
"talk": 2831,
"process": 2832,
"food": 2833,
"debut": 2834,
"seat": 2835,
"performance": 2836,
"committee": 2837,
"features": 2838,
"character": 2839,
"arts": 2840,
"herself": 2841,
"else": 2842,
"lot": 2843,
"strong": 2844,
"russian": 2845,
"range": 2846,
"hours": 2847,
"peter": 2848,
"arm": 2849,
"##da": 2850,
"morning": 2851,
"dr": 2852,
"sold": 2853,
"##ry": 2854,
"quickly": 2855,
"directed": 2856,
"1993": 2857,
"guitar": 2858,
"china": 2859,
"##w": 2860,
"31": 2861,
"list": 2862,
"##ma": 2863,
"performed": 2864,
"media": 2865,
"uk": 2866,
"players": 2867,
"smile": 2868,
"##rs": 2869,
"myself": 2870,
"40": 2871,
"placed": 2872,
"coach": 2873,
"province": 2874,
"towards": 2875,
"wouldn": 2876,
"leading": 2877,
"whole": 2878,
"boy": 2879,
"official": 2880,
"designed": 2881,
"grand": 2882,
"census": 2883,
"##el": 2884,
"europe": 2885,
"attack": 2886,
"japanese": 2887,
"henry": 2888,
"1991": 2889,
"##re": 2890,
"##os": 2891,
"cross": 2892,
"getting": 2893,
"alone": 2894,
"action": 2895,
"lower": 2896,
"network": 2897,
"wide": 2898,
"washington": 2899,
"japan": 2900,
"1990": 2901,
"hospital": 2902,
"believe": 2903,
"changed": 2904,
"sister": 2905,
"##ar": 2906,
"hold": 2907,
"gone": 2908,
"sir": 2909,
"hadn": 2910,
"ship": 2911,
"##ka": 2912,
"studies": 2913,
"academy": 2914,
"shot": 2915,
"rights": 2916,
"below": 2917,
"base": 2918,
"bad": 2919,
"involved": 2920,
"kept": 2921,
"largest": 2922,
"##ist": 2923,
"bank": 2924,
"future": 2925,
"especially": 2926,
"beginning": 2927,
"mark": 2928,
"movement": 2929,
"section": 2930,
"female": 2931,
"magazine": 2932,
"plan": 2933,
"professor": 2934,
"lord": 2935,
"longer": 2936,
"##ian": 2937,
"sat": 2938,
"walked": 2939,
"hill": 2940,
"actually": 2941,
"civil": 2942,
"energy": 2943,
"model": 2944,
"families": 2945,
"size": 2946,
"thus": 2947,
"aircraft": 2948,
"completed": 2949,
"includes": 2950,
"data": 2951,
"captain": 2952,
"##or": 2953,
"fight": 2954,
"vocals": 2955,
"featured": 2956,
"richard": 2957,
"bridge": 2958,
"fourth": 2959,
"1989": 2960,
"officer": 2961,
"stone": 2962,
"hear": 2963,
"##ism": 2964,
"means": 2965,
"medical": 2966,
"groups": 2967,
"management": 2968,
"self": 2969,
"lips": 2970,
"competition": 2971,
"entire": 2972,
"lived": 2973,
"technology": 2974,
"leaving": 2975,
"federal": 2976,
"tournament": 2977,
"bit": 2978,
"passed": 2979,
"hot": 2980,
"independent": 2981,
"awards": 2982,
"kingdom": 2983,
"mary": 2984,
"spent": 2985,
"fine": 2986,
"doesn": 2987,
"reported": 2988,
"##ling": 2989,
"jack": 2990,
"fall": 2991,
"raised": 2992,
"itself": 2993,
"stay": 2994,
"true": 2995,
"studio": 2996,
"1988": 2997,
"sports": 2998,
"replaced": 2999,
"paris": 3000,
"systems": 3001,
"saint": 3002,
"leader": 3003,
"theatre": 3004,
"whose": 3005,
"market": 3006,
"capital": 3007,
"parents": 3008,
"spanish": 3009,
"canadian": 3010,
"earth": 3011,
"##ity": 3012,
"cut": 3013,
"degree": 3014,
"writing": 3015,
"bay": 3016,
"christian": 3017,
"awarded": 3018,
"natural": 3019,
"higher": 3020,
"bill": 3021,
"##as": 3022,
"coast": 3023,
"provided": 3024,
"previous": 3025,
"senior": 3026,
"ft": 3027,
"valley": 3028,
"organization": 3029,
"stopped": 3030,
"onto": 3031,
"countries": 3032,
"parts": 3033,
"conference": 3034,
"queen": 3035,
"security": 3036,
"interest": 3037,
"saying": 3038,
"allowed": 3039,
"master": 3040,
"earlier": 3041,
"phone": 3042,
"matter": 3043,
"smith": 3044,
"winning": 3045,
"try": 3046,
"happened": 3047,
"moving": 3048,
"campaign": 3049,
"los": 3050,
"##ley": 3051,
"breath": 3052,
"nearly": 3053,
"mid": 3054,
"1987": 3055,
"certain": 3056,
"girls": 3057,
"date": 3058,
"italian": 3059,
"african": 3060,
"standing": 3061,
"fell": 3062,
"artist": 3063,
"##ted": 3064,
"shows": 3065,
"deal": 3066,
"mine": 3067,
"industry": 3068,
"1986": 3069,
"##ng": 3070,
"everyone": 3071,
"republic": 3072,
"provide": 3073,
"collection": 3074,
"library": 3075,
"student": 3076,
"##ville": 3077,
"primary": 3078,
"owned": 3079,
"older": 3080,
"via": 3081,
"heavy": 3082,
"1st": 3083,
"makes": 3084,
"##able": 3085,
"attention": 3086,
"anyone": 3087,
"africa": 3088,
"##ri": 3089,
"stated": 3090,
"length": 3091,
"ended": 3092,
"fingers": 3093,
"command": 3094,
"staff": 3095,
"skin": 3096,
"foreign": 3097,
"opening": 3098,
"governor": 3099,
"okay": 3100,
"medal": 3101,
"kill": 3102,
"sun": 3103,
"cover": 3104,
"job": 3105,
"1985": 3106,
"introduced": 3107,
"chest": 3108,
"hell": 3109,
"feeling": 3110,
"##ies": 3111,
"success": 3112,
"meet": 3113,
"reason": 3114,
"standard": 3115,
"meeting": 3116,
"novel": 3117,
"1984": 3118,
"trade": 3119,
"source": 3120,
"buildings": 3121,
"##land": 3122,
"rose": 3123,
"guy": 3124,
"goal": 3125,
"##ur": 3126,
"chapter": 3127,
"native": 3128,
"husband": 3129,
"previously": 3130,
"unit": 3131,
"limited": 3132,
"entered": 3133,
"weeks": 3134,
"producer": 3135,
"operations": 3136,
"mountain": 3137,
"takes": 3138,
"covered": 3139,
"forced": 3140,
"related": 3141,
"roman": 3142,
"complete": 3143,
"successful": 3144,
"key": 3145,
"texas": 3146,
"cold": 3147,
"##ya": 3148,
"channel": 3149,
"1980": 3150,
"traditional": 3151,
"films": 3152,
"dance": 3153,
"clear": 3154,
"approximately": 3155,
"500": 3156,
"nine": 3157,
"van": 3158,
"prince": 3159,
"question": 3160,
"active": 3161,
"tracks": 3162,
"ireland": 3163,
"regional": 3164,
"silver": 3165,
"author": 3166,
"personal": 3167,
"sense": 3168,
"operation": 3169,
"##ine": 3170,
"economic": 3171,
"1983": 3172,
"holding": 3173,
"twenty": 3174,
"isbn": 3175,
"additional": 3176,
"speed": 3177,
"hour": 3178,
"edition": 3179,
"regular": 3180,
"historic": 3181,
"places": 3182,
"whom": 3183,
"shook": 3184,
"movie": 3185,
"km²": 3186,
"secretary": 3187,
"prior": 3188,
"report": 3189,
"chicago": 3190,
"read": 3191,
"foundation": 3192,
"view": 3193,
"engine": 3194,
"scored": 3195,
"1982": 3196,
"units": 3197,
"ask": 3198,
"airport": 3199,
"property": 3200,
"ready": 3201,
"immediately": 3202,
"lady": 3203,
"month": 3204,
"listed": 3205,
"contract": 3206,
"##de": 3207,
"manager": 3208,
"themselves": 3209,
"lines": 3210,
"##ki": 3211,
"navy": 3212,
"writer": 3213,
"meant": 3214,
"##ts": 3215,
"runs": 3216,
"##ro": 3217,
"practice": 3218,
"championships": 3219,
"singer": 3220,
"glass": 3221,
"commission": 3222,
"required": 3223,
"forest": 3224,
"starting": 3225,
"culture": 3226,
"generally": 3227,
"giving": 3228,
"access": 3229,
"attended": 3230,
"test": 3231,
"couple": 3232,
"stand": 3233,
"catholic": 3234,
"martin": 3235,
"caught": 3236,
"executive": 3237,
"##less": 3238,
"eye": 3239,
"##ey": 3240,
"thinking": 3241,
"chair": 3242,
"quite": 3243,
"shoulder": 3244,
"1979": 3245,
"hope": 3246,
"decision": 3247,
"plays": 3248,
"defeated": 3249,
"municipality": 3250,
"whether": 3251,
"structure": 3252,
"offered": 3253,
"slowly": 3254,
"pain": 3255,
"ice": 3256,
"direction": 3257,
"##ion": 3258,
"paper": 3259,
"mission": 3260,
"1981": 3261,
"mostly": 3262,
"200": 3263,
"noted": 3264,
"individual": 3265,
"managed": 3266,
"nature": 3267,
"lives": 3268,
"plant": 3269,
"##ha": 3270,
"helped": 3271,
"except": 3272,
"studied": 3273,
"computer": 3274,
"figure": 3275,
"relationship": 3276,
"issue": 3277,
"significant": 3278,
"loss": 3279,
"die": 3280,
"smiled": 3281,
"gun": 3282,
"ago": 3283,
"highest": 3284,
"1972": 3285,
"##am": 3286,
"male": 3287,
"bring": 3288,
"goals": 3289,
"mexico": 3290,
"problem": 3291,
"distance": 3292,
"commercial": 3293,
"completely": 3294,
"location": 3295,
"annual": 3296,
"famous": 3297,
"drive": 3298,
"1976": 3299,
"neck": 3300,
"1978": 3301,
"surface": 3302,
"caused": 3303,
"italy": 3304,
"understand": 3305,
"greek": 3306,
"highway": 3307,
"wrong": 3308,
"hotel": 3309,
"comes": 3310,
"appearance": 3311,
"joseph": 3312,
"double": 3313,
"issues": 3314,
"musical": 3315,
"companies": 3316,
"castle": 3317,
"income": 3318,
"review": 3319,
"assembly": 3320,
"bass": 3321,
"initially": 3322,
"parliament": 3323,
"artists": 3324,
"experience": 3325,
"1974": 3326,
"particular": 3327,
"walk": 3328,
"foot": 3329,
"engineering": 3330,
"talking": 3331,
"window": 3332,
"dropped": 3333,
"##ter": 3334,
"miss": 3335,
"baby": 3336,
"boys": 3337,
"break": 3338,
"1975": 3339,
"stars": 3340,
"edge": 3341,
"remember": 3342,
"policy": 3343,
"carried": 3344,
"train": 3345,
"stadium": 3346,
"bar": 3347,
"sex": 3348,
"angeles": 3349,
"evidence": 3350,
"##ge": 3351,
"becoming": 3352,
"assistant": 3353,
"soviet": 3354,
"1977": 3355,
"upper": 3356,
"step": 3357,
"wing": 3358,
"1970": 3359,
"youth": 3360,
"financial": 3361,
"reach": 3362,
"##ll": 3363,
"actor": 3364,
"numerous": 3365,
"##se": 3366,
"##st": 3367,
"nodded": 3368,
"arrived": 3369,
"##ation": 3370,
"minute": 3371,
"##nt": 3372,
"believed": 3373,
"sorry": 3374,
"complex": 3375,
"beautiful": 3376,
"victory": 3377,
"associated": 3378,
"temple": 3379,
"1968": 3380,
"1973": 3381,
"chance": 3382,
"perhaps": 3383,
"metal": 3384,
"##son": 3385,
"1945": 3386,
"bishop": 3387,
"##et": 3388,
"lee": 3389,
"launched": 3390,
"particularly": 3391,
"tree": 3392,
"le": 3393,
"retired": 3394,
"subject": 3395,
"prize": 3396,
"contains": 3397,
"yeah": 3398,
"theory": 3399,
"empire": 3400,
"##ce": 3401,
"suddenly": 3402,
"waiting": 3403,
"trust": 3404,
"recording": 3405,
"##to": 3406,
"happy": 3407,
"terms": 3408,
"camp": 3409,
"champion": 3410,
"1971": 3411,
"religious": 3412,
"pass": 3413,
"zealand": 3414,
"names": 3415,
"2nd": 3416,
"port": 3417,
"ancient": 3418,
"tom": 3419,
"corner": 3420,
"represented": 3421,
"watch": 3422,
"legal": 3423,
"anti": 3424,
"justice": 3425,
"cause": 3426,
"watched": 3427,
"brothers": 3428,
"45": 3429,
"material": 3430,
"changes": 3431,
"simply": 3432,
"response": 3433,
"louis": 3434,
"fast": 3435,
"##ting": 3436,
"answer": 3437,
"60": 3438,
"historical": 3439,
"1969": 3440,
"stories": 3441,
"straight": 3442,
"create": 3443,
"feature": 3444,
"increased": 3445,
"rate": 3446,
"administration": 3447,
"virginia": 3448,
"el": 3449,
"activities": 3450,
"cultural": 3451,
"overall": 3452,
"winner": 3453,
"programs": 3454,
"basketball": 3455,
"legs": 3456,
"guard": 3457,
"beyond": 3458,
"cast": 3459,
"doctor": 3460,
"mm": 3461,
"flight": 3462,
"results": 3463,
"remains": 3464,
"cost": 3465,
"effect": 3466,
"winter": 3467,
"##ble": 3468,
"larger": 3469,
"islands": 3470,
"problems": 3471,
"chairman": 3472,
"grew": 3473,
"commander": 3474,
"isn": 3475,
"1967": 3476,
"pay": 3477,
"failed": 3478,
"selected": 3479,
"hurt": 3480,
"fort": 3481,
"box": 3482,
"regiment": 3483,
"majority": 3484,
"journal": 3485,
"35": 3486,
"edward": 3487,
"plans": 3488,
"##ke": 3489,
"##ni": 3490,
"shown": 3491,
"pretty": 3492,
"irish": 3493,
"characters": 3494,
"directly": 3495,
"scene": 3496,
"likely": 3497,
"operated": 3498,
"allow": 3499,
"spring": 3500,
"##j": 3501,
"junior": 3502,
"matches": 3503,
"looks": 3504,
"mike": 3505,
"houses": 3506,
"fellow": 3507,
"##tion": 3508,
"beach": 3509,
"marriage": 3510,
"##ham": 3511,
"##ive": 3512,
"rules": 3513,
"oil": 3514,
"65": 3515,
"florida": 3516,
"expected": 3517,
"nearby": 3518,
"congress": 3519,
"sam": 3520,
"peace": 3521,
"recent": 3522,
"iii": 3523,
"wait": 3524,
"subsequently": 3525,
"cell": 3526,
"##do": 3527,
"variety": 3528,
"serving": 3529,
"agreed": 3530,
"please": 3531,
"poor": 3532,
"joe": 3533,
"pacific": 3534,
"attempt": 3535,
"wood": 3536,
"democratic": 3537,
"piece": 3538,
"prime": 3539,
"##ca": 3540,
"rural": 3541,
"mile": 3542,
"touch": 3543,
"appears": 3544,
"township": 3545,
"1964": 3546,
"1966": 3547,
"soldiers": 3548,
"##men": 3549,
"##ized": 3550,
"1965": 3551,
"pennsylvania": 3552,
"closer": 3553,
"fighting": 3554,
"claimed": 3555,
"score": 3556,
"jones": 3557,
"physical": 3558,
"editor": 3559,
"##ous": 3560,
"filled": 3561,
"genus": 3562,
"specific": 3563,
"sitting": 3564,
"super": 3565,
"mom": 3566,
"##va": 3567,
"therefore": 3568,
"supported": 3569,
"status": 3570,
"fear": 3571,
"cases": 3572,
"store": 3573,
"meaning": 3574,
"wales": 3575,
"minor": 3576,
"spain": 3577,
"tower": 3578,
"focus": 3579,
"vice": 3580,
"frank": 3581,
"follow": 3582,
"parish": 3583,
"separate": 3584,
"golden": 3585,
"horse": 3586,
"fifth": 3587,
"remaining": 3588,
"branch": 3589,
"32": 3590,
"presented": 3591,
"stared": 3592,
"##id": 3593,
"uses": 3594,
"secret": 3595,
"forms": 3596,
"##co": 3597,
"baseball": 3598,
"exactly": 3599,
"##ck": 3600,
"choice": 3601,
"note": 3602,
"discovered": 3603,
"travel": 3604,
"composed": 3605,
"truth": 3606,
"russia": 3607,
"ball": 3608,
"color": 3609,
"kiss": 3610,
"dad": 3611,
"wind": 3612,
"continue": 3613,
"ring": 3614,
"referred": 3615,
"numbers": 3616,
"digital": 3617,
"greater": 3618,
"##ns": 3619,
"metres": 3620,
"slightly": 3621,
"direct": 3622,
"increase": 3623,
"1960": 3624,
"responsible": 3625,
"crew": 3626,
"rule": 3627,
"trees": 3628,
"troops": 3629,
"##no": 3630,
"broke": 3631,
"goes": 3632,
"individuals": 3633,
"hundred": 3634,
"weight": 3635,
"creek": 3636,
"sleep": 3637,
"memory": 3638,
"defense": 3639,
"provides": 3640,
"ordered": 3641,
"code": 3642,
"value": 3643,
"jewish": 3644,
"windows": 3645,
"1944": 3646,
"safe": 3647,
"judge": 3648,
"whatever": 3649,
"corps": 3650,
"realized": 3651,
"growing": 3652,
"pre": 3653,
"##ga": 3654,
"cities": 3655,
"alexander": 3656,
"gaze": 3657,
"lies": 3658,
"spread": 3659,
"scott": 3660,
"letter": 3661,
"showed": 3662,
"situation": 3663,
"mayor": 3664,
"transport": 3665,
"watching": 3666,
"workers": 3667,
"extended": 3668,
"##li": 3669,
"expression": 3670,
"normal": 3671,
"##ment": 3672,
"chart": 3673,
"multiple": 3674,
"border": 3675,
"##ba": 3676,
"host": 3677,
"##ner": 3678,
"daily": 3679,
"mrs": 3680,
"walls": 3681,
"piano": 3682,
"##ko": 3683,
"heat": 3684,
"cannot": 3685,
"##ate": 3686,
"earned": 3687,
"products": 3688,
"drama": 3689,
"era": 3690,
"authority": 3691,
"seasons": 3692,
"join": 3693,
"grade": 3694,
"##io": 3695,
"sign": 3696,
"difficult": 3697,
"machine": 3698,
"1963": 3699,
"territory": 3700,
"mainly": 3701,
"##wood": 3702,
"stations": 3703,
"squadron": 3704,
"1962": 3705,
"stepped": 3706,
"iron": 3707,
"19th": 3708,
"##led": 3709,
"serve": 3710,
"appear": 3711,
"sky": 3712,
"speak": 3713,
"broken": 3714,
"charge": 3715,
"knowledge": 3716,
"kilometres": 3717,
"removed": 3718,
"ships": 3719,
"article": 3720,
"campus": 3721,
"simple": 3722,
"##ty": 3723,
"pushed": 3724,
"britain": 3725,
"##ve": 3726,
"leaves": 3727,
"recently": 3728,
"cd": 3729,
"soft": 3730,
"boston": 3731,
"latter": 3732,
"easy": 3733,
"acquired": 3734,
"poland": 3735,
"##sa": 3736,
"quality": 3737,
"officers": 3738,
"presence": 3739,
"planned": 3740,
"nations": 3741,
"mass": 3742,
"broadcast": 3743,
"jean": 3744,
"share": 3745,
"image": 3746,
"influence": 3747,
"wild": 3748,
"offer": 3749,
"emperor": 3750,
"electric": 3751,
"reading": 3752,
"headed": 3753,
"ability": 3754,
"promoted": 3755,
"yellow": 3756,
"ministry": 3757,
"1942": 3758,
"throat": 3759,
"smaller": 3760,
"politician": 3761,
"##by": 3762,
"latin": 3763,
"spoke": 3764,
"cars": 3765,
"williams": 3766,
"males": 3767,
"lack": 3768,
"pop": 3769,
"80": 3770,
"##ier": 3771,
"acting": 3772,
"seeing": 3773,
"consists": 3774,
"##ti": 3775,
"estate": 3776,
"1961": 3777,
"pressure": 3778,
"johnson": 3779,
"newspaper": 3780,
"jr": 3781,
"chris": 3782,
"olympics": 3783,
"online": 3784,
"conditions": 3785,
"beat": 3786,
"elements": 3787,
"walking": 3788,
"vote": 3789,
"##field": 3790,
"needs": 3791,
"carolina": 3792,
"text": 3793,
"featuring": 3794,
"global": 3795,
"block": 3796,
"shirt": 3797,
"levels": 3798,
"francisco": 3799,
"purpose": 3800,
"females": 3801,
"et": 3802,
"dutch": 3803,
"duke": 3804,
"ahead": 3805,
"gas": 3806,
"twice": 3807,
"safety": 3808,
"serious": 3809,
"turning": 3810,
"highly": 3811,
"lieutenant": 3812,
"firm": 3813,
"maria": 3814,
"amount": 3815,
"mixed": 3816,
"daniel": 3817,
"proposed": 3818,
"perfect": 3819,
"agreement": 3820,
"affairs": 3821,
"3rd": 3822,
"seconds": 3823,
"contemporary": 3824,
"paid": 3825,
"1943": 3826,
"prison": 3827,
"save": 3828,
"kitchen": 3829,
"label": 3830,
"administrative": 3831,
"intended": 3832,
"constructed": 3833,
"academic": 3834,
"nice": 3835,
"teacher": 3836,
"races": 3837,
"1956": 3838,
"formerly": 3839,
"corporation": 3840,
"ben": 3841,
"nation": 3842,
"issued": 3843,
"shut": 3844,
"1958": 3845,
"drums": 3846,
"housing": 3847,
"victoria": 3848,
"seems": 3849,
"opera": 3850,
"1959": 3851,
"graduated": 3852,
"function": 3853,
"von": 3854,
"mentioned": 3855,
"picked": 3856,
"build": 3857,
"recognized": 3858,
"shortly": 3859,
"protection": 3860,
"picture": 3861,
"notable": 3862,
"exchange": 3863,
"elections": 3864,
"1980s": 3865,
"loved": 3866,
"percent": 3867,
"racing": 3868,
"fish": 3869,
"elizabeth": 3870,
"garden": 3871,
"volume": 3872,
"hockey": 3873,
"1941": 3874,
"beside": 3875,
"settled": 3876,
"##ford": 3877,
"1940": 3878,
"competed": 3879,
"replied": 3880,
"drew": 3881,
"1948": 3882,
"actress": 3883,
"marine": 3884,
"scotland": 3885,
"steel": 3886,
"glanced": 3887,
"farm": 3888,
"steve": 3889,
"1957": 3890,
"risk": 3891,
"tonight": 3892,
"positive": 3893,
"magic": 3894,
"singles": 3895,
"effects": 3896,
"gray": 3897,
"screen": 3898,
"dog": 3899,
"##ja": 3900,
"residents": 3901,
"bus": 3902,
"sides": 3903,
"none": 3904,
"secondary": 3905,
"literature": 3906,
"polish": 3907,
"destroyed": 3908,
"flying": 3909,
"founder": 3910,
"households": 3911,
"1939": 3912,
"lay": 3913,
"reserve": 3914,
"usa": 3915,
"gallery": 3916,
"##ler": 3917,
"1946": 3918,
"industrial": 3919,
"younger": 3920,
"approach": 3921,
"appearances": 3922,
"urban": 3923,
"ones": 3924,
"1950": 3925,
"finish": 3926,
"avenue": 3927,
"powerful": 3928,
"fully": 3929,
"growth": 3930,
"page": 3931,
"honor": 3932,
"jersey": 3933,
"projects": 3934,
"advanced": 3935,
"revealed": 3936,
"basic": 3937,
"90": 3938,
"infantry": 3939,
"pair": 3940,
"equipment": 3941,
"visit": 3942,
"33": 3943,
"evening": 3944,
"search": 3945,
"grant": 3946,
"effort": 3947,
"solo": 3948,
"treatment": 3949,
"buried": 3950,
"republican": 3951,
"primarily": 3952,
"bottom": 3953,
"owner": 3954,
"1970s": 3955,
"israel": 3956,
"gives": 3957,
"jim": 3958,
"dream": 3959,
"bob": 3960,
"remain": 3961,
"spot": 3962,
"70": 3963,
"notes": 3964,
"produce": 3965,
"champions": 3966,
"contact": 3967,
"ed": 3968,
"soul": 3969,
"accepted": 3970,
"ways": 3971,
"del": 3972,
"##ally": 3973,
"losing": 3974,
"split": 3975,
"price": 3976,
"capacity": 3977,
"basis": 3978,
"trial": 3979,
"questions": 3980,
"##ina": 3981,
"1955": 3982,
"20th": 3983,
"guess": 3984,
"officially": 3985,
"memorial": 3986,
"naval": 3987,
"initial": 3988,
"##ization": 3989,
"whispered": 3990,
"median": 3991,
"engineer": 3992,
"##ful": 3993,
"sydney": 3994,
"##go": 3995,
"columbia": 3996,
"strength": 3997,
"300": 3998,
"1952": 3999,
"tears": 4000,
"senate": 4001,
"00": 4002,
"card": 4003,
"asian": 4004,
"agent": 4005,
"1947": 4006,
"software": 4007,
"44": 4008,
"draw": 4009,
"warm": 4010,
"supposed": 4011,
"com": 4012,
"pro": 4013,
"##il": 4014,
"transferred": 4015,
"leaned": 4016,
"##at": 4017,
"candidate": 4018,
"escape": 4019,
"mountains": 4020,
"asia": 4021,
"potential": 4022,
"activity": 4023,
"entertainment": 4024,
"seem": 4025,
"traffic": 4026,
"jackson": 4027,
"murder": 4028,
"36": 4029,
"slow": 4030,
"product": 4031,
"orchestra": 4032,
"haven": 4033,
"agency": 4034,
"bbc": 4035,
"taught": 4036,
"website": 4037,
"comedy": 4038,
"unable": 4039,
"storm": 4040,
"planning": 4041,
"albums": 4042,
"rugby": 4043,
"environment": 4044,
"scientific": 4045,
"grabbed": 4046,
"protect": 4047,
"##hi": 4048,
"boat": 4049,
"typically": 4050,
"1954": 4051,
"1953": 4052,
"damage": 4053,
"principal": 4054,
"divided": 4055,
"dedicated": 4056,
"mount": 4057,
"ohio": 4058,
"##berg": 4059,
"pick": 4060,
"fought": 4061,
"driver": 4062,
"##der": 4063,
"empty": 4064,
"shoulders": 4065,
"sort": 4066,
"thank": 4067,
"berlin": 4068,
"prominent": 4069,
"account": 4070,
"freedom": 4071,
"necessary": 4072,
"efforts": 4073,
"alex": 4074,
"headquarters": 4075,
"follows": 4076,
"alongside": 4077,
"des": 4078,
"simon": 4079,
"andrew": 4080,
"suggested": 4081,
"operating": 4082,
"learning": 4083,
"steps": 4084,
"1949": 4085,
"sweet": 4086,
"technical": 4087,
"begin": 4088,
"easily": 4089,
"34": 4090,
"teeth": 4091,
"speaking": 4092,
"settlement": 4093,
"scale": 4094,
"##sh": 4095,
"renamed": 4096,
"ray": 4097,
"max": 4098,
"enemy": 4099,
"semi": 4100,
"joint": 4101,
"compared": 4102,
"##rd": 4103,
"scottish": 4104,
"leadership": 4105,
"analysis": 4106,
"offers": 4107,
"georgia": 4108,
"pieces": 4109,
"captured": 4110,
"animal": 4111,
"deputy": 4112,
"guest": 4113,
"organized": 4114,
"##lin": 4115,
"tony": 4116,
"combined": 4117,
"method": 4118,
"challenge": 4119,
"1960s": 4120,
"huge": 4121,
"wants": 4122,
"battalion": 4123,
"sons": 4124,
"rise": 4125,
"crime": 4126,
"types": 4127,
"facilities": 4128,
"telling": 4129,
"path": 4130,
"1951": 4131,
"platform": 4132,
"sit": 4133,
"1990s": 4134,
"##lo": 4135,
"tells": 4136,
"assigned": 4137,
"rich": 4138,
"pull": 4139,
"##ot": 4140,
"commonly": 4141,
"alive": 4142,
"##za": 4143,
"letters": 4144,
"concept": 4145,
"conducted": 4146,
"wearing": 4147,
"happen": 4148,
"bought": 4149,
"becomes": 4150,
"holy": 4151,
"gets": 4152,
"ocean": 4153,
"defeat": 4154,
"languages": 4155,
"purchased": 4156,
"coffee": 4157,
"occurred": 4158,
"titled": 4159,
"##q": 4160,
"declared": 4161,
"applied": 4162,
"sciences": 4163,
"concert": 4164,
"sounds": 4165,
"jazz": 4166,
"brain": 4167,
"##me": 4168,
"painting": 4169,
"fleet": 4170,
"tax": 4171,
"nick": 4172,
"##ius": 4173,
"michigan": 4174,
"count": 4175,
"animals": 4176,
"leaders": 4177,
"episodes": 4178,
"##line": 4179,
"content": 4180,
"##den": 4181,
"birth": 4182,
"##it": 4183,
"clubs": 4184,
"64": 4185,
"palace": 4186,
"critical": 4187,
"refused": 4188,
"fair": 4189,
"leg": 4190,
"laughed": 4191,
"returning": 4192,
"surrounding": 4193,
"participated": 4194,
"formation": 4195,
"lifted": 4196,
"pointed": 4197,
"connected": 4198,
"rome": 4199,
"medicine": 4200,
"laid": 4201,
"taylor": 4202,
"santa": 4203,
"powers": 4204,
"adam": 4205,
"tall": 4206,
"shared": 4207,
"focused": 4208,
"knowing": 4209,
"yards": 4210,
"entrance": 4211,
"falls": 4212,
"##wa": 4213,
"calling": 4214,
"##ad": 4215,
"sources": 4216,
"chosen": 4217,
"beneath": 4218,
"resources": 4219,
"yard": 4220,
"##ite": 4221,
"nominated": 4222,
"silence": 4223,
"zone": 4224,
"defined": 4225,
"##que": 4226,
"gained": 4227,
"thirty": 4228,
"38": 4229,
"bodies": 4230,
"moon": 4231,
"##ard": 4232,
"adopted": 4233,
"christmas": 4234,
"widely": 4235,
"register": 4236,
"apart": 4237,
"iran": 4238,
"premier": 4239,
"serves": 4240,
"du": 4241,
"unknown": 4242,
"parties": 4243,
"##les": 4244,
"generation": 4245,
"##ff": 4246,
"continues": 4247,
"quick": 4248,
"fields": 4249,
"brigade": 4250,
"quiet": 4251,
"teaching": 4252,
"clothes": 4253,
"impact": 4254,
"weapons": 4255,
"partner": 4256,
"flat": 4257,
"theater": 4258,
"supreme": 4259,
"1938": 4260,
"37": 4261,
"relations": 4262,
"##tor": 4263,
"plants": 4264,
"suffered": 4265,
"1936": 4266,
"wilson": 4267,
"kids": 4268,
"begins": 4269,
"##age": 4270,
"1918": 4271,
"seats": 4272,
"armed": 4273,
"internet": 4274,
"models": 4275,
"worth": 4276,
"laws": 4277,
"400": 4278,
"communities": 4279,
"classes": 4280,
"background": 4281,
"knows": 4282,
"thanks": 4283,
"quarter": 4284,
"reaching": 4285,
"humans": 4286,
"carry": 4287,
"killing": 4288,
"format": 4289,
"kong": 4290,
"hong": 4291,
"setting": 4292,
"75": 4293,
"architecture": 4294,
"disease": 4295,
"railroad": 4296,
"inc": 4297,
"possibly": 4298,
"wish": 4299,
"arthur": 4300,
"thoughts": 4301,
"harry": 4302,
"doors": 4303,
"density": 4304,
"##di": 4305,
"crowd": 4306,
"illinois": 4307,
"stomach": 4308,
"tone": 4309,
"unique": 4310,
"reports": 4311,
"anyway": 4312,
"##ir": 4313,
"liberal": 4314,
"der": 4315,
"vehicle": 4316,
"thick": 4317,
"dry": 4318,
"drug": 4319,
"faced": 4320,
"largely": 4321,
"facility": 4322,
"theme": 4323,
"holds": 4324,
"creation": 4325,
"strange": 4326,
"colonel": 4327,
"##mi": 4328,
"revolution": 4329,
"bell": 4330,
"politics": 4331,
"turns": 4332,
"silent": 4333,
"rail": 4334,
"relief": 4335,
"independence": 4336,
"combat": 4337,
"shape": 4338,
"write": 4339,
"determined": 4340,
"sales": 4341,
"learned": 4342,
"4th": 4343,
"finger": 4344,
"oxford": 4345,
"providing": 4346,
"1937": 4347,
"heritage": 4348,
"fiction": 4349,
"situated": 4350,
"designated": 4351,
"allowing": 4352,
"distribution": 4353,
"hosted": 4354,
"##est": 4355,
"sight": 4356,
"interview": 4357,
"estimated": 4358,
"reduced": 4359,
"##ria": 4360,
"toronto": 4361,
"footballer": 4362,
"keeping": 4363,
"guys": 4364,
"damn": 4365,
"claim": 4366,
"motion": 4367,
"sport": 4368,
"sixth": 4369,
"stayed": 4370,
"##ze": 4371,
"en": 4372,
"rear": 4373,
"receive": 4374,
"handed": 4375,
"twelve": 4376,
"dress": 4377,
"audience": 4378,
"granted": 4379,
"brazil": 4380,
"##well": 4381,
"spirit": 4382,
"##ated": 4383,
"noticed": 4384,
"etc": 4385,
"olympic": 4386,
"representative": 4387,
"eric": 4388,
"tight": 4389,
"trouble": 4390,
"reviews": 4391,
"drink": 4392,
"vampire": 4393,
"missing": 4394,
"roles": 4395,
"ranked": 4396,
"newly": 4397,
"household": 4398,
"finals": 4399,
"wave": 4400,
"critics": 4401,
"##ee": 4402,
"phase": 4403,
"massachusetts": 4404,
"pilot": 4405,
"unlike": 4406,
"philadelphia": 4407,
"bright": 4408,
"guns": 4409,
"crown": 4410,
"organizations": 4411,
"roof": 4412,
"42": 4413,
"respectively": 4414,
"clearly": 4415,
"tongue": 4416,
"marked": 4417,
"circle": 4418,
"fox": 4419,
"korea": 4420,
"bronze": 4421,
"brian": 4422,
"expanded": 4423,
"sexual": 4424,
"supply": 4425,
"yourself": 4426,
"inspired": 4427,
"labour": 4428,
"fc": 4429,
"##ah": 4430,
"reference": 4431,
"vision": 4432,
"draft": 4433,
"connection": 4434,
"brand": 4435,
"reasons": 4436,
"1935": 4437,
"classic": 4438,
"driving": 4439,
"trip": 4440,
"jesus": 4441,
"cells": 4442,
"entry": 4443,
"1920": 4444,
"neither": 4445,
"trail": 4446,
"claims": 4447,
"atlantic": 4448,
"orders": 4449,
"labor": 4450,
"nose": 4451,
"afraid": 4452,
"identified": 4453,
"intelligence": 4454,
"calls": 4455,
"cancer": 4456,
"attacked": 4457,
"passing": 4458,
"stephen": 4459,
"positions": 4460,
"imperial": 4461,
"grey": 4462,
"jason": 4463,
"39": 4464,
"sunday": 4465,
"48": 4466,
"swedish": 4467,
"avoid": 4468,
"extra": 4469,
"uncle": 4470,
"message": 4471,
"covers": 4472,
"allows": 4473,
"surprise": 4474,
"materials": 4475,
"fame": 4476,
"hunter": 4477,
"##ji": 4478,
"1930": 4479,
"citizens": 4480,
"figures": 4481,
"davis": 4482,
"environmental": 4483,
"confirmed": 4484,
"shit": 4485,
"titles": 4486,
"di": 4487,
"performing": 4488,
"difference": 4489,
"acts": 4490,
"attacks": 4491,
"##ov": 4492,
"existing": 4493,
"votes": 4494,
"opportunity": 4495,
"nor": 4496,
"shop": 4497,
"entirely": 4498,
"trains": 4499,
"opposite": 4500,
"pakistan": 4501,
"##pa": 4502,
"develop": 4503,
"resulted": 4504,
"representatives": 4505,
"actions": 4506,
"reality": 4507,
"pressed": 4508,
"##ish": 4509,
"barely": 4510,
"wine": 4511,
"conversation": 4512,
"faculty": 4513,
"northwest": 4514,
"ends": 4515,
"documentary": 4516,
"nuclear": 4517,
"stock": 4518,
"grace": 4519,
"sets": 4520,
"eat": 4521,
"alternative": 4522,
"##ps": 4523,
"bag": 4524,
"resulting": 4525,
"creating": 4526,
"surprised": 4527,
"cemetery": 4528,
"1919": 4529,
"drop": 4530,
"finding": 4531,
"sarah": 4532,
"cricket": 4533,
"streets": 4534,
"tradition": 4535,
"ride": 4536,
"1933": 4537,
"exhibition": 4538,
"target": 4539,
"ear": 4540,
"explained": 4541,
"rain": 4542,
"composer": 4543,
"injury": 4544,
"apartment": 4545,
"municipal": 4546,
"educational": 4547,
"occupied": 4548,
"netherlands": 4549,
"clean": 4550,
"billion": 4551,
"constitution": 4552,
"learn": 4553,
"1914": 4554,
"maximum": 4555,
"classical": 4556,
"francis": 4557,
"lose": 4558,
"opposition": 4559,
"jose": 4560,
"ontario": 4561,
"bear": 4562,
"core": 4563,
"hills": 4564,
"rolled": 4565,
"ending": 4566,
"drawn": 4567,
"permanent": 4568,
"fun": 4569,
"##tes": 4570,
"##lla": 4571,
"lewis": 4572,
"sites": 4573,
"chamber": 4574,
"ryan": 4575,
"##way": 4576,
"scoring": 4577,
"height": 4578,
"1934": 4579,
"##house": 4580,
"lyrics": 4581,
"staring": 4582,
"55": 4583,
"officials": 4584,
"1917": 4585,
"snow": 4586,
"oldest": 4587,
"##tic": 4588,
"orange": 4589,
"##ger": 4590,
"qualified": 4591,
"interior": 4592,
"apparently": 4593,
"succeeded": 4594,
"thousand": 4595,
"dinner": 4596,
"lights": 4597,
"existence": 4598,
"fans": 4599,
"heavily": 4600,
"41": 4601,
"greatest": 4602,
"conservative": 4603,
"send": 4604,
"bowl": 4605,
"plus": 4606,
"enter": 4607,
"catch": 4608,
"##un": 4609,
"economy": 4610,
"duty": 4611,
"1929": 4612,
"speech": 4613,
"authorities": 4614,
"princess": 4615,
"performances": 4616,
"versions": 4617,
"shall": 4618,
"graduate": 4619,
"pictures": 4620,
"effective": 4621,
"remembered": 4622,
"poetry": 4623,
"desk": 4624,
"crossed": 4625,
"starring": 4626,
"starts": 4627,
"passenger": 4628,
"sharp": 4629,
"##ant": 4630,
"acres": 4631,
"ass": 4632,
"weather": 4633,
"falling": 4634,
"rank": 4635,
"fund": 4636,
"supporting": 4637,
"check": 4638,
"adult": 4639,
"publishing": 4640,
"heads": 4641,
"cm": 4642,
"southeast": 4643,
"lane": 4644,
"##burg": 4645,
"application": 4646,
"bc": 4647,
"##ura": 4648,
"les": 4649,
"condition": 4650,
"transfer": 4651,
"prevent": 4652,
"display": 4653,
"ex": 4654,
"regions": 4655,
"earl": 4656,
"federation": 4657,
"cool": 4658,
"relatively": 4659,
"answered": 4660,
"besides": 4661,
"1928": 4662,
"obtained": 4663,
"portion": 4664,
"##town": 4665,
"mix": 4666,
"##ding": 4667,
"reaction": 4668,
"liked": 4669,
"dean": 4670,
"express": 4671,
"peak": 4672,
"1932": 4673,
"##tte": 4674,
"counter": 4675,
"religion": 4676,
"chain": 4677,
"rare": 4678,
"miller": 4679,
"convention": 4680,
"aid": 4681,
"lie": 4682,
"vehicles": 4683,
"mobile": 4684,
"perform": 4685,
"squad": 4686,
"wonder": 4687,
"lying": 4688,
"crazy": 4689,
"sword": 4690,
"##ping": 4691,
"attempted": 4692,
"centuries": 4693,
"weren": 4694,
"philosophy": 4695,
"category": 4696,
"##ize": 4697,
"anna": 4698,
"interested": 4699,
"47": 4700,
"sweden": 4701,
"wolf": 4702,
"frequently": 4703,
"abandoned": 4704,
"kg": 4705,
"literary": 4706,
"alliance": 4707,
"task": 4708,
"entitled": 4709,
"##ay": 4710,
"threw": 4711,
"promotion": 4712,
"factory": 4713,
"tiny": 4714,
"soccer": 4715,
"visited": 4716,
"matt": 4717,
"fm": 4718,
"achieved": 4719,
"52": 4720,
"defence": 4721,
"internal": 4722,
"persian": 4723,
"43": 4724,
"methods": 4725,
"##ging": 4726,
"arrested": 4727,
"otherwise": 4728,
"cambridge": 4729,
"programming": 4730,
"villages": 4731,
"elementary": 4732,
"districts": 4733,
"rooms": 4734,
"criminal": 4735,
"conflict": 4736,
"worry": 4737,
"trained": 4738,
"1931": 4739,
"attempts": 4740,
"waited": 4741,
"signal": 4742,
"bird": 4743,
"truck": 4744,
"subsequent": 4745,
"programme": 4746,
"##ol": 4747,
"ad": 4748,
"49": 4749,
"communist": 4750,
"details": 4751,
"faith": 4752,
"sector": 4753,
"patrick": 4754,
"carrying": 4755,
"laugh": 4756,
"##ss": 4757,
"controlled": 4758,
"korean": 4759,
"showing": 4760,
"origin": 4761,
"fuel": 4762,
"evil": 4763,
"1927": 4764,
"##ent": 4765,
"brief": 4766,
"identity": 4767,
"darkness": 4768,
"address": 4769,
"pool": 4770,
"missed": 4771,
"publication": 4772,
"web": 4773,
"planet": 4774,
"ian": 4775,
"anne": 4776,
"wings": 4777,
"invited": 4778,
"##tt": 4779,
"briefly": 4780,
"standards": 4781,
"kissed": 4782,
"##be": 4783,
"ideas": 4784,
"climate": 4785,
"causing": 4786,
"walter": 4787,
"worse": 4788,
"albert": 4789,
"articles": 4790,
"winners": 4791,
"desire": 4792,
"aged": 4793,
"northeast": 4794,
"dangerous": 4795,
"gate": 4796,
"doubt": 4797,
"1922": 4798,
"wooden": 4799,
"multi": 4800,
"##ky": 4801,
"poet": 4802,
"rising": 4803,
"funding": 4804,
"46": 4805,
"communications": 4806,
"communication": 4807,
"violence": 4808,
"copies": 4809,
"prepared": 4810,
"ford": 4811,
"investigation": 4812,
"skills": 4813,
"1924": 4814,
"pulling": 4815,
"electronic": 4816,
"##ak": 4817,
"##ial": 4818,
"##han": 4819,
"containing": 4820,
"ultimately": 4821,
"offices": 4822,
"singing": 4823,
"understanding": 4824,
"restaurant": 4825,
"tomorrow": 4826,
"fashion": 4827,
"christ": 4828,
"ward": 4829,
"da": 4830,
"pope": 4831,
"stands": 4832,
"5th": 4833,
"flow": 4834,
"studios": 4835,
"aired": 4836,
"commissioned": 4837,
"contained": 4838,
"exist": 4839,
"fresh": 4840,
"americans": 4841,
"##per": 4842,
"wrestling": 4843,
"approved": 4844,
"kid": 4845,
"employed": 4846,
"respect": 4847,
"suit": 4848,
"1925": 4849,
"angel": 4850,
"asking": 4851,
"increasing": 4852,
"frame": 4853,
"angry": 4854,
"selling": 4855,
"1950s": 4856,
"thin": 4857,
"finds": 4858,
"##nd": 4859,
"temperature": 4860,
"statement": 4861,
"ali": 4862,
"explain": 4863,
"inhabitants": 4864,
"towns": 4865,
"extensive": 4866,
"narrow": 4867,
"51": 4868,
"jane": 4869,
"flowers": 4870,
"images": 4871,
"promise": 4872,
"somewhere": 4873,
"object": 4874,
"fly": 4875,
"closely": 4876,
"##ls": 4877,
"1912": 4878,
"bureau": 4879,
"cape": 4880,
"1926": 4881,
"weekly": 4882,
"presidential": 4883,
"legislative": 4884,
"1921": 4885,
"##ai": 4886,
"##au": 4887,
"launch": 4888,
"founding": 4889,
"##ny": 4890,
"978": 4891,
"##ring": 4892,
"artillery": 4893,
"strike": 4894,
"un": 4895,
"institutions": 4896,
"roll": 4897,
"writers": 4898,
"landing": 4899,
"chose": 4900,
"kevin": 4901,
"anymore": 4902,
"pp": 4903,
"##ut": 4904,
"attorney": 4905,
"fit": 4906,
"dan": 4907,
"billboard": 4908,
"receiving": 4909,
"agricultural": 4910,
"breaking": 4911,
"sought": 4912,
"dave": 4913,
"admitted": 4914,
"lands": 4915,
"mexican": 4916,
"##bury": 4917,
"charlie": 4918,
"specifically": 4919,
"hole": 4920,
"iv": 4921,
"howard": 4922,
"credit": 4923,
"moscow": 4924,
"roads": 4925,
"accident": 4926,
"1923": 4927,
"proved": 4928,
"wear": 4929,
"struck": 4930,
"hey": 4931,
"guards": 4932,
"stuff": 4933,
"slid": 4934,
"expansion": 4935,
"1915": 4936,
"cat": 4937,
"anthony": 4938,
"##kin": 4939,
"melbourne": 4940,
"opposed": 4941,
"sub": 4942,
"southwest": 4943,
"architect": 4944,
"failure": 4945,
"plane": 4946,
"1916": 4947,
"##ron": 4948,
"map": 4949,
"camera": 4950,
"tank": 4951,
"listen": 4952,
"regarding": 4953,
"wet": 4954,
"introduction": 4955,
"metropolitan": 4956,
"link": 4957,
"ep": 4958,
"fighter": 4959,
"inch": 4960,
"grown": 4961,
"gene": 4962,
"anger": 4963,
"fixed": 4964,
"buy": 4965,
"dvd": 4966,
"khan": 4967,
"domestic": 4968,
"worldwide": 4969,
"chapel": 4970,
"mill": 4971,
"functions": 4972,
"examples": 4973,
"##head": 4974,
"developing": 4975,
"1910": 4976,
"turkey": 4977,
"hits": 4978,
"pocket": 4979,
"antonio": 4980,
"papers": 4981,
"grow": 4982,
"unless": 4983,
"circuit": 4984,
"18th": 4985,
"concerned": 4986,
"attached": 4987,
"journalist": 4988,
"selection": 4989,
"journey": 4990,
"converted": 4991,
"provincial": 4992,
"painted": 4993,
"hearing": 4994,
"aren": 4995,
"bands": 4996,
"negative": 4997,
"aside": 4998,
"wondered": 4999,
"knight": 5000,
"lap": 5001,
"survey": 5002,
"ma": 5003,
"##ow": 5004,
"noise": 5005,
"billy": 5006,
"##ium": 5007,
"shooting": 5008,
"guide": 5009,
"bedroom": 5010,
"priest": 5011,
"resistance": 5012,
"motor": 5013,
"homes": 5014,
"sounded": 5015,
"giant": 5016,
"##mer": 5017,
"150": 5018,
"scenes": 5019,
"equal": 5020,
"comic": 5021,
"patients": 5022,
"hidden": 5023,
"solid": 5024,
"actual": 5025,
"bringing": 5026,
"afternoon": 5027,
"touched": 5028,
"funds": 5029,
"wedding": 5030,
"consisted": 5031,
"marie": 5032,
"canal": 5033,
"sr": 5034,
"kim": 5035,
"treaty": 5036,
"turkish": 5037,
"recognition": 5038,
"residence": 5039,
"cathedral": 5040,
"broad": 5041,
"knees": 5042,
"incident": 5043,
"shaped": 5044,
"fired": 5045,
"norwegian": 5046,
"handle": 5047,
"cheek": 5048,
"contest": 5049,
"represent": 5050,
"##pe": 5051,
"representing": 5052,
"beauty": 5053,
"##sen": 5054,
"birds": 5055,
"advantage": 5056,
"emergency": 5057,
"wrapped": 5058,
"drawing": 5059,
"notice": 5060,
"pink": 5061,
"broadcasting": 5062,
"##ong": 5063,
"somehow": 5064,
"bachelor": 5065,
"seventh": 5066,
"collected": 5067,
"registered": 5068,
"establishment": 5069,
"alan": 5070,
"assumed": 5071,
"chemical": 5072,
"personnel": 5073,
"roger": 5074,
"retirement": 5075,
"jeff": 5076,
"portuguese": 5077,
"wore": 5078,
"tied": 5079,
"device": 5080,
"threat": 5081,
"progress": 5082,
"advance": 5083,
"##ised": 5084,
"banks": 5085,
"hired": 5086,
"manchester": 5087,
"nfl": 5088,
"teachers": 5089,
"structures": 5090,
"forever": 5091,
"##bo": 5092,
"tennis": 5093,
"helping": 5094,
"saturday": 5095,
"sale": 5096,
"applications": 5097,
"junction": 5098,
"hip": 5099,
"incorporated": 5100,
"neighborhood": 5101,
"dressed": 5102,
"ceremony": 5103,
"##ds": 5104,
"influenced": 5105,
"hers": 5106,
"visual": 5107,
"stairs": 5108,
"decades": 5109,
"inner": 5110,
"kansas": 5111,
"hung": 5112,
"hoped": 5113,
"gain": 5114,
"scheduled": 5115,
"downtown": 5116,
"engaged": 5117,
"austria": 5118,
"clock": 5119,
"norway": 5120,
"certainly": 5121,
"pale": 5122,
"protected": 5123,
"1913": 5124,
"victor": 5125,
"employees": 5126,
"plate": 5127,
"putting": 5128,
"surrounded": 5129,
"##ists": 5130,
"finishing": 5131,
"blues": 5132,
"tropical": 5133,
"##ries": 5134,
"minnesota": 5135,
"consider": 5136,
"philippines": 5137,
"accept": 5138,
"54": 5139,
"retrieved": 5140,
"1900": 5141,
"concern": 5142,
"anderson": 5143,
"properties": 5144,
"institution": 5145,
"gordon": 5146,
"successfully": 5147,
"vietnam": 5148,
"##dy": 5149,
"backing": 5150,
"outstanding": 5151,
"muslim": 5152,
"crossing": 5153,
"folk": 5154,
"producing": 5155,
"usual": 5156,
"demand": 5157,
"occurs": 5158,
"observed": 5159,
"lawyer": 5160,
"educated": 5161,
"##ana": 5162,
"kelly": 5163,
"string": 5164,
"pleasure": 5165,
"budget": 5166,
"items": 5167,
"quietly": 5168,
"colorado": 5169,
"philip": 5170,
"typical": 5171,
"##worth": 5172,
"derived": 5173,
"600": 5174,
"survived": 5175,
"asks": 5176,
"mental": 5177,
"##ide": 5178,
"56": 5179,
"jake": 5180,
"jews": 5181,
"distinguished": 5182,
"ltd": 5183,
"1911": 5184,
"sri": 5185,
"extremely": 5186,
"53": 5187,
"athletic": 5188,
"loud": 5189,
"thousands": 5190,
"worried": 5191,
"shadow": 5192,
"transportation": 5193,
"horses": 5194,
"weapon": 5195,
"arena": 5196,
"importance": 5197,
"users": 5198,
"tim": 5199,
"objects": 5200,
"contributed": 5201,
"dragon": 5202,
"douglas": 5203,
"aware": 5204,
"senator": 5205,
"johnny": 5206,
"jordan": 5207,
"sisters": 5208,
"engines": 5209,
"flag": 5210,
"investment": 5211,
"samuel": 5212,
"shock": 5213,
"capable": 5214,
"clark": 5215,
"row": 5216,
"wheel": 5217,
"refers": 5218,
"session": 5219,
"familiar": 5220,
"biggest": 5221,
"wins": 5222,
"hate": 5223,
"maintained": 5224,
"drove": 5225,
"hamilton": 5226,
"request": 5227,
"expressed": 5228,
"injured": 5229,
"underground": 5230,
"churches": 5231,
"walker": 5232,
"wars": 5233,
"tunnel": 5234,
"passes": 5235,
"stupid": 5236,
"agriculture": 5237,
"softly": 5238,
"cabinet": 5239,
"regarded": 5240,
"joining": 5241,
"indiana": 5242,
"##ea": 5243,
"##ms": 5244,
"push": 5245,
"dates": 5246,
"spend": 5247,
"behavior": 5248,
"woods": 5249,
"protein": 5250,
"gently": 5251,
"chase": 5252,
"morgan": 5253,
"mention": 5254,
"burning": 5255,
"wake": 5256,
"combination": 5257,
"occur": 5258,
"mirror": 5259,
"leads": 5260,
"jimmy": 5261,
"indeed": 5262,
"impossible": 5263,
"singapore": 5264,
"paintings": 5265,
"covering": 5266,
"##nes": 5267,
"soldier": 5268,
"locations": 5269,
"attendance": 5270,
"sell": 5271,
"historian": 5272,
"wisconsin": 5273,
"invasion": 5274,
"argued": 5275,
"painter": 5276,
"diego": 5277,
"changing": 5278,
"egypt": 5279,
"##don": 5280,
"experienced": 5281,
"inches": 5282,
"##ku": 5283,
"missouri": 5284,
"vol": 5285,
"grounds": 5286,
"spoken": 5287,
"switzerland": 5288,
"##gan": 5289,
"reform": 5290,
"rolling": 5291,
"ha": 5292,
"forget": 5293,
"massive": 5294,
"resigned": 5295,
"burned": 5296,
"allen": 5297,
"tennessee": 5298,
"locked": 5299,
"values": 5300,
"improved": 5301,
"##mo": 5302,
"wounded": 5303,
"universe": 5304,
"sick": 5305,
"dating": 5306,
"facing": 5307,
"pack": 5308,
"purchase": 5309,
"user": 5310,
"##pur": 5311,
"moments": 5312,
"##ul": 5313,
"merged": 5314,
"anniversary": 5315,
"1908": 5316,
"coal": 5317,
"brick": 5318,
"understood": 5319,
"causes": 5320,
"dynasty": 5321,
"queensland": 5322,
"establish": 5323,
"stores": 5324,
"crisis": 5325,
"promote": 5326,
"hoping": 5327,
"views": 5328,
"cards": 5329,
"referee": 5330,
"extension": 5331,
"##si": 5332,
"raise": 5333,
"arizona": 5334,
"improve": 5335,
"colonial": 5336,
"formal": 5337,
"charged": 5338,
"##rt": 5339,
"palm": 5340,
"lucky": 5341,
"hide": 5342,
"rescue": 5343,
"faces": 5344,
"95": 5345,
"feelings": 5346,
"candidates": 5347,
"juan": 5348,
"##ell": 5349,
"goods": 5350,
"6th": 5351,
"courses": 5352,
"weekend": 5353,
"59": 5354,
"luke": 5355,
"cash": 5356,
"fallen": 5357,
"##om": 5358,
"delivered": 5359,
"affected": 5360,
"installed": 5361,
"carefully": 5362,
"tries": 5363,
"swiss": 5364,
"hollywood": 5365,
"costs": 5366,
"lincoln": 5367,
"responsibility": 5368,
"##he": 5369,
"shore": 5370,
"file": 5371,
"proper": 5372,
"normally": 5373,
"maryland": 5374,
"assistance": 5375,
"jump": 5376,
"constant": 5377,
"offering": 5378,
"friendly": 5379,
"waters": 5380,
"persons": 5381,
"realize": 5382,
"contain": 5383,
"trophy": 5384,
"800": 5385,
"partnership": 5386,
"factor": 5387,
"58": 5388,
"musicians": 5389,
"cry": 5390,
"bound": 5391,
"oregon": 5392,
"indicated": 5393,
"hero": 5394,
"houston": 5395,
"medium": 5396,
"##ure": 5397,
"consisting": 5398,
"somewhat": 5399,
"##ara": 5400,
"57": 5401,
"cycle": 5402,
"##che": 5403,
"beer": 5404,
"moore": 5405,
"frederick": 5406,
"gotten": 5407,
"eleven": 5408,
"worst": 5409,
"weak": 5410,
"approached": 5411,
"arranged": 5412,
"chin": 5413,
"loan": 5414,
"universal": 5415,
"bond": 5416,
"fifteen": 5417,
"pattern": 5418,
"disappeared": 5419,
"##ney": 5420,
"translated": 5421,
"##zed": 5422,
"lip": 5423,
"arab": 5424,
"capture": 5425,
"interests": 5426,
"insurance": 5427,
"##chi": 5428,
"shifted": 5429,
"cave": 5430,
"prix": 5431,
"warning": 5432,
"sections": 5433,
"courts": 5434,
"coat": 5435,
"plot": 5436,
"smell": 5437,
"feed": 5438,
"golf": 5439,
"favorite": 5440,
"maintain": 5441,
"knife": 5442,
"vs": 5443,
"voted": 5444,
"degrees": 5445,
"finance": 5446,
"quebec": 5447,
"opinion": 5448,
"translation": 5449,
"manner": 5450,
"ruled": 5451,
"operate": 5452,
"productions": 5453,
"choose": 5454,
"musician": 5455,
"discovery": 5456,
"confused": 5457,
"tired": 5458,
"separated": 5459,
"stream": 5460,
"techniques": 5461,
"committed": 5462,
"attend": 5463,
"ranking": 5464,
"kings": 5465,
"throw": 5466,
"passengers": 5467,
"measure": 5468,
"horror": 5469,
"fan": 5470,
"mining": 5471,
"sand": 5472,
"danger": 5473,
"salt": 5474,
"calm": 5475,
"decade": 5476,
"dam": 5477,
"require": 5478,
"runner": 5479,
"##ik": 5480,
"rush": 5481,
"associate": 5482,
"greece": 5483,
"##ker": 5484,
"rivers": 5485,
"consecutive": 5486,
"matthew": 5487,
"##ski": 5488,
"sighed": 5489,
"sq": 5490,
"documents": 5491,
"steam": 5492,
"edited": 5493,
"closing": 5494,
"tie": 5495,
"accused": 5496,
"1905": 5497,
"##ini": 5498,
"islamic": 5499,
"distributed": 5500,
"directors": 5501,
"organisation": 5502,
"bruce": 5503,
"7th": 5504,
"breathing": 5505,
"mad": 5506,
"lit": 5507,
"arrival": 5508,
"concrete": 5509,
"taste": 5510,
"08": 5511,
"composition": 5512,
"shaking": 5513,
"faster": 5514,
"amateur": 5515,
"adjacent": 5516,
"stating": 5517,
"1906": 5518,
"twin": 5519,
"flew": 5520,
"##ran": 5521,
"tokyo": 5522,
"publications": 5523,
"##tone": 5524,
"obviously": 5525,
"ridge": 5526,
"storage": 5527,
"1907": 5528,
"carl": 5529,
"pages": 5530,
"concluded": 5531,
"desert": 5532,
"driven": 5533,
"universities": 5534,
"ages": 5535,
"terminal": 5536,
"sequence": 5537,
"borough": 5538,
"250": 5539,
"constituency": 5540,
"creative": 5541,
"cousin": 5542,
"economics": 5543,
"dreams": 5544,
"margaret": 5545,
"notably": 5546,
"reduce": 5547,
"montreal": 5548,
"mode": 5549,
"17th": 5550,
"ears": 5551,
"saved": 5552,
"jan": 5553,
"vocal": 5554,
"##ica": 5555,
"1909": 5556,
"andy": 5557,
"##jo": 5558,
"riding": 5559,
"roughly": 5560,
"threatened": 5561,
"##ise": 5562,
"meters": 5563,
"meanwhile": 5564,
"landed": 5565,
"compete": 5566,
"repeated": 5567,
"grass": 5568,
"czech": 5569,
"regularly": 5570,
"charges": 5571,
"tea": 5572,
"sudden": 5573,
"appeal": 5574,
"##ung": 5575,
"solution": 5576,
"describes": 5577,
"pierre": 5578,
"classification": 5579,
"glad": 5580,
"parking": 5581,
"##ning": 5582,
"belt": 5583,
"physics": 5584,
"99": 5585,
"rachel": 5586,
"add": 5587,
"hungarian": 5588,
"participate": 5589,
"expedition": 5590,
"damaged": 5591,
"gift": 5592,
"childhood": 5593,
"85": 5594,
"fifty": 5595,
"##red": 5596,
"mathematics": 5597,
"jumped": 5598,
"letting": 5599,
"defensive": 5600,
"mph": 5601,
"##ux": 5602,
"##gh": 5603,
"testing": 5604,
"##hip": 5605,
"hundreds": 5606,
"shoot": 5607,
"owners": 5608,
"matters": 5609,
"smoke": 5610,
"israeli": 5611,
"kentucky": 5612,
"dancing": 5613,
"mounted": 5614,
"grandfather": 5615,
"emma": 5616,
"designs": 5617,
"profit": 5618,
"argentina": 5619,
"##gs": 5620,
"truly": 5621,
"li": 5622,
"lawrence": 5623,
"cole": 5624,
"begun": 5625,
"detroit": 5626,
"willing": 5627,
"branches": 5628,
"smiling": 5629,
"decide": 5630,
"miami": 5631,
"enjoyed": 5632,
"recordings": 5633,
"##dale": 5634,
"poverty": 5635,
"ethnic": 5636,
"gay": 5637,
"##bi": 5638,
"gary": 5639,
"arabic": 5640,
"09": 5641,
"accompanied": 5642,
"##one": 5643,
"##ons": 5644,
"fishing": 5645,
"determine": 5646,
"residential": 5647,
"acid": 5648,
"##ary": 5649,
"alice": 5650,
"returns": 5651,
"starred": 5652,
"mail": 5653,
"##ang": 5654,
"jonathan": 5655,
"strategy": 5656,
"##ue": 5657,
"net": 5658,
"forty": 5659,
"cook": 5660,
"businesses": 5661,
"equivalent": 5662,
"commonwealth": 5663,
"distinct": 5664,
"ill": 5665,
"##cy": 5666,
"seriously": 5667,
"##ors": 5668,
"##ped": 5669,
"shift": 5670,
"harris": 5671,
"replace": 5672,
"rio": 5673,
"imagine": 5674,
"formula": 5675,
"ensure": 5676,
"##ber": 5677,
"additionally": 5678,
"scheme": 5679,
"conservation": 5680,
"occasionally": 5681,
"purposes": 5682,
"feels": 5683,
"favor": 5684,
"##and": 5685,
"##ore": 5686,
"1930s": 5687,
"contrast": 5688,
"hanging": 5689,
"hunt": 5690,
"movies": 5691,
"1904": 5692,
"instruments": 5693,
"victims": 5694,
"danish": 5695,
"christopher": 5696,
"busy": 5697,
"demon": 5698,
"sugar": 5699,
"earliest": 5700,
"colony": 5701,
"studying": 5702,
"balance": 5703,
"duties": 5704,
"##ks": 5705,
"belgium": 5706,
"slipped": 5707,
"carter": 5708,
"05": 5709,
"visible": 5710,
"stages": 5711,
"iraq": 5712,
"fifa": 5713,
"##im": 5714,
"commune": 5715,
"forming": 5716,
"zero": 5717,
"07": 5718,
"continuing": 5719,
"talked": 5720,
"counties": 5721,
"legend": 5722,
"bathroom": 5723,
"option": 5724,
"tail": 5725,
"clay": 5726,
"daughters": 5727,
"afterwards": 5728,
"severe": 5729,
"jaw": 5730,
"visitors": 5731,
"##ded": 5732,
"devices": 5733,
"aviation": 5734,
"russell": 5735,
"kate": 5736,
"##vi": 5737,
"entering": 5738,
"subjects": 5739,
"##ino": 5740,
"temporary": 5741,
"swimming": 5742,
"forth": 5743,
"smooth": 5744,
"ghost": 5745,
"audio": 5746,
"bush": 5747,
"operates": 5748,
"rocks": 5749,
"movements": 5750,
"signs": 5751,
"eddie": 5752,
"##tz": 5753,
"ann": 5754,
"voices": 5755,
"honorary": 5756,
"06": 5757,
"memories": 5758,
"dallas": 5759,
"pure": 5760,
"measures": 5761,
"racial": 5762,
"promised": 5763,
"66": 5764,
"harvard": 5765,
"ceo": 5766,
"16th": 5767,
"parliamentary": 5768,
"indicate": 5769,
"benefit": 5770,
"flesh": 5771,
"dublin": 5772,
"louisiana": 5773,
"1902": 5774,
"1901": 5775,
"patient": 5776,
"sleeping": 5777,
"1903": 5778,
"membership": 5779,
"coastal": 5780,
"medieval": 5781,
"wanting": 5782,
"element": 5783,
"scholars": 5784,
"rice": 5785,
"62": 5786,
"limit": 5787,
"survive": 5788,
"makeup": 5789,
"rating": 5790,
"definitely": 5791,
"collaboration": 5792,
"obvious": 5793,
"##tan": 5794,
"boss": 5795,
"ms": 5796,
"baron": 5797,
"birthday": 5798,
"linked": 5799,
"soil": 5800,
"diocese": 5801,
"##lan": 5802,
"ncaa": 5803,
"##mann": 5804,
"offensive": 5805,
"shell": 5806,
"shouldn": 5807,
"waist": 5808,
"##tus": 5809,
"plain": 5810,
"ross": 5811,
"organ": 5812,
"resolution": 5813,
"manufacturing": 5814,
"adding": 5815,
"relative": 5816,
"kennedy": 5817,
"98": 5818,
"whilst": 5819,
"moth": 5820,
"marketing": 5821,
"gardens": 5822,
"crash": 5823,
"72": 5824,
"heading": 5825,
"partners": 5826,
"credited": 5827,
"carlos": 5828,
"moves": 5829,
"cable": 5830,
"##zi": 5831,
"marshall": 5832,
"##out": 5833,
"depending": 5834,
"bottle": 5835,
"represents": 5836,
"rejected": 5837,
"responded": 5838,
"existed": 5839,
"04": 5840,
"jobs": 5841,
"denmark": 5842,
"lock": 5843,
"##ating": 5844,
"treated": 5845,
"graham": 5846,
"routes": 5847,
"talent": 5848,
"commissioner": 5849,
"drugs": 5850,
"secure": 5851,
"tests": 5852,
"reign": 5853,
"restored": 5854,
"photography": 5855,
"##gi": 5856,
"contributions": 5857,
"oklahoma": 5858,
"designer": 5859,
"disc": 5860,
"grin": 5861,
"seattle": 5862,
"robin": 5863,
"paused": 5864,
"atlanta": 5865,
"unusual": 5866,
"##gate": 5867,
"praised": 5868,
"las": 5869,
"laughing": 5870,
"satellite": 5871,
"hungary": 5872,
"visiting": 5873,
"##sky": 5874,
"interesting": 5875,
"factors": 5876,
"deck": 5877,
"poems": 5878,
"norman": 5879,
"##water": 5880,
"stuck": 5881,
"speaker": 5882,
"rifle": 5883,
"domain": 5884,
"premiered": 5885,
"##her": 5886,
"dc": 5887,
"comics": 5888,
"actors": 5889,
"01": 5890,
"reputation": 5891,
"eliminated": 5892,
"8th": 5893,
"ceiling": 5894,
"prisoners": 5895,
"script": 5896,
"##nce": 5897,
"leather": 5898,
"austin": 5899,
"mississippi": 5900,
"rapidly": 5901,
"admiral": 5902,
"parallel": 5903,
"charlotte": 5904,
"guilty": 5905,
"tools": 5906,
"gender": 5907,
"divisions": 5908,
"fruit": 5909,
"##bs": 5910,
"laboratory": 5911,
"nelson": 5912,
"fantasy": 5913,
"marry": 5914,
"rapid": 5915,
"aunt": 5916,
"tribe": 5917,
"requirements": 5918,
"aspects": 5919,
"suicide": 5920,
"amongst": 5921,
"adams": 5922,
"bone": 5923,
"ukraine": 5924,
"abc": 5925,
"kick": 5926,
"sees": 5927,
"edinburgh": 5928,
"clothing": 5929,
"column": 5930,
"rough": 5931,
"gods": 5932,
"hunting": 5933,
"broadway": 5934,
"gathered": 5935,
"concerns": 5936,
"##ek": 5937,
"spending": 5938,
"ty": 5939,
"12th": 5940,
"snapped": 5941,
"requires": 5942,
"solar": 5943,
"bones": 5944,
"cavalry": 5945,
"##tta": 5946,
"iowa": 5947,
"drinking": 5948,
"waste": 5949,
"index": 5950,
"franklin": 5951,
"charity": 5952,
"thompson": 5953,
"stewart": 5954,
"tip": 5955,
"flash": 5956,
"landscape": 5957,
"friday": 5958,
"enjoy": 5959,
"singh": 5960,
"poem": 5961,
"listening": 5962,
"##back": 5963,
"eighth": 5964,
"fred": 5965,
"differences": 5966,
"adapted": 5967,
"bomb": 5968,
"ukrainian": 5969,
"surgery": 5970,
"corporate": 5971,
"masters": 5972,
"anywhere": 5973,
"##more": 5974,
"waves": 5975,
"odd": 5976,
"sean": 5977,
"portugal": 5978,
"orleans": 5979,
"dick": 5980,
"debate": 5981,
"kent": 5982,
"eating": 5983,
"puerto": 5984,
"cleared": 5985,
"96": 5986,
"expect": 5987,
"cinema": 5988,
"97": 5989,
"guitarist": 5990,
"blocks": 5991,
"electrical": 5992,
"agree": 5993,
"involving": 5994,
"depth": 5995,
"dying": 5996,
"panel": 5997,
"struggle": 5998,
"##ged": 5999,
"peninsula": 6000,
"adults": 6001,
"novels": 6002,
"emerged": 6003,
"vienna": 6004,
"metro": 6005,
"debuted": 6006,
"shoes": 6007,
"tamil": 6008,
"songwriter": 6009,
"meets": 6010,
"prove": 6011,
"beating": 6012,
"instance": 6013,
"heaven": 6014,
"scared": 6015,
"sending": 6016,
"marks": 6017,
"artistic": 6018,
"passage": 6019,
"superior": 6020,
"03": 6021,
"significantly": 6022,
"shopping": 6023,
"##tive": 6024,
"retained": 6025,
"##izing": 6026,
"malaysia": 6027,
"technique": 6028,
"cheeks": 6029,
"##ola": 6030,
"warren": 6031,
"maintenance": 6032,
"destroy": 6033,
"extreme": 6034,
"allied": 6035,
"120": 6036,
"appearing": 6037,
"##yn": 6038,
"fill": 6039,
"advice": 6040,
"alabama": 6041,
"qualifying": 6042,
"policies": 6043,
"cleveland": 6044,
"hat": 6045,
"battery": 6046,
"smart": 6047,
"authors": 6048,
"10th": 6049,
"soundtrack": 6050,
"acted": 6051,
"dated": 6052,
"lb": 6053,
"glance": 6054,
"equipped": 6055,
"coalition": 6056,
"funny": 6057,
"outer": 6058,
"ambassador": 6059,
"roy": 6060,
"possibility": 6061,
"couples": 6062,
"campbell": 6063,
"dna": 6064,
"loose": 6065,
"ethan": 6066,
"supplies": 6067,
"1898": 6068,
"gonna": 6069,
"88": 6070,
"monster": 6071,
"##res": 6072,
"shake": 6073,
"agents": 6074,
"frequency": 6075,
"springs": 6076,
"dogs": 6077,
"practices": 6078,
"61": 6079,
"gang": 6080,
"plastic": 6081,
"easier": 6082,
"suggests": 6083,
"gulf": 6084,
"blade": 6085,
"exposed": 6086,
"colors": 6087,
"industries": 6088,
"markets": 6089,
"pan": 6090,
"nervous": 6091,
"electoral": 6092,
"charts": 6093,
"legislation": 6094,
"ownership": 6095,
"##idae": 6096,
"mac": 6097,
"appointment": 6098,
"shield": 6099,
"copy": 6100,
"assault": 6101,
"socialist": 6102,
"abbey": 6103,
"monument": 6104,
"license": 6105,
"throne": 6106,
"employment": 6107,
"jay": 6108,
"93": 6109,
"replacement": 6110,
"charter": 6111,
"cloud": 6112,
"powered": 6113,
"suffering": 6114,
"accounts": 6115,
"oak": 6116,
"connecticut": 6117,
"strongly": 6118,
"wright": 6119,
"colour": 6120,
"crystal": 6121,
"13th": 6122,
"context": 6123,
"welsh": 6124,
"networks": 6125,
"voiced": 6126,
"gabriel": 6127,
"jerry": 6128,
"##cing": 6129,
"forehead": 6130,
"mp": 6131,
"##ens": 6132,
"manage": 6133,
"schedule": 6134,
"totally": 6135,
"remix": 6136,
"##ii": 6137,
"forests": 6138,
"occupation": 6139,
"print": 6140,
"nicholas": 6141,
"brazilian": 6142,
"strategic": 6143,
"vampires": 6144,
"engineers": 6145,
"76": 6146,
"roots": 6147,
"seek": 6148,
"correct": 6149,
"instrumental": 6150,
"und": 6151,
"alfred": 6152,
"backed": 6153,
"hop": 6154,
"##des": 6155,
"stanley": 6156,
"robinson": 6157,
"traveled": 6158,
"wayne": 6159,
"welcome": 6160,
"austrian": 6161,
"achieve": 6162,
"67": 6163,
"exit": 6164,
"rates": 6165,
"1899": 6166,
"strip": 6167,
"whereas": 6168,
"##cs": 6169,
"sing": 6170,
"deeply": 6171,
"adventure": 6172,
"bobby": 6173,
"rick": 6174,
"jamie": 6175,
"careful": 6176,
"components": 6177,
"cap": 6178,
"useful": 6179,
"personality": 6180,
"knee": 6181,
"##shi": 6182,
"pushing": 6183,
"hosts": 6184,
"02": 6185,
"protest": 6186,
"ca": 6187,
"ottoman": 6188,
"symphony": 6189,
"##sis": 6190,
"63": 6191,
"boundary": 6192,
"1890": 6193,
"processes": 6194,
"considering": 6195,
"considerable": 6196,
"tons": 6197,
"##work": 6198,
"##ft": 6199,
"##nia": 6200,
"cooper": 6201,
"trading": 6202,
"dear": 6203,
"conduct": 6204,
"91": 6205,
"illegal": 6206,
"apple": 6207,
"revolutionary": 6208,
"holiday": 6209,
"definition": 6210,
"harder": 6211,
"##van": 6212,
"jacob": 6213,
"circumstances": 6214,
"destruction": 6215,
"##lle": 6216,
"popularity": 6217,
"grip": 6218,
"classified": 6219,
"liverpool": 6220,
"donald": 6221,
"baltimore": 6222,
"flows": 6223,
"seeking": 6224,
"honour": 6225,
"approval": 6226,
"92": 6227,
"mechanical": 6228,
"till": 6229,
"happening": 6230,
"statue": 6231,
"critic": 6232,
"increasingly": 6233,
"immediate": 6234,
"describe": 6235,
"commerce": 6236,
"stare": 6237,
"##ster": 6238,
"indonesia": 6239,
"meat": 6240,
"rounds": 6241,
"boats": 6242,
"baker": 6243,
"orthodox": 6244,
"depression": 6245,
"formally": 6246,
"worn": 6247,
"naked": 6248,
"claire": 6249,
"muttered": 6250,
"sentence": 6251,
"11th": 6252,
"emily": 6253,
"document": 6254,
"77": 6255,
"criticism": 6256,
"wished": 6257,
"vessel": 6258,
"spiritual": 6259,
"bent": 6260,
"virgin": 6261,
"parker": 6262,
"minimum": 6263,
"murray": 6264,
"lunch": 6265,
"danny": 6266,
"printed": 6267,
"compilation": 6268,
"keyboards": 6269,
"false": 6270,
"blow": 6271,
"belonged": 6272,
"68": 6273,
"raising": 6274,
"78": 6275,
"cutting": 6276,
"##board": 6277,
"pittsburgh": 6278,
"##up": 6279,
"9th": 6280,
"shadows": 6281,
"81": 6282,
"hated": 6283,
"indigenous": 6284,
"jon": 6285,
"15th": 6286,
"barry": 6287,
"scholar": 6288,
"ah": 6289,
"##zer": 6290,
"oliver": 6291,
"##gy": 6292,
"stick": 6293,
"susan": 6294,
"meetings": 6295,
"attracted": 6296,
"spell": 6297,
"romantic": 6298,
"##ver": 6299,
"ye": 6300,
"1895": 6301,
"photo": 6302,
"demanded": 6303,
"customers": 6304,
"##ac": 6305,
"1896": 6306,
"logan": 6307,
"revival": 6308,
"keys": 6309,
"modified": 6310,
"commanded": 6311,
"jeans": 6312,
"##ious": 6313,
"upset": 6314,
"raw": 6315,
"phil": 6316,
"detective": 6317,
"hiding": 6318,
"resident": 6319,
"vincent": 6320,
"##bly": 6321,
"experiences": 6322,
"diamond": 6323,
"defeating": 6324,
"coverage": 6325,
"lucas": 6326,
"external": 6327,
"parks": 6328,
"franchise": 6329,
"helen": 6330,
"bible": 6331,
"successor": 6332,
"percussion": 6333,
"celebrated": 6334,
"il": 6335,
"lift": 6336,
"profile": 6337,
"clan": 6338,
"romania": 6339,
"##ied": 6340,
"mills": 6341,
"##su": 6342,
"nobody": 6343,
"achievement": 6344,
"shrugged": 6345,
"fault": 6346,
"1897": 6347,
"rhythm": 6348,
"initiative": 6349,
"breakfast": 6350,
"carbon": 6351,
"700": 6352,
"69": 6353,
"lasted": 6354,
"violent": 6355,
"74": 6356,
"wound": 6357,
"ken": 6358,
"killer": 6359,
"gradually": 6360,
"filmed": 6361,
"°c": 6362,
"dollars": 6363,
"processing": 6364,
"94": 6365,
"remove": 6366,
"criticized": 6367,
"guests": 6368,
"sang": 6369,
"chemistry": 6370,
"##vin": 6371,
"legislature": 6372,
"disney": 6373,
"##bridge": 6374,
"uniform": 6375,
"escaped": 6376,
"integrated": 6377,
"proposal": 6378,
"purple": 6379,
"denied": 6380,
"liquid": 6381,
"karl": 6382,
"influential": 6383,
"morris": 6384,
"nights": 6385,
"stones": 6386,
"intense": 6387,
"experimental": 6388,
"twisted": 6389,
"71": 6390,
"84": 6391,
"##ld": 6392,
"pace": 6393,
"nazi": 6394,
"mitchell": 6395,
"ny": 6396,
"blind": 6397,
"reporter": 6398,
"newspapers": 6399,
"14th": 6400,
"centers": 6401,
"burn": 6402,
"basin": 6403,
"forgotten": 6404,
"surviving": 6405,
"filed": 6406,
"collections": 6407,
"monastery": 6408,
"losses": 6409,
"manual": 6410,
"couch": 6411,
"description": 6412,
"appropriate": 6413,
"merely": 6414,
"tag": 6415,
"missions": 6416,
"sebastian": 6417,
"restoration": 6418,
"replacing": 6419,
"triple": 6420,
"73": 6421,
"elder": 6422,
"julia": 6423,
"warriors": 6424,
"benjamin": 6425,
"julian": 6426,
"convinced": 6427,
"stronger": 6428,
"amazing": 6429,
"declined": 6430,
"versus": 6431,
"merchant": 6432,
"happens": 6433,
"output": 6434,
"finland": 6435,
"bare": 6436,
"barbara": 6437,
"absence": 6438,
"ignored": 6439,
"dawn": 6440,
"injuries": 6441,
"##port": 6442,
"producers": 6443,
"##ram": 6444,
"82": 6445,
"luis": 6446,
"##ities": 6447,
"kw": 6448,
"admit": 6449,
"expensive": 6450,
"electricity": 6451,
"nba": 6452,
"exception": 6453,
"symbol": 6454,
"##ving": 6455,
"ladies": 6456,
"shower": 6457,
"sheriff": 6458,
"characteristics": 6459,
"##je": 6460,
"aimed": 6461,
"button": 6462,
"ratio": 6463,
"effectively": 6464,
"summit": 6465,
"angle": 6466,
"jury": 6467,
"bears": 6468,
"foster": 6469,
"vessels": 6470,
"pants": 6471,
"executed": 6472,
"evans": 6473,
"dozen": 6474,
"advertising": 6475,
"kicked": 6476,
"patrol": 6477,
"1889": 6478,
"competitions": 6479,
"lifetime": 6480,
"principles": 6481,
"athletics": 6482,
"##logy": 6483,
"birmingham": 6484,
"sponsored": 6485,
"89": 6486,
"rob": 6487,
"nomination": 6488,
"1893": 6489,
"acoustic": 6490,
"##sm": 6491,
"creature": 6492,
"longest": 6493,
"##tra": 6494,
"credits": 6495,
"harbor": 6496,
"dust": 6497,
"josh": 6498,
"##so": 6499,
"territories": 6500,
"milk": 6501,
"infrastructure": 6502,
"completion": 6503,
"thailand": 6504,
"indians": 6505,
"leon": 6506,
"archbishop": 6507,
"##sy": 6508,
"assist": 6509,
"pitch": 6510,
"blake": 6511,
"arrangement": 6512,
"girlfriend": 6513,
"serbian": 6514,
"operational": 6515,
"hence": 6516,
"sad": 6517,
"scent": 6518,
"fur": 6519,
"dj": 6520,
"sessions": 6521,
"hp": 6522,
"refer": 6523,
"rarely": 6524,
"##ora": 6525,
"exists": 6526,
"1892": 6527,
"##ten": 6528,
"scientists": 6529,
"dirty": 6530,
"penalty": 6531,
"burst": 6532,
"portrait": 6533,
"seed": 6534,
"79": 6535,
"pole": 6536,
"limits": 6537,
"rival": 6538,
"1894": 6539,
"stable": 6540,
"alpha": 6541,
"grave": 6542,
"constitutional": 6543,
"alcohol": 6544,
"arrest": 6545,
"flower": 6546,
"mystery": 6547,
"devil": 6548,
"architectural": 6549,
"relationships": 6550,
"greatly": 6551,
"habitat": 6552,
"##istic": 6553,
"larry": 6554,
"progressive": 6555,
"remote": 6556,
"cotton": 6557,
"##ics": 6558,
"##ok": 6559,
"preserved": 6560,
"reaches": 6561,
"##ming": 6562,
"cited": 6563,
"86": 6564,
"vast": 6565,
"scholarship": 6566,
"decisions": 6567,
"cbs": 6568,
"joy": 6569,
"teach": 6570,
"1885": 6571,
"editions": 6572,
"knocked": 6573,
"eve": 6574,
"searching": 6575,
"partly": 6576,
"participation": 6577,
"gap": 6578,
"animated": 6579,
"fate": 6580,
"excellent": 6581,
"##ett": 6582,
"na": 6583,
"87": 6584,
"alternate": 6585,
"saints": 6586,
"youngest": 6587,
"##ily": 6588,
"climbed": 6589,
"##ita": 6590,
"##tors": 6591,
"suggest": 6592,
"##ct": 6593,
"discussion": 6594,
"staying": 6595,
"choir": 6596,
"lakes": 6597,
"jacket": 6598,
"revenue": 6599,
"nevertheless": 6600,
"peaked": 6601,
"instrument": 6602,
"wondering": 6603,
"annually": 6604,
"managing": 6605,
"neil": 6606,
"1891": 6607,
"signing": 6608,
"terry": 6609,
"##ice": 6610,
"apply": 6611,
"clinical": 6612,
"brooklyn": 6613,
"aim": 6614,
"catherine": 6615,
"fuck": 6616,
"farmers": 6617,
"figured": 6618,
"ninth": 6619,
"pride": 6620,
"hugh": 6621,
"evolution": 6622,
"ordinary": 6623,
"involvement": 6624,
"comfortable": 6625,
"shouted": 6626,
"tech": 6627,
"encouraged": 6628,
"taiwan": 6629,
"representation": 6630,
"sharing": 6631,
"##lia": 6632,
"##em": 6633,
"panic": 6634,
"exact": 6635,
"cargo": 6636,
"competing": 6637,
"fat": 6638,
"cried": 6639,
"83": 6640,
"1920s": 6641,
"occasions": 6642,
"pa": 6643,
"cabin": 6644,
"borders": 6645,
"utah": 6646,
"marcus": 6647,
"##isation": 6648,
"badly": 6649,
"muscles": 6650,
"##ance": 6651,
"victorian": 6652,
"transition": 6653,
"warner": 6654,
"bet": 6655,
"permission": 6656,
"##rin": 6657,
"slave": 6658,
"terrible": 6659,
"similarly": 6660,
"shares": 6661,
"seth": 6662,
"uefa": 6663,
"possession": 6664,
"medals": 6665,
"benefits": 6666,
"colleges": 6667,
"lowered": 6668,
"perfectly": 6669,
"mall": 6670,
"transit": 6671,
"##ye": 6672,
"##kar": 6673,
"publisher": 6674,
"##ened": 6675,
"harrison": 6676,
"deaths": 6677,
"elevation": 6678,
"##ae": 6679,
"asleep": 6680,
"machines": 6681,
"sigh": 6682,
"ash": 6683,
"hardly": 6684,
"argument": 6685,
"occasion": 6686,
"parent": 6687,
"leo": 6688,
"decline": 6689,
"1888": 6690,
"contribution": 6691,
"##ua": 6692,
"concentration": 6693,
"1000": 6694,
"opportunities": 6695,
"hispanic": 6696,
"guardian": 6697,
"extent": 6698,
"emotions": 6699,
"hips": 6700,
"mason": 6701,
"volumes": 6702,
"bloody": 6703,
"controversy": 6704,
"diameter": 6705,
"steady": 6706,
"mistake": 6707,
"phoenix": 6708,
"identify": 6709,
"violin": 6710,
"##sk": 6711,
"departure": 6712,
"richmond": 6713,
"spin": 6714,
"funeral": 6715,
"enemies": 6716,
"1864": 6717,
"gear": 6718,
"literally": 6719,
"connor": 6720,
"random": 6721,
"sergeant": 6722,
"grab": 6723,
"confusion": 6724,
"1865": 6725,
"transmission": 6726,
"informed": 6727,
"op": 6728,
"leaning": 6729,
"sacred": 6730,
"suspended": 6731,
"thinks": 6732,
"gates": 6733,
"portland": 6734,
"luck": 6735,
"agencies": 6736,
"yours": 6737,
"hull": 6738,
"expert": 6739,
"muscle": 6740,
"layer": 6741,
"practical": 6742,
"sculpture": 6743,
"jerusalem": 6744,
"latest": 6745,
"lloyd": 6746,
"statistics": 6747,
"deeper": 6748,
"recommended": 6749,
"warrior": 6750,
"arkansas": 6751,
"mess": 6752,
"supports": 6753,
"greg": 6754,
"eagle": 6755,
"1880": 6756,
"recovered": 6757,
"rated": 6758,
"concerts": 6759,
"rushed": 6760,
"##ano": 6761,
"stops": 6762,
"eggs": 6763,
"files": 6764,
"premiere": 6765,
"keith": 6766,
"##vo": 6767,
"delhi": 6768,
"turner": 6769,
"pit": 6770,
"affair": 6771,
"belief": 6772,
"paint": 6773,
"##zing": 6774,
"mate": 6775,
"##ach": 6776,
"##ev": 6777,
"victim": 6778,
"##ology": 6779,
"withdrew": 6780,
"bonus": 6781,
"styles": 6782,
"fled": 6783,
"##ud": 6784,
"glasgow": 6785,
"technologies": 6786,
"funded": 6787,
"nbc": 6788,
"adaptation": 6789,
"##ata": 6790,
"portrayed": 6791,
"cooperation": 6792,
"supporters": 6793,
"judges": 6794,
"bernard": 6795,
"justin": 6796,
"hallway": 6797,
"ralph": 6798,
"##ick": 6799,
"graduating": 6800,
"controversial": 6801,
"distant": 6802,
"continental": 6803,
"spider": 6804,
"bite": 6805,
"##ho": 6806,
"recognize": 6807,
"intention": 6808,
"mixing": 6809,
"##ese": 6810,
"egyptian": 6811,
"bow": 6812,
"tourism": 6813,
"suppose": 6814,
"claiming": 6815,
"tiger": 6816,
"dominated": 6817,
"participants": 6818,
"vi": 6819,
"##ru": 6820,
"nurse": 6821,
"partially": 6822,
"tape": 6823,
"##rum": 6824,
"psychology": 6825,
"##rn": 6826,
"essential": 6827,
"touring": 6828,
"duo": 6829,
"voting": 6830,
"civilian": 6831,
"emotional": 6832,
"channels": 6833,
"##king": 6834,
"apparent": 6835,
"hebrew": 6836,
"1887": 6837,
"tommy": 6838,
"carrier": 6839,
"intersection": 6840,
"beast": 6841,
"hudson": 6842,
"##gar": 6843,
"##zo": 6844,
"lab": 6845,
"nova": 6846,
"bench": 6847,
"discuss": 6848,
"costa": 6849,
"##ered": 6850,
"detailed": 6851,
"behalf": 6852,
"drivers": 6853,
"unfortunately": 6854,
"obtain": 6855,
"##lis": 6856,
"rocky": 6857,
"##dae": 6858,
"siege": 6859,
"friendship": 6860,
"honey": 6861,
"##rian": 6862,
"1861": 6863,
"amy": 6864,
"hang": 6865,
"posted": 6866,
"governments": 6867,
"collins": 6868,
"respond": 6869,
"wildlife": 6870,
"preferred": 6871,
"operator": 6872,
"##po": 6873,
"laura": 6874,
"pregnant": 6875,
"videos": 6876,
"dennis": 6877,
"suspected": 6878,
"boots": 6879,
"instantly": 6880,
"weird": 6881,
"automatic": 6882,
"businessman": 6883,
"alleged": 6884,
"placing": 6885,
"throwing": 6886,
"ph": 6887,
"mood": 6888,
"1862": 6889,
"perry": 6890,
"venue": 6891,
"jet": 6892,
"remainder": 6893,
"##lli": 6894,
"##ci": 6895,
"passion": 6896,
"biological": 6897,
"boyfriend": 6898,
"1863": 6899,
"dirt": 6900,
"buffalo": 6901,
"ron": 6902,
"segment": 6903,
"fa": 6904,
"abuse": 6905,
"##era": 6906,
"genre": 6907,
"thrown": 6908,
"stroke": 6909,
"colored": 6910,
"stress": 6911,
"exercise": 6912,
"displayed": 6913,
"##gen": 6914,
"struggled": 6915,
"##tti": 6916,
"abroad": 6917,
"dramatic": 6918,
"wonderful": 6919,
"thereafter": 6920,
"madrid": 6921,
"component": 6922,
"widespread": 6923,
"##sed": 6924,
"tale": 6925,
"citizen": 6926,
"todd": 6927,
"monday": 6928,
"1886": 6929,
"vancouver": 6930,
"overseas": 6931,
"forcing": 6932,
"crying": 6933,
"descent": 6934,
"##ris": 6935,
"discussed": 6936,
"substantial": 6937,
"ranks": 6938,
"regime": 6939,
"1870": 6940,
"provinces": 6941,
"switch": 6942,
"drum": 6943,
"zane": 6944,
"ted": 6945,
"tribes": 6946,
"proof": 6947,
"lp": 6948,
"cream": 6949,
"researchers": 6950,
"volunteer": 6951,
"manor": 6952,
"silk": 6953,
"milan": 6954,
"donated": 6955,
"allies": 6956,
"venture": 6957,
"principle": 6958,
"delivery": 6959,
"enterprise": 6960,
"##ves": 6961,
"##ans": 6962,
"bars": 6963,
"traditionally": 6964,
"witch": 6965,
"reminded": 6966,
"copper": 6967,
"##uk": 6968,
"pete": 6969,
"inter": 6970,
"links": 6971,
"colin": 6972,
"grinned": 6973,
"elsewhere": 6974,
"competitive": 6975,
"frequent": 6976,
"##oy": 6977,
"scream": 6978,
"##hu": 6979,
"tension": 6980,
"texts": 6981,
"submarine": 6982,
"finnish": 6983,
"defending": 6984,
"defend": 6985,
"pat": 6986,
"detail": 6987,
"1884": 6988,
"affiliated": 6989,
"stuart": 6990,
"themes": 6991,
"villa": 6992,
"periods": 6993,
"tool": 6994,
"belgian": 6995,
"ruling": 6996,
"crimes": 6997,
"answers": 6998,
"folded": 6999,
"licensed": 7000,
"resort": 7001,
"demolished": 7002,
"hans": 7003,
"lucy": 7004,
"1881": 7005,
"lion": 7006,
"traded": 7007,
"photographs": 7008,
"writes": 7009,
"craig": 7010,
"##fa": 7011,
"trials": 7012,
"generated": 7013,
"beth": 7014,
"noble": 7015,
"debt": 7016,
"percentage": 7017,
"yorkshire": 7018,
"erected": 7019,
"ss": 7020,
"viewed": 7021,
"grades": 7022,
"confidence": 7023,
"ceased": 7024,
"islam": 7025,
"telephone": 7026,
"retail": 7027,
"##ible": 7028,
"chile": 7029,
"m²": 7030,
"roberts": 7031,
"sixteen": 7032,
"##ich": 7033,
"commented": 7034,
"hampshire": 7035,
"innocent": 7036,
"dual": 7037,
"pounds": 7038,
"checked": 7039,
"regulations": 7040,
"afghanistan": 7041,
"sung": 7042,
"rico": 7043,
"liberty": 7044,
"assets": 7045,
"bigger": 7046,
"options": 7047,
"angels": 7048,
"relegated": 7049,
"tribute": 7050,
"wells": 7051,
"attending": 7052,
"leaf": 7053,
"##yan": 7054,
"butler": 7055,
"romanian": 7056,
"forum": 7057,
"monthly": 7058,
"lisa": 7059,
"patterns": 7060,
"gmina": 7061,
"##tory": 7062,
"madison": 7063,
"hurricane": 7064,
"rev": 7065,
"##ians": 7066,
"bristol": 7067,
"##ula": 7068,
"elite": 7069,
"valuable": 7070,
"disaster": 7071,
"democracy": 7072,
"awareness": 7073,
"germans": 7074,
"freyja": 7075,
"##ins": 7076,
"loop": 7077,
"absolutely": 7078,
"paying": 7079,
"populations": 7080,
"maine": 7081,
"sole": 7082,
"prayer": 7083,
"spencer": 7084,
"releases": 7085,
"doorway": 7086,
"bull": 7087,
"##ani": 7088,
"lover": 7089,
"midnight": 7090,
"conclusion": 7091,
"##sson": 7092,
"thirteen": 7093,
"lily": 7094,
"mediterranean": 7095,
"##lt": 7096,
"nhl": 7097,
"proud": 7098,
"sample": 7099,
"##hill": 7100,
"drummer": 7101,
"guinea": 7102,
"##ova": 7103,
"murphy": 7104,
"climb": 7105,
"##ston": 7106,
"instant": 7107,
"attributed": 7108,
"horn": 7109,
"ain": 7110,
"railways": 7111,
"steven": 7112,
"##ao": 7113,
"autumn": 7114,
"ferry": 7115,
"opponent": 7116,
"root": 7117,
"traveling": 7118,
"secured": 7119,
"corridor": 7120,
"stretched": 7121,
"tales": 7122,
"sheet": 7123,
"trinity": 7124,
"cattle": 7125,
"helps": 7126,
"indicates": 7127,
"manhattan": 7128,
"murdered": 7129,
"fitted": 7130,
"1882": 7131,
"gentle": 7132,
"grandmother": 7133,
"mines": 7134,
"shocked": 7135,
"vegas": 7136,
"produces": 7137,
"##light": 7138,
"caribbean": 7139,
"##ou": 7140,
"belong": 7141,
"continuous": 7142,
"desperate": 7143,
"drunk": 7144,
"historically": 7145,
"trio": 7146,
"waved": 7147,
"raf": 7148,
"dealing": 7149,
"nathan": 7150,
"bat": 7151,
"murmured": 7152,
"interrupted": 7153,
"residing": 7154,
"scientist": 7155,
"pioneer": 7156,
"harold": 7157,
"aaron": 7158,
"##net": 7159,
"delta": 7160,
"attempting": 7161,
"minority": 7162,
"mini": 7163,
"believes": 7164,
"chorus": 7165,
"tend": 7166,
"lots": 7167,
"eyed": 7168,
"indoor": 7169,
"load": 7170,
"shots": 7171,
"updated": 7172,
"jail": 7173,
"##llo": 7174,
"concerning": 7175,
"connecting": 7176,
"wealth": 7177,
"##ved": 7178,
"slaves": 7179,
"arrive": 7180,
"rangers": 7181,
"sufficient": 7182,
"rebuilt": 7183,
"##wick": 7184,
"cardinal": 7185,
"flood": 7186,
"muhammad": 7187,
"whenever": 7188,
"relation": 7189,
"runners": 7190,
"moral": 7191,
"repair": 7192,
"viewers": 7193,
"arriving": 7194,
"revenge": 7195,
"punk": 7196,
"assisted": 7197,
"bath": 7198,
"fairly": 7199,
"breathe": 7200,
"lists": 7201,
"innings": 7202,
"illustrated": 7203,
"whisper": 7204,
"nearest": 7205,
"voters": 7206,
"clinton": 7207,
"ties": 7208,
"ultimate": 7209,
"screamed": 7210,
"beijing": 7211,
"lions": 7212,
"andre": 7213,
"fictional": 7214,
"gathering": 7215,
"comfort": 7216,
"radar": 7217,
"suitable": 7218,
"dismissed": 7219,
"hms": 7220,
"ban": 7221,
"pine": 7222,
"wrist": 7223,
"atmosphere": 7224,
"voivodeship": 7225,
"bid": 7226,
"timber": 7227,
"##ned": 7228,
"##nan": 7229,
"giants": 7230,
"##ane": 7231,
"cameron": 7232,
"recovery": 7233,
"uss": 7234,
"identical": 7235,
"categories": 7236,
"switched": 7237,
"serbia": 7238,
"laughter": 7239,
"noah": 7240,
"ensemble": 7241,
"therapy": 7242,
"peoples": 7243,
"touching": 7244,
"##off": 7245,
"locally": 7246,
"pearl": 7247,
"platforms": 7248,
"everywhere": 7249,
"ballet": 7250,
"tables": 7251,
"lanka": 7252,
"herbert": 7253,
"outdoor": 7254,
"toured": 7255,
"derek": 7256,
"1883": 7257,
"spaces": 7258,
"contested": 7259,
"swept": 7260,
"1878": 7261,
"exclusive": 7262,
"slight": 7263,
"connections": 7264,
"##dra": 7265,
"winds": 7266,
"prisoner": 7267,
"collective": 7268,
"bangladesh": 7269,
"tube": 7270,
"publicly": 7271,
"wealthy": 7272,
"thai": 7273,
"##ys": 7274,
"isolated": 7275,
"select": 7276,
"##ric": 7277,
"insisted": 7278,
"pen": 7279,
"fortune": 7280,
"ticket": 7281,
"spotted": 7282,
"reportedly": 7283,
"animation": 7284,
"enforcement": 7285,
"tanks": 7286,
"110": 7287,
"decides": 7288,
"wider": 7289,
"lowest": 7290,
"owen": 7291,
"##time": 7292,
"nod": 7293,
"hitting": 7294,
"##hn": 7295,
"gregory": 7296,
"furthermore": 7297,
"magazines": 7298,
"fighters": 7299,
"solutions": 7300,
"##ery": 7301,
"pointing": 7302,
"requested": 7303,
"peru": 7304,
"reed": 7305,
"chancellor": 7306,
"knights": 7307,
"mask": 7308,
"worker": 7309,
"eldest": 7310,
"flames": 7311,
"reduction": 7312,
"1860": 7313,
"volunteers": 7314,
"##tis": 7315,
"reporting": 7316,
"##hl": 7317,
"wire": 7318,
"advisory": 7319,
"endemic": 7320,
"origins": 7321,
"settlers": 7322,
"pursue": 7323,
"knock": 7324,
"consumer": 7325,
"1876": 7326,
"eu": 7327,
"compound": 7328,
"creatures": 7329,
"mansion": 7330,
"sentenced": 7331,
"ivan": 7332,
"deployed": 7333,
"guitars": 7334,
"frowned": 7335,
"involves": 7336,
"mechanism": 7337,
"kilometers": 7338,
"perspective": 7339,
"shops": 7340,
"maps": 7341,
"terminus": 7342,
"duncan": 7343,
"alien": 7344,
"fist": 7345,
"bridges": 7346,
"##pers": 7347,
"heroes": 7348,
"fed": 7349,
"derby": 7350,
"swallowed": 7351,
"##ros": 7352,
"patent": 7353,
"sara": 7354,
"illness": 7355,
"characterized": 7356,
"adventures": 7357,
"slide": 7358,
"hawaii": 7359,
"jurisdiction": 7360,
"##op": 7361,
"organised": 7362,
"##side": 7363,
"adelaide": 7364,
"walks": 7365,
"biology": 7366,
"se": 7367,
"##ties": 7368,
"rogers": 7369,
"swing": 7370,
"tightly": 7371,
"boundaries": 7372,
"##rie": 7373,
"prepare": 7374,
"implementation": 7375,
"stolen": 7376,
"##sha": 7377,
"certified": 7378,
"colombia": 7379,
"edwards": 7380,
"garage": 7381,
"##mm": 7382,
"recalled": 7383,
"##ball": 7384,
"rage": 7385,
"harm": 7386,
"nigeria": 7387,
"breast": 7388,
"##ren": 7389,
"furniture": 7390,
"pupils": 7391,
"settle": 7392,
"##lus": 7393,
"cuba": 7394,
"balls": 7395,
"client": 7396,
"alaska": 7397,
"21st": 7398,
"linear": 7399,
"thrust": 7400,
"celebration": 7401,
"latino": 7402,
"genetic": 7403,
"terror": 7404,
"##cia": 7405,
"##ening": 7406,
"lightning": 7407,
"fee": 7408,
"witness": 7409,
"lodge": 7410,
"establishing": 7411,
"skull": 7412,
"##ique": 7413,
"earning": 7414,
"hood": 7415,
"##ei": 7416,
"rebellion": 7417,
"wang": 7418,
"sporting": 7419,
"warned": 7420,
"missile": 7421,
"devoted": 7422,
"activist": 7423,
"porch": 7424,
"worship": 7425,
"fourteen": 7426,
"package": 7427,
"1871": 7428,
"decorated": 7429,
"##shire": 7430,
"housed": 7431,
"##ock": 7432,
"chess": 7433,
"sailed": 7434,
"doctors": 7435,
"oscar": 7436,
"joan": 7437,
"treat": 7438,
"garcia": 7439,
"harbour": 7440,
"jeremy": 7441,
"##ire": 7442,
"traditions": 7443,
"dominant": 7444,
"jacques": 7445,
"##gon": 7446,
"##wan": 7447,
"relocated": 7448,
"1879": 7449,
"amendment": 7450,
"sized": 7451,
"companion": 7452,
"simultaneously": 7453,
"volleyball": 7454,
"spun": 7455,
"acre": 7456,
"increases": 7457,
"stopping": 7458,
"loves": 7459,
"belongs": 7460,
"affect": 7461,
"drafted": 7462,
"tossed": 7463,
"scout": 7464,
"battles": 7465,
"1875": 7466,
"filming": 7467,
"shoved": 7468,
"munich": 7469,
"tenure": 7470,
"vertical": 7471,
"romance": 7472,
"pc": 7473,
"##cher": 7474,
"argue": 7475,
"##ical": 7476,
"craft": 7477,
"ranging": 7478,
"www": 7479,
"opens": 7480,
"honest": 7481,
"tyler": 7482,
"yesterday": 7483,
"virtual": 7484,
"##let": 7485,
"muslims": 7486,
"reveal": 7487,
"snake": 7488,
"immigrants": 7489,
"radical": 7490,
"screaming": 7491,
"speakers": 7492,
"firing": 7493,
"saving": 7494,
"belonging": 7495,
"ease": 7496,
"lighting": 7497,
"prefecture": 7498,
"blame": 7499,
"farmer": 7500,
"hungry": 7501,
"grows": 7502,
"rubbed": 7503,
"beam": 7504,
"sur": 7505,
"subsidiary": 7506,
"##cha": 7507,
"armenian": 7508,
"sao": 7509,
"dropping": 7510,
"conventional": 7511,
"##fer": 7512,
"microsoft": 7513,
"reply": 7514,
"qualify": 7515,
"spots": 7516,
"1867": 7517,
"sweat": 7518,
"festivals": 7519,
"##ken": 7520,
"immigration": 7521,
"physician": 7522,
"discover": 7523,
"exposure": 7524,
"sandy": 7525,
"explanation": 7526,
"isaac": 7527,
"implemented": 7528,
"##fish": 7529,
"hart": 7530,
"initiated": 7531,
"connect": 7532,
"stakes": 7533,
"presents": 7534,
"heights": 7535,
"householder": 7536,
"pleased": 7537,
"tourist": 7538,
"regardless": 7539,
"slip": 7540,
"closest": 7541,
"##ction": 7542,
"surely": 7543,
"sultan": 7544,
"brings": 7545,
"riley": 7546,
"preparation": 7547,
"aboard": 7548,
"slammed": 7549,
"baptist": 7550,
"experiment": 7551,
"ongoing": 7552,
"interstate": 7553,
"organic": 7554,
"playoffs": 7555,
"##ika": 7556,
"1877": 7557,
"130": 7558,
"##tar": 7559,
"hindu": 7560,
"error": 7561,
"tours": 7562,
"tier": 7563,
"plenty": 7564,
"arrangements": 7565,
"talks": 7566,
"trapped": 7567,
"excited": 7568,
"sank": 7569,
"ho": 7570,
"athens": 7571,
"1872": 7572,
"denver": 7573,
"welfare": 7574,
"suburb": 7575,
"athletes": 7576,
"trick": 7577,
"diverse": 7578,
"belly": 7579,
"exclusively": 7580,
"yelled": 7581,
"1868": 7582,
"##med": 7583,
"conversion": 7584,
"##ette": 7585,
"1874": 7586,
"internationally": 7587,
"computers": 7588,
"conductor": 7589,
"abilities": 7590,
"sensitive": 7591,
"hello": 7592,
"dispute": 7593,
"measured": 7594,
"globe": 7595,
"rocket": 7596,
"prices": 7597,
"amsterdam": 7598,
"flights": 7599,
"tigers": 7600,
"inn": 7601,
"municipalities": 7602,
"emotion": 7603,
"references": 7604,
"3d": 7605,
"##mus": 7606,
"explains": 7607,
"airlines": 7608,
"manufactured": 7609,
"pm": 7610,
"archaeological": 7611,
"1873": 7612,
"interpretation": 7613,
"devon": 7614,
"comment": 7615,
"##ites": 7616,
"settlements": 7617,
"kissing": 7618,
"absolute": 7619,
"improvement": 7620,
"suite": 7621,
"impressed": 7622,
"barcelona": 7623,
"sullivan": 7624,
"jefferson": 7625,
"towers": 7626,
"jesse": 7627,
"julie": 7628,
"##tin": 7629,
"##lu": 7630,
"grandson": 7631,
"hi": 7632,
"gauge": 7633,
"regard": 7634,
"rings": 7635,
"interviews": 7636,
"trace": 7637,
"raymond": 7638,
"thumb": 7639,
"departments": 7640,
"burns": 7641,
"serial": 7642,
"bulgarian": 7643,
"scores": 7644,
"demonstrated": 7645,
"##ix": 7646,
"1866": 7647,
"kyle": 7648,
"alberta": 7649,
"underneath": 7650,
"romanized": 7651,
"##ward": 7652,
"relieved": 7653,
"acquisition": 7654,
"phrase": 7655,
"cliff": 7656,
"reveals": 7657,
"han": 7658,
"cuts": 7659,
"merger": 7660,
"custom": 7661,
"##dar": 7662,
"nee": 7663,
"gilbert": 7664,
"graduation": 7665,
"##nts": 7666,
"assessment": 7667,
"cafe": 7668,
"difficulty": 7669,
"demands": 7670,
"swung": 7671,
"democrat": 7672,
"jennifer": 7673,
"commons": 7674,
"1940s": 7675,
"grove": 7676,
"##yo": 7677,
"completing": 7678,
"focuses": 7679,
"sum": 7680,
"substitute": 7681,
"bearing": 7682,
"stretch": 7683,
"reception": 7684,
"##py": 7685,
"reflected": 7686,
"essentially": 7687,
"destination": 7688,
"pairs": 7689,
"##ched": 7690,
"survival": 7691,
"resource": 7692,
"##bach": 7693,
"promoting": 7694,
"doubles": 7695,
"messages": 7696,
"tear": 7697,
"##down": 7698,
"##fully": 7699,
"parade": 7700,
"florence": 7701,
"harvey": 7702,
"incumbent": 7703,
"partial": 7704,
"framework": 7705,
"900": 7706,
"pedro": 7707,
"frozen": 7708,
"procedure": 7709,
"olivia": 7710,
"controls": 7711,
"##mic": 7712,
"shelter": 7713,
"personally": 7714,
"temperatures": 7715,
"##od": 7716,
"brisbane": 7717,
"tested": 7718,
"sits": 7719,
"marble": 7720,
"comprehensive": 7721,
"oxygen": 7722,
"leonard": 7723,
"##kov": 7724,
"inaugural": 7725,
"iranian": 7726,
"referring": 7727,
"quarters": 7728,
"attitude": 7729,
"##ivity": 7730,
"mainstream": 7731,
"lined": 7732,
"mars": 7733,
"dakota": 7734,
"norfolk": 7735,
"unsuccessful": 7736,
"##°": 7737,
"explosion": 7738,
"helicopter": 7739,
"congressional": 7740,
"##sing": 7741,
"inspector": 7742,
"bitch": 7743,
"seal": 7744,
"departed": 7745,
"divine": 7746,
"##ters": 7747,
"coaching": 7748,
"examination": 7749,
"punishment": 7750,
"manufacturer": 7751,
"sink": 7752,
"columns": 7753,
"unincorporated": 7754,
"signals": 7755,
"nevada": 7756,
"squeezed": 7757,
"dylan": 7758,
"dining": 7759,
"photos": 7760,
"martial": 7761,
"manuel": 7762,
"eighteen": 7763,
"elevator": 7764,
"brushed": 7765,
"plates": 7766,
"ministers": 7767,
"ivy": 7768,
"congregation": 7769,
"##len": 7770,
"slept": 7771,
"specialized": 7772,
"taxes": 7773,
"curve": 7774,
"restricted": 7775,
"negotiations": 7776,
"likes": 7777,
"statistical": 7778,
"arnold": 7779,
"inspiration": 7780,
"execution": 7781,
"bold": 7782,
"intermediate": 7783,
"significance": 7784,
"margin": 7785,
"ruler": 7786,
"wheels": 7787,
"gothic": 7788,
"intellectual": 7789,
"dependent": 7790,
"listened": 7791,
"eligible": 7792,
"buses": 7793,
"widow": 7794,
"syria": 7795,
"earn": 7796,
"cincinnati": 7797,
"collapsed": 7798,
"recipient": 7799,
"secrets": 7800,
"accessible": 7801,
"philippine": 7802,
"maritime": 7803,
"goddess": 7804,
"clerk": 7805,
"surrender": 7806,
"breaks": 7807,
"playoff": 7808,
"database": 7809,
"##ified": 7810,
"##lon": 7811,
"ideal": 7812,
"beetle": 7813,
"aspect": 7814,
"soap": 7815,
"regulation": 7816,
"strings": 7817,
"expand": 7818,
"anglo": 7819,
"shorter": 7820,
"crosses": 7821,
"retreat": 7822,
"tough": 7823,
"coins": 7824,
"wallace": 7825,
"directions": 7826,
"pressing": 7827,
"##oon": 7828,
"shipping": 7829,
"locomotives": 7830,
"comparison": 7831,
"topics": 7832,
"nephew": 7833,
"##mes": 7834,
"distinction": 7835,
"honors": 7836,
"travelled": 7837,
"sierra": 7838,
"ibn": 7839,
"##over": 7840,
"fortress": 7841,
"sa": 7842,
"recognised": 7843,
"carved": 7844,
"1869": 7845,
"clients": 7846,
"##dan": 7847,
"intent": 7848,
"##mar": 7849,
"coaches": 7850,
"describing": 7851,
"bread": 7852,
"##ington": 7853,
"beaten": 7854,
"northwestern": 7855,
"##ona": 7856,
"merit": 7857,
"youtube": 7858,
"collapse": 7859,
"challenges": 7860,
"em": 7861,
"historians": 7862,
"objective": 7863,
"submitted": 7864,
"virus": 7865,
"attacking": 7866,
"drake": 7867,
"assume": 7868,
"##ere": 7869,
"diseases": 7870,
"marc": 7871,
"stem": 7872,
"leeds": 7873,
"##cus": 7874,
"##ab": 7875,
"farming": 7876,
"glasses": 7877,
"##lock": 7878,
"visits": 7879,
"nowhere": 7880,
"fellowship": 7881,
"relevant": 7882,
"carries": 7883,
"restaurants": 7884,
"experiments": 7885,
"101": 7886,
"constantly": 7887,
"bases": 7888,
"targets": 7889,
"shah": 7890,
"tenth": 7891,
"opponents": 7892,
"verse": 7893,
"territorial": 7894,
"##ira": 7895,
"writings": 7896,
"corruption": 7897,
"##hs": 7898,
"instruction": 7899,
"inherited": 7900,
"reverse": 7901,
"emphasis": 7902,
"##vic": 7903,
"employee": 7904,
"arch": 7905,
"keeps": 7906,
"rabbi": 7907,
"watson": 7908,
"payment": 7909,
"uh": 7910,
"##ala": 7911,
"nancy": 7912,
"##tre": 7913,
"venice": 7914,
"fastest": 7915,
"sexy": 7916,
"banned": 7917,
"adrian": 7918,
"properly": 7919,
"ruth": 7920,
"touchdown": 7921,
"dollar": 7922,
"boards": 7923,
"metre": 7924,
"circles": 7925,
"edges": 7926,
"favour": 7927,
"comments": 7928,
"ok": 7929,
"travels": 7930,
"liberation": 7931,
"scattered": 7932,
"firmly": 7933,
"##ular": 7934,
"holland": 7935,
"permitted": 7936,
"diesel": 7937,
"kenya": 7938,
"den": 7939,
"originated": 7940,
"##ral": 7941,
"demons": 7942,
"resumed": 7943,
"dragged": 7944,
"rider": 7945,
"##rus": 7946,
"servant": 7947,
"blinked": 7948,
"extend": 7949,
"torn": 7950,
"##ias": 7951,
"##sey": 7952,
"input": 7953,
"meal": 7954,
"everybody": 7955,
"cylinder": 7956,
"kinds": 7957,
"camps": 7958,
"##fe": 7959,
"bullet": 7960,
"logic": 7961,
"##wn": 7962,
"croatian": 7963,
"evolved": 7964,
"healthy": 7965,
"fool": 7966,
"chocolate": 7967,
"wise": 7968,
"preserve": 7969,
"pradesh": 7970,
"##ess": 7971,
"respective": 7972,
"1850": 7973,
"##ew": 7974,
"chicken": 7975,
"artificial": 7976,
"gross": 7977,
"corresponding": 7978,
"convicted": 7979,
"cage": 7980,
"caroline": 7981,
"dialogue": 7982,
"##dor": 7983,
"narrative": 7984,
"stranger": 7985,
"mario": 7986,
"br": 7987,
"christianity": 7988,
"failing": 7989,
"trent": 7990,
"commanding": 7991,
"buddhist": 7992,
"1848": 7993,
"maurice": 7994,
"focusing": 7995,
"yale": 7996,
"bike": 7997,
"altitude": 7998,
"##ering": 7999,
"mouse": 8000,
"revised": 8001,
"##sley": 8002,
"veteran": 8003,
"##ig": 8004,
"pulls": 8005,
"theology": 8006,
"crashed": 8007,
"campaigns": 8008,
"legion": 8009,
"##ability": 8010,
"drag": 8011,
"excellence": 8012,
"customer": 8013,
"cancelled": 8014,
"intensity": 8015,
"excuse": 8016,
"##lar": 8017,
"liga": 8018,
"participating": 8019,
"contributing": 8020,
"printing": 8021,
"##burn": 8022,
"variable": 8023,
"##rk": 8024,
"curious": 8025,
"bin": 8026,
"legacy": 8027,
"renaissance": 8028,
"##my": 8029,
"symptoms": 8030,
"binding": 8031,
"vocalist": 8032,
"dancer": 8033,
"##nie": 8034,
"grammar": 8035,
"gospel": 8036,
"democrats": 8037,
"ya": 8038,
"enters": 8039,
"sc": 8040,
"diplomatic": 8041,
"hitler": 8042,
"##ser": 8043,
"clouds": 8044,
"mathematical": 8045,
"quit": 8046,
"defended": 8047,
"oriented": 8048,
"##heim": 8049,
"fundamental": 8050,
"hardware": 8051,
"impressive": 8052,
"equally": 8053,
"convince": 8054,
"confederate": 8055,
"guilt": 8056,
"chuck": 8057,
"sliding": 8058,
"##ware": 8059,
"magnetic": 8060,
"narrowed": 8061,
"petersburg": 8062,
"bulgaria": 8063,
"otto": 8064,
"phd": 8065,
"skill": 8066,
"##ama": 8067,
"reader": 8068,
"hopes": 8069,
"pitcher": 8070,
"reservoir": 8071,
"hearts": 8072,
"automatically": 8073,
"expecting": 8074,
"mysterious": 8075,
"bennett": 8076,
"extensively": 8077,
"imagined": 8078,
"seeds": 8079,
"monitor": 8080,
"fix": 8081,
"##ative": 8082,
"journalism": 8083,
"struggling": 8084,
"signature": 8085,
"ranch": 8086,
"encounter": 8087,
"photographer": 8088,
"observation": 8089,
"protests": 8090,
"##pin": 8091,
"influences": 8092,
"##hr": 8093,
"calendar": 8094,
"##all": 8095,
"cruz": 8096,
"croatia": 8097,
"locomotive": 8098,
"hughes": 8099,
"naturally": 8100,
"shakespeare": 8101,
"basement": 8102,
"hook": 8103,
"uncredited": 8104,
"faded": 8105,
"theories": 8106,
"approaches": 8107,
"dare": 8108,
"phillips": 8109,
"filling": 8110,
"fury": 8111,
"obama": 8112,
"##ain": 8113,
"efficient": 8114,
"arc": 8115,
"deliver": 8116,
"min": 8117,
"raid": 8118,
"breeding": 8119,
"inducted": 8120,
"leagues": 8121,
"efficiency": 8122,
"axis": 8123,
"montana": 8124,
"eagles": 8125,
"##ked": 8126,
"supplied": 8127,
"instructions": 8128,
"karen": 8129,
"picking": 8130,
"indicating": 8131,
"trap": 8132,
"anchor": 8133,
"practically": 8134,
"christians": 8135,
"tomb": 8136,
"vary": 8137,
"occasional": 8138,
"electronics": 8139,
"lords": 8140,
"readers": 8141,
"newcastle": 8142,
"faint": 8143,
"innovation": 8144,
"collect": 8145,
"situations": 8146,
"engagement": 8147,
"160": 8148,
"claude": 8149,
"mixture": 8150,
"##feld": 8151,
"peer": 8152,
"tissue": 8153,
"logo": 8154,
"lean": 8155,
"##ration": 8156,
"°f": 8157,
"floors": 8158,
"##ven": 8159,
"architects": 8160,
"reducing": 8161,
"##our": 8162,
"##ments": 8163,
"rope": 8164,
"1859": 8165,
"ottawa": 8166,
"##har": 8167,
"samples": 8168,
"banking": 8169,
"declaration": 8170,
"proteins": 8171,
"resignation": 8172,
"francois": 8173,
"saudi": 8174,
"advocate": 8175,
"exhibited": 8176,
"armor": 8177,
"twins": 8178,
"divorce": 8179,
"##ras": 8180,
"abraham": 8181,
"reviewed": 8182,
"jo": 8183,
"temporarily": 8184,
"matrix": 8185,
"physically": 8186,
"pulse": 8187,
"curled": 8188,
"##ena": 8189,
"difficulties": 8190,
"bengal": 8191,
"usage": 8192,
"##ban": 8193,
"annie": 8194,
"riders": 8195,
"certificate": 8196,
"##pi": 8197,
"holes": 8198,
"warsaw": 8199,
"distinctive": 8200,
"jessica": 8201,
"##mon": 8202,
"mutual": 8203,
"1857": 8204,
"customs": 8205,
"circular": 8206,
"eugene": 8207,
"removal": 8208,
"loaded": 8209,
"mere": 8210,
"vulnerable": 8211,
"depicted": 8212,
"generations": 8213,
"dame": 8214,
"heir": 8215,
"enormous": 8216,
"lightly": 8217,
"climbing": 8218,
"pitched": 8219,
"lessons": 8220,
"pilots": 8221,
"nepal": 8222,
"ram": 8223,
"google": 8224,
"preparing": 8225,
"brad": 8226,
"louise": 8227,
"renowned": 8228,
"##₂": 8229,
"liam": 8230,
"##ably": 8231,
"plaza": 8232,
"shaw": 8233,
"sophie": 8234,
"brilliant": 8235,
"bills": 8236,
"##bar": 8237,
"##nik": 8238,
"fucking": 8239,
"mainland": 8240,
"server": 8241,
"pleasant": 8242,
"seized": 8243,
"veterans": 8244,
"jerked": 8245,
"fail": 8246,
"beta": 8247,
"brush": 8248,
"radiation": 8249,
"stored": 8250,
"warmth": 8251,
"southeastern": 8252,
"nate": 8253,
"sin": 8254,
"raced": 8255,
"berkeley": 8256,
"joke": 8257,
"athlete": 8258,
"designation": 8259,
"trunk": 8260,
"##low": 8261,
"roland": 8262,
"qualification": 8263,
"archives": 8264,
"heels": 8265,
"artwork": 8266,
"receives": 8267,
"judicial": 8268,
"reserves": 8269,
"##bed": 8270,
"woke": 8271,
"installation": 8272,
"abu": 8273,
"floating": 8274,
"fake": 8275,
"lesser": 8276,
"excitement": 8277,
"interface": 8278,
"concentrated": 8279,
"addressed": 8280,
"characteristic": 8281,
"amanda": 8282,
"saxophone": 8283,
"monk": 8284,
"auto": 8285,
"##bus": 8286,
"releasing": 8287,
"egg": 8288,
"dies": 8289,
"interaction": 8290,
"defender": 8291,
"ce": 8292,
"outbreak": 8293,
"glory": 8294,
"loving": 8295,
"##bert": 8296,
"sequel": 8297,
"consciousness": 8298,
"http": 8299,
"awake": 8300,
"ski": 8301,
"enrolled": 8302,
"##ress": 8303,
"handling": 8304,
"rookie": 8305,
"brow": 8306,
"somebody": 8307,
"biography": 8308,
"warfare": 8309,
"amounts": 8310,
"contracts": 8311,
"presentation": 8312,
"fabric": 8313,
"dissolved": 8314,
"challenged": 8315,
"meter": 8316,
"psychological": 8317,
"lt": 8318,
"elevated": 8319,
"rally": 8320,
"accurate": 8321,
"##tha": 8322,
"hospitals": 8323,
"undergraduate": 8324,
"specialist": 8325,
"venezuela": 8326,
"exhibit": 8327,
"shed": 8328,
"nursing": 8329,
"protestant": 8330,
"fluid": 8331,
"structural": 8332,
"footage": 8333,
"jared": 8334,
"consistent": 8335,
"prey": 8336,
"##ska": 8337,
"succession": 8338,
"reflect": 8339,
"exile": 8340,
"lebanon": 8341,
"wiped": 8342,
"suspect": 8343,
"shanghai": 8344,
"resting": 8345,
"integration": 8346,
"preservation": 8347,
"marvel": 8348,
"variant": 8349,
"pirates": 8350,
"sheep": 8351,
"rounded": 8352,
"capita": 8353,
"sailing": 8354,
"colonies": 8355,
"manuscript": 8356,
"deemed": 8357,
"variations": 8358,
"clarke": 8359,
"functional": 8360,
"emerging": 8361,
"boxing": 8362,
"relaxed": 8363,
"curse": 8364,
"azerbaijan": 8365,
"heavyweight": 8366,
"nickname": 8367,
"editorial": 8368,
"rang": 8369,
"grid": 8370,
"tightened": 8371,
"earthquake": 8372,
"flashed": 8373,
"miguel": 8374,
"rushing": 8375,
"##ches": 8376,
"improvements": 8377,
"boxes": 8378,
"brooks": 8379,
"180": 8380,
"consumption": 8381,
"molecular": 8382,
"felix": 8383,
"societies": 8384,
"repeatedly": 8385,
"variation": 8386,
"aids": 8387,
"civic": 8388,
"graphics": 8389,
"professionals": 8390,
"realm": 8391,
"autonomous": 8392,
"receiver": 8393,
"delayed": 8394,
"workshop": 8395,
"militia": 8396,
"chairs": 8397,
"trump": 8398,
"canyon": 8399,
"##point": 8400,
"harsh": 8401,
"extending": 8402,
"lovely": 8403,
"happiness": 8404,
"##jan": 8405,
"stake": 8406,
"eyebrows": 8407,
"embassy": 8408,
"wellington": 8409,
"hannah": 8410,
"##ella": 8411,
"sony": 8412,
"corners": 8413,
"bishops": 8414,
"swear": 8415,
"cloth": 8416,
"contents": 8417,
"xi": 8418,
"namely": 8419,
"commenced": 8420,
"1854": 8421,
"stanford": 8422,
"nashville": 8423,
"courage": 8424,
"graphic": 8425,
"commitment": 8426,
"garrison": 8427,
"##bin": 8428,
"hamlet": 8429,
"clearing": 8430,
"rebels": 8431,
"attraction": 8432,
"literacy": 8433,
"cooking": 8434,
"ruins": 8435,
"temples": 8436,
"jenny": 8437,
"humanity": 8438,
"celebrate": 8439,
"hasn": 8440,
"freight": 8441,
"sixty": 8442,
"rebel": 8443,
"bastard": 8444,
"##art": 8445,
"newton": 8446,
"##ada": 8447,
"deer": 8448,
"##ges": 8449,
"##ching": 8450,
"smiles": 8451,
"delaware": 8452,
"singers": 8453,
"##ets": 8454,
"approaching": 8455,
"assists": 8456,
"flame": 8457,
"##ph": 8458,
"boulevard": 8459,
"barrel": 8460,
"planted": 8461,
"##ome": 8462,
"pursuit": 8463,
"##sia": 8464,
"consequences": 8465,
"posts": 8466,
"shallow": 8467,
"invitation": 8468,
"rode": 8469,
"depot": 8470,
"ernest": 8471,
"kane": 8472,
"rod": 8473,
"concepts": 8474,
"preston": 8475,
"topic": 8476,
"chambers": 8477,
"striking": 8478,
"blast": 8479,
"arrives": 8480,
"descendants": 8481,
"montgomery": 8482,
"ranges": 8483,
"worlds": 8484,
"##lay": 8485,
"##ari": 8486,
"span": 8487,
"chaos": 8488,
"praise": 8489,
"##ag": 8490,
"fewer": 8491,
"1855": 8492,
"sanctuary": 8493,
"mud": 8494,
"fbi": 8495,
"##ions": 8496,
"programmes": 8497,
"maintaining": 8498,
"unity": 8499,
"harper": 8500,
"bore": 8501,
"handsome": 8502,
"closure": 8503,
"tournaments": 8504,
"thunder": 8505,
"nebraska": 8506,
"linda": 8507,
"facade": 8508,
"puts": 8509,
"satisfied": 8510,
"argentine": 8511,
"dale": 8512,
"cork": 8513,
"dome": 8514,
"panama": 8515,
"##yl": 8516,
"1858": 8517,
"tasks": 8518,
"experts": 8519,
"##ates": 8520,
"feeding": 8521,
"equation": 8522,
"##las": 8523,
"##ida": 8524,
"##tu": 8525,
"engage": 8526,
"bryan": 8527,
"##ax": 8528,
"um": 8529,
"quartet": 8530,
"melody": 8531,
"disbanded": 8532,
"sheffield": 8533,
"blocked": 8534,
"gasped": 8535,
"delay": 8536,
"kisses": 8537,
"maggie": 8538,
"connects": 8539,
"##non": 8540,
"sts": 8541,
"poured": 8542,
"creator": 8543,
"publishers": 8544,
"##we": 8545,
"guided": 8546,
"ellis": 8547,
"extinct": 8548,
"hug": 8549,
"gaining": 8550,
"##ord": 8551,
"complicated": 8552,
"##bility": 8553,
"poll": 8554,
"clenched": 8555,
"investigate": 8556,
"##use": 8557,
"thereby": 8558,
"quantum": 8559,
"spine": 8560,
"cdp": 8561,
"humor": 8562,
"kills": 8563,
"administered": 8564,
"semifinals": 8565,
"##du": 8566,
"encountered": 8567,
"ignore": 8568,
"##bu": 8569,
"commentary": 8570,
"##maker": 8571,
"bother": 8572,
"roosevelt": 8573,
"140": 8574,
"plains": 8575,
"halfway": 8576,
"flowing": 8577,
"cultures": 8578,
"crack": 8579,
"imprisoned": 8580,
"neighboring": 8581,
"airline": 8582,
"##ses": 8583,
"##view": 8584,
"##mate": 8585,
"##ec": 8586,
"gather": 8587,
"wolves": 8588,
"marathon": 8589,
"transformed": 8590,
"##ill": 8591,
"cruise": 8592,
"organisations": 8593,
"carol": 8594,
"punch": 8595,
"exhibitions": 8596,
"numbered": 8597,
"alarm": 8598,
"ratings": 8599,
"daddy": 8600,
"silently": 8601,
"##stein": 8602,
"queens": 8603,
"colours": 8604,
"impression": 8605,
"guidance": 8606,
"liu": 8607,
"tactical": 8608,
"##rat": 8609,
"marshal": 8610,
"della": 8611,
"arrow": 8612,
"##ings": 8613,
"rested": 8614,
"feared": 8615,
"tender": 8616,
"owns": 8617,
"bitter": 8618,
"advisor": 8619,
"escort": 8620,
"##ides": 8621,
"spare": 8622,
"farms": 8623,
"grants": 8624,
"##ene": 8625,
"dragons": 8626,
"encourage": 8627,
"colleagues": 8628,
"cameras": 8629,
"##und": 8630,
"sucked": 8631,
"pile": 8632,
"spirits": 8633,
"prague": 8634,
"statements": 8635,
"suspension": 8636,
"landmark": 8637,
"fence": 8638,
"torture": 8639,
"recreation": 8640,
"bags": 8641,
"permanently": 8642,
"survivors": 8643,
"pond": 8644,
"spy": 8645,
"predecessor": 8646,
"bombing": 8647,
"coup": 8648,
"##og": 8649,
"protecting": 8650,
"transformation": 8651,
"glow": 8652,
"##lands": 8653,
"##book": 8654,
"dug": 8655,
"priests": 8656,
"andrea": 8657,
"feat": 8658,
"barn": 8659,
"jumping": 8660,
"##chen": 8661,
"##ologist": 8662,
"##con": 8663,
"casualties": 8664,
"stern": 8665,
"auckland": 8666,
"pipe": 8667,
"serie": 8668,
"revealing": 8669,
"ba": 8670,
"##bel": 8671,
"trevor": 8672,
"mercy": 8673,
"spectrum": 8674,
"yang": 8675,
"consist": 8676,
"governing": 8677,
"collaborated": 8678,
"possessed": 8679,
"epic": 8680,
"comprises": 8681,
"blew": 8682,
"shane": 8683,
"##ack": 8684,
"lopez": 8685,
"honored": 8686,
"magical": 8687,
"sacrifice": 8688,
"judgment": 8689,
"perceived": 8690,
"hammer": 8691,
"mtv": 8692,
"baronet": 8693,
"tune": 8694,
"das": 8695,
"missionary": 8696,
"sheets": 8697,
"350": 8698,
"neutral": 8699,
"oral": 8700,
"threatening": 8701,
"attractive": 8702,
"shade": 8703,
"aims": 8704,
"seminary": 8705,
"##master": 8706,
"estates": 8707,
"1856": 8708,
"michel": 8709,
"wounds": 8710,
"refugees": 8711,
"manufacturers": 8712,
"##nic": 8713,
"mercury": 8714,
"syndrome": 8715,
"porter": 8716,
"##iya": 8717,
"##din": 8718,
"hamburg": 8719,
"identification": 8720,
"upstairs": 8721,
"purse": 8722,
"widened": 8723,
"pause": 8724,
"cared": 8725,
"breathed": 8726,
"affiliate": 8727,
"santiago": 8728,
"prevented": 8729,
"celtic": 8730,
"fisher": 8731,
"125": 8732,
"recruited": 8733,
"byzantine": 8734,
"reconstruction": 8735,
"farther": 8736,
"##mp": 8737,
"diet": 8738,
"sake": 8739,
"au": 8740,
"spite": 8741,
"sensation": 8742,
"##ert": 8743,
"blank": 8744,
"separation": 8745,
"105": 8746,
"##hon": 8747,
"vladimir": 8748,
"armies": 8749,
"anime": 8750,
"##lie": 8751,
"accommodate": 8752,
"orbit": 8753,
"cult": 8754,
"sofia": 8755,
"archive": 8756,
"##ify": 8757,
"##box": 8758,
"founders": 8759,
"sustained": 8760,
"disorder": 8761,
"honours": 8762,
"northeastern": 8763,
"mia": 8764,
"crops": 8765,
"violet": 8766,
"threats": 8767,
"blanket": 8768,
"fires": 8769,
"canton": 8770,
"followers": 8771,
"southwestern": 8772,
"prototype": 8773,
"voyage": 8774,
"assignment": 8775,
"altered": 8776,
"moderate": 8777,
"protocol": 8778,
"pistol": 8779,
"##eo": 8780,
"questioned": 8781,
"brass": 8782,
"lifting": 8783,
"1852": 8784,
"math": 8785,
"authored": 8786,
"##ual": 8787,
"doug": 8788,
"dimensional": 8789,
"dynamic": 8790,
"##san": 8791,
"1851": 8792,
"pronounced": 8793,
"grateful": 8794,
"quest": 8795,
"uncomfortable": 8796,
"boom": 8797,
"presidency": 8798,
"stevens": 8799,
"relating": 8800,
"politicians": 8801,
"chen": 8802,
"barrier": 8803,
"quinn": 8804,
"diana": 8805,
"mosque": 8806,
"tribal": 8807,
"cheese": 8808,
"palmer": 8809,
"portions": 8810,
"sometime": 8811,
"chester": 8812,
"treasure": 8813,
"wu": 8814,
"bend": 8815,
"download": 8816,
"millions": 8817,
"reforms": 8818,
"registration": 8819,
"##osa": 8820,
"consequently": 8821,
"monitoring": 8822,
"ate": 8823,
"preliminary": 8824,
"brandon": 8825,
"invented": 8826,
"ps": 8827,
"eaten": 8828,
"exterior": 8829,
"intervention": 8830,
"ports": 8831,
"documented": 8832,
"log": 8833,
"displays": 8834,
"lecture": 8835,
"sally": 8836,
"favourite": 8837,
"##itz": 8838,
"vermont": 8839,
"lo": 8840,
"invisible": 8841,
"isle": 8842,
"breed": 8843,
"##ator": 8844,
"journalists": 8845,
"relay": 8846,
"speaks": 8847,
"backward": 8848,
"explore": 8849,
"midfielder": 8850,
"actively": 8851,
"stefan": 8852,
"procedures": 8853,
"cannon": 8854,
"blond": 8855,
"kenneth": 8856,
"centered": 8857,
"servants": 8858,
"chains": 8859,
"libraries": 8860,
"malcolm": 8861,
"essex": 8862,
"henri": 8863,
"slavery": 8864,
"##hal": 8865,
"facts": 8866,
"fairy": 8867,
"coached": 8868,
"cassie": 8869,
"cats": 8870,
"washed": 8871,
"cop": 8872,
"##fi": 8873,
"announcement": 8874,
"item": 8875,
"2000s": 8876,
"vinyl": 8877,
"activated": 8878,
"marco": 8879,
"frontier": 8880,
"growled": 8881,
"curriculum": 8882,
"##das": 8883,
"loyal": 8884,
"accomplished": 8885,
"leslie": 8886,
"ritual": 8887,
"kenny": 8888,
"##00": 8889,
"vii": 8890,
"napoleon": 8891,
"hollow": 8892,
"hybrid": 8893,
"jungle": 8894,
"stationed": 8895,
"friedrich": 8896,
"counted": 8897,
"##ulated": 8898,
"platinum": 8899,
"theatrical": 8900,
"seated": 8901,
"col": 8902,
"rubber": 8903,
"glen": 8904,
"1840": 8905,
"diversity": 8906,
"healing": 8907,
"extends": 8908,
"id": 8909,
"provisions": 8910,
"administrator": 8911,
"columbus": 8912,
"##oe": 8913,
"tributary": 8914,
"te": 8915,
"assured": 8916,
"org": 8917,
"##uous": 8918,
"prestigious": 8919,
"examined": 8920,
"lectures": 8921,
"grammy": 8922,
"ronald": 8923,
"associations": 8924,
"bailey": 8925,
"allan": 8926,
"essays": 8927,
"flute": 8928,
"believing": 8929,
"consultant": 8930,
"proceedings": 8931,
"travelling": 8932,
"1853": 8933,
"kit": 8934,
"kerala": 8935,
"yugoslavia": 8936,
"buddy": 8937,
"methodist": 8938,
"##ith": 8939,
"burial": 8940,
"centres": 8941,
"batman": 8942,
"##nda": 8943,
"discontinued": 8944,
"bo": 8945,
"dock": 8946,
"stockholm": 8947,
"lungs": 8948,
"severely": 8949,
"##nk": 8950,
"citing": 8951,
"manga": 8952,
"##ugh": 8953,
"steal": 8954,
"mumbai": 8955,
"iraqi": 8956,
"robot": 8957,
"celebrity": 8958,
"bride": 8959,
"broadcasts": 8960,
"abolished": 8961,
"pot": 8962,
"joel": 8963,
"overhead": 8964,
"franz": 8965,
"packed": 8966,
"reconnaissance": 8967,
"johann": 8968,
"acknowledged": 8969,
"introduce": 8970,
"handled": 8971,
"doctorate": 8972,
"developments": 8973,
"drinks": 8974,
"alley": 8975,
"palestine": 8976,
"##nis": 8977,
"##aki": 8978,
"proceeded": 8979,
"recover": 8980,
"bradley": 8981,
"grain": 8982,
"patch": 8983,
"afford": 8984,
"infection": 8985,
"nationalist": 8986,
"legendary": 8987,
"##ath": 8988,
"interchange": 8989,
"virtually": 8990,
"gen": 8991,
"gravity": 8992,
"exploration": 8993,
"amber": 8994,
"vital": 8995,
"wishes": 8996,
"powell": 8997,
"doctrine": 8998,
"elbow": 8999,
"screenplay": 9000,
"##bird": 9001,
"contribute": 9002,
"indonesian": 9003,
"pet": 9004,
"creates": 9005,
"##com": 9006,
"enzyme": 9007,
"kylie": 9008,
"discipline": 9009,
"drops": 9010,
"manila": 9011,
"hunger": 9012,
"##ien": 9013,
"layers": 9014,
"suffer": 9015,
"fever": 9016,
"bits": 9017,
"monica": 9018,
"keyboard": 9019,
"manages": 9020,
"##hood": 9021,
"searched": 9022,
"appeals": 9023,
"##bad": 9024,
"testament": 9025,
"grande": 9026,
"reid": 9027,
"##war": 9028,
"beliefs": 9029,
"congo": 9030,
"##ification": 9031,
"##dia": 9032,
"si": 9033,
"requiring": 9034,
"##via": 9035,
"casey": 9036,
"1849": 9037,
"regret": 9038,
"streak": 9039,
"rape": 9040,
"depends": 9041,
"syrian": 9042,
"sprint": 9043,
"pound": 9044,
"tourists": 9045,
"upcoming": 9046,
"pub": 9047,
"##xi": 9048,
"tense": 9049,
"##els": 9050,
"practiced": 9051,
"echo": 9052,
"nationwide": 9053,
"guild": 9054,
"motorcycle": 9055,
"liz": 9056,
"##zar": 9057,
"chiefs": 9058,
"desired": 9059,
"elena": 9060,
"bye": 9061,
"precious": 9062,
"absorbed": 9063,
"relatives": 9064,
"booth": 9065,
"pianist": 9066,
"##mal": 9067,
"citizenship": 9068,
"exhausted": 9069,
"wilhelm": 9070,
"##ceae": 9071,
"##hed": 9072,
"noting": 9073,
"quarterback": 9074,
"urge": 9075,
"hectares": 9076,
"##gue": 9077,
"ace": 9078,
"holly": 9079,
"##tal": 9080,
"blonde": 9081,
"davies": 9082,
"parked": 9083,
"sustainable": 9084,
"stepping": 9085,
"twentieth": 9086,
"airfield": 9087,
"galaxy": 9088,
"nest": 9089,
"chip": 9090,
"##nell": 9091,
"tan": 9092,
"shaft": 9093,
"paulo": 9094,
"requirement": 9095,
"##zy": 9096,
"paradise": 9097,
"tobacco": 9098,
"trans": 9099,
"renewed": 9100,
"vietnamese": 9101,
"##cker": 9102,
"##ju": 9103,
"suggesting": 9104,
"catching": 9105,
"holmes": 9106,
"enjoying": 9107,
"md": 9108,
"trips": 9109,
"colt": 9110,
"holder": 9111,
"butterfly": 9112,
"nerve": 9113,
"reformed": 9114,
"cherry": 9115,
"bowling": 9116,
"trailer": 9117,
"carriage": 9118,
"goodbye": 9119,
"appreciate": 9120,
"toy": 9121,
"joshua": 9122,
"interactive": 9123,
"enabled": 9124,
"involve": 9125,
"##kan": 9126,
"collar": 9127,
"determination": 9128,
"bunch": 9129,
"facebook": 9130,
"recall": 9131,
"shorts": 9132,
"superintendent": 9133,
"episcopal": 9134,
"frustration": 9135,
"giovanni": 9136,
"nineteenth": 9137,
"laser": 9138,
"privately": 9139,
"array": 9140,
"circulation": 9141,
"##ovic": 9142,
"armstrong": 9143,
"deals": 9144,
"painful": 9145,
"permit": 9146,
"discrimination": 9147,
"##wi": 9148,
"aires": 9149,
"retiring": 9150,
"cottage": 9151,
"ni": 9152,
"##sta": 9153,
"horizon": 9154,
"ellen": 9155,
"jamaica": 9156,
"ripped": 9157,
"fernando": 9158,
"chapters": 9159,
"playstation": 9160,
"patron": 9161,
"lecturer": 9162,
"navigation": 9163,
"behaviour": 9164,
"genes": 9165,
"georgian": 9166,
"export": 9167,
"solomon": 9168,
"rivals": 9169,
"swift": 9170,
"seventeen": 9171,
"rodriguez": 9172,
"princeton": 9173,
"independently": 9174,
"sox": 9175,
"1847": 9176,
"arguing": 9177,
"entity": 9178,
"casting": 9179,
"hank": 9180,
"criteria": 9181,
"oakland": 9182,
"geographic": 9183,
"milwaukee": 9184,
"reflection": 9185,
"expanding": 9186,
"conquest": 9187,
"dubbed": 9188,
"##tv": 9189,
"halt": 9190,
"brave": 9191,
"brunswick": 9192,
"doi": 9193,
"arched": 9194,
"curtis": 9195,
"divorced": 9196,
"predominantly": 9197,
"somerset": 9198,
"streams": 9199,
"ugly": 9200,
"zoo": 9201,
"horrible": 9202,
"curved": 9203,
"buenos": 9204,
"fierce": 9205,
"dictionary": 9206,
"vector": 9207,
"theological": 9208,
"unions": 9209,
"handful": 9210,
"stability": 9211,
"chan": 9212,
"punjab": 9213,
"segments": 9214,
"##lly": 9215,
"altar": 9216,
"ignoring": 9217,
"gesture": 9218,
"monsters": 9219,
"pastor": 9220,
"##stone": 9221,
"thighs": 9222,
"unexpected": 9223,
"operators": 9224,
"abruptly": 9225,
"coin": 9226,
"compiled": 9227,
"associates": 9228,
"improving": 9229,
"migration": 9230,
"pin": 9231,
"##ose": 9232,
"compact": 9233,
"collegiate": 9234,
"reserved": 9235,
"##urs": 9236,
"quarterfinals": 9237,
"roster": 9238,
"restore": 9239,
"assembled": 9240,
"hurry": 9241,
"oval": 9242,
"##cies": 9243,
"1846": 9244,
"flags": 9245,
"martha": 9246,
"##del": 9247,
"victories": 9248,
"sharply": 9249,
"##rated": 9250,
"argues": 9251,
"deadly": 9252,
"neo": 9253,
"drawings": 9254,
"symbols": 9255,
"performer": 9256,
"##iel": 9257,
"griffin": 9258,
"restrictions": 9259,
"editing": 9260,
"andrews": 9261,
"java": 9262,
"journals": 9263,
"arabia": 9264,
"compositions": 9265,
"dee": 9266,
"pierce": 9267,
"removing": 9268,
"hindi": 9269,
"casino": 9270,
"runway": 9271,
"civilians": 9272,
"minds": 9273,
"nasa": 9274,
"hotels": 9275,
"##zation": 9276,
"refuge": 9277,
"rent": 9278,
"retain": 9279,
"potentially": 9280,
"conferences": 9281,
"suburban": 9282,
"conducting": 9283,
"##tto": 9284,
"##tions": 9285,
"##tle": 9286,
"descended": 9287,
"massacre": 9288,
"##cal": 9289,
"ammunition": 9290,
"terrain": 9291,
"fork": 9292,
"souls": 9293,
"counts": 9294,
"chelsea": 9295,
"durham": 9296,
"drives": 9297,
"cab": 9298,
"##bank": 9299,
"perth": 9300,
"realizing": 9301,
"palestinian": 9302,
"finn": 9303,
"simpson": 9304,
"##dal": 9305,
"betty": 9306,
"##ule": 9307,
"moreover": 9308,
"particles": 9309,
"cardinals": 9310,
"tent": 9311,
"evaluation": 9312,
"extraordinary": 9313,
"##oid": 9314,
"inscription": 9315,
"##works": 9316,
"wednesday": 9317,
"chloe": 9318,
"maintains": 9319,
"panels": 9320,
"ashley": 9321,
"trucks": 9322,
"##nation": 9323,
"cluster": 9324,
"sunlight": 9325,
"strikes": 9326,
"zhang": 9327,
"##wing": 9328,
"dialect": 9329,
"canon": 9330,
"##ap": 9331,
"tucked": 9332,
"##ws": 9333,
"collecting": 9334,
"##mas": 9335,
"##can": 9336,
"##sville": 9337,
"maker": 9338,
"quoted": 9339,
"evan": 9340,
"franco": 9341,
"aria": 9342,
"buying": 9343,
"cleaning": 9344,
"eva": 9345,
"closet": 9346,
"provision": 9347,
"apollo": 9348,
"clinic": 9349,
"rat": 9350,
"##ez": 9351,
"necessarily": 9352,
"ac": 9353,
"##gle": 9354,
"##ising": 9355,
"venues": 9356,
"flipped": 9357,
"cent": 9358,
"spreading": 9359,
"trustees": 9360,
"checking": 9361,
"authorized": 9362,
"##sco": 9363,
"disappointed": 9364,
"##ado": 9365,
"notion": 9366,
"duration": 9367,
"trumpet": 9368,
"hesitated": 9369,
"topped": 9370,
"brussels": 9371,
"rolls": 9372,
"theoretical": 9373,
"hint": 9374,
"define": 9375,
"aggressive": 9376,
"repeat": 9377,
"wash": 9378,
"peaceful": 9379,
"optical": 9380,
"width": 9381,
"allegedly": 9382,
"mcdonald": 9383,
"strict": 9384,
"copyright": 9385,
"##illa": 9386,
"investors": 9387,
"mar": 9388,
"jam": 9389,
"witnesses": 9390,
"sounding": 9391,
"miranda": 9392,
"michelle": 9393,
"privacy": 9394,
"hugo": 9395,
"harmony": 9396,
"##pp": 9397,
"valid": 9398,
"lynn": 9399,
"glared": 9400,
"nina": 9401,
"102": 9402,
"headquartered": 9403,
"diving": 9404,
"boarding": 9405,
"gibson": 9406,
"##ncy": 9407,
"albanian": 9408,
"marsh": 9409,
"routine": 9410,
"dealt": 9411,
"enhanced": 9412,
"er": 9413,
"intelligent": 9414,
"substance": 9415,
"targeted": 9416,
"enlisted": 9417,
"discovers": 9418,
"spinning": 9419,
"observations": 9420,
"pissed": 9421,
"smoking": 9422,
"rebecca": 9423,
"capitol": 9424,
"visa": 9425,
"varied": 9426,
"costume": 9427,
"seemingly": 9428,
"indies": 9429,
"compensation": 9430,
"surgeon": 9431,
"thursday": 9432,
"arsenal": 9433,
"westminster": 9434,
"suburbs": 9435,
"rid": 9436,
"anglican": 9437,
"##ridge": 9438,
"knots": 9439,
"foods": 9440,
"alumni": 9441,
"lighter": 9442,
"fraser": 9443,
"whoever": 9444,
"portal": 9445,
"scandal": 9446,
"##ray": 9447,
"gavin": 9448,
"advised": 9449,
"instructor": 9450,
"flooding": 9451,
"terrorist": 9452,
"##ale": 9453,
"teenage": 9454,
"interim": 9455,
"senses": 9456,
"duck": 9457,
"teen": 9458,
"thesis": 9459,
"abby": 9460,
"eager": 9461,
"overcome": 9462,
"##ile": 9463,
"newport": 9464,
"glenn": 9465,
"rises": 9466,
"shame": 9467,
"##cc": 9468,
"prompted": 9469,
"priority": 9470,
"forgot": 9471,
"bomber": 9472,
"nicolas": 9473,
"protective": 9474,
"360": 9475,
"cartoon": 9476,
"katherine": 9477,
"breeze": 9478,
"lonely": 9479,
"trusted": 9480,
"henderson": 9481,
"richardson": 9482,
"relax": 9483,
"banner": 9484,
"candy": 9485,
"palms": 9486,
"remarkable": 9487,
"##rio": 9488,
"legends": 9489,
"cricketer": 9490,
"essay": 9491,
"ordained": 9492,
"edmund": 9493,
"rifles": 9494,
"trigger": 9495,
"##uri": 9496,
"##away": 9497,
"sail": 9498,
"alert": 9499,
"1830": 9500,
"audiences": 9501,
"penn": 9502,
"sussex": 9503,
"siblings": 9504,
"pursued": 9505,
"indianapolis": 9506,
"resist": 9507,
"rosa": 9508,
"consequence": 9509,
"succeed": 9510,
"avoided": 9511,
"1845": 9512,
"##ulation": 9513,
"inland": 9514,
"##tie": 9515,
"##nna": 9516,
"counsel": 9517,
"profession": 9518,
"chronicle": 9519,
"hurried": 9520,
"##una": 9521,
"eyebrow": 9522,
"eventual": 9523,
"bleeding": 9524,
"innovative": 9525,
"cure": 9526,
"##dom": 9527,
"committees": 9528,
"accounting": 9529,
"con": 9530,
"scope": 9531,
"hardy": 9532,
"heather": 9533,
"tenor": 9534,
"gut": 9535,
"herald": 9536,
"codes": 9537,
"tore": 9538,
"scales": 9539,
"wagon": 9540,
"##oo": 9541,
"luxury": 9542,
"tin": 9543,
"prefer": 9544,
"fountain": 9545,
"triangle": 9546,
"bonds": 9547,
"darling": 9548,
"convoy": 9549,
"dried": 9550,
"traced": 9551,
"beings": 9552,
"troy": 9553,
"accidentally": 9554,
"slam": 9555,
"findings": 9556,
"smelled": 9557,
"joey": 9558,
"lawyers": 9559,
"outcome": 9560,
"steep": 9561,
"bosnia": 9562,
"configuration": 9563,
"shifting": 9564,
"toll": 9565,
"brook": 9566,
"performers": 9567,
"lobby": 9568,
"philosophical": 9569,
"construct": 9570,
"shrine": 9571,
"aggregate": 9572,
"boot": 9573,
"cox": 9574,
"phenomenon": 9575,
"savage": 9576,
"insane": 9577,
"solely": 9578,
"reynolds": 9579,
"lifestyle": 9580,
"##ima": 9581,
"nationally": 9582,
"holdings": 9583,
"consideration": 9584,
"enable": 9585,
"edgar": 9586,
"mo": 9587,
"mama": 9588,
"##tein": 9589,
"fights": 9590,
"relegation": 9591,
"chances": 9592,
"atomic": 9593,
"hub": 9594,
"conjunction": 9595,
"awkward": 9596,
"reactions": 9597,
"currency": 9598,
"finale": 9599,
"kumar": 9600,
"underwent": 9601,
"steering": 9602,
"elaborate": 9603,
"gifts": 9604,
"comprising": 9605,
"melissa": 9606,
"veins": 9607,
"reasonable": 9608,
"sunshine": 9609,
"chi": 9610,
"solve": 9611,
"trails": 9612,
"inhabited": 9613,
"elimination": 9614,
"ethics": 9615,
"huh": 9616,
"ana": 9617,
"molly": 9618,
"consent": 9619,
"apartments": 9620,
"layout": 9621,
"marines": 9622,
"##ces": 9623,
"hunters": 9624,
"bulk": 9625,
"##oma": 9626,
"hometown": 9627,
"##wall": 9628,
"##mont": 9629,
"cracked": 9630,
"reads": 9631,
"neighbouring": 9632,
"withdrawn": 9633,
"admission": 9634,
"wingspan": 9635,
"damned": 9636,
"anthology": 9637,
"lancashire": 9638,
"brands": 9639,
"batting": 9640,
"forgive": 9641,
"cuban": 9642,
"awful": 9643,
"##lyn": 9644,
"104": 9645,
"dimensions": 9646,
"imagination": 9647,
"##ade": 9648,
"dante": 9649,
"##ship": 9650,
"tracking": 9651,
"desperately": 9652,
"goalkeeper": 9653,
"##yne": 9654,
"groaned": 9655,
"workshops": 9656,
"confident": 9657,
"burton": 9658,
"gerald": 9659,
"milton": 9660,
"circus": 9661,
"uncertain": 9662,
"slope": 9663,
"copenhagen": 9664,
"sophia": 9665,
"fog": 9666,
"philosopher": 9667,
"portraits": 9668,
"accent": 9669,
"cycling": 9670,
"varying": 9671,
"gripped": 9672,
"larvae": 9673,
"garrett": 9674,
"specified": 9675,
"scotia": 9676,
"mature": 9677,
"luther": 9678,
"kurt": 9679,
"rap": 9680,
"##kes": 9681,
"aerial": 9682,
"750": 9683,
"ferdinand": 9684,
"heated": 9685,
"es": 9686,
"transported": 9687,
"##shan": 9688,
"safely": 9689,
"nonetheless": 9690,
"##orn": 9691,
"##gal": 9692,
"motors": 9693,
"demanding": 9694,
"##sburg": 9695,
"startled": 9696,
"##brook": 9697,
"ally": 9698,
"generate": 9699,
"caps": 9700,
"ghana": 9701,
"stained": 9702,
"demo": 9703,
"mentions": 9704,
"beds": 9705,
"ap": 9706,
"afterward": 9707,
"diary": 9708,
"##bling": 9709,
"utility": 9710,
"##iro": 9711,
"richards": 9712,
"1837": 9713,
"conspiracy": 9714,
"conscious": 9715,
"shining": 9716,
"footsteps": 9717,
"observer": 9718,
"cyprus": 9719,
"urged": 9720,
"loyalty": 9721,
"developer": 9722,
"probability": 9723,
"olive": 9724,
"upgraded": 9725,
"gym": 9726,
"miracle": 9727,
"insects": 9728,
"graves": 9729,
"1844": 9730,
"ourselves": 9731,
"hydrogen": 9732,
"amazon": 9733,
"katie": 9734,
"tickets": 9735,
"poets": 9736,
"##pm": 9737,
"planes": 9738,
"##pan": 9739,
"prevention": 9740,
"witnessed": 9741,
"dense": 9742,
"jin": 9743,
"randy": 9744,
"tang": 9745,
"warehouse": 9746,
"monroe": 9747,
"bang": 9748,
"archived": 9749,
"elderly": 9750,
"investigations": 9751,
"alec": 9752,
"granite": 9753,
"mineral": 9754,
"conflicts": 9755,
"controlling": 9756,
"aboriginal": 9757,
"carlo": 9758,
"##zu": 9759,
"mechanics": 9760,
"stan": 9761,
"stark": 9762,
"rhode": 9763,
"skirt": 9764,
"est": 9765,
"##berry": 9766,
"bombs": 9767,
"respected": 9768,
"##horn": 9769,
"imposed": 9770,
"limestone": 9771,
"deny": 9772,
"nominee": 9773,
"memphis": 9774,
"grabbing": 9775,
"disabled": 9776,
"##als": 9777,
"amusement": 9778,
"aa": 9779,
"frankfurt": 9780,
"corn": 9781,
"referendum": 9782,
"varies": 9783,
"slowed": 9784,
"disk": 9785,
"firms": 9786,
"unconscious": 9787,
"incredible": 9788,
"clue": 9789,
"sue": 9790,
"##zhou": 9791,
"twist": 9792,
"##cio": 9793,
"joins": 9794,
"idaho": 9795,
"chad": 9796,
"developers": 9797,
"computing": 9798,
"destroyer": 9799,
"103": 9800,
"mortal": 9801,
"tucker": 9802,
"kingston": 9803,
"choices": 9804,
"yu": 9805,
"carson": 9806,
"1800": 9807,
"os": 9808,
"whitney": 9809,
"geneva": 9810,
"pretend": 9811,
"dimension": 9812,
"staged": 9813,
"plateau": 9814,
"maya": 9815,
"##une": 9816,
"freestyle": 9817,
"##bc": 9818,
"rovers": 9819,
"hiv": 9820,
"##ids": 9821,
"tristan": 9822,
"classroom": 9823,
"prospect": 9824,
"##hus": 9825,
"honestly": 9826,
"diploma": 9827,
"lied": 9828,
"thermal": 9829,
"auxiliary": 9830,
"feast": 9831,
"unlikely": 9832,
"iata": 9833,
"##tel": 9834,
"morocco": 9835,
"pounding": 9836,
"treasury": 9837,
"lithuania": 9838,
"considerably": 9839,
"1841": 9840,
"dish": 9841,
"1812": 9842,
"geological": 9843,
"matching": 9844,
"stumbled": 9845,
"destroying": 9846,
"marched": 9847,
"brien": 9848,
"advances": 9849,
"cake": 9850,
"nicole": 9851,
"belle": 9852,
"settling": 9853,
"measuring": 9854,
"directing": 9855,
"##mie": 9856,
"tuesday": 9857,
"bassist": 9858,
"capabilities": 9859,
"stunned": 9860,
"fraud": 9861,
"torpedo": 9862,
"##list": 9863,
"##phone": 9864,
"anton": 9865,
"wisdom": 9866,
"surveillance": 9867,
"ruined": 9868,
"##ulate": 9869,
"lawsuit": 9870,
"healthcare": 9871,
"theorem": 9872,
"halls": 9873,
"trend": 9874,
"aka": 9875,
"horizontal": 9876,
"dozens": 9877,
"acquire": 9878,
"lasting": 9879,
"swim": 9880,
"hawk": 9881,
"gorgeous": 9882,
"fees": 9883,
"vicinity": 9884,
"decrease": 9885,
"adoption": 9886,
"tactics": 9887,
"##ography": 9888,
"pakistani": 9889,
"##ole": 9890,
"draws": 9891,
"##hall": 9892,
"willie": 9893,
"burke": 9894,
"heath": 9895,
"algorithm": 9896,
"integral": 9897,
"powder": 9898,
"elliott": 9899,
"brigadier": 9900,
"jackie": 9901,
"tate": 9902,
"varieties": 9903,
"darker": 9904,
"##cho": 9905,
"lately": 9906,
"cigarette": 9907,
"specimens": 9908,
"adds": 9909,
"##ree": 9910,
"##ensis": 9911,
"##inger": 9912,
"exploded": 9913,
"finalist": 9914,
"cia": 9915,
"murders": 9916,
"wilderness": 9917,
"arguments": 9918,
"nicknamed": 9919,
"acceptance": 9920,
"onwards": 9921,
"manufacture": 9922,
"robertson": 9923,
"jets": 9924,
"tampa": 9925,
"enterprises": 9926,
"blog": 9927,
"loudly": 9928,
"composers": 9929,
"nominations": 9930,
"1838": 9931,
"ai": 9932,
"malta": 9933,
"inquiry": 9934,
"automobile": 9935,
"hosting": 9936,
"viii": 9937,
"rays": 9938,
"tilted": 9939,
"grief": 9940,
"museums": 9941,
"strategies": 9942,
"furious": 9943,
"euro": 9944,
"equality": 9945,
"cohen": 9946,
"poison": 9947,
"surrey": 9948,
"wireless": 9949,
"governed": 9950,
"ridiculous": 9951,
"moses": 9952,
"##esh": 9953,
"##room": 9954,
"vanished": 9955,
"##ito": 9956,
"barnes": 9957,
"attract": 9958,
"morrison": 9959,
"istanbul": 9960,
"##iness": 9961,
"absent": 9962,
"rotation": 9963,
"petition": 9964,
"janet": 9965,
"##logical": 9966,
"satisfaction": 9967,
"custody": 9968,
"deliberately": 9969,
"observatory": 9970,
"comedian": 9971,
"surfaces": 9972,
"pinyin": 9973,
"novelist": 9974,
"strictly": 9975,
"canterbury": 9976,
"oslo": 9977,
"monks": 9978,
"embrace": 9979,
"ibm": 9980,
"jealous": 9981,
"photograph": 9982,
"continent": 9983,
"dorothy": 9984,
"marina": 9985,
"doc": 9986,
"excess": 9987,
"holden": 9988,
"allegations": 9989,
"explaining": 9990,
"stack": 9991,
"avoiding": 9992,
"lance": 9993,
"storyline": 9994,
"majesty": 9995,
"poorly": 9996,
"spike": 9997,
"dos": 9998,
"bradford": 9999,
"raven": 10000,
"travis": 10001,
"classics": 10002,
"proven": 10003,
"voltage": 10004,
"pillow": 10005,
"fists": 10006,
"butt": 10007,
"1842": 10008,
"interpreted": 10009,
"##car": 10010,
"1839": 10011,
"gage": 10012,
"telegraph": 10013,
"lens": 10014,
"promising": 10015,
"expelled": 10016,
"casual": 10017,
"collector": 10018,
"zones": 10019,
"##min": 10020,
"silly": 10021,
"nintendo": 10022,
"##kh": 10023,
"##bra": 10024,
"downstairs": 10025,
"chef": 10026,
"suspicious": 10027,
"afl": 10028,
"flies": 10029,
"vacant": 10030,
"uganda": 10031,
"pregnancy": 10032,
"condemned": 10033,
"lutheran": 10034,
"estimates": 10035,
"cheap": 10036,
"decree": 10037,
"saxon": 10038,
"proximity": 10039,
"stripped": 10040,
"idiot": 10041,
"deposits": 10042,
"contrary": 10043,
"presenter": 10044,
"magnus": 10045,
"glacier": 10046,
"im": 10047,
"offense": 10048,
"edwin": 10049,
"##ori": 10050,
"upright": 10051,
"##long": 10052,
"bolt": 10053,
"##ois": 10054,
"toss": 10055,
"geographical": 10056,
"##izes": 10057,
"environments": 10058,
"delicate": 10059,
"marking": 10060,
"abstract": 10061,
"xavier": 10062,
"nails": 10063,
"windsor": 10064,
"plantation": 10065,
"occurring": 10066,
"equity": 10067,
"saskatchewan": 10068,
"fears": 10069,
"drifted": 10070,
"sequences": 10071,
"vegetation": 10072,
"revolt": 10073,
"##stic": 10074,
"1843": 10075,
"sooner": 10076,
"fusion": 10077,
"opposing": 10078,
"nato": 10079,
"skating": 10080,
"1836": 10081,
"secretly": 10082,
"ruin": 10083,
"lease": 10084,
"##oc": 10085,
"edit": 10086,
"##nne": 10087,
"flora": 10088,
"anxiety": 10089,
"ruby": 10090,
"##ological": 10091,
"##mia": 10092,
"tel": 10093,
"bout": 10094,
"taxi": 10095,
"emmy": 10096,
"frost": 10097,
"rainbow": 10098,
"compounds": 10099,
"foundations": 10100,
"rainfall": 10101,
"assassination": 10102,
"nightmare": 10103,
"dominican": 10104,
"##win": 10105,
"achievements": 10106,
"deserve": 10107,
"orlando": 10108,
"intact": 10109,
"armenia": 10110,
"##nte": 10111,
"calgary": 10112,
"valentine": 10113,
"106": 10114,
"marion": 10115,
"proclaimed": 10116,
"theodore": 10117,
"bells": 10118,
"courtyard": 10119,
"thigh": 10120,
"gonzalez": 10121,
"console": 10122,
"troop": 10123,
"minimal": 10124,
"monte": 10125,
"everyday": 10126,
"##ence": 10127,
"##if": 10128,
"supporter": 10129,
"terrorism": 10130,
"buck": 10131,
"openly": 10132,
"presbyterian": 10133,
"activists": 10134,
"carpet": 10135,
"##iers": 10136,
"rubbing": 10137,
"uprising": 10138,
"##yi": 10139,
"cute": 10140,
"conceived": 10141,
"legally": 10142,
"##cht": 10143,
"millennium": 10144,
"cello": 10145,
"velocity": 10146,
"ji": 10147,
"rescued": 10148,
"cardiff": 10149,
"1835": 10150,
"rex": 10151,
"concentrate": 10152,
"senators": 10153,
"beard": 10154,
"rendered": 10155,
"glowing": 10156,
"battalions": 10157,
"scouts": 10158,
"competitors": 10159,
"sculptor": 10160,
"catalogue": 10161,
"arctic": 10162,
"ion": 10163,
"raja": 10164,
"bicycle": 10165,
"wow": 10166,
"glancing": 10167,
"lawn": 10168,
"##woman": 10169,
"gentleman": 10170,
"lighthouse": 10171,
"publish": 10172,
"predicted": 10173,
"calculated": 10174,
"##val": 10175,
"variants": 10176,
"##gne": 10177,
"strain": 10178,
"##ui": 10179,
"winston": 10180,
"deceased": 10181,
"##nus": 10182,
"touchdowns": 10183,
"brady": 10184,
"caleb": 10185,
"sinking": 10186,
"echoed": 10187,
"crush": 10188,
"hon": 10189,
"blessed": 10190,
"protagonist": 10191,
"hayes": 10192,
"endangered": 10193,
"magnitude": 10194,
"editors": 10195,
"##tine": 10196,
"estimate": 10197,
"responsibilities": 10198,
"##mel": 10199,
"backup": 10200,
"laying": 10201,
"consumed": 10202,
"sealed": 10203,
"zurich": 10204,
"lovers": 10205,
"frustrated": 10206,
"##eau": 10207,
"ahmed": 10208,
"kicking": 10209,
"mit": 10210,
"treasurer": 10211,
"1832": 10212,
"biblical": 10213,
"refuse": 10214,
"terrified": 10215,
"pump": 10216,
"agrees": 10217,
"genuine": 10218,
"imprisonment": 10219,
"refuses": 10220,
"plymouth": 10221,
"##hen": 10222,
"lou": 10223,
"##nen": 10224,
"tara": 10225,
"trembling": 10226,
"antarctic": 10227,
"ton": 10228,
"learns": 10229,
"##tas": 10230,
"crap": 10231,
"crucial": 10232,
"faction": 10233,
"atop": 10234,
"##borough": 10235,
"wrap": 10236,
"lancaster": 10237,
"odds": 10238,
"hopkins": 10239,
"erik": 10240,
"lyon": 10241,
"##eon": 10242,
"bros": 10243,
"##ode": 10244,
"snap": 10245,
"locality": 10246,
"tips": 10247,
"empress": 10248,
"crowned": 10249,
"cal": 10250,
"acclaimed": 10251,
"chuckled": 10252,
"##ory": 10253,
"clara": 10254,
"sends": 10255,
"mild": 10256,
"towel": 10257,
"##fl": 10258,
"##day": 10259,
"##а": 10260,
"wishing": 10261,
"assuming": 10262,
"interviewed": 10263,
"##bal": 10264,
"##die": 10265,
"interactions": 10266,
"eden": 10267,
"cups": 10268,
"helena": 10269,
"##lf": 10270,
"indie": 10271,
"beck": 10272,
"##fire": 10273,
"batteries": 10274,
"filipino": 10275,
"wizard": 10276,
"parted": 10277,
"##lam": 10278,
"traces": 10279,
"##born": 10280,
"rows": 10281,
"idol": 10282,
"albany": 10283,
"delegates": 10284,
"##ees": 10285,
"##sar": 10286,
"discussions": 10287,
"##ex": 10288,
"notre": 10289,
"instructed": 10290,
"belgrade": 10291,
"highways": 10292,
"suggestion": 10293,
"lauren": 10294,
"possess": 10295,
"orientation": 10296,
"alexandria": 10297,
"abdul": 10298,
"beats": 10299,
"salary": 10300,
"reunion": 10301,
"ludwig": 10302,
"alright": 10303,
"wagner": 10304,
"intimate": 10305,
"pockets": 10306,
"slovenia": 10307,
"hugged": 10308,
"brighton": 10309,
"merchants": 10310,
"cruel": 10311,
"stole": 10312,
"trek": 10313,
"slopes": 10314,
"repairs": 10315,
"enrollment": 10316,
"politically": 10317,
"underlying": 10318,
"promotional": 10319,
"counting": 10320,
"boeing": 10321,
"##bb": 10322,
"isabella": 10323,
"naming": 10324,
"##и": 10325,
"keen": 10326,
"bacteria": 10327,
"listing": 10328,
"separately": 10329,
"belfast": 10330,
"ussr": 10331,
"450": 10332,
"lithuanian": 10333,
"anybody": 10334,
"ribs": 10335,
"sphere": 10336,
"martinez": 10337,
"cock": 10338,
"embarrassed": 10339,
"proposals": 10340,
"fragments": 10341,
"nationals": 10342,
"##fs": 10343,
"##wski": 10344,
"premises": 10345,
"fin": 10346,
"1500": 10347,
"alpine": 10348,
"matched": 10349,
"freely": 10350,
"bounded": 10351,
"jace": 10352,
"sleeve": 10353,
"##af": 10354,
"gaming": 10355,
"pier": 10356,
"populated": 10357,
"evident": 10358,
"##like": 10359,
"frances": 10360,
"flooded": 10361,
"##dle": 10362,
"frightened": 10363,
"pour": 10364,
"trainer": 10365,
"framed": 10366,
"visitor": 10367,
"challenging": 10368,
"pig": 10369,
"wickets": 10370,
"##fold": 10371,
"infected": 10372,
"email": 10373,
"##pes": 10374,
"arose": 10375,
"##aw": 10376,
"reward": 10377,
"ecuador": 10378,
"oblast": 10379,
"vale": 10380,
"ch": 10381,
"shuttle": 10382,
"##usa": 10383,
"bach": 10384,
"rankings": 10385,
"forbidden": 10386,
"cornwall": 10387,
"accordance": 10388,
"salem": 10389,
"consumers": 10390,
"bruno": 10391,
"fantastic": 10392,
"toes": 10393,
"machinery": 10394,
"resolved": 10395,
"julius": 10396,
"remembering": 10397,
"propaganda": 10398,
"iceland": 10399,
"bombardment": 10400,
"tide": 10401,
"contacts": 10402,
"wives": 10403,
"##rah": 10404,
"concerto": 10405,
"macdonald": 10406,
"albania": 10407,
"implement": 10408,
"daisy": 10409,
"tapped": 10410,
"sudan": 10411,
"helmet": 10412,
"angela": 10413,
"mistress": 10414,
"##lic": 10415,
"crop": 10416,
"sunk": 10417,
"finest": 10418,
"##craft": 10419,
"hostile": 10420,
"##ute": 10421,
"##tsu": 10422,
"boxer": 10423,
"fr": 10424,
"paths": 10425,
"adjusted": 10426,
"habit": 10427,
"ballot": 10428,
"supervision": 10429,
"soprano": 10430,
"##zen": 10431,
"bullets": 10432,
"wicked": 10433,
"sunset": 10434,
"regiments": 10435,
"disappear": 10436,
"lamp": 10437,
"performs": 10438,
"app": 10439,
"##gia": 10440,
"##oa": 10441,
"rabbit": 10442,
"digging": 10443,
"incidents": 10444,
"entries": 10445,
"##cion": 10446,
"dishes": 10447,
"##oi": 10448,
"introducing": 10449,
"##ati": 10450,
"##fied": 10451,
"freshman": 10452,
"slot": 10453,
"jill": 10454,
"tackles": 10455,
"baroque": 10456,
"backs": 10457,
"##iest": 10458,
"lone": 10459,
"sponsor": 10460,
"destiny": 10461,
"altogether": 10462,
"convert": 10463,
"##aro": 10464,
"consensus": 10465,
"shapes": 10466,
"demonstration": 10467,
"basically": 10468,
"feminist": 10469,
"auction": 10470,
"artifacts": 10471,
"##bing": 10472,
"strongest": 10473,
"twitter": 10474,
"halifax": 10475,
"2019": 10476,
"allmusic": 10477,
"mighty": 10478,
"smallest": 10479,
"precise": 10480,
"alexandra": 10481,
"viola": 10482,
"##los": 10483,
"##ille": 10484,
"manuscripts": 10485,
"##illo": 10486,
"dancers": 10487,
"ari": 10488,
"managers": 10489,
"monuments": 10490,
"blades": 10491,
"barracks": 10492,
"springfield": 10493,
"maiden": 10494,
"consolidated": 10495,
"electron": 10496,
"##end": 10497,
"berry": 10498,
"airing": 10499,
"wheat": 10500,
"nobel": 10501,
"inclusion": 10502,
"blair": 10503,
"payments": 10504,
"geography": 10505,
"bee": 10506,
"cc": 10507,
"eleanor": 10508,
"react": 10509,
"##hurst": 10510,
"afc": 10511,
"manitoba": 10512,
"##yu": 10513,
"su": 10514,
"lineup": 10515,
"fitness": 10516,
"recreational": 10517,
"investments": 10518,
"airborne": 10519,
"disappointment": 10520,
"##dis": 10521,
"edmonton": 10522,
"viewing": 10523,
"##row": 10524,
"renovation": 10525,
"##cast": 10526,
"infant": 10527,
"bankruptcy": 10528,
"roses": 10529,
"aftermath": 10530,
"pavilion": 10531,
"##yer": 10532,
"carpenter": 10533,
"withdrawal": 10534,
"ladder": 10535,
"##hy": 10536,
"discussing": 10537,
"popped": 10538,
"reliable": 10539,
"agreements": 10540,
"rochester": 10541,
"##abad": 10542,
"curves": 10543,
"bombers": 10544,
"220": 10545,
"rao": 10546,
"reverend": 10547,
"decreased": 10548,
"choosing": 10549,
"107": 10550,
"stiff": 10551,
"consulting": 10552,
"naples": 10553,
"crawford": 10554,
"tracy": 10555,
"ka": 10556,
"ribbon": 10557,
"cops": 10558,
"##lee": 10559,
"crushed": 10560,
"deciding": 10561,
"unified": 10562,
"teenager": 10563,
"accepting": 10564,
"flagship": 10565,
"explorer": 10566,
"poles": 10567,
"sanchez": 10568,
"inspection": 10569,
"revived": 10570,
"skilled": 10571,
"induced": 10572,
"exchanged": 10573,
"flee": 10574,
"locals": 10575,
"tragedy": 10576,
"swallow": 10577,
"loading": 10578,
"hanna": 10579,
"demonstrate": 10580,
"##ela": 10581,
"salvador": 10582,
"flown": 10583,
"contestants": 10584,
"civilization": 10585,
"##ines": 10586,
"wanna": 10587,
"rhodes": 10588,
"fletcher": 10589,
"hector": 10590,
"knocking": 10591,
"considers": 10592,
"##ough": 10593,
"nash": 10594,
"mechanisms": 10595,
"sensed": 10596,
"mentally": 10597,
"walt": 10598,
"unclear": 10599,
"##eus": 10600,
"renovated": 10601,
"madame": 10602,
"##cks": 10603,
"crews": 10604,
"governmental": 10605,
"##hin": 10606,
"undertaken": 10607,
"monkey": 10608,
"##ben": 10609,
"##ato": 10610,
"fatal": 10611,
"armored": 10612,
"copa": 10613,
"caves": 10614,
"governance": 10615,
"grasp": 10616,
"perception": 10617,
"certification": 10618,
"froze": 10619,
"damp": 10620,
"tugged": 10621,
"wyoming": 10622,
"##rg": 10623,
"##ero": 10624,
"newman": 10625,
"##lor": 10626,
"nerves": 10627,
"curiosity": 10628,
"graph": 10629,
"115": 10630,
"##ami": 10631,
"withdraw": 10632,
"tunnels": 10633,
"dull": 10634,
"meredith": 10635,
"moss": 10636,
"exhibits": 10637,
"neighbors": 10638,
"communicate": 10639,
"accuracy": 10640,
"explored": 10641,
"raiders": 10642,
"republicans": 10643,
"secular": 10644,
"kat": 10645,
"superman": 10646,
"penny": 10647,
"criticised": 10648,
"##tch": 10649,
"freed": 10650,
"update": 10651,
"conviction": 10652,
"wade": 10653,
"ham": 10654,
"likewise": 10655,
"delegation": 10656,
"gotta": 10657,
"doll": 10658,
"promises": 10659,
"technological": 10660,
"myth": 10661,
"nationality": 10662,
"resolve": 10663,
"convent": 10664,
"##mark": 10665,
"sharon": 10666,
"dig": 10667,
"sip": 10668,
"coordinator": 10669,
"entrepreneur": 10670,
"fold": 10671,
"##dine": 10672,
"capability": 10673,
"councillor": 10674,
"synonym": 10675,
"blown": 10676,
"swan": 10677,
"cursed": 10678,
"1815": 10679,
"jonas": 10680,
"haired": 10681,
"sofa": 10682,
"canvas": 10683,
"keeper": 10684,
"rivalry": 10685,
"##hart": 10686,
"rapper": 10687,
"speedway": 10688,
"swords": 10689,
"postal": 10690,
"maxwell": 10691,
"estonia": 10692,
"potter": 10693,
"recurring": 10694,
"##nn": 10695,
"##ave": 10696,
"errors": 10697,
"##oni": 10698,
"cognitive": 10699,
"1834": 10700,
"##²": 10701,
"claws": 10702,
"nadu": 10703,
"roberto": 10704,
"bce": 10705,
"wrestler": 10706,
"ellie": 10707,
"##ations": 10708,
"infinite": 10709,
"ink": 10710,
"##tia": 10711,
"presumably": 10712,
"finite": 10713,
"staircase": 10714,
"108": 10715,
"noel": 10716,
"patricia": 10717,
"nacional": 10718,
"##cation": 10719,
"chill": 10720,
"eternal": 10721,
"tu": 10722,
"preventing": 10723,
"prussia": 10724,
"fossil": 10725,
"limbs": 10726,
"##logist": 10727,
"ernst": 10728,
"frog": 10729,
"perez": 10730,
"rene": 10731,
"##ace": 10732,
"pizza": 10733,
"prussian": 10734,
"##ios": 10735,
"##vy": 10736,
"molecules": 10737,
"regulatory": 10738,
"answering": 10739,
"opinions": 10740,
"sworn": 10741,
"lengths": 10742,
"supposedly": 10743,
"hypothesis": 10744,
"upward": 10745,
"habitats": 10746,
"seating": 10747,
"ancestors": 10748,
"drank": 10749,
"yield": 10750,
"hd": 10751,
"synthesis": 10752,
"researcher": 10753,
"modest": 10754,
"##var": 10755,
"mothers": 10756,
"peered": 10757,
"voluntary": 10758,
"homeland": 10759,
"##the": 10760,
"acclaim": 10761,
"##igan": 10762,
"static": 10763,
"valve": 10764,
"luxembourg": 10765,
"alto": 10766,
"carroll": 10767,
"fe": 10768,
"receptor": 10769,
"norton": 10770,
"ambulance": 10771,
"##tian": 10772,
"johnston": 10773,
"catholics": 10774,
"depicting": 10775,
"jointly": 10776,
"elephant": 10777,
"gloria": 10778,
"mentor": 10779,
"badge": 10780,
"ahmad": 10781,
"distinguish": 10782,
"remarked": 10783,
"councils": 10784,
"precisely": 10785,
"allison": 10786,
"advancing": 10787,
"detection": 10788,
"crowded": 10789,
"##10": 10790,
"cooperative": 10791,
"ankle": 10792,
"mercedes": 10793,
"dagger": 10794,
"surrendered": 10795,
"pollution": 10796,
"commit": 10797,
"subway": 10798,
"jeffrey": 10799,
"lesson": 10800,
"sculptures": 10801,
"provider": 10802,
"##fication": 10803,
"membrane": 10804,
"timothy": 10805,
"rectangular": 10806,
"fiscal": 10807,
"heating": 10808,
"teammate": 10809,
"basket": 10810,
"particle": 10811,
"anonymous": 10812,
"deployment": 10813,
"##ple": 10814,
"missiles": 10815,
"courthouse": 10816,
"proportion": 10817,
"shoe": 10818,
"sec": 10819,
"##ller": 10820,
"complaints": 10821,
"forbes": 10822,
"blacks": 10823,
"abandon": 10824,
"remind": 10825,
"sizes": 10826,
"overwhelming": 10827,
"autobiography": 10828,
"natalie": 10829,
"##awa": 10830,
"risks": 10831,
"contestant": 10832,
"countryside": 10833,
"babies": 10834,
"scorer": 10835,
"invaded": 10836,
"enclosed": 10837,
"proceed": 10838,
"hurling": 10839,
"disorders": 10840,
"##cu": 10841,
"reflecting": 10842,
"continuously": 10843,
"cruiser": 10844,
"graduates": 10845,
"freeway": 10846,
"investigated": 10847,
"ore": 10848,
"deserved": 10849,
"maid": 10850,
"blocking": 10851,
"phillip": 10852,
"jorge": 10853,
"shakes": 10854,
"dove": 10855,
"mann": 10856,
"variables": 10857,
"lacked": 10858,
"burden": 10859,
"accompanying": 10860,
"que": 10861,
"consistently": 10862,
"organizing": 10863,
"provisional": 10864,
"complained": 10865,
"endless": 10866,
"##rm": 10867,
"tubes": 10868,
"juice": 10869,
"georges": 10870,
"krishna": 10871,
"mick": 10872,
"labels": 10873,
"thriller": 10874,
"##uch": 10875,
"laps": 10876,
"arcade": 10877,
"sage": 10878,
"snail": 10879,
"##table": 10880,
"shannon": 10881,
"fi": 10882,
"laurence": 10883,
"seoul": 10884,
"vacation": 10885,
"presenting": 10886,
"hire": 10887,
"churchill": 10888,
"surprisingly": 10889,
"prohibited": 10890,
"savannah": 10891,
"technically": 10892,
"##oli": 10893,
"170": 10894,
"##lessly": 10895,
"testimony": 10896,
"suited": 10897,
"speeds": 10898,
"toys": 10899,
"romans": 10900,
"mlb": 10901,
"flowering": 10902,
"measurement": 10903,
"talented": 10904,
"kay": 10905,
"settings": 10906,
"charleston": 10907,
"expectations": 10908,
"shattered": 10909,
"achieving": 10910,
"triumph": 10911,
"ceremonies": 10912,
"portsmouth": 10913,
"lanes": 10914,
"mandatory": 10915,
"loser": 10916,
"stretching": 10917,
"cologne": 10918,
"realizes": 10919,
"seventy": 10920,
"cornell": 10921,
"careers": 10922,
"webb": 10923,
"##ulating": 10924,
"americas": 10925,
"budapest": 10926,
"ava": 10927,
"suspicion": 10928,
"##ison": 10929,
"yo": 10930,
"conrad": 10931,
"##hai": 10932,
"sterling": 10933,
"jessie": 10934,
"rector": 10935,
"##az": 10936,
"1831": 10937,
"transform": 10938,
"organize": 10939,
"loans": 10940,
"christine": 10941,
"volcanic": 10942,
"warrant": 10943,
"slender": 10944,
"summers": 10945,
"subfamily": 10946,
"newer": 10947,
"danced": 10948,
"dynamics": 10949,
"rhine": 10950,
"proceeds": 10951,
"heinrich": 10952,
"gastropod": 10953,
"commands": 10954,
"sings": 10955,
"facilitate": 10956,
"easter": 10957,
"ra": 10958,
"positioned": 10959,
"responses": 10960,
"expense": 10961,
"fruits": 10962,
"yanked": 10963,
"imported": 10964,
"25th": 10965,
"velvet": 10966,
"vic": 10967,
"primitive": 10968,
"tribune": 10969,
"baldwin": 10970,
"neighbourhood": 10971,
"donna": 10972,
"rip": 10973,
"hay": 10974,
"pr": 10975,
"##uro": 10976,
"1814": 10977,
"espn": 10978,
"welcomed": 10979,
"##aria": 10980,
"qualifier": 10981,
"glare": 10982,
"highland": 10983,
"timing": 10984,
"##cted": 10985,
"shells": 10986,
"eased": 10987,
"geometry": 10988,
"louder": 10989,
"exciting": 10990,
"slovakia": 10991,
"##sion": 10992,
"##iz": 10993,
"##lot": 10994,
"savings": 10995,
"prairie": 10996,
"##ques": 10997,
"marching": 10998,
"rafael": 10999,
"tonnes": 11000,
"##lled": 11001,
"curtain": 11002,
"preceding": 11003,
"shy": 11004,
"heal": 11005,
"greene": 11006,
"worthy": 11007,
"##pot": 11008,
"detachment": 11009,
"bury": 11010,
"sherman": 11011,
"##eck": 11012,
"reinforced": 11013,
"seeks": 11014,
"bottles": 11015,
"contracted": 11016,
"duchess": 11017,
"outfit": 11018,
"walsh": 11019,
"##sc": 11020,
"mickey": 11021,
"##ase": 11022,
"geoffrey": 11023,
"archer": 11024,
"squeeze": 11025,
"dawson": 11026,
"eliminate": 11027,
"invention": 11028,
"##enberg": 11029,
"neal": 11030,
"##eth": 11031,
"stance": 11032,
"dealer": 11033,
"coral": 11034,
"maple": 11035,
"retire": 11036,
"polo": 11037,
"simplified": 11038,
"##ht": 11039,
"1833": 11040,
"hid": 11041,
"watts": 11042,
"backwards": 11043,
"jules": 11044,
"##oke": 11045,
"genesis": 11046,
"mt": 11047,
"frames": 11048,
"rebounds": 11049,
"burma": 11050,
"woodland": 11051,
"moist": 11052,
"santos": 11053,
"whispers": 11054,
"drained": 11055,
"subspecies": 11056,
"##aa": 11057,
"streaming": 11058,
"ulster": 11059,
"burnt": 11060,
"correspondence": 11061,
"maternal": 11062,
"gerard": 11063,
"denis": 11064,
"stealing": 11065,
"##load": 11066,
"genius": 11067,
"duchy": 11068,
"##oria": 11069,
"inaugurated": 11070,
"momentum": 11071,
"suits": 11072,
"placement": 11073,
"sovereign": 11074,
"clause": 11075,
"thames": 11076,
"##hara": 11077,
"confederation": 11078,
"reservation": 11079,
"sketch": 11080,
"yankees": 11081,
"lets": 11082,
"rotten": 11083,
"charm": 11084,
"hal": 11085,
"verses": 11086,
"ultra": 11087,
"commercially": 11088,
"dot": 11089,
"salon": 11090,
"citation": 11091,
"adopt": 11092,
"winnipeg": 11093,
"mist": 11094,
"allocated": 11095,
"cairo": 11096,
"##boy": 11097,
"jenkins": 11098,
"interference": 11099,
"objectives": 11100,
"##wind": 11101,
"1820": 11102,
"portfolio": 11103,
"armoured": 11104,
"sectors": 11105,
"##eh": 11106,
"initiatives": 11107,
"##world": 11108,
"integrity": 11109,
"exercises": 11110,
"robe": 11111,
"tap": 11112,
"ab": 11113,
"gazed": 11114,
"##tones": 11115,
"distracted": 11116,
"rulers": 11117,
"111": 11118,
"favorable": 11119,
"jerome": 11120,
"tended": 11121,
"cart": 11122,
"factories": 11123,
"##eri": 11124,
"diplomat": 11125,
"valued": 11126,
"gravel": 11127,
"charitable": 11128,
"##try": 11129,
"calvin": 11130,
"exploring": 11131,
"chang": 11132,
"shepherd": 11133,
"terrace": 11134,
"pdf": 11135,
"pupil": 11136,
"##ural": 11137,
"reflects": 11138,
"ups": 11139,
"##rch": 11140,
"governors": 11141,
"shelf": 11142,
"depths": 11143,
"##nberg": 11144,
"trailed": 11145,
"crest": 11146,
"tackle": 11147,
"##nian": 11148,
"##ats": 11149,
"hatred": 11150,
"##kai": 11151,
"clare": 11152,
"makers": 11153,
"ethiopia": 11154,
"longtime": 11155,
"detected": 11156,
"embedded": 11157,
"lacking": 11158,
"slapped": 11159,
"rely": 11160,
"thomson": 11161,
"anticipation": 11162,
"iso": 11163,
"morton": 11164,
"successive": 11165,
"agnes": 11166,
"screenwriter": 11167,
"straightened": 11168,
"philippe": 11169,
"playwright": 11170,
"haunted": 11171,
"licence": 11172,
"iris": 11173,
"intentions": 11174,
"sutton": 11175,
"112": 11176,
"logical": 11177,
"correctly": 11178,
"##weight": 11179,
"branded": 11180,
"licked": 11181,
"tipped": 11182,
"silva": 11183,
"ricky": 11184,
"narrator": 11185,
"requests": 11186,
"##ents": 11187,
"greeted": 11188,
"supernatural": 11189,
"cow": 11190,
"##wald": 11191,
"lung": 11192,
"refusing": 11193,
"employer": 11194,
"strait": 11195,
"gaelic": 11196,
"liner": 11197,
"##piece": 11198,
"zoe": 11199,
"sabha": 11200,
"##mba": 11201,
"driveway": 11202,
"harvest": 11203,
"prints": 11204,
"bates": 11205,
"reluctantly": 11206,
"threshold": 11207,
"algebra": 11208,
"ira": 11209,
"wherever": 11210,
"coupled": 11211,
"240": 11212,
"assumption": 11213,
"picks": 11214,
"##air": 11215,
"designers": 11216,
"raids": 11217,
"gentlemen": 11218,
"##ean": 11219,
"roller": 11220,
"blowing": 11221,
"leipzig": 11222,
"locks": 11223,
"screw": 11224,
"dressing": 11225,
"strand": 11226,
"##lings": 11227,
"scar": 11228,
"dwarf": 11229,
"depicts": 11230,
"##nu": 11231,
"nods": 11232,
"##mine": 11233,
"differ": 11234,
"boris": 11235,
"##eur": 11236,
"yuan": 11237,
"flip": 11238,
"##gie": 11239,
"mob": 11240,
"invested": 11241,
"questioning": 11242,
"applying": 11243,
"##ture": 11244,
"shout": 11245,
"##sel": 11246,
"gameplay": 11247,
"blamed": 11248,
"illustrations": 11249,
"bothered": 11250,
"weakness": 11251,
"rehabilitation": 11252,
"##of": 11253,
"##zes": 11254,
"envelope": 11255,
"rumors": 11256,
"miners": 11257,
"leicester": 11258,
"subtle": 11259,
"kerry": 11260,
"##ico": 11261,
"ferguson": 11262,
"##fu": 11263,
"premiership": 11264,
"ne": 11265,
"##cat": 11266,
"bengali": 11267,
"prof": 11268,
"catches": 11269,
"remnants": 11270,
"dana": 11271,
"##rily": 11272,
"shouting": 11273,
"presidents": 11274,
"baltic": 11275,
"ought": 11276,
"ghosts": 11277,
"dances": 11278,
"sailors": 11279,
"shirley": 11280,
"fancy": 11281,
"dominic": 11282,
"##bie": 11283,
"madonna": 11284,
"##rick": 11285,
"bark": 11286,
"buttons": 11287,
"gymnasium": 11288,
"ashes": 11289,
"liver": 11290,
"toby": 11291,
"oath": 11292,
"providence": 11293,
"doyle": 11294,
"evangelical": 11295,
"nixon": 11296,
"cement": 11297,
"carnegie": 11298,
"embarked": 11299,
"hatch": 11300,
"surroundings": 11301,
"guarantee": 11302,
"needing": 11303,
"pirate": 11304,
"essence": 11305,
"##bee": 11306,
"filter": 11307,
"crane": 11308,
"hammond": 11309,
"projected": 11310,
"immune": 11311,
"percy": 11312,
"twelfth": 11313,
"##ult": 11314,
"regent": 11315,
"doctoral": 11316,
"damon": 11317,
"mikhail": 11318,
"##ichi": 11319,
"lu": 11320,
"critically": 11321,
"elect": 11322,
"realised": 11323,
"abortion": 11324,
"acute": 11325,
"screening": 11326,
"mythology": 11327,
"steadily": 11328,
"##fc": 11329,
"frown": 11330,
"nottingham": 11331,
"kirk": 11332,
"wa": 11333,
"minneapolis": 11334,
"##rra": 11335,
"module": 11336,
"algeria": 11337,
"mc": 11338,
"nautical": 11339,
"encounters": 11340,
"surprising": 11341,
"statues": 11342,
"availability": 11343,
"shirts": 11344,
"pie": 11345,
"alma": 11346,
"brows": 11347,
"munster": 11348,
"mack": 11349,
"soup": 11350,
"crater": 11351,
"tornado": 11352,
"sanskrit": 11353,
"cedar": 11354,
"explosive": 11355,
"bordered": 11356,
"dixon": 11357,
"planets": 11358,
"stamp": 11359,
"exam": 11360,
"happily": 11361,
"##bble": 11362,
"carriers": 11363,
"kidnapped": 11364,
"##vis": 11365,
"accommodation": 11366,
"emigrated": 11367,
"##met": 11368,
"knockout": 11369,
"correspondent": 11370,
"violation": 11371,
"profits": 11372,
"peaks": 11373,
"lang": 11374,
"specimen": 11375,
"agenda": 11376,
"ancestry": 11377,
"pottery": 11378,
"spelling": 11379,
"equations": 11380,
"obtaining": 11381,
"ki": 11382,
"linking": 11383,
"1825": 11384,
"debris": 11385,
"asylum": 11386,
"##20": 11387,
"buddhism": 11388,
"teddy": 11389,
"##ants": 11390,
"gazette": 11391,
"##nger": 11392,
"##sse": 11393,
"dental": 11394,
"eligibility": 11395,
"utc": 11396,
"fathers": 11397,
"averaged": 11398,
"zimbabwe": 11399,
"francesco": 11400,
"coloured": 11401,
"hissed": 11402,
"translator": 11403,
"lynch": 11404,
"mandate": 11405,
"humanities": 11406,
"mackenzie": 11407,
"uniforms": 11408,
"lin": 11409,
"##iana": 11410,
"##gio": 11411,
"asset": 11412,
"mhz": 11413,
"fitting": 11414,
"samantha": 11415,
"genera": 11416,
"wei": 11417,
"rim": 11418,
"beloved": 11419,
"shark": 11420,
"riot": 11421,
"entities": 11422,
"expressions": 11423,
"indo": 11424,
"carmen": 11425,
"slipping": 11426,
"owing": 11427,
"abbot": 11428,
"neighbor": 11429,
"sidney": 11430,
"##av": 11431,
"rats": 11432,
"recommendations": 11433,
"encouraging": 11434,
"squadrons": 11435,
"anticipated": 11436,
"commanders": 11437,
"conquered": 11438,
"##oto": 11439,
"donations": 11440,
"diagnosed": 11441,
"##mond": 11442,
"divide": 11443,
"##iva": 11444,
"guessed": 11445,
"decoration": 11446,
"vernon": 11447,
"auditorium": 11448,
"revelation": 11449,
"conversations": 11450,
"##kers": 11451,
"##power": 11452,
"herzegovina": 11453,
"dash": 11454,
"alike": 11455,
"protested": 11456,
"lateral": 11457,
"herman": 11458,
"accredited": 11459,
"mg": 11460,
"##gent": 11461,
"freeman": 11462,
"mel": 11463,
"fiji": 11464,
"crow": 11465,
"crimson": 11466,
"##rine": 11467,
"livestock": 11468,
"##pped": 11469,
"humanitarian": 11470,
"bored": 11471,
"oz": 11472,
"whip": 11473,
"##lene": 11474,
"##ali": 11475,
"legitimate": 11476,
"alter": 11477,
"grinning": 11478,
"spelled": 11479,
"anxious": 11480,
"oriental": 11481,
"wesley": 11482,
"##nin": 11483,
"##hole": 11484,
"carnival": 11485,
"controller": 11486,
"detect": 11487,
"##ssa": 11488,
"bowed": 11489,
"educator": 11490,
"kosovo": 11491,
"macedonia": 11492,
"##sin": 11493,
"occupy": 11494,
"mastering": 11495,
"stephanie": 11496,
"janeiro": 11497,
"para": 11498,
"unaware": 11499,
"nurses": 11500,
"noon": 11501,
"135": 11502,
"cam": 11503,
"hopefully": 11504,
"ranger": 11505,
"combine": 11506,
"sociology": 11507,
"polar": 11508,
"rica": 11509,
"##eer": 11510,
"neill": 11511,
"##sman": 11512,
"holocaust": 11513,
"##ip": 11514,
"doubled": 11515,
"lust": 11516,
"1828": 11517,
"109": 11518,
"decent": 11519,
"cooling": 11520,
"unveiled": 11521,
"##card": 11522,
"1829": 11523,
"nsw": 11524,
"homer": 11525,
"chapman": 11526,
"meyer": 11527,
"##gin": 11528,
"dive": 11529,
"mae": 11530,
"reagan": 11531,
"expertise": 11532,
"##gled": 11533,
"darwin": 11534,
"brooke": 11535,
"sided": 11536,
"prosecution": 11537,
"investigating": 11538,
"comprised": 11539,
"petroleum": 11540,
"genres": 11541,
"reluctant": 11542,
"differently": 11543,
"trilogy": 11544,
"johns": 11545,
"vegetables": 11546,
"corpse": 11547,
"highlighted": 11548,
"lounge": 11549,
"pension": 11550,
"unsuccessfully": 11551,
"elegant": 11552,
"aided": 11553,
"ivory": 11554,
"beatles": 11555,
"amelia": 11556,
"cain": 11557,
"dubai": 11558,
"sunny": 11559,
"immigrant": 11560,
"babe": 11561,
"click": 11562,
"##nder": 11563,
"underwater": 11564,
"pepper": 11565,
"combining": 11566,
"mumbled": 11567,
"atlas": 11568,
"horns": 11569,
"accessed": 11570,
"ballad": 11571,
"physicians": 11572,
"homeless": 11573,
"gestured": 11574,
"rpm": 11575,
"freak": 11576,
"louisville": 11577,
"corporations": 11578,
"patriots": 11579,
"prizes": 11580,
"rational": 11581,
"warn": 11582,
"modes": 11583,
"decorative": 11584,
"overnight": 11585,
"din": 11586,
"troubled": 11587,
"phantom": 11588,
"##ort": 11589,
"monarch": 11590,
"sheer": 11591,
"##dorf": 11592,
"generals": 11593,
"guidelines": 11594,
"organs": 11595,
"addresses": 11596,
"##zon": 11597,
"enhance": 11598,
"curling": 11599,
"parishes": 11600,
"cord": 11601,
"##kie": 11602,
"linux": 11603,
"caesar": 11604,
"deutsche": 11605,
"bavaria": 11606,
"##bia": 11607,
"coleman": 11608,
"cyclone": 11609,
"##eria": 11610,
"bacon": 11611,
"petty": 11612,
"##yama": 11613,
"##old": 11614,
"hampton": 11615,
"diagnosis": 11616,
"1824": 11617,
"throws": 11618,
"complexity": 11619,
"rita": 11620,
"disputed": 11621,
"##₃": 11622,
"pablo": 11623,
"##sch": 11624,
"marketed": 11625,
"trafficking": 11626,
"##ulus": 11627,
"examine": 11628,
"plague": 11629,
"formats": 11630,
"##oh": 11631,
"vault": 11632,
"faithful": 11633,
"##bourne": 11634,
"webster": 11635,
"##ox": 11636,
"highlights": 11637,
"##ient": 11638,
"##ann": 11639,
"phones": 11640,
"vacuum": 11641,
"sandwich": 11642,
"modeling": 11643,
"##gated": 11644,
"bolivia": 11645,
"clergy": 11646,
"qualities": 11647,
"isabel": 11648,
"##nas": 11649,
"##ars": 11650,
"wears": 11651,
"screams": 11652,
"reunited": 11653,
"annoyed": 11654,
"bra": 11655,
"##ancy": 11656,
"##rate": 11657,
"differential": 11658,
"transmitter": 11659,
"tattoo": 11660,
"container": 11661,
"poker": 11662,
"##och": 11663,
"excessive": 11664,
"resides": 11665,
"cowboys": 11666,
"##tum": 11667,
"augustus": 11668,
"trash": 11669,
"providers": 11670,
"statute": 11671,
"retreated": 11672,
"balcony": 11673,
"reversed": 11674,
"void": 11675,
"storey": 11676,
"preceded": 11677,
"masses": 11678,
"leap": 11679,
"laughs": 11680,
"neighborhoods": 11681,
"wards": 11682,
"schemes": 11683,
"falcon": 11684,
"santo": 11685,
"battlefield": 11686,
"pad": 11687,
"ronnie": 11688,
"thread": 11689,
"lesbian": 11690,
"venus": 11691,
"##dian": 11692,
"beg": 11693,
"sandstone": 11694,
"daylight": 11695,
"punched": 11696,
"gwen": 11697,
"analog": 11698,
"stroked": 11699,
"wwe": 11700,
"acceptable": 11701,
"measurements": 11702,
"dec": 11703,
"toxic": 11704,
"##kel": 11705,
"adequate": 11706,
"surgical": 11707,
"economist": 11708,
"parameters": 11709,
"varsity": 11710,
"##sberg": 11711,
"quantity": 11712,
"ella": 11713,
"##chy": 11714,
"##rton": 11715,
"countess": 11716,
"generating": 11717,
"precision": 11718,
"diamonds": 11719,
"expressway": 11720,
"ga": 11721,
"##ı": 11722,
"1821": 11723,
"uruguay": 11724,
"talents": 11725,
"galleries": 11726,
"expenses": 11727,
"scanned": 11728,
"colleague": 11729,
"outlets": 11730,
"ryder": 11731,
"lucien": 11732,
"##ila": 11733,
"paramount": 11734,
"##bon": 11735,
"syracuse": 11736,
"dim": 11737,
"fangs": 11738,
"gown": 11739,
"sweep": 11740,
"##sie": 11741,
"toyota": 11742,
"missionaries": 11743,
"websites": 11744,
"##nsis": 11745,
"sentences": 11746,
"adviser": 11747,
"val": 11748,
"trademark": 11749,
"spells": 11750,
"##plane": 11751,
"patience": 11752,
"starter": 11753,
"slim": 11754,
"##borg": 11755,
"toe": 11756,
"incredibly": 11757,
"shoots": 11758,
"elliot": 11759,
"nobility": 11760,
"##wyn": 11761,
"cowboy": 11762,
"endorsed": 11763,
"gardner": 11764,
"tendency": 11765,
"persuaded": 11766,
"organisms": 11767,
"emissions": 11768,
"kazakhstan": 11769,
"amused": 11770,
"boring": 11771,
"chips": 11772,
"themed": 11773,
"##hand": 11774,
"llc": 11775,
"constantinople": 11776,
"chasing": 11777,
"systematic": 11778,
"guatemala": 11779,
"borrowed": 11780,
"erin": 11781,
"carey": 11782,
"##hard": 11783,
"highlands": 11784,
"struggles": 11785,
"1810": 11786,
"##ifying": 11787,
"##ced": 11788,
"wong": 11789,
"exceptions": 11790,
"develops": 11791,
"enlarged": 11792,
"kindergarten": 11793,
"castro": 11794,
"##ern": 11795,
"##rina": 11796,
"leigh": 11797,
"zombie": 11798,
"juvenile": 11799,
"##most": 11800,
"consul": 11801,
"##nar": 11802,
"sailor": 11803,
"hyde": 11804,
"clarence": 11805,
"intensive": 11806,
"pinned": 11807,
"nasty": 11808,
"useless": 11809,
"jung": 11810,
"clayton": 11811,
"stuffed": 11812,
"exceptional": 11813,
"ix": 11814,
"apostolic": 11815,
"230": 11816,
"transactions": 11817,
"##dge": 11818,
"exempt": 11819,
"swinging": 11820,
"cove": 11821,
"religions": 11822,
"##ash": 11823,
"shields": 11824,
"dairy": 11825,
"bypass": 11826,
"190": 11827,
"pursuing": 11828,
"bug": 11829,
"joyce": 11830,
"bombay": 11831,
"chassis": 11832,
"southampton": 11833,
"chat": 11834,
"interact": 11835,
"redesignated": 11836,
"##pen": 11837,
"nascar": 11838,
"pray": 11839,
"salmon": 11840,
"rigid": 11841,
"regained": 11842,
"malaysian": 11843,
"grim": 11844,
"publicity": 11845,
"constituted": 11846,
"capturing": 11847,
"toilet": 11848,
"delegate": 11849,
"purely": 11850,
"tray": 11851,
"drift": 11852,
"loosely": 11853,
"striker": 11854,
"weakened": 11855,
"trinidad": 11856,
"mitch": 11857,
"itv": 11858,
"defines": 11859,
"transmitted": 11860,
"ming": 11861,
"scarlet": 11862,
"nodding": 11863,
"fitzgerald": 11864,
"fu": 11865,
"narrowly": 11866,
"sp": 11867,
"tooth": 11868,
"standings": 11869,
"virtue": 11870,
"##₁": 11871,
"##wara": 11872,
"##cting": 11873,
"chateau": 11874,
"gloves": 11875,
"lid": 11876,
"##nel": 11877,
"hurting": 11878,
"conservatory": 11879,
"##pel": 11880,
"sinclair": 11881,
"reopened": 11882,
"sympathy": 11883,
"nigerian": 11884,
"strode": 11885,
"advocated": 11886,
"optional": 11887,
"chronic": 11888,
"discharge": 11889,
"##rc": 11890,
"suck": 11891,
"compatible": 11892,
"laurel": 11893,
"stella": 11894,
"shi": 11895,
"fails": 11896,
"wage": 11897,
"dodge": 11898,
"128": 11899,
"informal": 11900,
"sorts": 11901,
"levi": 11902,
"buddha": 11903,
"villagers": 11904,
"##aka": 11905,
"chronicles": 11906,
"heavier": 11907,
"summoned": 11908,
"gateway": 11909,
"3000": 11910,
"eleventh": 11911,
"jewelry": 11912,
"translations": 11913,
"accordingly": 11914,
"seas": 11915,
"##ency": 11916,
"fiber": 11917,
"pyramid": 11918,
"cubic": 11919,
"dragging": 11920,
"##ista": 11921,
"caring": 11922,
"##ops": 11923,
"android": 11924,
"contacted": 11925,
"lunar": 11926,
"##dt": 11927,
"kai": 11928,
"lisbon": 11929,
"patted": 11930,
"1826": 11931,
"sacramento": 11932,
"theft": 11933,
"madagascar": 11934,
"subtropical": 11935,
"disputes": 11936,
"ta": 11937,
"holidays": 11938,
"piper": 11939,
"willow": 11940,
"mare": 11941,
"cane": 11942,
"itunes": 11943,
"newfoundland": 11944,
"benny": 11945,
"companions": 11946,
"dong": 11947,
"raj": 11948,
"observe": 11949,
"roar": 11950,
"charming": 11951,
"plaque": 11952,
"tibetan": 11953,
"fossils": 11954,
"enacted": 11955,
"manning": 11956,
"bubble": 11957,
"tina": 11958,
"tanzania": 11959,
"##eda": 11960,
"##hir": 11961,
"funk": 11962,
"swamp": 11963,
"deputies": 11964,
"cloak": 11965,
"ufc": 11966,
"scenario": 11967,
"par": 11968,
"scratch": 11969,
"metals": 11970,
"anthem": 11971,
"guru": 11972,
"engaging": 11973,
"specially": 11974,
"##boat": 11975,
"dialects": 11976,
"nineteen": 11977,
"cecil": 11978,
"duet": 11979,
"disability": 11980,
"messenger": 11981,
"unofficial": 11982,
"##lies": 11983,
"defunct": 11984,
"eds": 11985,
"moonlight": 11986,
"drainage": 11987,
"surname": 11988,
"puzzle": 11989,
"honda": 11990,
"switching": 11991,
"conservatives": 11992,
"mammals": 11993,
"knox": 11994,
"broadcaster": 11995,
"sidewalk": 11996,
"cope": 11997,
"##ried": 11998,
"benson": 11999,
"princes": 12000,
"peterson": 12001,
"##sal": 12002,
"bedford": 12003,
"sharks": 12004,
"eli": 12005,
"wreck": 12006,
"alberto": 12007,
"gasp": 12008,
"archaeology": 12009,
"lgbt": 12010,
"teaches": 12011,
"securities": 12012,
"madness": 12013,
"compromise": 12014,
"waving": 12015,
"coordination": 12016,
"davidson": 12017,
"visions": 12018,
"leased": 12019,
"possibilities": 12020,
"eighty": 12021,
"jun": 12022,
"fernandez": 12023,
"enthusiasm": 12024,
"assassin": 12025,
"sponsorship": 12026,
"reviewer": 12027,
"kingdoms": 12028,
"estonian": 12029,
"laboratories": 12030,
"##fy": 12031,
"##nal": 12032,
"applies": 12033,
"verb": 12034,
"celebrations": 12035,
"##zzo": 12036,
"rowing": 12037,
"lightweight": 12038,
"sadness": 12039,
"submit": 12040,
"mvp": 12041,
"balanced": 12042,
"dude": 12043,
"##vas": 12044,
"explicitly": 12045,
"metric": 12046,
"magnificent": 12047,
"mound": 12048,
"brett": 12049,
"mohammad": 12050,
"mistakes": 12051,
"irregular": 12052,
"##hing": 12053,
"##ass": 12054,
"sanders": 12055,
"betrayed": 12056,
"shipped": 12057,
"surge": 12058,
"##enburg": 12059,
"reporters": 12060,
"termed": 12061,
"georg": 12062,
"pity": 12063,
"verbal": 12064,
"bulls": 12065,
"abbreviated": 12066,
"enabling": 12067,
"appealed": 12068,
"##are": 12069,
"##atic": 12070,
"sicily": 12071,
"sting": 12072,
"heel": 12073,
"sweetheart": 12074,
"bart": 12075,
"spacecraft": 12076,
"brutal": 12077,
"monarchy": 12078,
"##tter": 12079,
"aberdeen": 12080,
"cameo": 12081,
"diane": 12082,
"##ub": 12083,
"survivor": 12084,
"clyde": 12085,
"##aries": 12086,
"complaint": 12087,
"##makers": 12088,
"clarinet": 12089,
"delicious": 12090,
"chilean": 12091,
"karnataka": 12092,
"coordinates": 12093,
"1818": 12094,
"panties": 12095,
"##rst": 12096,
"pretending": 12097,
"ar": 12098,
"dramatically": 12099,
"kiev": 12100,
"bella": 12101,
"tends": 12102,
"distances": 12103,
"113": 12104,
"catalog": 12105,
"launching": 12106,
"instances": 12107,
"telecommunications": 12108,
"portable": 12109,
"lindsay": 12110,
"vatican": 12111,
"##eim": 12112,
"angles": 12113,
"aliens": 12114,
"marker": 12115,
"stint": 12116,
"screens": 12117,
"bolton": 12118,
"##rne": 12119,
"judy": 12120,
"wool": 12121,
"benedict": 12122,
"plasma": 12123,
"europa": 12124,
"spark": 12125,
"imaging": 12126,
"filmmaker": 12127,
"swiftly": 12128,
"##een": 12129,
"contributor": 12130,
"##nor": 12131,
"opted": 12132,
"stamps": 12133,
"apologize": 12134,
"financing": 12135,
"butter": 12136,
"gideon": 12137,
"sophisticated": 12138,
"alignment": 12139,
"avery": 12140,
"chemicals": 12141,
"yearly": 12142,
"speculation": 12143,
"prominence": 12144,
"professionally": 12145,
"##ils": 12146,
"immortal": 12147,
"institutional": 12148,
"inception": 12149,
"wrists": 12150,
"identifying": 12151,
"tribunal": 12152,
"derives": 12153,
"gains": 12154,
"##wo": 12155,
"papal": 12156,
"preference": 12157,
"linguistic": 12158,
"vince": 12159,
"operative": 12160,
"brewery": 12161,
"##ont": 12162,
"unemployment": 12163,
"boyd": 12164,
"##ured": 12165,
"##outs": 12166,
"albeit": 12167,
"prophet": 12168,
"1813": 12169,
"bi": 12170,
"##rr": 12171,
"##face": 12172,
"##rad": 12173,
"quarterly": 12174,
"asteroid": 12175,
"cleaned": 12176,
"radius": 12177,
"temper": 12178,
"##llen": 12179,
"telugu": 12180,
"jerk": 12181,
"viscount": 12182,
"menu": 12183,
"##ote": 12184,
"glimpse": 12185,
"##aya": 12186,
"yacht": 12187,
"hawaiian": 12188,
"baden": 12189,
"##rl": 12190,
"laptop": 12191,
"readily": 12192,
"##gu": 12193,
"monetary": 12194,
"offshore": 12195,
"scots": 12196,
"watches": 12197,
"##yang": 12198,
"##arian": 12199,
"upgrade": 12200,
"needle": 12201,
"xbox": 12202,
"lea": 12203,
"encyclopedia": 12204,
"flank": 12205,
"fingertips": 12206,
"##pus": 12207,
"delight": 12208,
"teachings": 12209,
"confirm": 12210,
"roth": 12211,
"beaches": 12212,
"midway": 12213,
"winters": 12214,
"##iah": 12215,
"teasing": 12216,
"daytime": 12217,
"beverly": 12218,
"gambling": 12219,
"bonnie": 12220,
"##backs": 12221,
"regulated": 12222,
"clement": 12223,
"hermann": 12224,
"tricks": 12225,
"knot": 12226,
"##shing": 12227,
"##uring": 12228,
"##vre": 12229,
"detached": 12230,
"ecological": 12231,
"owed": 12232,
"specialty": 12233,
"byron": 12234,
"inventor": 12235,
"bats": 12236,
"stays": 12237,
"screened": 12238,
"unesco": 12239,
"midland": 12240,
"trim": 12241,
"affection": 12242,
"##ander": 12243,
"##rry": 12244,
"jess": 12245,
"thoroughly": 12246,
"feedback": 12247,
"##uma": 12248,
"chennai": 12249,
"strained": 12250,
"heartbeat": 12251,
"wrapping": 12252,
"overtime": 12253,
"pleaded": 12254,
"##sworth": 12255,
"mon": 12256,
"leisure": 12257,
"oclc": 12258,
"##tate": 12259,
"##ele": 12260,
"feathers": 12261,
"angelo": 12262,
"thirds": 12263,
"nuts": 12264,
"surveys": 12265,
"clever": 12266,
"gill": 12267,
"commentator": 12268,
"##dos": 12269,
"darren": 12270,
"rides": 12271,
"gibraltar": 12272,
"##nc": 12273,
"##mu": 12274,
"dissolution": 12275,
"dedication": 12276,
"shin": 12277,
"meals": 12278,
"saddle": 12279,
"elvis": 12280,
"reds": 12281,
"chaired": 12282,
"taller": 12283,
"appreciation": 12284,
"functioning": 12285,
"niece": 12286,
"favored": 12287,
"advocacy": 12288,
"robbie": 12289,
"criminals": 12290,
"suffolk": 12291,
"yugoslav": 12292,
"passport": 12293,
"constable": 12294,
"congressman": 12295,
"hastings": 12296,
"vera": 12297,
"##rov": 12298,
"consecrated": 12299,
"sparks": 12300,
"ecclesiastical": 12301,
"confined": 12302,
"##ovich": 12303,
"muller": 12304,
"floyd": 12305,
"nora": 12306,
"1822": 12307,
"paved": 12308,
"1827": 12309,
"cumberland": 12310,
"ned": 12311,
"saga": 12312,
"spiral": 12313,
"##flow": 12314,
"appreciated": 12315,
"yi": 12316,
"collaborative": 12317,
"treating": 12318,
"similarities": 12319,
"feminine": 12320,
"finishes": 12321,
"##ib": 12322,
"jade": 12323,
"import": 12324,
"##nse": 12325,
"##hot": 12326,
"champagne": 12327,
"mice": 12328,
"securing": 12329,
"celebrities": 12330,
"helsinki": 12331,
"attributes": 12332,
"##gos": 12333,
"cousins": 12334,
"phases": 12335,
"ache": 12336,
"lucia": 12337,
"gandhi": 12338,
"submission": 12339,
"vicar": 12340,
"spear": 12341,
"shine": 12342,
"tasmania": 12343,
"biting": 12344,
"detention": 12345,
"constitute": 12346,
"tighter": 12347,
"seasonal": 12348,
"##gus": 12349,
"terrestrial": 12350,
"matthews": 12351,
"##oka": 12352,
"effectiveness": 12353,
"parody": 12354,
"philharmonic": 12355,
"##onic": 12356,
"1816": 12357,
"strangers": 12358,
"encoded": 12359,
"consortium": 12360,
"guaranteed": 12361,
"regards": 12362,
"shifts": 12363,
"tortured": 12364,
"collision": 12365,
"supervisor": 12366,
"inform": 12367,
"broader": 12368,
"insight": 12369,
"theaters": 12370,
"armour": 12371,
"emeritus": 12372,
"blink": 12373,
"incorporates": 12374,
"mapping": 12375,
"##50": 12376,
"##ein": 12377,
"handball": 12378,
"flexible": 12379,
"##nta": 12380,
"substantially": 12381,
"generous": 12382,
"thief": 12383,
"##own": 12384,
"carr": 12385,
"loses": 12386,
"1793": 12387,
"prose": 12388,
"ucla": 12389,
"romeo": 12390,
"generic": 12391,
"metallic": 12392,
"realization": 12393,
"damages": 12394,
"mk": 12395,
"commissioners": 12396,
"zach": 12397,
"default": 12398,
"##ther": 12399,
"helicopters": 12400,
"lengthy": 12401,
"stems": 12402,
"spa": 12403,
"partnered": 12404,
"spectators": 12405,
"rogue": 12406,
"indication": 12407,
"penalties": 12408,
"teresa": 12409,
"1801": 12410,
"sen": 12411,
"##tric": 12412,
"dalton": 12413,
"##wich": 12414,
"irving": 12415,
"photographic": 12416,
"##vey": 12417,
"dell": 12418,
"deaf": 12419,
"peters": 12420,
"excluded": 12421,
"unsure": 12422,
"##vable": 12423,
"patterson": 12424,
"crawled": 12425,
"##zio": 12426,
"resided": 12427,
"whipped": 12428,
"latvia": 12429,
"slower": 12430,
"ecole": 12431,
"pipes": 12432,
"employers": 12433,
"maharashtra": 12434,
"comparable": 12435,
"va": 12436,
"textile": 12437,
"pageant": 12438,
"##gel": 12439,
"alphabet": 12440,
"binary": 12441,
"irrigation": 12442,
"chartered": 12443,
"choked": 12444,
"antoine": 12445,
"offs": 12446,
"waking": 12447,
"supplement": 12448,
"##wen": 12449,
"quantities": 12450,
"demolition": 12451,
"regain": 12452,
"locate": 12453,
"urdu": 12454,
"folks": 12455,
"alt": 12456,
"114": 12457,
"##mc": 12458,
"scary": 12459,
"andreas": 12460,
"whites": 12461,
"##ava": 12462,
"classrooms": 12463,
"mw": 12464,
"aesthetic": 12465,
"publishes": 12466,
"valleys": 12467,
"guides": 12468,
"cubs": 12469,
"johannes": 12470,
"bryant": 12471,
"conventions": 12472,
"affecting": 12473,
"##itt": 12474,
"drain": 12475,
"awesome": 12476,
"isolation": 12477,
"prosecutor": 12478,
"ambitious": 12479,
"apology": 12480,
"captive": 12481,
"downs": 12482,
"atmospheric": 12483,
"lorenzo": 12484,
"aisle": 12485,
"beef": 12486,
"foul": 12487,
"##onia": 12488,
"kidding": 12489,
"composite": 12490,
"disturbed": 12491,
"illusion": 12492,
"natives": 12493,
"##ffer": 12494,
"emi": 12495,
"rockets": 12496,
"riverside": 12497,
"wartime": 12498,
"painters": 12499,
"adolf": 12500,
"melted": 12501,
"##ail": 12502,
"uncertainty": 12503,
"simulation": 12504,
"hawks": 12505,
"progressed": 12506,
"meantime": 12507,
"builder": 12508,
"spray": 12509,
"breach": 12510,
"unhappy": 12511,
"regina": 12512,
"russians": 12513,
"##urg": 12514,
"determining": 12515,
"##tation": 12516,
"tram": 12517,
"1806": 12518,
"##quin": 12519,
"aging": 12520,
"##12": 12521,
"1823": 12522,
"garion": 12523,
"rented": 12524,
"mister": 12525,
"diaz": 12526,
"terminated": 12527,
"clip": 12528,
"1817": 12529,
"depend": 12530,
"nervously": 12531,
"disco": 12532,
"owe": 12533,
"defenders": 12534,
"shiva": 12535,
"notorious": 12536,
"disbelief": 12537,
"shiny": 12538,
"worcester": 12539,
"##gation": 12540,
"##yr": 12541,
"trailing": 12542,
"undertook": 12543,
"islander": 12544,
"belarus": 12545,
"limitations": 12546,
"watershed": 12547,
"fuller": 12548,
"overlooking": 12549,
"utilized": 12550,
"raphael": 12551,
"1819": 12552,
"synthetic": 12553,
"breakdown": 12554,
"klein": 12555,
"##nate": 12556,
"moaned": 12557,
"memoir": 12558,
"lamb": 12559,
"practicing": 12560,
"##erly": 12561,
"cellular": 12562,
"arrows": 12563,
"exotic": 12564,
"##graphy": 12565,
"witches": 12566,
"117": 12567,
"charted": 12568,
"rey": 12569,
"hut": 12570,
"hierarchy": 12571,
"subdivision": 12572,
"freshwater": 12573,
"giuseppe": 12574,
"aloud": 12575,
"reyes": 12576,
"qatar": 12577,
"marty": 12578,
"sideways": 12579,
"utterly": 12580,
"sexually": 12581,
"jude": 12582,
"prayers": 12583,
"mccarthy": 12584,
"softball": 12585,
"blend": 12586,
"damien": 12587,
"##gging": 12588,
"##metric": 12589,
"wholly": 12590,
"erupted": 12591,
"lebanese": 12592,
"negro": 12593,
"revenues": 12594,
"tasted": 12595,
"comparative": 12596,
"teamed": 12597,
"transaction": 12598,
"labeled": 12599,
"maori": 12600,
"sovereignty": 12601,
"parkway": 12602,
"trauma": 12603,
"gran": 12604,
"malay": 12605,
"121": 12606,
"advancement": 12607,
"descendant": 12608,
"2020": 12609,
"buzz": 12610,
"salvation": 12611,
"inventory": 12612,
"symbolic": 12613,
"##making": 12614,
"antarctica": 12615,
"mps": 12616,
"##gas": 12617,
"##bro": 12618,
"mohammed": 12619,
"myanmar": 12620,
"holt": 12621,
"submarines": 12622,
"tones": 12623,
"##lman": 12624,
"locker": 12625,
"patriarch": 12626,
"bangkok": 12627,
"emerson": 12628,
"remarks": 12629,
"predators": 12630,
"kin": 12631,
"afghan": 12632,
"confession": 12633,
"norwich": 12634,
"rental": 12635,
"emerge": 12636,
"advantages": 12637,
"##zel": 12638,
"rca": 12639,
"##hold": 12640,
"shortened": 12641,
"storms": 12642,
"aidan": 12643,
"##matic": 12644,
"autonomy": 12645,
"compliance": 12646,
"##quet": 12647,
"dudley": 12648,
"atp": 12649,
"##osis": 12650,
"1803": 12651,
"motto": 12652,
"documentation": 12653,
"summary": 12654,
"professors": 12655,
"spectacular": 12656,
"christina": 12657,
"archdiocese": 12658,
"flashing": 12659,
"innocence": 12660,
"remake": 12661,
"##dell": 12662,
"psychic": 12663,
"reef": 12664,
"scare": 12665,
"employ": 12666,
"rs": 12667,
"sticks": 12668,
"meg": 12669,
"gus": 12670,
"leans": 12671,
"##ude": 12672,
"accompany": 12673,
"bergen": 12674,
"tomas": 12675,
"##iko": 12676,
"doom": 12677,
"wages": 12678,
"pools": 12679,
"##nch": 12680,
"##bes": 12681,
"breasts": 12682,
"scholarly": 12683,
"alison": 12684,
"outline": 12685,
"brittany": 12686,
"breakthrough": 12687,
"willis": 12688,
"realistic": 12689,
"##cut": 12690,
"##boro": 12691,
"competitor": 12692,
"##stan": 12693,
"pike": 12694,
"picnic": 12695,
"icon": 12696,
"designing": 12697,
"commercials": 12698,
"washing": 12699,
"villain": 12700,
"skiing": 12701,
"micro": 12702,
"costumes": 12703,
"auburn": 12704,
"halted": 12705,
"executives": 12706,
"##hat": 12707,
"logistics": 12708,
"cycles": 12709,
"vowel": 12710,
"applicable": 12711,
"barrett": 12712,
"exclaimed": 12713,
"eurovision": 12714,
"eternity": 12715,
"ramon": 12716,
"##umi": 12717,
"##lls": 12718,
"modifications": 12719,
"sweeping": 12720,
"disgust": 12721,
"##uck": 12722,
"torch": 12723,
"aviv": 12724,
"ensuring": 12725,
"rude": 12726,
"dusty": 12727,
"sonic": 12728,
"donovan": 12729,
"outskirts": 12730,
"cu": 12731,
"pathway": 12732,
"##band": 12733,
"##gun": 12734,
"##lines": 12735,
"disciplines": 12736,
"acids": 12737,
"cadet": 12738,
"paired": 12739,
"##40": 12740,
"sketches": 12741,
"##sive": 12742,
"marriages": 12743,
"##⁺": 12744,
"folding": 12745,
"peers": 12746,
"slovak": 12747,
"implies": 12748,
"admired": 12749,
"##beck": 12750,
"1880s": 12751,
"leopold": 12752,
"instinct": 12753,
"attained": 12754,
"weston": 12755,
"megan": 12756,
"horace": 12757,
"##ination": 12758,
"dorsal": 12759,
"ingredients": 12760,
"evolutionary": 12761,
"##its": 12762,
"complications": 12763,
"deity": 12764,
"lethal": 12765,
"brushing": 12766,
"levy": 12767,
"deserted": 12768,
"institutes": 12769,
"posthumously": 12770,
"delivering": 12771,
"telescope": 12772,
"coronation": 12773,
"motivated": 12774,
"rapids": 12775,
"luc": 12776,
"flicked": 12777,
"pays": 12778,
"volcano": 12779,
"tanner": 12780,
"weighed": 12781,
"##nica": 12782,
"crowds": 12783,
"frankie": 12784,
"gifted": 12785,
"addressing": 12786,
"granddaughter": 12787,
"winding": 12788,
"##rna": 12789,
"constantine": 12790,
"gomez": 12791,
"##front": 12792,
"landscapes": 12793,
"rudolf": 12794,
"anthropology": 12795,
"slate": 12796,
"werewolf": 12797,
"##lio": 12798,
"astronomy": 12799,
"circa": 12800,
"rouge": 12801,
"dreaming": 12802,
"sack": 12803,
"knelt": 12804,
"drowned": 12805,
"naomi": 12806,
"prolific": 12807,
"tracked": 12808,
"freezing": 12809,
"herb": 12810,
"##dium": 12811,
"agony": 12812,
"randall": 12813,
"twisting": 12814,
"wendy": 12815,
"deposit": 12816,
"touches": 12817,
"vein": 12818,
"wheeler": 12819,
"##bbled": 12820,
"##bor": 12821,
"batted": 12822,
"retaining": 12823,
"tire": 12824,
"presently": 12825,
"compare": 12826,
"specification": 12827,
"daemon": 12828,
"nigel": 12829,
"##grave": 12830,
"merry": 12831,
"recommendation": 12832,
"czechoslovakia": 12833,
"sandra": 12834,
"ng": 12835,
"roma": 12836,
"##sts": 12837,
"lambert": 12838,
"inheritance": 12839,
"sheikh": 12840,
"winchester": 12841,
"cries": 12842,
"examining": 12843,
"##yle": 12844,
"comeback": 12845,
"cuisine": 12846,
"nave": 12847,
"##iv": 12848,
"ko": 12849,
"retrieve": 12850,
"tomatoes": 12851,
"barker": 12852,
"polished": 12853,
"defining": 12854,
"irene": 12855,
"lantern": 12856,
"personalities": 12857,
"begging": 12858,
"tract": 12859,
"swore": 12860,
"1809": 12861,
"175": 12862,
"##gic": 12863,
"omaha": 12864,
"brotherhood": 12865,
"##rley": 12866,
"haiti": 12867,
"##ots": 12868,
"exeter": 12869,
"##ete": 12870,
"##zia": 12871,
"steele": 12872,
"dumb": 12873,
"pearson": 12874,
"210": 12875,
"surveyed": 12876,
"elisabeth": 12877,
"trends": 12878,
"##ef": 12879,
"fritz": 12880,
"##rf": 12881,
"premium": 12882,
"bugs": 12883,
"fraction": 12884,
"calmly": 12885,
"viking": 12886,
"##birds": 12887,
"tug": 12888,
"inserted": 12889,
"unusually": 12890,
"##ield": 12891,
"confronted": 12892,
"distress": 12893,
"crashing": 12894,
"brent": 12895,
"turks": 12896,
"resign": 12897,
"##olo": 12898,
"cambodia": 12899,
"gabe": 12900,
"sauce": 12901,
"##kal": 12902,
"evelyn": 12903,
"116": 12904,
"extant": 12905,
"clusters": 12906,
"quarry": 12907,
"teenagers": 12908,
"luna": 12909,
"##lers": 12910,
"##ister": 12911,
"affiliation": 12912,
"drill": 12913,
"##ashi": 12914,
"panthers": 12915,
"scenic": 12916,
"libya": 12917,
"anita": 12918,
"strengthen": 12919,
"inscriptions": 12920,
"##cated": 12921,
"lace": 12922,
"sued": 12923,
"judith": 12924,
"riots": 12925,
"##uted": 12926,
"mint": 12927,
"##eta": 12928,
"preparations": 12929,
"midst": 12930,
"dub": 12931,
"challenger": 12932,
"##vich": 12933,
"mock": 12934,
"cf": 12935,
"displaced": 12936,
"wicket": 12937,
"breaths": 12938,
"enables": 12939,
"schmidt": 12940,
"analyst": 12941,
"##lum": 12942,
"ag": 12943,
"highlight": 12944,
"automotive": 12945,
"axe": 12946,
"josef": 12947,
"newark": 12948,
"sufficiently": 12949,
"resembles": 12950,
"50th": 12951,
"##pal": 12952,
"flushed": 12953,
"mum": 12954,
"traits": 12955,
"##ante": 12956,
"commodore": 12957,
"incomplete": 12958,
"warming": 12959,
"titular": 12960,
"ceremonial": 12961,
"ethical": 12962,
"118": 12963,
"celebrating": 12964,
"eighteenth": 12965,
"cao": 12966,
"lima": 12967,
"medalist": 12968,
"mobility": 12969,
"strips": 12970,
"snakes": 12971,
"##city": 12972,
"miniature": 12973,
"zagreb": 12974,
"barton": 12975,
"escapes": 12976,
"umbrella": 12977,
"automated": 12978,
"doubted": 12979,
"differs": 12980,
"cooled": 12981,
"georgetown": 12982,
"dresden": 12983,
"cooked": 12984,
"fade": 12985,
"wyatt": 12986,
"rna": 12987,
"jacobs": 12988,
"carlton": 12989,
"abundant": 12990,
"stereo": 12991,
"boost": 12992,
"madras": 12993,
"inning": 12994,
"##hia": 12995,
"spur": 12996,
"ip": 12997,
"malayalam": 12998,
"begged": 12999,
"osaka": 13000,
"groan": 13001,
"escaping": 13002,
"charging": 13003,
"dose": 13004,
"vista": 13005,
"##aj": 13006,
"bud": 13007,
"papa": 13008,
"communists": 13009,
"advocates": 13010,
"edged": 13011,
"tri": 13012,
"##cent": 13013,
"resemble": 13014,
"peaking": 13015,
"necklace": 13016,
"fried": 13017,
"montenegro": 13018,
"saxony": 13019,
"goose": 13020,
"glances": 13021,
"stuttgart": 13022,
"curator": 13023,
"recruit": 13024,
"grocery": 13025,
"sympathetic": 13026,
"##tting": 13027,
"##fort": 13028,
"127": 13029,
"lotus": 13030,
"randolph": 13031,
"ancestor": 13032,
"##rand": 13033,
"succeeding": 13034,
"jupiter": 13035,
"1798": 13036,
"macedonian": 13037,
"##heads": 13038,
"hiking": 13039,
"1808": 13040,
"handing": 13041,
"fischer": 13042,
"##itive": 13043,
"garbage": 13044,
"node": 13045,
"##pies": 13046,
"prone": 13047,
"singular": 13048,
"papua": 13049,
"inclined": 13050,
"attractions": 13051,
"italia": 13052,
"pouring": 13053,
"motioned": 13054,
"grandma": 13055,
"garnered": 13056,
"jacksonville": 13057,
"corp": 13058,
"ego": 13059,
"ringing": 13060,
"aluminum": 13061,
"##hausen": 13062,
"ordering": 13063,
"##foot": 13064,
"drawer": 13065,
"traders": 13066,
"synagogue": 13067,
"##play": 13068,
"##kawa": 13069,
"resistant": 13070,
"wandering": 13071,
"fragile": 13072,
"fiona": 13073,
"teased": 13074,
"var": 13075,
"hardcore": 13076,
"soaked": 13077,
"jubilee": 13078,
"decisive": 13079,
"exposition": 13080,
"mercer": 13081,
"poster": 13082,
"valencia": 13083,
"hale": 13084,
"kuwait": 13085,
"1811": 13086,
"##ises": 13087,
"##wr": 13088,
"##eed": 13089,
"tavern": 13090,
"gamma": 13091,
"122": 13092,
"johan": 13093,
"##uer": 13094,
"airways": 13095,
"amino": 13096,
"gil": 13097,
"##ury": 13098,
"vocational": 13099,
"domains": 13100,
"torres": 13101,
"##sp": 13102,
"generator": 13103,
"folklore": 13104,
"outcomes": 13105,
"##keeper": 13106,
"canberra": 13107,
"shooter": 13108,
"fl": 13109,
"beams": 13110,
"confrontation": 13111,
"##lling": 13112,
"##gram": 13113,
"feb": 13114,
"aligned": 13115,
"forestry": 13116,
"pipeline": 13117,
"jax": 13118,
"motorway": 13119,
"conception": 13120,
"decay": 13121,
"##tos": 13122,
"coffin": 13123,
"##cott": 13124,
"stalin": 13125,
"1805": 13126,
"escorted": 13127,
"minded": 13128,
"##nam": 13129,
"sitcom": 13130,
"purchasing": 13131,
"twilight": 13132,
"veronica": 13133,
"additions": 13134,
"passive": 13135,
"tensions": 13136,
"straw": 13137,
"123": 13138,
"frequencies": 13139,
"1804": 13140,
"refugee": 13141,
"cultivation": 13142,
"##iate": 13143,
"christie": 13144,
"clary": 13145,
"bulletin": 13146,
"crept": 13147,
"disposal": 13148,
"##rich": 13149,
"##zong": 13150,
"processor": 13151,
"crescent": 13152,
"##rol": 13153,
"bmw": 13154,
"emphasized": 13155,
"whale": 13156,
"nazis": 13157,
"aurora": 13158,
"##eng": 13159,
"dwelling": 13160,
"hauled": 13161,
"sponsors": 13162,
"toledo": 13163,
"mega": 13164,
"ideology": 13165,
"theatres": 13166,
"tessa": 13167,
"cerambycidae": 13168,
"saves": 13169,
"turtle": 13170,
"cone": 13171,
"suspects": 13172,
"kara": 13173,
"rusty": 13174,
"yelling": 13175,
"greeks": 13176,
"mozart": 13177,
"shades": 13178,
"cocked": 13179,
"participant": 13180,
"##tro": 13181,
"shire": 13182,
"spit": 13183,
"freeze": 13184,
"necessity": 13185,
"##cos": 13186,
"inmates": 13187,
"nielsen": 13188,
"councillors": 13189,
"loaned": 13190,
"uncommon": 13191,
"omar": 13192,
"peasants": 13193,
"botanical": 13194,
"offspring": 13195,
"daniels": 13196,
"formations": 13197,
"jokes": 13198,
"1794": 13199,
"pioneers": 13200,
"sigma": 13201,
"licensing": 13202,
"##sus": 13203,
"wheelchair": 13204,
"polite": 13205,
"1807": 13206,
"liquor": 13207,
"pratt": 13208,
"trustee": 13209,
"##uta": 13210,
"forewings": 13211,
"balloon": 13212,
"##zz": 13213,
"kilometre": 13214,
"camping": 13215,
"explicit": 13216,
"casually": 13217,
"shawn": 13218,
"foolish": 13219,
"teammates": 13220,
"nm": 13221,
"hassan": 13222,
"carrie": 13223,
"judged": 13224,
"satisfy": 13225,
"vanessa": 13226,
"knives": 13227,
"selective": 13228,
"cnn": 13229,
"flowed": 13230,
"##lice": 13231,
"eclipse": 13232,
"stressed": 13233,
"eliza": 13234,
"mathematician": 13235,
"cease": 13236,
"cultivated": 13237,
"##roy": 13238,
"commissions": 13239,
"browns": 13240,
"##ania": 13241,
"destroyers": 13242,
"sheridan": 13243,
"meadow": 13244,
"##rius": 13245,
"minerals": 13246,
"##cial": 13247,
"downstream": 13248,
"clash": 13249,
"gram": 13250,
"memoirs": 13251,
"ventures": 13252,
"baha": 13253,
"seymour": 13254,
"archie": 13255,
"midlands": 13256,
"edith": 13257,
"fare": 13258,
"flynn": 13259,
"invite": 13260,
"canceled": 13261,
"tiles": 13262,
"stabbed": 13263,
"boulder": 13264,
"incorporate": 13265,
"amended": 13266,
"camden": 13267,
"facial": 13268,
"mollusk": 13269,
"unreleased": 13270,
"descriptions": 13271,
"yoga": 13272,
"grabs": 13273,
"550": 13274,
"raises": 13275,
"ramp": 13276,
"shiver": 13277,
"##rose": 13278,
"coined": 13279,
"pioneering": 13280,
"tunes": 13281,
"qing": 13282,
"warwick": 13283,
"tops": 13284,
"119": 13285,
"melanie": 13286,
"giles": 13287,
"##rous": 13288,
"wandered": 13289,
"##inal": 13290,
"annexed": 13291,
"nov": 13292,
"30th": 13293,
"unnamed": 13294,
"##ished": 13295,
"organizational": 13296,
"airplane": 13297,
"normandy": 13298,
"stoke": 13299,
"whistle": 13300,
"blessing": 13301,
"violations": 13302,
"chased": 13303,
"holders": 13304,
"shotgun": 13305,
"##ctic": 13306,
"outlet": 13307,
"reactor": 13308,
"##vik": 13309,
"tires": 13310,
"tearing": 13311,
"shores": 13312,
"fortified": 13313,
"mascot": 13314,
"constituencies": 13315,
"nc": 13316,
"columnist": 13317,
"productive": 13318,
"tibet": 13319,
"##rta": 13320,
"lineage": 13321,
"hooked": 13322,
"oct": 13323,
"tapes": 13324,
"judging": 13325,
"cody": 13326,
"##gger": 13327,
"hansen": 13328,
"kashmir": 13329,
"triggered": 13330,
"##eva": 13331,
"solved": 13332,
"cliffs": 13333,
"##tree": 13334,
"resisted": 13335,
"anatomy": 13336,
"protesters": 13337,
"transparent": 13338,
"implied": 13339,
"##iga": 13340,
"injection": 13341,
"mattress": 13342,
"excluding": 13343,
"##mbo": 13344,
"defenses": 13345,
"helpless": 13346,
"devotion": 13347,
"##elli": 13348,
"growl": 13349,
"liberals": 13350,
"weber": 13351,
"phenomena": 13352,
"atoms": 13353,
"plug": 13354,
"##iff": 13355,
"mortality": 13356,
"apprentice": 13357,
"howe": 13358,
"convincing": 13359,
"aaa": 13360,
"swimmer": 13361,
"barber": 13362,
"leone": 13363,
"promptly": 13364,
"sodium": 13365,
"def": 13366,
"nowadays": 13367,
"arise": 13368,
"##oning": 13369,
"gloucester": 13370,
"corrected": 13371,
"dignity": 13372,
"norm": 13373,
"erie": 13374,
"##ders": 13375,
"elders": 13376,
"evacuated": 13377,
"sylvia": 13378,
"compression": 13379,
"##yar": 13380,
"hartford": 13381,
"pose": 13382,
"backpack": 13383,
"reasoning": 13384,
"accepts": 13385,
"24th": 13386,
"wipe": 13387,
"millimetres": 13388,
"marcel": 13389,
"##oda": 13390,
"dodgers": 13391,
"albion": 13392,
"1790": 13393,
"overwhelmed": 13394,
"aerospace": 13395,
"oaks": 13396,
"1795": 13397,
"showcase": 13398,
"acknowledge": 13399,
"recovering": 13400,
"nolan": 13401,
"ashe": 13402,
"hurts": 13403,
"geology": 13404,
"fashioned": 13405,
"disappearance": 13406,
"farewell": 13407,
"swollen": 13408,
"shrug": 13409,
"marquis": 13410,
"wimbledon": 13411,
"124": 13412,
"rue": 13413,
"1792": 13414,
"commemorate": 13415,
"reduces": 13416,
"experiencing": 13417,
"inevitable": 13418,
"calcutta": 13419,
"intel": 13420,
"##court": 13421,
"murderer": 13422,
"sticking": 13423,
"fisheries": 13424,
"imagery": 13425,
"bloom": 13426,
"280": 13427,
"brake": 13428,
"##inus": 13429,
"gustav": 13430,
"hesitation": 13431,
"memorable": 13432,
"po": 13433,
"viral": 13434,
"beans": 13435,
"accidents": 13436,
"tunisia": 13437,
"antenna": 13438,
"spilled": 13439,
"consort": 13440,
"treatments": 13441,
"aye": 13442,
"perimeter": 13443,
"##gard": 13444,
"donation": 13445,
"hostage": 13446,
"migrated": 13447,
"banker": 13448,
"addiction": 13449,
"apex": 13450,
"lil": 13451,
"trout": 13452,
"##ously": 13453,
"conscience": 13454,
"##nova": 13455,
"rams": 13456,
"sands": 13457,
"genome": 13458,
"passionate": 13459,
"troubles": 13460,
"##lets": 13461,
"##set": 13462,
"amid": 13463,
"##ibility": 13464,
"##ret": 13465,
"higgins": 13466,
"exceed": 13467,
"vikings": 13468,
"##vie": 13469,
"payne": 13470,
"##zan": 13471,
"muscular": 13472,
"##ste": 13473,
"defendant": 13474,
"sucking": 13475,
"##wal": 13476,
"ibrahim": 13477,
"fuselage": 13478,
"claudia": 13479,
"vfl": 13480,
"europeans": 13481,
"snails": 13482,
"interval": 13483,
"##garh": 13484,
"preparatory": 13485,
"statewide": 13486,
"tasked": 13487,
"lacrosse": 13488,
"viktor": 13489,
"##lation": 13490,
"angola": 13491,
"##hra": 13492,
"flint": 13493,
"implications": 13494,
"employs": 13495,
"teens": 13496,
"patrons": 13497,
"stall": 13498,
"weekends": 13499,
"barriers": 13500,
"scrambled": 13501,
"nucleus": 13502,
"tehran": 13503,
"jenna": 13504,
"parsons": 13505,
"lifelong": 13506,
"robots": 13507,
"displacement": 13508,
"5000": 13509,
"##bles": 13510,
"precipitation": 13511,
"##gt": 13512,
"knuckles": 13513,
"clutched": 13514,
"1802": 13515,
"marrying": 13516,
"ecology": 13517,
"marx": 13518,
"accusations": 13519,
"declare": 13520,
"scars": 13521,
"kolkata": 13522,
"mat": 13523,
"meadows": 13524,
"bermuda": 13525,
"skeleton": 13526,
"finalists": 13527,
"vintage": 13528,
"crawl": 13529,
"coordinate": 13530,
"affects": 13531,
"subjected": 13532,
"orchestral": 13533,
"mistaken": 13534,
"##tc": 13535,
"mirrors": 13536,
"dipped": 13537,
"relied": 13538,
"260": 13539,
"arches": 13540,
"candle": 13541,
"##nick": 13542,
"incorporating": 13543,
"wildly": 13544,
"fond": 13545,
"basilica": 13546,
"owl": 13547,
"fringe": 13548,
"rituals": 13549,
"whispering": 13550,
"stirred": 13551,
"feud": 13552,
"tertiary": 13553,
"slick": 13554,
"goat": 13555,
"honorable": 13556,
"whereby": 13557,
"skip": 13558,
"ricardo": 13559,
"stripes": 13560,
"parachute": 13561,
"adjoining": 13562,
"submerged": 13563,
"synthesizer": 13564,
"##gren": 13565,
"intend": 13566,
"positively": 13567,
"ninety": 13568,
"phi": 13569,
"beaver": 13570,
"partition": 13571,
"fellows": 13572,
"alexis": 13573,
"prohibition": 13574,
"carlisle": 13575,
"bizarre": 13576,
"fraternity": 13577,
"##bre": 13578,
"doubts": 13579,
"icy": 13580,
"cbc": 13581,
"aquatic": 13582,
"sneak": 13583,
"sonny": 13584,
"combines": 13585,
"airports": 13586,
"crude": 13587,
"supervised": 13588,
"spatial": 13589,
"merge": 13590,
"alfonso": 13591,
"##bic": 13592,
"corrupt": 13593,
"scan": 13594,
"undergo": 13595,
"##ams": 13596,
"disabilities": 13597,
"colombian": 13598,
"comparing": 13599,
"dolphins": 13600,
"perkins": 13601,
"##lish": 13602,
"reprinted": 13603,
"unanimous": 13604,
"bounced": 13605,
"hairs": 13606,
"underworld": 13607,
"midwest": 13608,
"semester": 13609,
"bucket": 13610,
"paperback": 13611,
"miniseries": 13612,
"coventry": 13613,
"demise": 13614,
"##leigh": 13615,
"demonstrations": 13616,
"sensor": 13617,
"rotating": 13618,
"yan": 13619,
"##hler": 13620,
"arrange": 13621,
"soils": 13622,
"##idge": 13623,
"hyderabad": 13624,
"labs": 13625,
"##dr": 13626,
"brakes": 13627,
"grandchildren": 13628,
"##nde": 13629,
"negotiated": 13630,
"rover": 13631,
"ferrari": 13632,
"continuation": 13633,
"directorate": 13634,
"augusta": 13635,
"stevenson": 13636,
"counterpart": 13637,
"gore": 13638,
"##rda": 13639,
"nursery": 13640,
"rican": 13641,
"ave": 13642,
"collectively": 13643,
"broadly": 13644,
"pastoral": 13645,
"repertoire": 13646,
"asserted": 13647,
"discovering": 13648,
"nordic": 13649,
"styled": 13650,
"fiba": 13651,
"cunningham": 13652,
"harley": 13653,
"middlesex": 13654,
"survives": 13655,
"tumor": 13656,
"tempo": 13657,
"zack": 13658,
"aiming": 13659,
"lok": 13660,
"urgent": 13661,
"##rade": 13662,
"##nto": 13663,
"devils": 13664,
"##ement": 13665,
"contractor": 13666,
"turin": 13667,
"##wl": 13668,
"##ool": 13669,
"bliss": 13670,
"repaired": 13671,
"simmons": 13672,
"moan": 13673,
"astronomical": 13674,
"cr": 13675,
"negotiate": 13676,
"lyric": 13677,
"1890s": 13678,
"lara": 13679,
"bred": 13680,
"clad": 13681,
"angus": 13682,
"pbs": 13683,
"##ience": 13684,
"engineered": 13685,
"posed": 13686,
"##lk": 13687,
"hernandez": 13688,
"possessions": 13689,
"elbows": 13690,
"psychiatric": 13691,
"strokes": 13692,
"confluence": 13693,
"electorate": 13694,
"lifts": 13695,
"campuses": 13696,
"lava": 13697,
"alps": 13698,
"##ep": 13699,
"##ution": 13700,
"##date": 13701,
"physicist": 13702,
"woody": 13703,
"##page": 13704,
"##ographic": 13705,
"##itis": 13706,
"juliet": 13707,
"reformation": 13708,
"sparhawk": 13709,
"320": 13710,
"complement": 13711,
"suppressed": 13712,
"jewel": 13713,
"##½": 13714,
"floated": 13715,
"##kas": 13716,
"continuity": 13717,
"sadly": 13718,
"##ische": 13719,
"inability": 13720,
"melting": 13721,
"scanning": 13722,
"paula": 13723,
"flour": 13724,
"judaism": 13725,
"safer": 13726,
"vague": 13727,
"##lm": 13728,
"solving": 13729,
"curb": 13730,
"##stown": 13731,
"financially": 13732,
"gable": 13733,
"bees": 13734,
"expired": 13735,
"miserable": 13736,
"cassidy": 13737,
"dominion": 13738,
"1789": 13739,
"cupped": 13740,
"145": 13741,
"robbery": 13742,
"facto": 13743,
"amos": 13744,
"warden": 13745,
"resume": 13746,
"tallest": 13747,
"marvin": 13748,
"ing": 13749,
"pounded": 13750,
"usd": 13751,
"declaring": 13752,
"gasoline": 13753,
"##aux": 13754,
"darkened": 13755,
"270": 13756,
"650": 13757,
"sophomore": 13758,
"##mere": 13759,
"erection": 13760,
"gossip": 13761,
"televised": 13762,
"risen": 13763,
"dial": 13764,
"##eu": 13765,
"pillars": 13766,
"##link": 13767,
"passages": 13768,
"profound": 13769,
"##tina": 13770,
"arabian": 13771,
"ashton": 13772,
"silicon": 13773,
"nail": 13774,
"##ead": 13775,
"##lated": 13776,
"##wer": 13777,
"##hardt": 13778,
"fleming": 13779,
"firearms": 13780,
"ducked": 13781,
"circuits": 13782,
"blows": 13783,
"waterloo": 13784,
"titans": 13785,
"##lina": 13786,
"atom": 13787,
"fireplace": 13788,
"cheshire": 13789,
"financed": 13790,
"activation": 13791,
"algorithms": 13792,
"##zzi": 13793,
"constituent": 13794,
"catcher": 13795,
"cherokee": 13796,
"partnerships": 13797,
"sexuality": 13798,
"platoon": 13799,
"tragic": 13800,
"vivian": 13801,
"guarded": 13802,
"whiskey": 13803,
"meditation": 13804,
"poetic": 13805,
"##late": 13806,
"##nga": 13807,
"##ake": 13808,
"porto": 13809,
"listeners": 13810,
"dominance": 13811,
"kendra": 13812,
"mona": 13813,
"chandler": 13814,
"factions": 13815,
"22nd": 13816,
"salisbury": 13817,
"attitudes": 13818,
"derivative": 13819,
"##ido": 13820,
"##haus": 13821,
"intake": 13822,
"paced": 13823,
"javier": 13824,
"illustrator": 13825,
"barrels": 13826,
"bias": 13827,
"cockpit": 13828,
"burnett": 13829,
"dreamed": 13830,
"ensuing": 13831,
"##anda": 13832,
"receptors": 13833,
"someday": 13834,
"hawkins": 13835,
"mattered": 13836,
"##lal": 13837,
"slavic": 13838,
"1799": 13839,
"jesuit": 13840,
"cameroon": 13841,
"wasted": 13842,
"tai": 13843,
"wax": 13844,
"lowering": 13845,
"victorious": 13846,
"freaking": 13847,
"outright": 13848,
"hancock": 13849,
"librarian": 13850,
"sensing": 13851,
"bald": 13852,
"calcium": 13853,
"myers": 13854,
"tablet": 13855,
"announcing": 13856,
"barack": 13857,
"shipyard": 13858,
"pharmaceutical": 13859,
"##uan": 13860,
"greenwich": 13861,
"flush": 13862,
"medley": 13863,
"patches": 13864,
"wolfgang": 13865,
"pt": 13866,
"speeches": 13867,
"acquiring": 13868,
"exams": 13869,
"nikolai": 13870,
"##gg": 13871,
"hayden": 13872,
"kannada": 13873,
"##type": 13874,
"reilly": 13875,
"##pt": 13876,
"waitress": 13877,
"abdomen": 13878,
"devastated": 13879,
"capped": 13880,
"pseudonym": 13881,
"pharmacy": 13882,
"fulfill": 13883,
"paraguay": 13884,
"1796": 13885,
"clicked": 13886,
"##trom": 13887,
"archipelago": 13888,
"syndicated": 13889,
"##hman": 13890,
"lumber": 13891,
"orgasm": 13892,
"rejection": 13893,
"clifford": 13894,
"lorraine": 13895,
"advent": 13896,
"mafia": 13897,
"rodney": 13898,
"brock": 13899,
"##ght": 13900,
"##used": 13901,
"##elia": 13902,
"cassette": 13903,
"chamberlain": 13904,
"despair": 13905,
"mongolia": 13906,
"sensors": 13907,
"developmental": 13908,
"upstream": 13909,
"##eg": 13910,
"##alis": 13911,
"spanning": 13912,
"165": 13913,
"trombone": 13914,
"basque": 13915,
"seeded": 13916,
"interred": 13917,
"renewable": 13918,
"rhys": 13919,
"leapt": 13920,
"revision": 13921,
"molecule": 13922,
"##ages": 13923,
"chord": 13924,
"vicious": 13925,
"nord": 13926,
"shivered": 13927,
"23rd": 13928,
"arlington": 13929,
"debts": 13930,
"corpus": 13931,
"sunrise": 13932,
"bays": 13933,
"blackburn": 13934,
"centimetres": 13935,
"##uded": 13936,
"shuddered": 13937,
"gm": 13938,
"strangely": 13939,
"gripping": 13940,
"cartoons": 13941,
"isabelle": 13942,
"orbital": 13943,
"##ppa": 13944,
"seals": 13945,
"proving": 13946,
"##lton": 13947,
"refusal": 13948,
"strengthened": 13949,
"bust": 13950,
"assisting": 13951,
"baghdad": 13952,
"batsman": 13953,
"portrayal": 13954,
"mara": 13955,
"pushes": 13956,
"spears": 13957,
"og": 13958,
"##cock": 13959,
"reside": 13960,
"nathaniel": 13961,
"brennan": 13962,
"1776": 13963,
"confirmation": 13964,
"caucus": 13965,
"##worthy": 13966,
"markings": 13967,
"yemen": 13968,
"nobles": 13969,
"ku": 13970,
"lazy": 13971,
"viewer": 13972,
"catalan": 13973,
"encompasses": 13974,
"sawyer": 13975,
"##fall": 13976,
"sparked": 13977,
"substances": 13978,
"patents": 13979,
"braves": 13980,
"arranger": 13981,
"evacuation": 13982,
"sergio": 13983,
"persuade": 13984,
"dover": 13985,
"tolerance": 13986,
"penguin": 13987,
"cum": 13988,
"jockey": 13989,
"insufficient": 13990,
"townships": 13991,
"occupying": 13992,
"declining": 13993,
"plural": 13994,
"processed": 13995,
"projection": 13996,
"puppet": 13997,
"flanders": 13998,
"introduces": 13999,
"liability": 14000,
"##yon": 14001,
"gymnastics": 14002,
"antwerp": 14003,
"taipei": 14004,
"hobart": 14005,
"candles": 14006,
"jeep": 14007,
"wes": 14008,
"observers": 14009,
"126": 14010,
"chaplain": 14011,
"bundle": 14012,
"glorious": 14013,
"##hine": 14014,
"hazel": 14015,
"flung": 14016,
"sol": 14017,
"excavations": 14018,
"dumped": 14019,
"stares": 14020,
"sh": 14021,
"bangalore": 14022,
"triangular": 14023,
"icelandic": 14024,
"intervals": 14025,
"expressing": 14026,
"turbine": 14027,
"##vers": 14028,
"songwriting": 14029,
"crafts": 14030,
"##igo": 14031,
"jasmine": 14032,
"ditch": 14033,
"rite": 14034,
"##ways": 14035,
"entertaining": 14036,
"comply": 14037,
"sorrow": 14038,
"wrestlers": 14039,
"basel": 14040,
"emirates": 14041,
"marian": 14042,
"rivera": 14043,
"helpful": 14044,
"##some": 14045,
"caution": 14046,
"downward": 14047,
"networking": 14048,
"##atory": 14049,
"##tered": 14050,
"darted": 14051,
"genocide": 14052,
"emergence": 14053,
"replies": 14054,
"specializing": 14055,
"spokesman": 14056,
"convenient": 14057,
"unlocked": 14058,
"fading": 14059,
"augustine": 14060,
"concentrations": 14061,
"resemblance": 14062,
"elijah": 14063,
"investigator": 14064,
"andhra": 14065,
"##uda": 14066,
"promotes": 14067,
"bean": 14068,
"##rrell": 14069,
"fleeing": 14070,
"wan": 14071,
"simone": 14072,
"announcer": 14073,
"##ame": 14074,
"##bby": 14075,
"lydia": 14076,
"weaver": 14077,
"132": 14078,
"residency": 14079,
"modification": 14080,
"##fest": 14081,
"stretches": 14082,
"##ast": 14083,
"alternatively": 14084,
"nat": 14085,
"lowe": 14086,
"lacks": 14087,
"##ented": 14088,
"pam": 14089,
"tile": 14090,
"concealed": 14091,
"inferior": 14092,
"abdullah": 14093,
"residences": 14094,
"tissues": 14095,
"vengeance": 14096,
"##ided": 14097,
"moisture": 14098,
"peculiar": 14099,
"groove": 14100,
"zip": 14101,
"bologna": 14102,
"jennings": 14103,
"ninja": 14104,
"oversaw": 14105,
"zombies": 14106,
"pumping": 14107,
"batch": 14108,
"livingston": 14109,
"emerald": 14110,
"installations": 14111,
"1797": 14112,
"peel": 14113,
"nitrogen": 14114,
"rama": 14115,
"##fying": 14116,
"##star": 14117,
"schooling": 14118,
"strands": 14119,
"responding": 14120,
"werner": 14121,
"##ost": 14122,
"lime": 14123,
"casa": 14124,
"accurately": 14125,
"targeting": 14126,
"##rod": 14127,
"underway": 14128,
"##uru": 14129,
"hemisphere": 14130,
"lester": 14131,
"##yard": 14132,
"occupies": 14133,
"2d": 14134,
"griffith": 14135,
"angrily": 14136,
"reorganized": 14137,
"##owing": 14138,
"courtney": 14139,
"deposited": 14140,
"##dd": 14141,
"##30": 14142,
"estadio": 14143,
"##ifies": 14144,
"dunn": 14145,
"exiled": 14146,
"##ying": 14147,
"checks": 14148,
"##combe": 14149,
"##о": 14150,
"##fly": 14151,
"successes": 14152,
"unexpectedly": 14153,
"blu": 14154,
"assessed": 14155,
"##flower": 14156,
"##ه": 14157,
"observing": 14158,
"sacked": 14159,
"spiders": 14160,
"kn": 14161,
"##tail": 14162,
"mu": 14163,
"nodes": 14164,
"prosperity": 14165,
"audrey": 14166,
"divisional": 14167,
"155": 14168,
"broncos": 14169,
"tangled": 14170,
"adjust": 14171,
"feeds": 14172,
"erosion": 14173,
"paolo": 14174,
"surf": 14175,
"directory": 14176,
"snatched": 14177,
"humid": 14178,
"admiralty": 14179,
"screwed": 14180,
"gt": 14181,
"reddish": 14182,
"##nese": 14183,
"modules": 14184,
"trench": 14185,
"lamps": 14186,
"bind": 14187,
"leah": 14188,
"bucks": 14189,
"competes": 14190,
"##nz": 14191,
"##form": 14192,
"transcription": 14193,
"##uc": 14194,
"isles": 14195,
"violently": 14196,
"clutching": 14197,
"pga": 14198,
"cyclist": 14199,
"inflation": 14200,
"flats": 14201,
"ragged": 14202,
"unnecessary": 14203,
"##hian": 14204,
"stubborn": 14205,
"coordinated": 14206,
"harriet": 14207,
"baba": 14208,
"disqualified": 14209,
"330": 14210,
"insect": 14211,
"wolfe": 14212,
"##fies": 14213,
"reinforcements": 14214,
"rocked": 14215,
"duel": 14216,
"winked": 14217,
"embraced": 14218,
"bricks": 14219,
"##raj": 14220,
"hiatus": 14221,
"defeats": 14222,
"pending": 14223,
"brightly": 14224,
"jealousy": 14225,
"##xton": 14226,
"##hm": 14227,
"##uki": 14228,
"lena": 14229,
"gdp": 14230,
"colorful": 14231,
"##dley": 14232,
"stein": 14233,
"kidney": 14234,
"##shu": 14235,
"underwear": 14236,
"wanderers": 14237,
"##haw": 14238,
"##icus": 14239,
"guardians": 14240,
"m³": 14241,
"roared": 14242,
"habits": 14243,
"##wise": 14244,
"permits": 14245,
"gp": 14246,
"uranium": 14247,
"punished": 14248,
"disguise": 14249,
"bundesliga": 14250,
"elise": 14251,
"dundee": 14252,
"erotic": 14253,
"partisan": 14254,
"pi": 14255,
"collectors": 14256,
"float": 14257,
"individually": 14258,
"rendering": 14259,
"behavioral": 14260,
"bucharest": 14261,
"ser": 14262,
"hare": 14263,
"valerie": 14264,
"corporal": 14265,
"nutrition": 14266,
"proportional": 14267,
"##isa": 14268,
"immense": 14269,
"##kis": 14270,
"pavement": 14271,
"##zie": 14272,
"##eld": 14273,
"sutherland": 14274,
"crouched": 14275,
"1775": 14276,
"##lp": 14277,
"suzuki": 14278,
"trades": 14279,
"endurance": 14280,
"operas": 14281,
"crosby": 14282,
"prayed": 14283,
"priory": 14284,
"rory": 14285,
"socially": 14286,
"##urn": 14287,
"gujarat": 14288,
"##pu": 14289,
"walton": 14290,
"cube": 14291,
"pasha": 14292,
"privilege": 14293,
"lennon": 14294,
"floods": 14295,
"thorne": 14296,
"waterfall": 14297,
"nipple": 14298,
"scouting": 14299,
"approve": 14300,
"##lov": 14301,
"minorities": 14302,
"voter": 14303,
"dwight": 14304,
"extensions": 14305,
"assure": 14306,
"ballroom": 14307,
"slap": 14308,
"dripping": 14309,
"privileges": 14310,
"rejoined": 14311,
"confessed": 14312,
"demonstrating": 14313,
"patriotic": 14314,
"yell": 14315,
"investor": 14316,
"##uth": 14317,
"pagan": 14318,
"slumped": 14319,
"squares": 14320,
"##cle": 14321,
"##kins": 14322,
"confront": 14323,
"bert": 14324,
"embarrassment": 14325,
"##aid": 14326,
"aston": 14327,
"urging": 14328,
"sweater": 14329,
"starr": 14330,
"yuri": 14331,
"brains": 14332,
"williamson": 14333,
"commuter": 14334,
"mortar": 14335,
"structured": 14336,
"selfish": 14337,
"exports": 14338,
"##jon": 14339,
"cds": 14340,
"##him": 14341,
"unfinished": 14342,
"##rre": 14343,
"mortgage": 14344,
"destinations": 14345,
"##nagar": 14346,
"canoe": 14347,
"solitary": 14348,
"buchanan": 14349,
"delays": 14350,
"magistrate": 14351,
"fk": 14352,
"##pling": 14353,
"motivation": 14354,
"##lier": 14355,
"##vier": 14356,
"recruiting": 14357,
"assess": 14358,
"##mouth": 14359,
"malik": 14360,
"antique": 14361,
"1791": 14362,
"pius": 14363,
"rahman": 14364,
"reich": 14365,
"tub": 14366,
"zhou": 14367,
"smashed": 14368,
"airs": 14369,
"galway": 14370,
"xii": 14371,
"conditioning": 14372,
"honduras": 14373,
"discharged": 14374,
"dexter": 14375,
"##pf": 14376,
"lionel": 14377,
"129": 14378,
"debates": 14379,
"lemon": 14380,
"tiffany": 14381,
"volunteered": 14382,
"dom": 14383,
"dioxide": 14384,
"procession": 14385,
"devi": 14386,
"sic": 14387,
"tremendous": 14388,
"advertisements": 14389,
"colts": 14390,
"transferring": 14391,
"verdict": 14392,
"hanover": 14393,
"decommissioned": 14394,
"utter": 14395,
"relate": 14396,
"pac": 14397,
"racism": 14398,
"##top": 14399,
"beacon": 14400,
"limp": 14401,
"similarity": 14402,
"terra": 14403,
"occurrence": 14404,
"ant": 14405,
"##how": 14406,
"becky": 14407,
"capt": 14408,
"updates": 14409,
"armament": 14410,
"richie": 14411,
"pal": 14412,
"##graph": 14413,
"halloween": 14414,
"mayo": 14415,
"##ssen": 14416,
"##bone": 14417,
"cara": 14418,
"serena": 14419,
"fcc": 14420,
"dolls": 14421,
"obligations": 14422,
"##dling": 14423,
"violated": 14424,
"lafayette": 14425,
"jakarta": 14426,
"exploitation": 14427,
"##ime": 14428,
"infamous": 14429,
"iconic": 14430,
"##lah": 14431,
"##park": 14432,
"kitty": 14433,
"moody": 14434,
"reginald": 14435,
"dread": 14436,
"spill": 14437,
"crystals": 14438,
"olivier": 14439,
"modeled": 14440,
"bluff": 14441,
"equilibrium": 14442,
"separating": 14443,
"notices": 14444,
"ordnance": 14445,
"extinction": 14446,
"onset": 14447,
"cosmic": 14448,
"attachment": 14449,
"sammy": 14450,
"expose": 14451,
"privy": 14452,
"anchored": 14453,
"##bil": 14454,
"abbott": 14455,
"admits": 14456,
"bending": 14457,
"baritone": 14458,
"emmanuel": 14459,
"policeman": 14460,
"vaughan": 14461,
"winged": 14462,
"climax": 14463,
"dresses": 14464,
"denny": 14465,
"polytechnic": 14466,
"mohamed": 14467,
"burmese": 14468,
"authentic": 14469,
"nikki": 14470,
"genetics": 14471,
"grandparents": 14472,
"homestead": 14473,
"gaza": 14474,
"postponed": 14475,
"metacritic": 14476,
"una": 14477,
"##sby": 14478,
"##bat": 14479,
"unstable": 14480,
"dissertation": 14481,
"##rial": 14482,
"##cian": 14483,
"curls": 14484,
"obscure": 14485,
"uncovered": 14486,
"bronx": 14487,
"praying": 14488,
"disappearing": 14489,
"##hoe": 14490,
"prehistoric": 14491,
"coke": 14492,
"turret": 14493,
"mutations": 14494,
"nonprofit": 14495,
"pits": 14496,
"monaco": 14497,
"##ي": 14498,
"##usion": 14499,
"prominently": 14500,
"dispatched": 14501,
"podium": 14502,
"##mir": 14503,
"uci": 14504,
"##uation": 14505,
"133": 14506,
"fortifications": 14507,
"birthplace": 14508,
"kendall": 14509,
"##lby": 14510,
"##oll": 14511,
"preacher": 14512,
"rack": 14513,
"goodman": 14514,
"##rman": 14515,
"persistent": 14516,
"##ott": 14517,
"countless": 14518,
"jaime": 14519,
"recorder": 14520,
"lexington": 14521,
"persecution": 14522,
"jumps": 14523,
"renewal": 14524,
"wagons": 14525,
"##11": 14526,
"crushing": 14527,
"##holder": 14528,
"decorations": 14529,
"##lake": 14530,
"abundance": 14531,
"wrath": 14532,
"laundry": 14533,
"£1": 14534,
"garde": 14535,
"##rp": 14536,
"jeanne": 14537,
"beetles": 14538,
"peasant": 14539,
"##sl": 14540,
"splitting": 14541,
"caste": 14542,
"sergei": 14543,
"##rer": 14544,
"##ema": 14545,
"scripts": 14546,
"##ively": 14547,
"rub": 14548,
"satellites": 14549,
"##vor": 14550,
"inscribed": 14551,
"verlag": 14552,
"scrapped": 14553,
"gale": 14554,
"packages": 14555,
"chick": 14556,
"potato": 14557,
"slogan": 14558,
"kathleen": 14559,
"arabs": 14560,
"##culture": 14561,
"counterparts": 14562,
"reminiscent": 14563,
"choral": 14564,
"##tead": 14565,
"rand": 14566,
"retains": 14567,
"bushes": 14568,
"dane": 14569,
"accomplish": 14570,
"courtesy": 14571,
"closes": 14572,
"##oth": 14573,
"slaughter": 14574,
"hague": 14575,
"krakow": 14576,
"lawson": 14577,
"tailed": 14578,
"elias": 14579,
"ginger": 14580,
"##ttes": 14581,
"canopy": 14582,
"betrayal": 14583,
"rebuilding": 14584,
"turf": 14585,
"##hof": 14586,
"frowning": 14587,
"allegiance": 14588,
"brigades": 14589,
"kicks": 14590,
"rebuild": 14591,
"polls": 14592,
"alias": 14593,
"nationalism": 14594,
"td": 14595,
"rowan": 14596,
"audition": 14597,
"bowie": 14598,
"fortunately": 14599,
"recognizes": 14600,
"harp": 14601,
"dillon": 14602,
"horrified": 14603,
"##oro": 14604,
"renault": 14605,
"##tics": 14606,
"ropes": 14607,
"##α": 14608,
"presumed": 14609,
"rewarded": 14610,
"infrared": 14611,
"wiping": 14612,
"accelerated": 14613,
"illustration": 14614,
"##rid": 14615,
"presses": 14616,
"practitioners": 14617,
"badminton": 14618,
"##iard": 14619,
"detained": 14620,
"##tera": 14621,
"recognizing": 14622,
"relates": 14623,
"misery": 14624,
"##sies": 14625,
"##tly": 14626,
"reproduction": 14627,
"piercing": 14628,
"potatoes": 14629,
"thornton": 14630,
"esther": 14631,
"manners": 14632,
"hbo": 14633,
"##aan": 14634,
"ours": 14635,
"bullshit": 14636,
"ernie": 14637,
"perennial": 14638,
"sensitivity": 14639,
"illuminated": 14640,
"rupert": 14641,
"##jin": 14642,
"##iss": 14643,
"##ear": 14644,
"rfc": 14645,
"nassau": 14646,
"##dock": 14647,
"staggered": 14648,
"socialism": 14649,
"##haven": 14650,
"appointments": 14651,
"nonsense": 14652,
"prestige": 14653,
"sharma": 14654,
"haul": 14655,
"##tical": 14656,
"solidarity": 14657,
"gps": 14658,
"##ook": 14659,
"##rata": 14660,
"igor": 14661,
"pedestrian": 14662,
"##uit": 14663,
"baxter": 14664,
"tenants": 14665,
"wires": 14666,
"medication": 14667,
"unlimited": 14668,
"guiding": 14669,
"impacts": 14670,
"diabetes": 14671,
"##rama": 14672,
"sasha": 14673,
"pas": 14674,
"clive": 14675,
"extraction": 14676,
"131": 14677,
"continually": 14678,
"constraints": 14679,
"##bilities": 14680,
"sonata": 14681,
"hunted": 14682,
"sixteenth": 14683,
"chu": 14684,
"planting": 14685,
"quote": 14686,
"mayer": 14687,
"pretended": 14688,
"abs": 14689,
"spat": 14690,
"##hua": 14691,
"ceramic": 14692,
"##cci": 14693,
"curtains": 14694,
"pigs": 14695,
"pitching": 14696,
"##dad": 14697,
"latvian": 14698,
"sore": 14699,
"dayton": 14700,
"##sted": 14701,
"##qi": 14702,
"patrols": 14703,
"slice": 14704,
"playground": 14705,
"##nted": 14706,
"shone": 14707,
"stool": 14708,
"apparatus": 14709,
"inadequate": 14710,
"mates": 14711,
"treason": 14712,
"##ija": 14713,
"desires": 14714,
"##liga": 14715,
"##croft": 14716,
"somalia": 14717,
"laurent": 14718,
"mir": 14719,
"leonardo": 14720,
"oracle": 14721,
"grape": 14722,
"obliged": 14723,
"chevrolet": 14724,
"thirteenth": 14725,
"stunning": 14726,
"enthusiastic": 14727,
"##ede": 14728,
"accounted": 14729,
"concludes": 14730,
"currents": 14731,
"basil": 14732,
"##kovic": 14733,
"drought": 14734,
"##rica": 14735,
"mai": 14736,
"##aire": 14737,
"shove": 14738,
"posting": 14739,
"##shed": 14740,
"pilgrimage": 14741,
"humorous": 14742,
"packing": 14743,
"fry": 14744,
"pencil": 14745,
"wines": 14746,
"smells": 14747,
"144": 14748,
"marilyn": 14749,
"aching": 14750,
"newest": 14751,
"clung": 14752,
"bon": 14753,
"neighbours": 14754,
"sanctioned": 14755,
"##pie": 14756,
"mug": 14757,
"##stock": 14758,
"drowning": 14759,
"##mma": 14760,
"hydraulic": 14761,
"##vil": 14762,
"hiring": 14763,
"reminder": 14764,
"lilly": 14765,
"investigators": 14766,
"##ncies": 14767,
"sour": 14768,
"##eous": 14769,
"compulsory": 14770,
"packet": 14771,
"##rion": 14772,
"##graphic": 14773,
"##elle": 14774,
"cannes": 14775,
"##inate": 14776,
"depressed": 14777,
"##rit": 14778,
"heroic": 14779,
"importantly": 14780,
"theresa": 14781,
"##tled": 14782,
"conway": 14783,
"saturn": 14784,
"marginal": 14785,
"rae": 14786,
"##xia": 14787,
"corresponds": 14788,
"royce": 14789,
"pact": 14790,
"jasper": 14791,
"explosives": 14792,
"packaging": 14793,
"aluminium": 14794,
"##ttered": 14795,
"denotes": 14796,
"rhythmic": 14797,
"spans": 14798,
"assignments": 14799,
"hereditary": 14800,
"outlined": 14801,
"originating": 14802,
"sundays": 14803,
"lad": 14804,
"reissued": 14805,
"greeting": 14806,
"beatrice": 14807,
"##dic": 14808,
"pillar": 14809,
"marcos": 14810,
"plots": 14811,
"handbook": 14812,
"alcoholic": 14813,
"judiciary": 14814,
"avant": 14815,
"slides": 14816,
"extract": 14817,
"masculine": 14818,
"blur": 14819,
"##eum": 14820,
"##force": 14821,
"homage": 14822,
"trembled": 14823,
"owens": 14824,
"hymn": 14825,
"trey": 14826,
"omega": 14827,
"signaling": 14828,
"socks": 14829,
"accumulated": 14830,
"reacted": 14831,
"attic": 14832,
"theo": 14833,
"lining": 14834,
"angie": 14835,
"distraction": 14836,
"primera": 14837,
"talbot": 14838,
"##key": 14839,
"1200": 14840,
"ti": 14841,
"creativity": 14842,
"billed": 14843,
"##hey": 14844,
"deacon": 14845,
"eduardo": 14846,
"identifies": 14847,
"proposition": 14848,
"dizzy": 14849,
"gunner": 14850,
"hogan": 14851,
"##yam": 14852,
"##pping": 14853,
"##hol": 14854,
"ja": 14855,
"##chan": 14856,
"jensen": 14857,
"reconstructed": 14858,
"##berger": 14859,
"clearance": 14860,
"darius": 14861,
"##nier": 14862,
"abe": 14863,
"harlem": 14864,
"plea": 14865,
"dei": 14866,
"circled": 14867,
"emotionally": 14868,
"notation": 14869,
"fascist": 14870,
"neville": 14871,
"exceeded": 14872,
"upwards": 14873,
"viable": 14874,
"ducks": 14875,
"##fo": 14876,
"workforce": 14877,
"racer": 14878,
"limiting": 14879,
"shri": 14880,
"##lson": 14881,
"possesses": 14882,
"1600": 14883,
"kerr": 14884,
"moths": 14885,
"devastating": 14886,
"laden": 14887,
"disturbing": 14888,
"locking": 14889,
"##cture": 14890,
"gal": 14891,
"fearing": 14892,
"accreditation": 14893,
"flavor": 14894,
"aide": 14895,
"1870s": 14896,
"mountainous": 14897,
"##baum": 14898,
"melt": 14899,
"##ures": 14900,
"motel": 14901,
"texture": 14902,
"servers": 14903,
"soda": 14904,
"##mb": 14905,
"herd": 14906,
"##nium": 14907,
"erect": 14908,
"puzzled": 14909,
"hum": 14910,
"peggy": 14911,
"examinations": 14912,
"gould": 14913,
"testified": 14914,
"geoff": 14915,
"ren": 14916,
"devised": 14917,
"sacks": 14918,
"##law": 14919,
"denial": 14920,
"posters": 14921,
"grunted": 14922,
"cesar": 14923,
"tutor": 14924,
"ec": 14925,
"gerry": 14926,
"offerings": 14927,
"byrne": 14928,
"falcons": 14929,
"combinations": 14930,
"ct": 14931,
"incoming": 14932,
"pardon": 14933,
"rocking": 14934,
"26th": 14935,
"avengers": 14936,
"flared": 14937,
"mankind": 14938,
"seller": 14939,
"uttar": 14940,
"loch": 14941,
"nadia": 14942,
"stroking": 14943,
"exposing": 14944,
"##hd": 14945,
"fertile": 14946,
"ancestral": 14947,
"instituted": 14948,
"##has": 14949,
"noises": 14950,
"prophecy": 14951,
"taxation": 14952,
"eminent": 14953,
"vivid": 14954,
"pol": 14955,
"##bol": 14956,
"dart": 14957,
"indirect": 14958,
"multimedia": 14959,
"notebook": 14960,
"upside": 14961,
"displaying": 14962,
"adrenaline": 14963,
"referenced": 14964,
"geometric": 14965,
"##iving": 14966,
"progression": 14967,
"##ddy": 14968,
"blunt": 14969,
"announce": 14970,
"##far": 14971,
"implementing": 14972,
"##lav": 14973,
"aggression": 14974,
"liaison": 14975,
"cooler": 14976,
"cares": 14977,
"headache": 14978,
"plantations": 14979,
"gorge": 14980,
"dots": 14981,
"impulse": 14982,
"thickness": 14983,
"ashamed": 14984,
"averaging": 14985,
"kathy": 14986,
"obligation": 14987,
"precursor": 14988,
"137": 14989,
"fowler": 14990,
"symmetry": 14991,
"thee": 14992,
"225": 14993,
"hears": 14994,
"##rai": 14995,
"undergoing": 14996,
"ads": 14997,
"butcher": 14998,
"bowler": 14999,
"##lip": 15000,
"cigarettes": 15001,
"subscription": 15002,
"goodness": 15003,
"##ically": 15004,
"browne": 15005,
"##hos": 15006,
"##tech": 15007,
"kyoto": 15008,
"donor": 15009,
"##erty": 15010,
"damaging": 15011,
"friction": 15012,
"drifting": 15013,
"expeditions": 15014,
"hardened": 15015,
"prostitution": 15016,
"152": 15017,
"fauna": 15018,
"blankets": 15019,
"claw": 15020,
"tossing": 15021,
"snarled": 15022,
"butterflies": 15023,
"recruits": 15024,
"investigative": 15025,
"coated": 15026,
"healed": 15027,
"138": 15028,
"communal": 15029,
"hai": 15030,
"xiii": 15031,
"academics": 15032,
"boone": 15033,
"psychologist": 15034,
"restless": 15035,
"lahore": 15036,
"stephens": 15037,
"mba": 15038,
"brendan": 15039,
"foreigners": 15040,
"printer": 15041,
"##pc": 15042,
"ached": 15043,
"explode": 15044,
"27th": 15045,
"deed": 15046,
"scratched": 15047,
"dared": 15048,
"##pole": 15049,
"cardiac": 15050,
"1780": 15051,
"okinawa": 15052,
"proto": 15053,
"commando": 15054,
"compelled": 15055,
"oddly": 15056,
"electrons": 15057,
"##base": 15058,
"replica": 15059,
"thanksgiving": 15060,
"##rist": 15061,
"sheila": 15062,
"deliberate": 15063,
"stafford": 15064,
"tidal": 15065,
"representations": 15066,
"hercules": 15067,
"ou": 15068,
"##path": 15069,
"##iated": 15070,
"kidnapping": 15071,
"lenses": 15072,
"##tling": 15073,
"deficit": 15074,
"samoa": 15075,
"mouths": 15076,
"consuming": 15077,
"computational": 15078,
"maze": 15079,
"granting": 15080,
"smirk": 15081,
"razor": 15082,
"fixture": 15083,
"ideals": 15084,
"inviting": 15085,
"aiden": 15086,
"nominal": 15087,
"##vs": 15088,
"issuing": 15089,
"julio": 15090,
"pitt": 15091,
"ramsey": 15092,
"docks": 15093,
"##oss": 15094,
"exhaust": 15095,
"##owed": 15096,
"bavarian": 15097,
"draped": 15098,
"anterior": 15099,
"mating": 15100,
"ethiopian": 15101,
"explores": 15102,
"noticing": 15103,
"##nton": 15104,
"discarded": 15105,
"convenience": 15106,
"hoffman": 15107,
"endowment": 15108,
"beasts": 15109,
"cartridge": 15110,
"mormon": 15111,
"paternal": 15112,
"probe": 15113,
"sleeves": 15114,
"interfere": 15115,
"lump": 15116,
"deadline": 15117,
"##rail": 15118,
"jenks": 15119,
"bulldogs": 15120,
"scrap": 15121,
"alternating": 15122,
"justified": 15123,
"reproductive": 15124,
"nam": 15125,
"seize": 15126,
"descending": 15127,
"secretariat": 15128,
"kirby": 15129,
"coupe": 15130,
"grouped": 15131,
"smash": 15132,
"panther": 15133,
"sedan": 15134,
"tapping": 15135,
"##18": 15136,
"lola": 15137,
"cheer": 15138,
"germanic": 15139,
"unfortunate": 15140,
"##eter": 15141,
"unrelated": 15142,
"##fan": 15143,
"subordinate": 15144,
"##sdale": 15145,
"suzanne": 15146,
"advertisement": 15147,
"##ility": 15148,
"horsepower": 15149,
"##lda": 15150,
"cautiously": 15151,
"discourse": 15152,
"luigi": 15153,
"##mans": 15154,
"##fields": 15155,
"noun": 15156,
"prevalent": 15157,
"mao": 15158,
"schneider": 15159,
"everett": 15160,
"surround": 15161,
"governorate": 15162,
"kira": 15163,
"##avia": 15164,
"westward": 15165,
"##take": 15166,
"misty": 15167,
"rails": 15168,
"sustainability": 15169,
"134": 15170,
"unused": 15171,
"##rating": 15172,
"packs": 15173,
"toast": 15174,
"unwilling": 15175,
"regulate": 15176,
"thy": 15177,
"suffrage": 15178,
"nile": 15179,
"awe": 15180,
"assam": 15181,
"definitions": 15182,
"travelers": 15183,
"affordable": 15184,
"##rb": 15185,
"conferred": 15186,
"sells": 15187,
"undefeated": 15188,
"beneficial": 15189,
"torso": 15190,
"basal": 15191,
"repeating": 15192,
"remixes": 15193,
"##pass": 15194,
"bahrain": 15195,
"cables": 15196,
"fang": 15197,
"##itated": 15198,
"excavated": 15199,
"numbering": 15200,
"statutory": 15201,
"##rey": 15202,
"deluxe": 15203,
"##lian": 15204,
"forested": 15205,
"ramirez": 15206,
"derbyshire": 15207,
"zeus": 15208,
"slamming": 15209,
"transfers": 15210,
"astronomer": 15211,
"banana": 15212,
"lottery": 15213,
"berg": 15214,
"histories": 15215,
"bamboo": 15216,
"##uchi": 15217,
"resurrection": 15218,
"posterior": 15219,
"bowls": 15220,
"vaguely": 15221,
"##thi": 15222,
"thou": 15223,
"preserving": 15224,
"tensed": 15225,
"offence": 15226,
"##inas": 15227,
"meyrick": 15228,
"callum": 15229,
"ridden": 15230,
"watt": 15231,
"langdon": 15232,
"tying": 15233,
"lowland": 15234,
"snorted": 15235,
"daring": 15236,
"truman": 15237,
"##hale": 15238,
"##girl": 15239,
"aura": 15240,
"overly": 15241,
"filing": 15242,
"weighing": 15243,
"goa": 15244,
"infections": 15245,
"philanthropist": 15246,
"saunders": 15247,
"eponymous": 15248,
"##owski": 15249,
"latitude": 15250,
"perspectives": 15251,
"reviewing": 15252,
"mets": 15253,
"commandant": 15254,
"radial": 15255,
"##kha": 15256,
"flashlight": 15257,
"reliability": 15258,
"koch": 15259,
"vowels": 15260,
"amazed": 15261,
"ada": 15262,
"elaine": 15263,
"supper": 15264,
"##rth": 15265,
"##encies": 15266,
"predator": 15267,
"debated": 15268,
"soviets": 15269,
"cola": 15270,
"##boards": 15271,
"##nah": 15272,
"compartment": 15273,
"crooked": 15274,
"arbitrary": 15275,
"fourteenth": 15276,
"##ctive": 15277,
"havana": 15278,
"majors": 15279,
"steelers": 15280,
"clips": 15281,
"profitable": 15282,
"ambush": 15283,
"exited": 15284,
"packers": 15285,
"##tile": 15286,
"nude": 15287,
"cracks": 15288,
"fungi": 15289,
"##е": 15290,
"limb": 15291,
"trousers": 15292,
"josie": 15293,
"shelby": 15294,
"tens": 15295,
"frederic": 15296,
"##ος": 15297,
"definite": 15298,
"smoothly": 15299,
"constellation": 15300,
"insult": 15301,
"baton": 15302,
"discs": 15303,
"lingering": 15304,
"##nco": 15305,
"conclusions": 15306,
"lent": 15307,
"staging": 15308,
"becker": 15309,
"grandpa": 15310,
"shaky": 15311,
"##tron": 15312,
"einstein": 15313,
"obstacles": 15314,
"sk": 15315,
"adverse": 15316,
"elle": 15317,
"economically": 15318,
"##moto": 15319,
"mccartney": 15320,
"thor": 15321,
"dismissal": 15322,
"motions": 15323,
"readings": 15324,
"nostrils": 15325,
"treatise": 15326,
"##pace": 15327,
"squeezing": 15328,
"evidently": 15329,
"prolonged": 15330,
"1783": 15331,
"venezuelan": 15332,
"je": 15333,
"marguerite": 15334,
"beirut": 15335,
"takeover": 15336,
"shareholders": 15337,
"##vent": 15338,
"denise": 15339,
"digit": 15340,
"airplay": 15341,
"norse": 15342,
"##bbling": 15343,
"imaginary": 15344,
"pills": 15345,
"hubert": 15346,
"blaze": 15347,
"vacated": 15348,
"eliminating": 15349,
"##ello": 15350,
"vine": 15351,
"mansfield": 15352,
"##tty": 15353,
"retrospective": 15354,
"barrow": 15355,
"borne": 15356,
"clutch": 15357,
"bail": 15358,
"forensic": 15359,
"weaving": 15360,
"##nett": 15361,
"##witz": 15362,
"desktop": 15363,
"citadel": 15364,
"promotions": 15365,
"worrying": 15366,
"dorset": 15367,
"ieee": 15368,
"subdivided": 15369,
"##iating": 15370,
"manned": 15371,
"expeditionary": 15372,
"pickup": 15373,
"synod": 15374,
"chuckle": 15375,
"185": 15376,
"barney": 15377,
"##rz": 15378,
"##ffin": 15379,
"functionality": 15380,
"karachi": 15381,
"litigation": 15382,
"meanings": 15383,
"uc": 15384,
"lick": 15385,
"turbo": 15386,
"anders": 15387,
"##ffed": 15388,
"execute": 15389,
"curl": 15390,
"oppose": 15391,
"ankles": 15392,
"typhoon": 15393,
"##د": 15394,
"##ache": 15395,
"##asia": 15396,
"linguistics": 15397,
"compassion": 15398,
"pressures": 15399,
"grazing": 15400,
"perfection": 15401,
"##iting": 15402,
"immunity": 15403,
"monopoly": 15404,
"muddy": 15405,
"backgrounds": 15406,
"136": 15407,
"namibia": 15408,
"francesca": 15409,
"monitors": 15410,
"attracting": 15411,
"stunt": 15412,
"tuition": 15413,
"##ии": 15414,
"vegetable": 15415,
"##mates": 15416,
"##quent": 15417,
"mgm": 15418,
"jen": 15419,
"complexes": 15420,
"forts": 15421,
"##ond": 15422,
"cellar": 15423,
"bites": 15424,
"seventeenth": 15425,
"royals": 15426,
"flemish": 15427,
"failures": 15428,
"mast": 15429,
"charities": 15430,
"##cular": 15431,
"peruvian": 15432,
"capitals": 15433,
"macmillan": 15434,
"ipswich": 15435,
"outward": 15436,
"frigate": 15437,
"postgraduate": 15438,
"folds": 15439,
"employing": 15440,
"##ouse": 15441,
"concurrently": 15442,
"fiery": 15443,
"##tai": 15444,
"contingent": 15445,
"nightmares": 15446,
"monumental": 15447,
"nicaragua": 15448,
"##kowski": 15449,
"lizard": 15450,
"mal": 15451,
"fielding": 15452,
"gig": 15453,
"reject": 15454,
"##pad": 15455,
"harding": 15456,
"##ipe": 15457,
"coastline": 15458,
"##cin": 15459,
"##nos": 15460,
"beethoven": 15461,
"humphrey": 15462,
"innovations": 15463,
"##tam": 15464,
"##nge": 15465,
"norris": 15466,
"doris": 15467,
"solicitor": 15468,
"huang": 15469,
"obey": 15470,
"141": 15471,
"##lc": 15472,
"niagara": 15473,
"##tton": 15474,
"shelves": 15475,
"aug": 15476,
"bourbon": 15477,
"curry": 15478,
"nightclub": 15479,
"specifications": 15480,
"hilton": 15481,
"##ndo": 15482,
"centennial": 15483,
"dispersed": 15484,
"worm": 15485,
"neglected": 15486,
"briggs": 15487,
"sm": 15488,
"font": 15489,
"kuala": 15490,
"uneasy": 15491,
"plc": 15492,
"##nstein": 15493,
"##bound": 15494,
"##aking": 15495,
"##burgh": 15496,
"awaiting": 15497,
"pronunciation": 15498,
"##bbed": 15499,
"##quest": 15500,
"eh": 15501,
"optimal": 15502,
"zhu": 15503,
"raped": 15504,
"greens": 15505,
"presided": 15506,
"brenda": 15507,
"worries": 15508,
"##life": 15509,
"venetian": 15510,
"marxist": 15511,
"turnout": 15512,
"##lius": 15513,
"refined": 15514,
"braced": 15515,
"sins": 15516,
"grasped": 15517,
"sunderland": 15518,
"nickel": 15519,
"speculated": 15520,
"lowell": 15521,
"cyrillic": 15522,
"communism": 15523,
"fundraising": 15524,
"resembling": 15525,
"colonists": 15526,
"mutant": 15527,
"freddie": 15528,
"usc": 15529,
"##mos": 15530,
"gratitude": 15531,
"##run": 15532,
"mural": 15533,
"##lous": 15534,
"chemist": 15535,
"wi": 15536,
"reminds": 15537,
"28th": 15538,
"steals": 15539,
"tess": 15540,
"pietro": 15541,
"##ingen": 15542,
"promoter": 15543,
"ri": 15544,
"microphone": 15545,
"honoured": 15546,
"rai": 15547,
"sant": 15548,
"##qui": 15549,
"feather": 15550,
"##nson": 15551,
"burlington": 15552,
"kurdish": 15553,
"terrorists": 15554,
"deborah": 15555,
"sickness": 15556,
"##wed": 15557,
"##eet": 15558,
"hazard": 15559,
"irritated": 15560,
"desperation": 15561,
"veil": 15562,
"clarity": 15563,
"##rik": 15564,
"jewels": 15565,
"xv": 15566,
"##gged": 15567,
"##ows": 15568,
"##cup": 15569,
"berkshire": 15570,
"unfair": 15571,
"mysteries": 15572,
"orchid": 15573,
"winced": 15574,
"exhaustion": 15575,
"renovations": 15576,
"stranded": 15577,
"obe": 15578,
"infinity": 15579,
"##nies": 15580,
"adapt": 15581,
"redevelopment": 15582,
"thanked": 15583,
"registry": 15584,
"olga": 15585,
"domingo": 15586,
"noir": 15587,
"tudor": 15588,
"ole": 15589,
"##atus": 15590,
"commenting": 15591,
"behaviors": 15592,
"##ais": 15593,
"crisp": 15594,
"pauline": 15595,
"probable": 15596,
"stirling": 15597,
"wigan": 15598,
"##bian": 15599,
"paralympics": 15600,
"panting": 15601,
"surpassed": 15602,
"##rew": 15603,
"luca": 15604,
"barred": 15605,
"pony": 15606,
"famed": 15607,
"##sters": 15608,
"cassandra": 15609,
"waiter": 15610,
"carolyn": 15611,
"exported": 15612,
"##orted": 15613,
"andres": 15614,
"destructive": 15615,
"deeds": 15616,
"jonah": 15617,
"castles": 15618,
"vacancy": 15619,
"suv": 15620,
"##glass": 15621,
"1788": 15622,
"orchard": 15623,
"yep": 15624,
"famine": 15625,
"belarusian": 15626,
"sprang": 15627,
"##forth": 15628,
"skinny": 15629,
"##mis": 15630,
"administrators": 15631,
"rotterdam": 15632,
"zambia": 15633,
"zhao": 15634,
"boiler": 15635,
"discoveries": 15636,
"##ride": 15637,
"##physics": 15638,
"lucius": 15639,
"disappointing": 15640,
"outreach": 15641,
"spoon": 15642,
"##frame": 15643,
"qualifications": 15644,
"unanimously": 15645,
"enjoys": 15646,
"regency": 15647,
"##iidae": 15648,
"stade": 15649,
"realism": 15650,
"veterinary": 15651,
"rodgers": 15652,
"dump": 15653,
"alain": 15654,
"chestnut": 15655,
"castile": 15656,
"censorship": 15657,
"rumble": 15658,
"gibbs": 15659,
"##itor": 15660,
"communion": 15661,
"reggae": 15662,
"inactivated": 15663,
"logs": 15664,
"loads": 15665,
"##houses": 15666,
"homosexual": 15667,
"##iano": 15668,
"ale": 15669,
"informs": 15670,
"##cas": 15671,
"phrases": 15672,
"plaster": 15673,
"linebacker": 15674,
"ambrose": 15675,
"kaiser": 15676,
"fascinated": 15677,
"850": 15678,
"limerick": 15679,
"recruitment": 15680,
"forge": 15681,
"mastered": 15682,
"##nding": 15683,
"leinster": 15684,
"rooted": 15685,
"threaten": 15686,
"##strom": 15687,
"borneo": 15688,
"##hes": 15689,
"suggestions": 15690,
"scholarships": 15691,
"propeller": 15692,
"documentaries": 15693,
"patronage": 15694,
"coats": 15695,
"constructing": 15696,
"invest": 15697,
"neurons": 15698,
"comet": 15699,
"entirety": 15700,
"shouts": 15701,
"identities": 15702,
"annoying": 15703,
"unchanged": 15704,
"wary": 15705,
"##antly": 15706,
"##ogy": 15707,
"neat": 15708,
"oversight": 15709,
"##kos": 15710,
"phillies": 15711,
"replay": 15712,
"constance": 15713,
"##kka": 15714,
"incarnation": 15715,
"humble": 15716,
"skies": 15717,
"minus": 15718,
"##acy": 15719,
"smithsonian": 15720,
"##chel": 15721,
"guerrilla": 15722,
"jar": 15723,
"cadets": 15724,
"##plate": 15725,
"surplus": 15726,
"audit": 15727,
"##aru": 15728,
"cracking": 15729,
"joanna": 15730,
"louisa": 15731,
"pacing": 15732,
"##lights": 15733,
"intentionally": 15734,
"##iri": 15735,
"diner": 15736,
"nwa": 15737,
"imprint": 15738,
"australians": 15739,
"tong": 15740,
"unprecedented": 15741,
"bunker": 15742,
"naive": 15743,
"specialists": 15744,
"ark": 15745,
"nichols": 15746,
"railing": 15747,
"leaked": 15748,
"pedal": 15749,
"##uka": 15750,
"shrub": 15751,
"longing": 15752,
"roofs": 15753,
"v8": 15754,
"captains": 15755,
"neural": 15756,
"tuned": 15757,
"##ntal": 15758,
"##jet": 15759,
"emission": 15760,
"medina": 15761,
"frantic": 15762,
"codex": 15763,
"definitive": 15764,
"sid": 15765,
"abolition": 15766,
"intensified": 15767,
"stocks": 15768,
"enrique": 15769,
"sustain": 15770,
"genoa": 15771,
"oxide": 15772,
"##written": 15773,
"clues": 15774,
"cha": 15775,
"##gers": 15776,
"tributaries": 15777,
"fragment": 15778,
"venom": 15779,
"##rity": 15780,
"##ente": 15781,
"##sca": 15782,
"muffled": 15783,
"vain": 15784,
"sire": 15785,
"laos": 15786,
"##ingly": 15787,
"##hana": 15788,
"hastily": 15789,
"snapping": 15790,
"surfaced": 15791,
"sentiment": 15792,
"motive": 15793,
"##oft": 15794,
"contests": 15795,
"approximate": 15796,
"mesa": 15797,
"luckily": 15798,
"dinosaur": 15799,
"exchanges": 15800,
"propelled": 15801,
"accord": 15802,
"bourne": 15803,
"relieve": 15804,
"tow": 15805,
"masks": 15806,
"offended": 15807,
"##ues": 15808,
"cynthia": 15809,
"##mmer": 15810,
"rains": 15811,
"bartender": 15812,
"zinc": 15813,
"reviewers": 15814,
"lois": 15815,
"##sai": 15816,
"legged": 15817,
"arrogant": 15818,
"rafe": 15819,
"rosie": 15820,
"comprise": 15821,
"handicap": 15822,
"blockade": 15823,
"inlet": 15824,
"lagoon": 15825,
"copied": 15826,
"drilling": 15827,
"shelley": 15828,
"petals": 15829,
"##inian": 15830,
"mandarin": 15831,
"obsolete": 15832,
"##inated": 15833,
"onward": 15834,
"arguably": 15835,
"productivity": 15836,
"cindy": 15837,
"praising": 15838,
"seldom": 15839,
"busch": 15840,
"discusses": 15841,
"raleigh": 15842,
"shortage": 15843,
"ranged": 15844,
"stanton": 15845,
"encouragement": 15846,
"firstly": 15847,
"conceded": 15848,
"overs": 15849,
"temporal": 15850,
"##uke": 15851,
"cbe": 15852,
"##bos": 15853,
"woo": 15854,
"certainty": 15855,
"pumps": 15856,
"##pton": 15857,
"stalked": 15858,
"##uli": 15859,
"lizzie": 15860,
"periodic": 15861,
"thieves": 15862,
"weaker": 15863,
"##night": 15864,
"gases": 15865,
"shoving": 15866,
"chooses": 15867,
"wc": 15868,
"##chemical": 15869,
"prompting": 15870,
"weights": 15871,
"##kill": 15872,
"robust": 15873,
"flanked": 15874,
"sticky": 15875,
"hu": 15876,
"tuberculosis": 15877,
"##eb": 15878,
"##eal": 15879,
"christchurch": 15880,
"resembled": 15881,
"wallet": 15882,
"reese": 15883,
"inappropriate": 15884,
"pictured": 15885,
"distract": 15886,
"fixing": 15887,
"fiddle": 15888,
"giggled": 15889,
"burger": 15890,
"heirs": 15891,
"hairy": 15892,
"mechanic": 15893,
"torque": 15894,
"apache": 15895,
"obsessed": 15896,
"chiefly": 15897,
"cheng": 15898,
"logging": 15899,
"##tag": 15900,
"extracted": 15901,
"meaningful": 15902,
"numb": 15903,
"##vsky": 15904,
"gloucestershire": 15905,
"reminding": 15906,
"##bay": 15907,
"unite": 15908,
"##lit": 15909,
"breeds": 15910,
"diminished": 15911,
"clown": 15912,
"glove": 15913,
"1860s": 15914,
"##ن": 15915,
"##ug": 15916,
"archibald": 15917,
"focal": 15918,
"freelance": 15919,
"sliced": 15920,
"depiction": 15921,
"##yk": 15922,
"organism": 15923,
"switches": 15924,
"sights": 15925,
"stray": 15926,
"crawling": 15927,
"##ril": 15928,
"lever": 15929,
"leningrad": 15930,
"interpretations": 15931,
"loops": 15932,
"anytime": 15933,
"reel": 15934,
"alicia": 15935,
"delighted": 15936,
"##ech": 15937,
"inhaled": 15938,
"xiv": 15939,
"suitcase": 15940,
"bernie": 15941,
"vega": 15942,
"licenses": 15943,
"northampton": 15944,
"exclusion": 15945,
"induction": 15946,
"monasteries": 15947,
"racecourse": 15948,
"homosexuality": 15949,
"##right": 15950,
"##sfield": 15951,
"##rky": 15952,
"dimitri": 15953,
"michele": 15954,
"alternatives": 15955,
"ions": 15956,
"commentators": 15957,
"genuinely": 15958,
"objected": 15959,
"pork": 15960,
"hospitality": 15961,
"fencing": 15962,
"stephan": 15963,
"warships": 15964,
"peripheral": 15965,
"wit": 15966,
"drunken": 15967,
"wrinkled": 15968,
"quentin": 15969,
"spends": 15970,
"departing": 15971,
"chung": 15972,
"numerical": 15973,
"spokesperson": 15974,
"##zone": 15975,
"johannesburg": 15976,
"caliber": 15977,
"killers": 15978,
"##udge": 15979,
"assumes": 15980,
"neatly": 15981,
"demographic": 15982,
"abigail": 15983,
"bloc": 15984,
"##vel": 15985,
"mounting": 15986,
"##lain": 15987,
"bentley": 15988,
"slightest": 15989,
"xu": 15990,
"recipients": 15991,
"##jk": 15992,
"merlin": 15993,
"##writer": 15994,
"seniors": 15995,
"prisons": 15996,
"blinking": 15997,
"hindwings": 15998,
"flickered": 15999,
"kappa": 16000,
"##hel": 16001,
"80s": 16002,
"strengthening": 16003,
"appealing": 16004,
"brewing": 16005,
"gypsy": 16006,
"mali": 16007,
"lashes": 16008,
"hulk": 16009,
"unpleasant": 16010,
"harassment": 16011,
"bio": 16012,
"treaties": 16013,
"predict": 16014,
"instrumentation": 16015,
"pulp": 16016,
"troupe": 16017,
"boiling": 16018,
"mantle": 16019,
"##ffe": 16020,
"ins": 16021,
"##vn": 16022,
"dividing": 16023,
"handles": 16024,
"verbs": 16025,
"##onal": 16026,
"coconut": 16027,
"senegal": 16028,
"340": 16029,
"thorough": 16030,
"gum": 16031,
"momentarily": 16032,
"##sto": 16033,
"cocaine": 16034,
"panicked": 16035,
"destined": 16036,
"##turing": 16037,
"teatro": 16038,
"denying": 16039,
"weary": 16040,
"captained": 16041,
"mans": 16042,
"##hawks": 16043,
"##code": 16044,
"wakefield": 16045,
"bollywood": 16046,
"thankfully": 16047,
"##16": 16048,
"cyril": 16049,
"##wu": 16050,
"amendments": 16051,
"##bahn": 16052,
"consultation": 16053,
"stud": 16054,
"reflections": 16055,
"kindness": 16056,
"1787": 16057,
"internally": 16058,
"##ovo": 16059,
"tex": 16060,
"mosaic": 16061,
"distribute": 16062,
"paddy": 16063,
"seeming": 16064,
"143": 16065,
"##hic": 16066,
"piers": 16067,
"##15": 16068,
"##mura": 16069,
"##verse": 16070,
"popularly": 16071,
"winger": 16072,
"kang": 16073,
"sentinel": 16074,
"mccoy": 16075,
"##anza": 16076,
"covenant": 16077,
"##bag": 16078,
"verge": 16079,
"fireworks": 16080,
"suppress": 16081,
"thrilled": 16082,
"dominate": 16083,
"##jar": 16084,
"swansea": 16085,
"##60": 16086,
"142": 16087,
"reconciliation": 16088,
"##ndi": 16089,
"stiffened": 16090,
"cue": 16091,
"dorian": 16092,
"##uf": 16093,
"damascus": 16094,
"amor": 16095,
"ida": 16096,
"foremost": 16097,
"##aga": 16098,
"porsche": 16099,
"unseen": 16100,
"dir": 16101,
"##had": 16102,
"##azi": 16103,
"stony": 16104,
"lexi": 16105,
"melodies": 16106,
"##nko": 16107,
"angular": 16108,
"integer": 16109,
"podcast": 16110,
"ants": 16111,
"inherent": 16112,
"jaws": 16113,
"justify": 16114,
"persona": 16115,
"##olved": 16116,
"josephine": 16117,
"##nr": 16118,
"##ressed": 16119,
"customary": 16120,
"flashes": 16121,
"gala": 16122,
"cyrus": 16123,
"glaring": 16124,
"backyard": 16125,
"ariel": 16126,
"physiology": 16127,
"greenland": 16128,
"html": 16129,
"stir": 16130,
"avon": 16131,
"atletico": 16132,
"finch": 16133,
"methodology": 16134,
"ked": 16135,
"##lent": 16136,
"mas": 16137,
"catholicism": 16138,
"townsend": 16139,
"branding": 16140,
"quincy": 16141,
"fits": 16142,
"containers": 16143,
"1777": 16144,
"ashore": 16145,
"aragon": 16146,
"##19": 16147,
"forearm": 16148,
"poisoning": 16149,
"##sd": 16150,
"adopting": 16151,
"conquer": 16152,
"grinding": 16153,
"amnesty": 16154,
"keller": 16155,
"finances": 16156,
"evaluate": 16157,
"forged": 16158,
"lankan": 16159,
"instincts": 16160,
"##uto": 16161,
"guam": 16162,
"bosnian": 16163,
"photographed": 16164,
"workplace": 16165,
"desirable": 16166,
"protector": 16167,
"##dog": 16168,
"allocation": 16169,
"intently": 16170,
"encourages": 16171,
"willy": 16172,
"##sten": 16173,
"bodyguard": 16174,
"electro": 16175,
"brighter": 16176,
"##ν": 16177,
"bihar": 16178,
"##chev": 16179,
"lasts": 16180,
"opener": 16181,
"amphibious": 16182,
"sal": 16183,
"verde": 16184,
"arte": 16185,
"##cope": 16186,
"captivity": 16187,
"vocabulary": 16188,
"yields": 16189,
"##tted": 16190,
"agreeing": 16191,
"desmond": 16192,
"pioneered": 16193,
"##chus": 16194,
"strap": 16195,
"campaigned": 16196,
"railroads": 16197,
"##ович": 16198,
"emblem": 16199,
"##dre": 16200,
"stormed": 16201,
"501": 16202,
"##ulous": 16203,
"marijuana": 16204,
"northumberland": 16205,
"##gn": 16206,
"##nath": 16207,
"bowen": 16208,
"landmarks": 16209,
"beaumont": 16210,
"##qua": 16211,
"danube": 16212,
"##bler": 16213,
"attorneys": 16214,
"th": 16215,
"ge": 16216,
"flyers": 16217,
"critique": 16218,
"villains": 16219,
"cass": 16220,
"mutation": 16221,
"acc": 16222,
"##0s": 16223,
"colombo": 16224,
"mckay": 16225,
"motif": 16226,
"sampling": 16227,
"concluding": 16228,
"syndicate": 16229,
"##rell": 16230,
"neon": 16231,
"stables": 16232,
"ds": 16233,
"warnings": 16234,
"clint": 16235,
"mourning": 16236,
"wilkinson": 16237,
"##tated": 16238,
"merrill": 16239,
"leopard": 16240,
"evenings": 16241,
"exhaled": 16242,
"emil": 16243,
"sonia": 16244,
"ezra": 16245,
"discrete": 16246,
"stove": 16247,
"farrell": 16248,
"fifteenth": 16249,
"prescribed": 16250,
"superhero": 16251,
"##rier": 16252,
"worms": 16253,
"helm": 16254,
"wren": 16255,
"##duction": 16256,
"##hc": 16257,
"expo": 16258,
"##rator": 16259,
"hq": 16260,
"unfamiliar": 16261,
"antony": 16262,
"prevents": 16263,
"acceleration": 16264,
"fiercely": 16265,
"mari": 16266,
"painfully": 16267,
"calculations": 16268,
"cheaper": 16269,
"ign": 16270,
"clifton": 16271,
"irvine": 16272,
"davenport": 16273,
"mozambique": 16274,
"##np": 16275,
"pierced": 16276,
"##evich": 16277,
"wonders": 16278,
"##wig": 16279,
"##cate": 16280,
"##iling": 16281,
"crusade": 16282,
"ware": 16283,
"##uel": 16284,
"enzymes": 16285,
"reasonably": 16286,
"mls": 16287,
"##coe": 16288,
"mater": 16289,
"ambition": 16290,
"bunny": 16291,
"eliot": 16292,
"kernel": 16293,
"##fin": 16294,
"asphalt": 16295,
"headmaster": 16296,
"torah": 16297,
"aden": 16298,
"lush": 16299,
"pins": 16300,
"waived": 16301,
"##care": 16302,
"##yas": 16303,
"joao": 16304,
"substrate": 16305,
"enforce": 16306,
"##grad": 16307,
"##ules": 16308,
"alvarez": 16309,
"selections": 16310,
"epidemic": 16311,
"tempted": 16312,
"##bit": 16313,
"bremen": 16314,
"translates": 16315,
"ensured": 16316,
"waterfront": 16317,
"29th": 16318,
"forrest": 16319,
"manny": 16320,
"malone": 16321,
"kramer": 16322,
"reigning": 16323,
"cookies": 16324,
"simpler": 16325,
"absorption": 16326,
"205": 16327,
"engraved": 16328,
"##ffy": 16329,
"evaluated": 16330,
"1778": 16331,
"haze": 16332,
"146": 16333,
"comforting": 16334,
"crossover": 16335,
"##abe": 16336,
"thorn": 16337,
"##rift": 16338,
"##imo": 16339,
"##pop": 16340,
"suppression": 16341,
"fatigue": 16342,
"cutter": 16343,
"##tr": 16344,
"201": 16345,
"wurttemberg": 16346,
"##orf": 16347,
"enforced": 16348,
"hovering": 16349,
"proprietary": 16350,
"gb": 16351,
"samurai": 16352,
"syllable": 16353,
"ascent": 16354,
"lacey": 16355,
"tick": 16356,
"lars": 16357,
"tractor": 16358,
"merchandise": 16359,
"rep": 16360,
"bouncing": 16361,
"defendants": 16362,
"##yre": 16363,
"huntington": 16364,
"##ground": 16365,
"##oko": 16366,
"standardized": 16367,
"##hor": 16368,
"##hima": 16369,
"assassinated": 16370,
"nu": 16371,
"predecessors": 16372,
"rainy": 16373,
"liar": 16374,
"assurance": 16375,
"lyrical": 16376,
"##uga": 16377,
"secondly": 16378,
"flattened": 16379,
"ios": 16380,
"parameter": 16381,
"undercover": 16382,
"##mity": 16383,
"bordeaux": 16384,
"punish": 16385,
"ridges": 16386,
"markers": 16387,
"exodus": 16388,
"inactive": 16389,
"hesitate": 16390,
"debbie": 16391,
"nyc": 16392,
"pledge": 16393,
"savoy": 16394,
"nagar": 16395,
"offset": 16396,
"organist": 16397,
"##tium": 16398,
"hesse": 16399,
"marin": 16400,
"converting": 16401,
"##iver": 16402,
"diagram": 16403,
"propulsion": 16404,
"pu": 16405,
"validity": 16406,
"reverted": 16407,
"supportive": 16408,
"##dc": 16409,
"ministries": 16410,
"clans": 16411,
"responds": 16412,
"proclamation": 16413,
"##inae": 16414,
"##ø": 16415,
"##rea": 16416,
"ein": 16417,
"pleading": 16418,
"patriot": 16419,
"sf": 16420,
"birch": 16421,
"islanders": 16422,
"strauss": 16423,
"hates": 16424,
"##dh": 16425,
"brandenburg": 16426,
"concession": 16427,
"rd": 16428,
"##ob": 16429,
"1900s": 16430,
"killings": 16431,
"textbook": 16432,
"antiquity": 16433,
"cinematography": 16434,
"wharf": 16435,
"embarrassing": 16436,
"setup": 16437,
"creed": 16438,
"farmland": 16439,
"inequality": 16440,
"centred": 16441,
"signatures": 16442,
"fallon": 16443,
"370": 16444,
"##ingham": 16445,
"##uts": 16446,
"ceylon": 16447,
"gazing": 16448,
"directive": 16449,
"laurie": 16450,
"##tern": 16451,
"globally": 16452,
"##uated": 16453,
"##dent": 16454,
"allah": 16455,
"excavation": 16456,
"threads": 16457,
"##cross": 16458,
"148": 16459,
"frantically": 16460,
"icc": 16461,
"utilize": 16462,
"determines": 16463,
"respiratory": 16464,
"thoughtful": 16465,
"receptions": 16466,
"##dicate": 16467,
"merging": 16468,
"chandra": 16469,
"seine": 16470,
"147": 16471,
"builders": 16472,
"builds": 16473,
"diagnostic": 16474,
"dev": 16475,
"visibility": 16476,
"goddamn": 16477,
"analyses": 16478,
"dhaka": 16479,
"cho": 16480,
"proves": 16481,
"chancel": 16482,
"concurrent": 16483,
"curiously": 16484,
"canadians": 16485,
"pumped": 16486,
"restoring": 16487,
"1850s": 16488,
"turtles": 16489,
"jaguar": 16490,
"sinister": 16491,
"spinal": 16492,
"traction": 16493,
"declan": 16494,
"vows": 16495,
"1784": 16496,
"glowed": 16497,
"capitalism": 16498,
"swirling": 16499,
"install": 16500,
"universidad": 16501,
"##lder": 16502,
"##oat": 16503,
"soloist": 16504,
"##genic": 16505,
"##oor": 16506,
"coincidence": 16507,
"beginnings": 16508,
"nissan": 16509,
"dip": 16510,
"resorts": 16511,
"caucasus": 16512,
"combustion": 16513,
"infectious": 16514,
"##eno": 16515,
"pigeon": 16516,
"serpent": 16517,
"##itating": 16518,
"conclude": 16519,
"masked": 16520,
"salad": 16521,
"jew": 16522,
"##gr": 16523,
"surreal": 16524,
"toni": 16525,
"##wc": 16526,
"harmonica": 16527,
"151": 16528,
"##gins": 16529,
"##etic": 16530,
"##coat": 16531,
"fishermen": 16532,
"intending": 16533,
"bravery": 16534,
"##wave": 16535,
"klaus": 16536,
"titan": 16537,
"wembley": 16538,
"taiwanese": 16539,
"ransom": 16540,
"40th": 16541,
"incorrect": 16542,
"hussein": 16543,
"eyelids": 16544,
"jp": 16545,
"cooke": 16546,
"dramas": 16547,
"utilities": 16548,
"##etta": 16549,
"##print": 16550,
"eisenhower": 16551,
"principally": 16552,
"granada": 16553,
"lana": 16554,
"##rak": 16555,
"openings": 16556,
"concord": 16557,
"##bl": 16558,
"bethany": 16559,
"connie": 16560,
"morality": 16561,
"sega": 16562,
"##mons": 16563,
"##nard": 16564,
"earnings": 16565,
"##kara": 16566,
"##cine": 16567,
"wii": 16568,
"communes": 16569,
"##rel": 16570,
"coma": 16571,
"composing": 16572,
"softened": 16573,
"severed": 16574,
"grapes": 16575,
"##17": 16576,
"nguyen": 16577,
"analyzed": 16578,
"warlord": 16579,
"hubbard": 16580,
"heavenly": 16581,
"behave": 16582,
"slovenian": 16583,
"##hit": 16584,
"##ony": 16585,
"hailed": 16586,
"filmmakers": 16587,
"trance": 16588,
"caldwell": 16589,
"skye": 16590,
"unrest": 16591,
"coward": 16592,
"likelihood": 16593,
"##aging": 16594,
"bern": 16595,
"sci": 16596,
"taliban": 16597,
"honolulu": 16598,
"propose": 16599,
"##wang": 16600,
"1700": 16601,
"browser": 16602,
"imagining": 16603,
"cobra": 16604,
"contributes": 16605,
"dukes": 16606,
"instinctively": 16607,
"conan": 16608,
"violinist": 16609,
"##ores": 16610,
"accessories": 16611,
"gradual": 16612,
"##amp": 16613,
"quotes": 16614,
"sioux": 16615,
"##dating": 16616,
"undertake": 16617,
"intercepted": 16618,
"sparkling": 16619,
"compressed": 16620,
"139": 16621,
"fungus": 16622,
"tombs": 16623,
"haley": 16624,
"imposing": 16625,
"rests": 16626,
"degradation": 16627,
"lincolnshire": 16628,
"retailers": 16629,
"wetlands": 16630,
"tulsa": 16631,
"distributor": 16632,
"dungeon": 16633,
"nun": 16634,
"greenhouse": 16635,
"convey": 16636,
"atlantis": 16637,
"aft": 16638,
"exits": 16639,
"oman": 16640,
"dresser": 16641,
"lyons": 16642,
"##sti": 16643,
"joking": 16644,
"eddy": 16645,
"judgement": 16646,
"omitted": 16647,
"digits": 16648,
"##cts": 16649,
"##game": 16650,
"juniors": 16651,
"##rae": 16652,
"cents": 16653,
"stricken": 16654,
"une": 16655,
"##ngo": 16656,
"wizards": 16657,
"weir": 16658,
"breton": 16659,
"nan": 16660,
"technician": 16661,
"fibers": 16662,
"liking": 16663,
"royalty": 16664,
"##cca": 16665,
"154": 16666,
"persia": 16667,
"terribly": 16668,
"magician": 16669,
"##rable": 16670,
"##unt": 16671,
"vance": 16672,
"cafeteria": 16673,
"booker": 16674,
"camille": 16675,
"warmer": 16676,
"##static": 16677,
"consume": 16678,
"cavern": 16679,
"gaps": 16680,
"compass": 16681,
"contemporaries": 16682,
"foyer": 16683,
"soothing": 16684,
"graveyard": 16685,
"maj": 16686,
"plunged": 16687,
"blush": 16688,
"##wear": 16689,
"cascade": 16690,
"demonstrates": 16691,
"ordinance": 16692,
"##nov": 16693,
"boyle": 16694,
"##lana": 16695,
"rockefeller": 16696,
"shaken": 16697,
"banjo": 16698,
"izzy": 16699,
"##ense": 16700,
"breathless": 16701,
"vines": 16702,
"##32": 16703,
"##eman": 16704,
"alterations": 16705,
"chromosome": 16706,
"dwellings": 16707,
"feudal": 16708,
"mole": 16709,
"153": 16710,
"catalonia": 16711,
"relics": 16712,
"tenant": 16713,
"mandated": 16714,
"##fm": 16715,
"fridge": 16716,
"hats": 16717,
"honesty": 16718,
"patented": 16719,
"raul": 16720,
"heap": 16721,
"cruisers": 16722,
"accusing": 16723,
"enlightenment": 16724,
"infants": 16725,
"wherein": 16726,
"chatham": 16727,
"contractors": 16728,
"zen": 16729,
"affinity": 16730,
"hc": 16731,
"osborne": 16732,
"piston": 16733,
"156": 16734,
"traps": 16735,
"maturity": 16736,
"##rana": 16737,
"lagos": 16738,
"##zal": 16739,
"peering": 16740,
"##nay": 16741,
"attendant": 16742,
"dealers": 16743,
"protocols": 16744,
"subset": 16745,
"prospects": 16746,
"biographical": 16747,
"##cre": 16748,
"artery": 16749,
"##zers": 16750,
"insignia": 16751,
"nuns": 16752,
"endured": 16753,
"##eration": 16754,
"recommend": 16755,
"schwartz": 16756,
"serbs": 16757,
"berger": 16758,
"cromwell": 16759,
"crossroads": 16760,
"##ctor": 16761,
"enduring": 16762,
"clasped": 16763,
"grounded": 16764,
"##bine": 16765,
"marseille": 16766,
"twitched": 16767,
"abel": 16768,
"choke": 16769,
"https": 16770,
"catalyst": 16771,
"moldova": 16772,
"italians": 16773,
"##tist": 16774,
"disastrous": 16775,
"wee": 16776,
"##oured": 16777,
"##nti": 16778,
"wwf": 16779,
"nope": 16780,
"##piration": 16781,
"##asa": 16782,
"expresses": 16783,
"thumbs": 16784,
"167": 16785,
"##nza": 16786,
"coca": 16787,
"1781": 16788,
"cheating": 16789,
"##ption": 16790,
"skipped": 16791,
"sensory": 16792,
"heidelberg": 16793,
"spies": 16794,
"satan": 16795,
"dangers": 16796,
"semifinal": 16797,
"202": 16798,
"bohemia": 16799,
"whitish": 16800,
"confusing": 16801,
"shipbuilding": 16802,
"relies": 16803,
"surgeons": 16804,
"landings": 16805,
"ravi": 16806,
"baku": 16807,
"moor": 16808,
"suffix": 16809,
"alejandro": 16810,
"##yana": 16811,
"litre": 16812,
"upheld": 16813,
"##unk": 16814,
"rajasthan": 16815,
"##rek": 16816,
"coaster": 16817,
"insists": 16818,
"posture": 16819,
"scenarios": 16820,
"etienne": 16821,
"favoured": 16822,
"appoint": 16823,
"transgender": 16824,
"elephants": 16825,
"poked": 16826,
"greenwood": 16827,
"defences": 16828,
"fulfilled": 16829,
"militant": 16830,
"somali": 16831,
"1758": 16832,
"chalk": 16833,
"potent": 16834,
"##ucci": 16835,
"migrants": 16836,
"wink": 16837,
"assistants": 16838,
"nos": 16839,
"restriction": 16840,
"activism": 16841,
"niger": 16842,
"##ario": 16843,
"colon": 16844,
"shaun": 16845,
"##sat": 16846,
"daphne": 16847,
"##erated": 16848,
"swam": 16849,
"congregations": 16850,
"reprise": 16851,
"considerations": 16852,
"magnet": 16853,
"playable": 16854,
"xvi": 16855,
"##р": 16856,
"overthrow": 16857,
"tobias": 16858,
"knob": 16859,
"chavez": 16860,
"coding": 16861,
"##mers": 16862,
"propped": 16863,
"katrina": 16864,
"orient": 16865,
"newcomer": 16866,
"##suke": 16867,
"temperate": 16868,
"##pool": 16869,
"farmhouse": 16870,
"interrogation": 16871,
"##vd": 16872,
"committing": 16873,
"##vert": 16874,
"forthcoming": 16875,
"strawberry": 16876,
"joaquin": 16877,
"macau": 16878,
"ponds": 16879,
"shocking": 16880,
"siberia": 16881,
"##cellular": 16882,
"chant": 16883,
"contributors": 16884,
"##nant": 16885,
"##ologists": 16886,
"sped": 16887,
"absorb": 16888,
"hail": 16889,
"1782": 16890,
"spared": 16891,
"##hore": 16892,
"barbados": 16893,
"karate": 16894,
"opus": 16895,
"originates": 16896,
"saul": 16897,
"##xie": 16898,
"evergreen": 16899,
"leaped": 16900,
"##rock": 16901,
"correlation": 16902,
"exaggerated": 16903,
"weekday": 16904,
"unification": 16905,
"bump": 16906,
"tracing": 16907,
"brig": 16908,
"afb": 16909,
"pathways": 16910,
"utilizing": 16911,
"##ners": 16912,
"mod": 16913,
"mb": 16914,
"disturbance": 16915,
"kneeling": 16916,
"##stad": 16917,
"##guchi": 16918,
"100th": 16919,
"pune": 16920,
"##thy": 16921,
"decreasing": 16922,
"168": 16923,
"manipulation": 16924,
"miriam": 16925,
"academia": 16926,
"ecosystem": 16927,
"occupational": 16928,
"rbi": 16929,
"##lem": 16930,
"rift": 16931,
"##14": 16932,
"rotary": 16933,
"stacked": 16934,
"incorporation": 16935,
"awakening": 16936,
"generators": 16937,
"guerrero": 16938,
"racist": 16939,
"##omy": 16940,
"cyber": 16941,
"derivatives": 16942,
"culminated": 16943,
"allie": 16944,
"annals": 16945,
"panzer": 16946,
"sainte": 16947,
"wikipedia": 16948,
"pops": 16949,
"zu": 16950,
"austro": 16951,
"##vate": 16952,
"algerian": 16953,
"politely": 16954,
"nicholson": 16955,
"mornings": 16956,
"educate": 16957,
"tastes": 16958,
"thrill": 16959,
"dartmouth": 16960,
"##gating": 16961,
"db": 16962,
"##jee": 16963,
"regan": 16964,
"differing": 16965,
"concentrating": 16966,
"choreography": 16967,
"divinity": 16968,
"##media": 16969,
"pledged": 16970,
"alexandre": 16971,
"routing": 16972,
"gregor": 16973,
"madeline": 16974,
"##idal": 16975,
"apocalypse": 16976,
"##hora": 16977,
"gunfire": 16978,
"culminating": 16979,
"elves": 16980,
"fined": 16981,
"liang": 16982,
"lam": 16983,
"programmed": 16984,
"tar": 16985,
"guessing": 16986,
"transparency": 16987,
"gabrielle": 16988,
"##gna": 16989,
"cancellation": 16990,
"flexibility": 16991,
"##lining": 16992,
"accession": 16993,
"shea": 16994,
"stronghold": 16995,
"nets": 16996,
"specializes": 16997,
"##rgan": 16998,
"abused": 16999,
"hasan": 17000,
"sgt": 17001,
"ling": 17002,
"exceeding": 17003,
"##₄": 17004,
"admiration": 17005,
"supermarket": 17006,
"##ark": 17007,
"photographers": 17008,
"specialised": 17009,
"tilt": 17010,
"resonance": 17011,
"hmm": 17012,
"perfume": 17013,
"380": 17014,
"sami": 17015,
"threatens": 17016,
"garland": 17017,
"botany": 17018,
"guarding": 17019,
"boiled": 17020,
"greet": 17021,
"puppy": 17022,
"russo": 17023,
"supplier": 17024,
"wilmington": 17025,
"vibrant": 17026,
"vijay": 17027,
"##bius": 17028,
"paralympic": 17029,
"grumbled": 17030,
"paige": 17031,
"faa": 17032,
"licking": 17033,
"margins": 17034,
"hurricanes": 17035,
"##gong": 17036,
"fest": 17037,
"grenade": 17038,
"ripping": 17039,
"##uz": 17040,
"counseling": 17041,
"weigh": 17042,
"##sian": 17043,
"needles": 17044,
"wiltshire": 17045,
"edison": 17046,
"costly": 17047,
"##not": 17048,
"fulton": 17049,
"tramway": 17050,
"redesigned": 17051,
"staffordshire": 17052,
"cache": 17053,
"gasping": 17054,
"watkins": 17055,
"sleepy": 17056,
"candidacy": 17057,
"##group": 17058,
"monkeys": 17059,
"timeline": 17060,
"throbbing": 17061,
"##bid": 17062,
"##sos": 17063,
"berth": 17064,
"uzbekistan": 17065,
"vanderbilt": 17066,
"bothering": 17067,
"overturned": 17068,
"ballots": 17069,
"gem": 17070,
"##iger": 17071,
"sunglasses": 17072,
"subscribers": 17073,
"hooker": 17074,
"compelling": 17075,
"ang": 17076,
"exceptionally": 17077,
"saloon": 17078,
"stab": 17079,
"##rdi": 17080,
"carla": 17081,
"terrifying": 17082,
"rom": 17083,
"##vision": 17084,
"coil": 17085,
"##oids": 17086,
"satisfying": 17087,
"vendors": 17088,
"31st": 17089,
"mackay": 17090,
"deities": 17091,
"overlooked": 17092,
"ambient": 17093,
"bahamas": 17094,
"felipe": 17095,
"olympia": 17096,
"whirled": 17097,
"botanist": 17098,
"advertised": 17099,
"tugging": 17100,
"##dden": 17101,
"disciples": 17102,
"morales": 17103,
"unionist": 17104,
"rites": 17105,
"foley": 17106,
"morse": 17107,
"motives": 17108,
"creepy": 17109,
"##₀": 17110,
"soo": 17111,
"##sz": 17112,
"bargain": 17113,
"highness": 17114,
"frightening": 17115,
"turnpike": 17116,
"tory": 17117,
"reorganization": 17118,
"##cer": 17119,
"depict": 17120,
"biographer": 17121,
"##walk": 17122,
"unopposed": 17123,
"manifesto": 17124,
"##gles": 17125,
"institut": 17126,
"emile": 17127,
"accidental": 17128,
"kapoor": 17129,
"##dam": 17130,
"kilkenny": 17131,
"cortex": 17132,
"lively": 17133,
"##13": 17134,
"romanesque": 17135,
"jain": 17136,
"shan": 17137,
"cannons": 17138,
"##ood": 17139,
"##ske": 17140,
"petrol": 17141,
"echoing": 17142,
"amalgamated": 17143,
"disappears": 17144,
"cautious": 17145,
"proposes": 17146,
"sanctions": 17147,
"trenton": 17148,
"##ر": 17149,
"flotilla": 17150,
"aus": 17151,
"contempt": 17152,
"tor": 17153,
"canary": 17154,
"cote": 17155,
"theirs": 17156,
"##hun": 17157,
"conceptual": 17158,
"deleted": 17159,
"fascinating": 17160,
"paso": 17161,
"blazing": 17162,
"elf": 17163,
"honourable": 17164,
"hutchinson": 17165,
"##eiro": 17166,
"##outh": 17167,
"##zin": 17168,
"surveyor": 17169,
"tee": 17170,
"amidst": 17171,
"wooded": 17172,
"reissue": 17173,
"intro": 17174,
"##ono": 17175,
"cobb": 17176,
"shelters": 17177,
"newsletter": 17178,
"hanson": 17179,
"brace": 17180,
"encoding": 17181,
"confiscated": 17182,
"dem": 17183,
"caravan": 17184,
"marino": 17185,
"scroll": 17186,
"melodic": 17187,
"cows": 17188,
"imam": 17189,
"##adi": 17190,
"##aneous": 17191,
"northward": 17192,
"searches": 17193,
"biodiversity": 17194,
"cora": 17195,
"310": 17196,
"roaring": 17197,
"##bers": 17198,
"connell": 17199,
"theologian": 17200,
"halo": 17201,
"compose": 17202,
"pathetic": 17203,
"unmarried": 17204,
"dynamo": 17205,
"##oot": 17206,
"az": 17207,
"calculation": 17208,
"toulouse": 17209,
"deserves": 17210,
"humour": 17211,
"nr": 17212,
"forgiveness": 17213,
"tam": 17214,
"undergone": 17215,
"martyr": 17216,
"pamela": 17217,
"myths": 17218,
"whore": 17219,
"counselor": 17220,
"hicks": 17221,
"290": 17222,
"heavens": 17223,
"battleship": 17224,
"electromagnetic": 17225,
"##bbs": 17226,
"stellar": 17227,
"establishments": 17228,
"presley": 17229,
"hopped": 17230,
"##chin": 17231,
"temptation": 17232,
"90s": 17233,
"wills": 17234,
"nas": 17235,
"##yuan": 17236,
"nhs": 17237,
"##nya": 17238,
"seminars": 17239,
"##yev": 17240,
"adaptations": 17241,
"gong": 17242,
"asher": 17243,
"lex": 17244,
"indicator": 17245,
"sikh": 17246,
"tobago": 17247,
"cites": 17248,
"goin": 17249,
"##yte": 17250,
"satirical": 17251,
"##gies": 17252,
"characterised": 17253,
"correspond": 17254,
"bubbles": 17255,
"lure": 17256,
"participates": 17257,
"##vid": 17258,
"eruption": 17259,
"skate": 17260,
"therapeutic": 17261,
"1785": 17262,
"canals": 17263,
"wholesale": 17264,
"defaulted": 17265,
"sac": 17266,
"460": 17267,
"petit": 17268,
"##zzled": 17269,
"virgil": 17270,
"leak": 17271,
"ravens": 17272,
"256": 17273,
"portraying": 17274,
"##yx": 17275,
"ghetto": 17276,
"creators": 17277,
"dams": 17278,
"portray": 17279,
"vicente": 17280,
"##rington": 17281,
"fae": 17282,
"namesake": 17283,
"bounty": 17284,
"##arium": 17285,
"joachim": 17286,
"##ota": 17287,
"##iser": 17288,
"aforementioned": 17289,
"axle": 17290,
"snout": 17291,
"depended": 17292,
"dismantled": 17293,
"reuben": 17294,
"480": 17295,
"##ibly": 17296,
"gallagher": 17297,
"##lau": 17298,
"##pd": 17299,
"earnest": 17300,
"##ieu": 17301,
"##iary": 17302,
"inflicted": 17303,
"objections": 17304,
"##llar": 17305,
"asa": 17306,
"gritted": 17307,
"##athy": 17308,
"jericho": 17309,
"##sea": 17310,
"##was": 17311,
"flick": 17312,
"underside": 17313,
"ceramics": 17314,
"undead": 17315,
"substituted": 17316,
"195": 17317,
"eastward": 17318,
"undoubtedly": 17319,
"wheeled": 17320,
"chimney": 17321,
"##iche": 17322,
"guinness": 17323,
"cb": 17324,
"##ager": 17325,
"siding": 17326,
"##bell": 17327,
"traitor": 17328,
"baptiste": 17329,
"disguised": 17330,
"inauguration": 17331,
"149": 17332,
"tipperary": 17333,
"choreographer": 17334,
"perched": 17335,
"warmed": 17336,
"stationary": 17337,
"eco": 17338,
"##ike": 17339,
"##ntes": 17340,
"bacterial": 17341,
"##aurus": 17342,
"flores": 17343,
"phosphate": 17344,
"##core": 17345,
"attacker": 17346,
"invaders": 17347,
"alvin": 17348,
"intersects": 17349,
"a1": 17350,
"indirectly": 17351,
"immigrated": 17352,
"businessmen": 17353,
"cornelius": 17354,
"valves": 17355,
"narrated": 17356,
"pill": 17357,
"sober": 17358,
"ul": 17359,
"nationale": 17360,
"monastic": 17361,
"applicants": 17362,
"scenery": 17363,
"##jack": 17364,
"161": 17365,
"motifs": 17366,
"constitutes": 17367,
"cpu": 17368,
"##osh": 17369,
"jurisdictions": 17370,
"sd": 17371,
"tuning": 17372,
"irritation": 17373,
"woven": 17374,
"##uddin": 17375,
"fertility": 17376,
"gao": 17377,
"##erie": 17378,
"antagonist": 17379,
"impatient": 17380,
"glacial": 17381,
"hides": 17382,
"boarded": 17383,
"denominations": 17384,
"interception": 17385,
"##jas": 17386,
"cookie": 17387,
"nicola": 17388,
"##tee": 17389,
"algebraic": 17390,
"marquess": 17391,
"bahn": 17392,
"parole": 17393,
"buyers": 17394,
"bait": 17395,
"turbines": 17396,
"paperwork": 17397,
"bestowed": 17398,
"natasha": 17399,
"renee": 17400,
"oceans": 17401,
"purchases": 17402,
"157": 17403,
"vaccine": 17404,
"215": 17405,
"##tock": 17406,
"fixtures": 17407,
"playhouse": 17408,
"integrate": 17409,
"jai": 17410,
"oswald": 17411,
"intellectuals": 17412,
"##cky": 17413,
"booked": 17414,
"nests": 17415,
"mortimer": 17416,
"##isi": 17417,
"obsession": 17418,
"sept": 17419,
"##gler": 17420,
"##sum": 17421,
"440": 17422,
"scrutiny": 17423,
"simultaneous": 17424,
"squinted": 17425,
"##shin": 17426,
"collects": 17427,
"oven": 17428,
"shankar": 17429,
"penned": 17430,
"remarkably": 17431,
"##я": 17432,
"slips": 17433,
"luggage": 17434,
"spectral": 17435,
"1786": 17436,
"collaborations": 17437,
"louie": 17438,
"consolidation": 17439,
"##ailed": 17440,
"##ivating": 17441,
"420": 17442,
"hoover": 17443,
"blackpool": 17444,
"harness": 17445,
"ignition": 17446,
"vest": 17447,
"tails": 17448,
"belmont": 17449,
"mongol": 17450,
"skinner": 17451,
"##nae": 17452,
"visually": 17453,
"mage": 17454,
"derry": 17455,
"##tism": 17456,
"##unce": 17457,
"stevie": 17458,
"transitional": 17459,
"##rdy": 17460,
"redskins": 17461,
"drying": 17462,
"prep": 17463,
"prospective": 17464,
"##21": 17465,
"annoyance": 17466,
"oversee": 17467,
"##loaded": 17468,
"fills": 17469,
"##books": 17470,
"##iki": 17471,
"announces": 17472,
"fda": 17473,
"scowled": 17474,
"respects": 17475,
"prasad": 17476,
"mystic": 17477,
"tucson": 17478,
"##vale": 17479,
"revue": 17480,
"springer": 17481,
"bankrupt": 17482,
"1772": 17483,
"aristotle": 17484,
"salvatore": 17485,
"habsburg": 17486,
"##geny": 17487,
"dal": 17488,
"natal": 17489,
"nut": 17490,
"pod": 17491,
"chewing": 17492,
"darts": 17493,
"moroccan": 17494,
"walkover": 17495,
"rosario": 17496,
"lenin": 17497,
"punjabi": 17498,
"##ße": 17499,
"grossed": 17500,
"scattering": 17501,
"wired": 17502,
"invasive": 17503,
"hui": 17504,
"polynomial": 17505,
"corridors": 17506,
"wakes": 17507,
"gina": 17508,
"portrays": 17509,
"##cratic": 17510,
"arid": 17511,
"retreating": 17512,
"erich": 17513,
"irwin": 17514,
"sniper": 17515,
"##dha": 17516,
"linen": 17517,
"lindsey": 17518,
"maneuver": 17519,
"butch": 17520,
"shutting": 17521,
"socio": 17522,
"bounce": 17523,
"commemorative": 17524,
"postseason": 17525,
"jeremiah": 17526,
"pines": 17527,
"275": 17528,
"mystical": 17529,
"beads": 17530,
"bp": 17531,
"abbas": 17532,
"furnace": 17533,
"bidding": 17534,
"consulted": 17535,
"assaulted": 17536,
"empirical": 17537,
"rubble": 17538,
"enclosure": 17539,
"sob": 17540,
"weakly": 17541,
"cancel": 17542,
"polly": 17543,
"yielded": 17544,
"##emann": 17545,
"curly": 17546,
"prediction": 17547,
"battered": 17548,
"70s": 17549,
"vhs": 17550,
"jacqueline": 17551,
"render": 17552,
"sails": 17553,
"barked": 17554,
"detailing": 17555,
"grayson": 17556,
"riga": 17557,
"sloane": 17558,
"raging": 17559,
"##yah": 17560,
"herbs": 17561,
"bravo": 17562,
"##athlon": 17563,
"alloy": 17564,
"giggle": 17565,
"imminent": 17566,
"suffers": 17567,
"assumptions": 17568,
"waltz": 17569,
"##itate": 17570,
"accomplishments": 17571,
"##ited": 17572,
"bathing": 17573,
"remixed": 17574,
"deception": 17575,
"prefix": 17576,
"##emia": 17577,
"deepest": 17578,
"##tier": 17579,
"##eis": 17580,
"balkan": 17581,
"frogs": 17582,
"##rong": 17583,
"slab": 17584,
"##pate": 17585,
"philosophers": 17586,
"peterborough": 17587,
"grains": 17588,
"imports": 17589,
"dickinson": 17590,
"rwanda": 17591,
"##atics": 17592,
"1774": 17593,
"dirk": 17594,
"lan": 17595,
"tablets": 17596,
"##rove": 17597,
"clone": 17598,
"##rice": 17599,
"caretaker": 17600,
"hostilities": 17601,
"mclean": 17602,
"##gre": 17603,
"regimental": 17604,
"treasures": 17605,
"norms": 17606,
"impose": 17607,
"tsar": 17608,
"tango": 17609,
"diplomacy": 17610,
"variously": 17611,
"complain": 17612,
"192": 17613,
"recognise": 17614,
"arrests": 17615,
"1779": 17616,
"celestial": 17617,
"pulitzer": 17618,
"##dus": 17619,
"bing": 17620,
"libretto": 17621,
"##moor": 17622,
"adele": 17623,
"splash": 17624,
"##rite": 17625,
"expectation": 17626,
"lds": 17627,
"confronts": 17628,
"##izer": 17629,
"spontaneous": 17630,
"harmful": 17631,
"wedge": 17632,
"entrepreneurs": 17633,
"buyer": 17634,
"##ope": 17635,
"bilingual": 17636,
"translate": 17637,
"rugged": 17638,
"conner": 17639,
"circulated": 17640,
"uae": 17641,
"eaton": 17642,
"##gra": 17643,
"##zzle": 17644,
"lingered": 17645,
"lockheed": 17646,
"vishnu": 17647,
"reelection": 17648,
"alonso": 17649,
"##oom": 17650,
"joints": 17651,
"yankee": 17652,
"headline": 17653,
"cooperate": 17654,
"heinz": 17655,
"laureate": 17656,
"invading": 17657,
"##sford": 17658,
"echoes": 17659,
"scandinavian": 17660,
"##dham": 17661,
"hugging": 17662,
"vitamin": 17663,
"salute": 17664,
"micah": 17665,
"hind": 17666,
"trader": 17667,
"##sper": 17668,
"radioactive": 17669,
"##ndra": 17670,
"militants": 17671,
"poisoned": 17672,
"ratified": 17673,
"remark": 17674,
"campeonato": 17675,
"deprived": 17676,
"wander": 17677,
"prop": 17678,
"##dong": 17679,
"outlook": 17680,
"##tani": 17681,
"##rix": 17682,
"##eye": 17683,
"chiang": 17684,
"darcy": 17685,
"##oping": 17686,
"mandolin": 17687,
"spice": 17688,
"statesman": 17689,
"babylon": 17690,
"182": 17691,
"walled": 17692,
"forgetting": 17693,
"afro": 17694,
"##cap": 17695,
"158": 17696,
"giorgio": 17697,
"buffer": 17698,
"##polis": 17699,
"planetary": 17700,
"##gis": 17701,
"overlap": 17702,
"terminals": 17703,
"kinda": 17704,
"centenary": 17705,
"##bir": 17706,
"arising": 17707,
"manipulate": 17708,
"elm": 17709,
"ke": 17710,
"1770": 17711,
"ak": 17712,
"##tad": 17713,
"chrysler": 17714,
"mapped": 17715,
"moose": 17716,
"pomeranian": 17717,
"quad": 17718,
"macarthur": 17719,
"assemblies": 17720,
"shoreline": 17721,
"recalls": 17722,
"stratford": 17723,
"##rted": 17724,
"noticeable": 17725,
"##evic": 17726,
"imp": 17727,
"##rita": 17728,
"##sque": 17729,
"accustomed": 17730,
"supplying": 17731,
"tents": 17732,
"disgusted": 17733,
"vogue": 17734,
"sipped": 17735,
"filters": 17736,
"khz": 17737,
"reno": 17738,
"selecting": 17739,
"luftwaffe": 17740,
"mcmahon": 17741,
"tyne": 17742,
"masterpiece": 17743,
"carriages": 17744,
"collided": 17745,
"dunes": 17746,
"exercised": 17747,
"flare": 17748,
"remembers": 17749,
"muzzle": 17750,
"##mobile": 17751,
"heck": 17752,
"##rson": 17753,
"burgess": 17754,
"lunged": 17755,
"middleton": 17756,
"boycott": 17757,
"bilateral": 17758,
"##sity": 17759,
"hazardous": 17760,
"lumpur": 17761,
"multiplayer": 17762,
"spotlight": 17763,
"jackets": 17764,
"goldman": 17765,
"liege": 17766,
"porcelain": 17767,
"rag": 17768,
"waterford": 17769,
"benz": 17770,
"attracts": 17771,
"hopeful": 17772,
"battling": 17773,
"ottomans": 17774,
"kensington": 17775,
"baked": 17776,
"hymns": 17777,
"cheyenne": 17778,
"lattice": 17779,
"levine": 17780,
"borrow": 17781,
"polymer": 17782,
"clashes": 17783,
"michaels": 17784,
"monitored": 17785,
"commitments": 17786,
"denounced": 17787,
"##25": 17788,
"##von": 17789,
"cavity": 17790,
"##oney": 17791,
"hobby": 17792,
"akin": 17793,
"##holders": 17794,
"futures": 17795,
"intricate": 17796,
"cornish": 17797,
"patty": 17798,
"##oned": 17799,
"illegally": 17800,
"dolphin": 17801,
"##lag": 17802,
"barlow": 17803,
"yellowish": 17804,
"maddie": 17805,
"apologized": 17806,
"luton": 17807,
"plagued": 17808,
"##puram": 17809,
"nana": 17810,
"##rds": 17811,
"sway": 17812,
"fanny": 17813,
"łodz": 17814,
"##rino": 17815,
"psi": 17816,
"suspicions": 17817,
"hanged": 17818,
"##eding": 17819,
"initiate": 17820,
"charlton": 17821,
"##por": 17822,
"nak": 17823,
"competent": 17824,
"235": 17825,
"analytical": 17826,
"annex": 17827,
"wardrobe": 17828,
"reservations": 17829,
"##rma": 17830,
"sect": 17831,
"162": 17832,
"fairfax": 17833,
"hedge": 17834,
"piled": 17835,
"buckingham": 17836,
"uneven": 17837,
"bauer": 17838,
"simplicity": 17839,
"snyder": 17840,
"interpret": 17841,
"accountability": 17842,
"donors": 17843,
"moderately": 17844,
"byrd": 17845,
"continents": 17846,
"##cite": 17847,
"##max": 17848,
"disciple": 17849,
"hr": 17850,
"jamaican": 17851,
"ping": 17852,
"nominees": 17853,
"##uss": 17854,
"mongolian": 17855,
"diver": 17856,
"attackers": 17857,
"eagerly": 17858,
"ideological": 17859,
"pillows": 17860,
"miracles": 17861,
"apartheid": 17862,
"revolver": 17863,
"sulfur": 17864,
"clinics": 17865,
"moran": 17866,
"163": 17867,
"##enko": 17868,
"ile": 17869,
"katy": 17870,
"rhetoric": 17871,
"##icated": 17872,
"chronology": 17873,
"recycling": 17874,
"##hrer": 17875,
"elongated": 17876,
"mughal": 17877,
"pascal": 17878,
"profiles": 17879,
"vibration": 17880,
"databases": 17881,
"domination": 17882,
"##fare": 17883,
"##rant": 17884,
"matthias": 17885,
"digest": 17886,
"rehearsal": 17887,
"polling": 17888,
"weiss": 17889,
"initiation": 17890,
"reeves": 17891,
"clinging": 17892,
"flourished": 17893,
"impress": 17894,
"ngo": 17895,
"##hoff": 17896,
"##ume": 17897,
"buckley": 17898,
"symposium": 17899,
"rhythms": 17900,
"weed": 17901,
"emphasize": 17902,
"transforming": 17903,
"##taking": 17904,
"##gence": 17905,
"##yman": 17906,
"accountant": 17907,
"analyze": 17908,
"flicker": 17909,
"foil": 17910,
"priesthood": 17911,
"voluntarily": 17912,
"decreases": 17913,
"##80": 17914,
"##hya": 17915,
"slater": 17916,
"sv": 17917,
"charting": 17918,
"mcgill": 17919,
"##lde": 17920,
"moreno": 17921,
"##iu": 17922,
"besieged": 17923,
"zur": 17924,
"robes": 17925,
"##phic": 17926,
"admitting": 17927,
"api": 17928,
"deported": 17929,
"turmoil": 17930,
"peyton": 17931,
"earthquakes": 17932,
"##ares": 17933,
"nationalists": 17934,
"beau": 17935,
"clair": 17936,
"brethren": 17937,
"interrupt": 17938,
"welch": 17939,
"curated": 17940,
"galerie": 17941,
"requesting": 17942,
"164": 17943,
"##ested": 17944,
"impending": 17945,
"steward": 17946,
"viper": 17947,
"##vina": 17948,
"complaining": 17949,
"beautifully": 17950,
"brandy": 17951,
"foam": 17952,
"nl": 17953,
"1660": 17954,
"##cake": 17955,
"alessandro": 17956,
"punches": 17957,
"laced": 17958,
"explanations": 17959,
"##lim": 17960,
"attribute": 17961,
"clit": 17962,
"reggie": 17963,
"discomfort": 17964,
"##cards": 17965,
"smoothed": 17966,
"whales": 17967,
"##cene": 17968,
"adler": 17969,
"countered": 17970,
"duffy": 17971,
"disciplinary": 17972,
"widening": 17973,
"recipe": 17974,
"reliance": 17975,
"conducts": 17976,
"goats": 17977,
"gradient": 17978,
"preaching": 17979,
"##shaw": 17980,
"matilda": 17981,
"quasi": 17982,
"striped": 17983,
"meridian": 17984,
"cannabis": 17985,
"cordoba": 17986,
"certificates": 17987,
"##agh": 17988,
"##tering": 17989,
"graffiti": 17990,
"hangs": 17991,
"pilgrims": 17992,
"repeats": 17993,
"##ych": 17994,
"revive": 17995,
"urine": 17996,
"etat": 17997,
"##hawk": 17998,
"fueled": 17999,
"belts": 18000,
"fuzzy": 18001,
"susceptible": 18002,
"##hang": 18003,
"mauritius": 18004,
"salle": 18005,
"sincere": 18006,
"beers": 18007,
"hooks": 18008,
"##cki": 18009,
"arbitration": 18010,
"entrusted": 18011,
"advise": 18012,
"sniffed": 18013,
"seminar": 18014,
"junk": 18015,
"donnell": 18016,
"processors": 18017,
"principality": 18018,
"strapped": 18019,
"celia": 18020,
"mendoza": 18021,
"everton": 18022,
"fortunes": 18023,
"prejudice": 18024,
"starving": 18025,
"reassigned": 18026,
"steamer": 18027,
"##lund": 18028,
"tuck": 18029,
"evenly": 18030,
"foreman": 18031,
"##ffen": 18032,
"dans": 18033,
"375": 18034,
"envisioned": 18035,
"slit": 18036,
"##xy": 18037,
"baseman": 18038,
"liberia": 18039,
"rosemary": 18040,
"##weed": 18041,
"electrified": 18042,
"periodically": 18043,
"potassium": 18044,
"stride": 18045,
"contexts": 18046,
"sperm": 18047,
"slade": 18048,
"mariners": 18049,
"influx": 18050,
"bianca": 18051,
"subcommittee": 18052,
"##rane": 18053,
"spilling": 18054,
"icao": 18055,
"estuary": 18056,
"##nock": 18057,
"delivers": 18058,
"iphone": 18059,
"##ulata": 18060,
"isa": 18061,
"mira": 18062,
"bohemian": 18063,
"dessert": 18064,
"##sbury": 18065,
"welcoming": 18066,
"proudly": 18067,
"slowing": 18068,
"##chs": 18069,
"musee": 18070,
"ascension": 18071,
"russ": 18072,
"##vian": 18073,
"waits": 18074,
"##psy": 18075,
"africans": 18076,
"exploit": 18077,
"##morphic": 18078,
"gov": 18079,
"eccentric": 18080,
"crab": 18081,
"peck": 18082,
"##ull": 18083,
"entrances": 18084,
"formidable": 18085,
"marketplace": 18086,
"groom": 18087,
"bolted": 18088,
"metabolism": 18089,
"patton": 18090,
"robbins": 18091,
"courier": 18092,
"payload": 18093,
"endure": 18094,
"##ifier": 18095,
"andes": 18096,
"refrigerator": 18097,
"##pr": 18098,
"ornate": 18099,
"##uca": 18100,
"ruthless": 18101,
"illegitimate": 18102,
"masonry": 18103,
"strasbourg": 18104,
"bikes": 18105,
"adobe": 18106,
"##³": 18107,
"apples": 18108,
"quintet": 18109,
"willingly": 18110,
"niche": 18111,
"bakery": 18112,
"corpses": 18113,
"energetic": 18114,
"##cliffe": 18115,
"##sser": 18116,
"##ards": 18117,
"177": 18118,
"centimeters": 18119,
"centro": 18120,
"fuscous": 18121,
"cretaceous": 18122,
"rancho": 18123,
"##yde": 18124,
"andrei": 18125,
"telecom": 18126,
"tottenham": 18127,
"oasis": 18128,
"ordination": 18129,
"vulnerability": 18130,
"presiding": 18131,
"corey": 18132,
"cp": 18133,
"penguins": 18134,
"sims": 18135,
"##pis": 18136,
"malawi": 18137,
"piss": 18138,
"##48": 18139,
"correction": 18140,
"##cked": 18141,
"##ffle": 18142,
"##ryn": 18143,
"countdown": 18144,
"detectives": 18145,
"psychiatrist": 18146,
"psychedelic": 18147,
"dinosaurs": 18148,
"blouse": 18149,
"##get": 18150,
"choi": 18151,
"vowed": 18152,
"##oz": 18153,
"randomly": 18154,
"##pol": 18155,
"49ers": 18156,
"scrub": 18157,
"blanche": 18158,
"bruins": 18159,
"dusseldorf": 18160,
"##using": 18161,
"unwanted": 18162,
"##ums": 18163,
"212": 18164,
"dominique": 18165,
"elevations": 18166,
"headlights": 18167,
"om": 18168,
"laguna": 18169,
"##oga": 18170,
"1750": 18171,
"famously": 18172,
"ignorance": 18173,
"shrewsbury": 18174,
"##aine": 18175,
"ajax": 18176,
"breuning": 18177,
"che": 18178,
"confederacy": 18179,
"greco": 18180,
"overhaul": 18181,
"##screen": 18182,
"paz": 18183,
"skirts": 18184,
"disagreement": 18185,
"cruelty": 18186,
"jagged": 18187,
"phoebe": 18188,
"shifter": 18189,
"hovered": 18190,
"viruses": 18191,
"##wes": 18192,
"mandy": 18193,
"##lined": 18194,
"##gc": 18195,
"landlord": 18196,
"squirrel": 18197,
"dashed": 18198,
"##ι": 18199,
"ornamental": 18200,
"gag": 18201,
"wally": 18202,
"grange": 18203,
"literal": 18204,
"spurs": 18205,
"undisclosed": 18206,
"proceeding": 18207,
"yin": 18208,
"##text": 18209,
"billie": 18210,
"orphan": 18211,
"spanned": 18212,
"humidity": 18213,
"indy": 18214,
"weighted": 18215,
"presentations": 18216,
"explosions": 18217,
"lucian": 18218,
"##tary": 18219,
"vaughn": 18220,
"hindus": 18221,
"##anga": 18222,
"##hell": 18223,
"psycho": 18224,
"171": 18225,
"daytona": 18226,
"protects": 18227,
"efficiently": 18228,
"rematch": 18229,
"sly": 18230,
"tandem": 18231,
"##oya": 18232,
"rebranded": 18233,
"impaired": 18234,
"hee": 18235,
"metropolis": 18236,
"peach": 18237,
"godfrey": 18238,
"diaspora": 18239,
"ethnicity": 18240,
"prosperous": 18241,
"gleaming": 18242,
"dar": 18243,
"grossing": 18244,
"playback": 18245,
"##rden": 18246,
"stripe": 18247,
"pistols": 18248,
"##tain": 18249,
"births": 18250,
"labelled": 18251,
"##cating": 18252,
"172": 18253,
"rudy": 18254,
"alba": 18255,
"##onne": 18256,
"aquarium": 18257,
"hostility": 18258,
"##gb": 18259,
"##tase": 18260,
"shudder": 18261,
"sumatra": 18262,
"hardest": 18263,
"lakers": 18264,
"consonant": 18265,
"creeping": 18266,
"demos": 18267,
"homicide": 18268,
"capsule": 18269,
"zeke": 18270,
"liberties": 18271,
"expulsion": 18272,
"pueblo": 18273,
"##comb": 18274,
"trait": 18275,
"transporting": 18276,
"##ddin": 18277,
"##neck": 18278,
"##yna": 18279,
"depart": 18280,
"gregg": 18281,
"mold": 18282,
"ledge": 18283,
"hangar": 18284,
"oldham": 18285,
"playboy": 18286,
"termination": 18287,
"analysts": 18288,
"gmbh": 18289,
"romero": 18290,
"##itic": 18291,
"insist": 18292,
"cradle": 18293,
"filthy": 18294,
"brightness": 18295,
"slash": 18296,
"shootout": 18297,
"deposed": 18298,
"bordering": 18299,
"##truct": 18300,
"isis": 18301,
"microwave": 18302,
"tumbled": 18303,
"sheltered": 18304,
"cathy": 18305,
"werewolves": 18306,
"messy": 18307,
"andersen": 18308,
"convex": 18309,
"clapped": 18310,
"clinched": 18311,
"satire": 18312,
"wasting": 18313,
"edo": 18314,
"vc": 18315,
"rufus": 18316,
"##jak": 18317,
"mont": 18318,
"##etti": 18319,
"poznan": 18320,
"##keeping": 18321,
"restructuring": 18322,
"transverse": 18323,
"##rland": 18324,
"azerbaijani": 18325,
"slovene": 18326,
"gestures": 18327,
"roommate": 18328,
"choking": 18329,
"shear": 18330,
"##quist": 18331,
"vanguard": 18332,
"oblivious": 18333,
"##hiro": 18334,
"disagreed": 18335,
"baptism": 18336,
"##lich": 18337,
"coliseum": 18338,
"##aceae": 18339,
"salvage": 18340,
"societe": 18341,
"cory": 18342,
"locke": 18343,
"relocation": 18344,
"relying": 18345,
"versailles": 18346,
"ahl": 18347,
"swelling": 18348,
"##elo": 18349,
"cheerful": 18350,
"##word": 18351,
"##edes": 18352,
"gin": 18353,
"sarajevo": 18354,
"obstacle": 18355,
"diverted": 18356,
"##nac": 18357,
"messed": 18358,
"thoroughbred": 18359,
"fluttered": 18360,
"utrecht": 18361,
"chewed": 18362,
"acquaintance": 18363,
"assassins": 18364,
"dispatch": 18365,
"mirza": 18366,
"##wart": 18367,
"nike": 18368,
"salzburg": 18369,
"swell": 18370,
"yen": 18371,
"##gee": 18372,
"idle": 18373,
"ligue": 18374,
"samson": 18375,
"##nds": 18376,
"##igh": 18377,
"playful": 18378,
"spawned": 18379,
"##cise": 18380,
"tease": 18381,
"##case": 18382,
"burgundy": 18383,
"##bot": 18384,
"stirring": 18385,
"skeptical": 18386,
"interceptions": 18387,
"marathi": 18388,
"##dies": 18389,
"bedrooms": 18390,
"aroused": 18391,
"pinch": 18392,
"##lik": 18393,
"preferences": 18394,
"tattoos": 18395,
"buster": 18396,
"digitally": 18397,
"projecting": 18398,
"rust": 18399,
"##ital": 18400,
"kitten": 18401,
"priorities": 18402,
"addison": 18403,
"pseudo": 18404,
"##guard": 18405,
"dusk": 18406,
"icons": 18407,
"sermon": 18408,
"##psis": 18409,
"##iba": 18410,
"bt": 18411,
"##lift": 18412,
"##xt": 18413,
"ju": 18414,
"truce": 18415,
"rink": 18416,
"##dah": 18417,
"##wy": 18418,
"defects": 18419,
"psychiatry": 18420,
"offences": 18421,
"calculate": 18422,
"glucose": 18423,
"##iful": 18424,
"##rized": 18425,
"##unda": 18426,
"francaise": 18427,
"##hari": 18428,
"richest": 18429,
"warwickshire": 18430,
"carly": 18431,
"1763": 18432,
"purity": 18433,
"redemption": 18434,
"lending": 18435,
"##cious": 18436,
"muse": 18437,
"bruises": 18438,
"cerebral": 18439,
"aero": 18440,
"carving": 18441,
"##name": 18442,
"preface": 18443,
"terminology": 18444,
"invade": 18445,
"monty": 18446,
"##int": 18447,
"anarchist": 18448,
"blurred": 18449,
"##iled": 18450,
"rossi": 18451,
"treats": 18452,
"guts": 18453,
"shu": 18454,
"foothills": 18455,
"ballads": 18456,
"undertaking": 18457,
"premise": 18458,
"cecilia": 18459,
"affiliates": 18460,
"blasted": 18461,
"conditional": 18462,
"wilder": 18463,
"minors": 18464,
"drone": 18465,
"rudolph": 18466,
"buffy": 18467,
"swallowing": 18468,
"horton": 18469,
"attested": 18470,
"##hop": 18471,
"rutherford": 18472,
"howell": 18473,
"primetime": 18474,
"livery": 18475,
"penal": 18476,
"##bis": 18477,
"minimize": 18478,
"hydro": 18479,
"wrecked": 18480,
"wrought": 18481,
"palazzo": 18482,
"##gling": 18483,
"cans": 18484,
"vernacular": 18485,
"friedman": 18486,
"nobleman": 18487,
"shale": 18488,
"walnut": 18489,
"danielle": 18490,
"##ection": 18491,
"##tley": 18492,
"sears": 18493,
"##kumar": 18494,
"chords": 18495,
"lend": 18496,
"flipping": 18497,
"streamed": 18498,
"por": 18499,
"dracula": 18500,
"gallons": 18501,
"sacrifices": 18502,
"gamble": 18503,
"orphanage": 18504,
"##iman": 18505,
"mckenzie": 18506,
"##gible": 18507,
"boxers": 18508,
"daly": 18509,
"##balls": 18510,
"##ان": 18511,
"208": 18512,
"##ific": 18513,
"##rative": 18514,
"##iq": 18515,
"exploited": 18516,
"slated": 18517,
"##uity": 18518,
"circling": 18519,
"hillary": 18520,
"pinched": 18521,
"goldberg": 18522,
"provost": 18523,
"campaigning": 18524,
"lim": 18525,
"piles": 18526,
"ironically": 18527,
"jong": 18528,
"mohan": 18529,
"successors": 18530,
"usaf": 18531,
"##tem": 18532,
"##ught": 18533,
"autobiographical": 18534,
"haute": 18535,
"preserves": 18536,
"##ending": 18537,
"acquitted": 18538,
"comparisons": 18539,
"203": 18540,
"hydroelectric": 18541,
"gangs": 18542,
"cypriot": 18543,
"torpedoes": 18544,
"rushes": 18545,
"chrome": 18546,
"derive": 18547,
"bumps": 18548,
"instability": 18549,
"fiat": 18550,
"pets": 18551,
"##mbe": 18552,
"silas": 18553,
"dye": 18554,
"reckless": 18555,
"settler": 18556,
"##itation": 18557,
"info": 18558,
"heats": 18559,
"##writing": 18560,
"176": 18561,
"canonical": 18562,
"maltese": 18563,
"fins": 18564,
"mushroom": 18565,
"stacy": 18566,
"aspen": 18567,
"avid": 18568,
"##kur": 18569,
"##loading": 18570,
"vickers": 18571,
"gaston": 18572,
"hillside": 18573,
"statutes": 18574,
"wilde": 18575,
"gail": 18576,
"kung": 18577,
"sabine": 18578,
"comfortably": 18579,
"motorcycles": 18580,
"##rgo": 18581,
"169": 18582,
"pneumonia": 18583,
"fetch": 18584,
"##sonic": 18585,
"axel": 18586,
"faintly": 18587,
"parallels": 18588,
"##oop": 18589,
"mclaren": 18590,
"spouse": 18591,
"compton": 18592,
"interdisciplinary": 18593,
"miner": 18594,
"##eni": 18595,
"181": 18596,
"clamped": 18597,
"##chal": 18598,
"##llah": 18599,
"separates": 18600,
"versa": 18601,
"##mler": 18602,
"scarborough": 18603,
"labrador": 18604,
"##lity": 18605,
"##osing": 18606,
"rutgers": 18607,
"hurdles": 18608,
"como": 18609,
"166": 18610,
"burt": 18611,
"divers": 18612,
"##100": 18613,
"wichita": 18614,
"cade": 18615,
"coincided": 18616,
"##erson": 18617,
"bruised": 18618,
"mla": 18619,
"##pper": 18620,
"vineyard": 18621,
"##ili": 18622,
"##brush": 18623,
"notch": 18624,
"mentioning": 18625,
"jase": 18626,
"hearted": 18627,
"kits": 18628,
"doe": 18629,
"##acle": 18630,
"pomerania": 18631,
"##ady": 18632,
"ronan": 18633,
"seizure": 18634,
"pavel": 18635,
"problematic": 18636,
"##zaki": 18637,
"domenico": 18638,
"##ulin": 18639,
"catering": 18640,
"penelope": 18641,
"dependence": 18642,
"parental": 18643,
"emilio": 18644,
"ministerial": 18645,
"atkinson": 18646,
"##bolic": 18647,
"clarkson": 18648,
"chargers": 18649,
"colby": 18650,
"grill": 18651,
"peeked": 18652,
"arises": 18653,
"summon": 18654,
"##aged": 18655,
"fools": 18656,
"##grapher": 18657,
"faculties": 18658,
"qaeda": 18659,
"##vial": 18660,
"garner": 18661,
"refurbished": 18662,
"##hwa": 18663,
"geelong": 18664,
"disasters": 18665,
"nudged": 18666,
"bs": 18667,
"shareholder": 18668,
"lori": 18669,
"algae": 18670,
"reinstated": 18671,
"rot": 18672,
"##ades": 18673,
"##nous": 18674,
"invites": 18675,
"stainless": 18676,
"183": 18677,
"inclusive": 18678,
"##itude": 18679,
"diocesan": 18680,
"til": 18681,
"##icz": 18682,
"denomination": 18683,
"##xa": 18684,
"benton": 18685,
"floral": 18686,
"registers": 18687,
"##ider": 18688,
"##erman": 18689,
"##kell": 18690,
"absurd": 18691,
"brunei": 18692,
"guangzhou": 18693,
"hitter": 18694,
"retaliation": 18695,
"##uled": 18696,
"##eve": 18697,
"blanc": 18698,
"nh": 18699,
"consistency": 18700,
"contamination": 18701,
"##eres": 18702,
"##rner": 18703,
"dire": 18704,
"palermo": 18705,
"broadcasters": 18706,
"diaries": 18707,
"inspire": 18708,
"vols": 18709,
"brewer": 18710,
"tightening": 18711,
"ky": 18712,
"mixtape": 18713,
"hormone": 18714,
"##tok": 18715,
"stokes": 18716,
"##color": 18717,
"##dly": 18718,
"##ssi": 18719,
"pg": 18720,
"##ometer": 18721,
"##lington": 18722,
"sanitation": 18723,
"##tility": 18724,
"intercontinental": 18725,
"apps": 18726,
"##adt": 18727,
"¹⁄₂": 18728,
"cylinders": 18729,
"economies": 18730,
"favourable": 18731,
"unison": 18732,
"croix": 18733,
"gertrude": 18734,
"odyssey": 18735,
"vanity": 18736,
"dangling": 18737,
"##logists": 18738,
"upgrades": 18739,
"dice": 18740,
"middleweight": 18741,
"practitioner": 18742,
"##ight": 18743,
"206": 18744,
"henrik": 18745,
"parlor": 18746,
"orion": 18747,
"angered": 18748,
"lac": 18749,
"python": 18750,
"blurted": 18751,
"##rri": 18752,
"sensual": 18753,
"intends": 18754,
"swings": 18755,
"angled": 18756,
"##phs": 18757,
"husky": 18758,
"attain": 18759,
"peerage": 18760,
"precinct": 18761,
"textiles": 18762,
"cheltenham": 18763,
"shuffled": 18764,
"dai": 18765,
"confess": 18766,
"tasting": 18767,
"bhutan": 18768,
"##riation": 18769,
"tyrone": 18770,
"segregation": 18771,
"abrupt": 18772,
"ruiz": 18773,
"##rish": 18774,
"smirked": 18775,
"blackwell": 18776,
"confidential": 18777,
"browning": 18778,
"amounted": 18779,
"##put": 18780,
"vase": 18781,
"scarce": 18782,
"fabulous": 18783,
"raided": 18784,
"staple": 18785,
"guyana": 18786,
"unemployed": 18787,
"glider": 18788,
"shay": 18789,
"##tow": 18790,
"carmine": 18791,
"troll": 18792,
"intervene": 18793,
"squash": 18794,
"superstar": 18795,
"##uce": 18796,
"cylindrical": 18797,
"len": 18798,
"roadway": 18799,
"researched": 18800,
"handy": 18801,
"##rium": 18802,
"##jana": 18803,
"meta": 18804,
"lao": 18805,
"declares": 18806,
"##rring": 18807,
"##tadt": 18808,
"##elin": 18809,
"##kova": 18810,
"willem": 18811,
"shrubs": 18812,
"napoleonic": 18813,
"realms": 18814,
"skater": 18815,
"qi": 18816,
"volkswagen": 18817,
"##ł": 18818,
"tad": 18819,
"hara": 18820,
"archaeologist": 18821,
"awkwardly": 18822,
"eerie": 18823,
"##kind": 18824,
"wiley": 18825,
"##heimer": 18826,
"##24": 18827,
"titus": 18828,
"organizers": 18829,
"cfl": 18830,
"crusaders": 18831,
"lama": 18832,
"usb": 18833,
"vent": 18834,
"enraged": 18835,
"thankful": 18836,
"occupants": 18837,
"maximilian": 18838,
"##gaard": 18839,
"possessing": 18840,
"textbooks": 18841,
"##oran": 18842,
"collaborator": 18843,
"quaker": 18844,
"##ulo": 18845,
"avalanche": 18846,
"mono": 18847,
"silky": 18848,
"straits": 18849,
"isaiah": 18850,
"mustang": 18851,
"surged": 18852,
"resolutions": 18853,
"potomac": 18854,
"descend": 18855,
"cl": 18856,
"kilograms": 18857,
"plato": 18858,
"strains": 18859,
"saturdays": 18860,
"##olin": 18861,
"bernstein": 18862,
"##ype": 18863,
"holstein": 18864,
"ponytail": 18865,
"##watch": 18866,
"belize": 18867,
"conversely": 18868,
"heroine": 18869,
"perpetual": 18870,
"##ylus": 18871,
"charcoal": 18872,
"piedmont": 18873,
"glee": 18874,
"negotiating": 18875,
"backdrop": 18876,
"prologue": 18877,
"##jah": 18878,
"##mmy": 18879,
"pasadena": 18880,
"climbs": 18881,
"ramos": 18882,
"sunni": 18883,
"##holm": 18884,
"##tner": 18885,
"##tri": 18886,
"anand": 18887,
"deficiency": 18888,
"hertfordshire": 18889,
"stout": 18890,
"##avi": 18891,
"aperture": 18892,
"orioles": 18893,
"##irs": 18894,
"doncaster": 18895,
"intrigued": 18896,
"bombed": 18897,
"coating": 18898,
"otis": 18899,
"##mat": 18900,
"cocktail": 18901,
"##jit": 18902,
"##eto": 18903,
"amir": 18904,
"arousal": 18905,
"sar": 18906,
"##proof": 18907,
"##act": 18908,
"##ories": 18909,
"dixie": 18910,
"pots": 18911,
"##bow": 18912,
"whereabouts": 18913,
"159": 18914,
"##fted": 18915,
"drains": 18916,
"bullying": 18917,
"cottages": 18918,
"scripture": 18919,
"coherent": 18920,
"fore": 18921,
"poe": 18922,
"appetite": 18923,
"##uration": 18924,
"sampled": 18925,
"##ators": 18926,
"##dp": 18927,
"derrick": 18928,
"rotor": 18929,
"jays": 18930,
"peacock": 18931,
"installment": 18932,
"##rro": 18933,
"advisors": 18934,
"##coming": 18935,
"rodeo": 18936,
"scotch": 18937,
"##mot": 18938,
"##db": 18939,
"##fen": 18940,
"##vant": 18941,
"ensued": 18942,
"rodrigo": 18943,
"dictatorship": 18944,
"martyrs": 18945,
"twenties": 18946,
"##н": 18947,
"towed": 18948,
"incidence": 18949,
"marta": 18950,
"rainforest": 18951,
"sai": 18952,
"scaled": 18953,
"##cles": 18954,
"oceanic": 18955,
"qualifiers": 18956,
"symphonic": 18957,
"mcbride": 18958,
"dislike": 18959,
"generalized": 18960,
"aubrey": 18961,
"colonization": 18962,
"##iation": 18963,
"##lion": 18964,
"##ssing": 18965,
"disliked": 18966,
"lublin": 18967,
"salesman": 18968,
"##ulates": 18969,
"spherical": 18970,
"whatsoever": 18971,
"sweating": 18972,
"avalon": 18973,
"contention": 18974,
"punt": 18975,
"severity": 18976,
"alderman": 18977,
"atari": 18978,
"##dina": 18979,
"##grant": 18980,
"##rop": 18981,
"scarf": 18982,
"seville": 18983,
"vertices": 18984,
"annexation": 18985,
"fairfield": 18986,
"fascination": 18987,
"inspiring": 18988,
"launches": 18989,
"palatinate": 18990,
"regretted": 18991,
"##rca": 18992,
"feral": 18993,
"##iom": 18994,
"elk": 18995,
"nap": 18996,
"olsen": 18997,
"reddy": 18998,
"yong": 18999,
"##leader": 19000,
"##iae": 19001,
"garment": 19002,
"transports": 19003,
"feng": 19004,
"gracie": 19005,
"outrage": 19006,
"viceroy": 19007,
"insides": 19008,
"##esis": 19009,
"breakup": 19010,
"grady": 19011,
"organizer": 19012,
"softer": 19013,
"grimaced": 19014,
"222": 19015,
"murals": 19016,
"galicia": 19017,
"arranging": 19018,
"vectors": 19019,
"##rsten": 19020,
"bas": 19021,
"##sb": 19022,
"##cens": 19023,
"sloan": 19024,
"##eka": 19025,
"bitten": 19026,
"ara": 19027,
"fender": 19028,
"nausea": 19029,
"bumped": 19030,
"kris": 19031,
"banquet": 19032,
"comrades": 19033,
"detector": 19034,
"persisted": 19035,
"##llan": 19036,
"adjustment": 19037,
"endowed": 19038,
"cinemas": 19039,
"##shot": 19040,
"sellers": 19041,
"##uman": 19042,
"peek": 19043,
"epa": 19044,
"kindly": 19045,
"neglect": 19046,
"simpsons": 19047,
"talon": 19048,
"mausoleum": 19049,
"runaway": 19050,
"hangul": 19051,
"lookout": 19052,
"##cic": 19053,
"rewards": 19054,
"coughed": 19055,
"acquainted": 19056,
"chloride": 19057,
"##ald": 19058,
"quicker": 19059,
"accordion": 19060,
"neolithic": 19061,
"##qa": 19062,
"artemis": 19063,
"coefficient": 19064,
"lenny": 19065,
"pandora": 19066,
"tx": 19067,
"##xed": 19068,
"ecstasy": 19069,
"litter": 19070,
"segunda": 19071,
"chairperson": 19072,
"gemma": 19073,
"hiss": 19074,
"rumor": 19075,
"vow": 19076,
"nasal": 19077,
"antioch": 19078,
"compensate": 19079,
"patiently": 19080,
"transformers": 19081,
"##eded": 19082,
"judo": 19083,
"morrow": 19084,
"penis": 19085,
"posthumous": 19086,
"philips": 19087,
"bandits": 19088,
"husbands": 19089,
"denote": 19090,
"flaming": 19091,
"##any": 19092,
"##phones": 19093,
"langley": 19094,
"yorker": 19095,
"1760": 19096,
"walters": 19097,
"##uo": 19098,
"##kle": 19099,
"gubernatorial": 19100,
"fatty": 19101,
"samsung": 19102,
"leroy": 19103,
"outlaw": 19104,
"##nine": 19105,
"unpublished": 19106,
"poole": 19107,
"jakob": 19108,
"##ᵢ": 19109,
"##ₙ": 19110,
"crete": 19111,
"distorted": 19112,
"superiority": 19113,
"##dhi": 19114,
"intercept": 19115,
"crust": 19116,
"mig": 19117,
"claus": 19118,
"crashes": 19119,
"positioning": 19120,
"188": 19121,
"stallion": 19122,
"301": 19123,
"frontal": 19124,
"armistice": 19125,
"##estinal": 19126,
"elton": 19127,
"aj": 19128,
"encompassing": 19129,
"camel": 19130,
"commemorated": 19131,
"malaria": 19132,
"woodward": 19133,
"calf": 19134,
"cigar": 19135,
"penetrate": 19136,
"##oso": 19137,
"willard": 19138,
"##rno": 19139,
"##uche": 19140,
"illustrate": 19141,
"amusing": 19142,
"convergence": 19143,
"noteworthy": 19144,
"##lma": 19145,
"##rva": 19146,
"journeys": 19147,
"realise": 19148,
"manfred": 19149,
"##sable": 19150,
"410": 19151,
"##vocation": 19152,
"hearings": 19153,
"fiance": 19154,
"##posed": 19155,
"educators": 19156,
"provoked": 19157,
"adjusting": 19158,
"##cturing": 19159,
"modular": 19160,
"stockton": 19161,
"paterson": 19162,
"vlad": 19163,
"rejects": 19164,
"electors": 19165,
"selena": 19166,
"maureen": 19167,
"##tres": 19168,
"uber": 19169,
"##rce": 19170,
"swirled": 19171,
"##num": 19172,
"proportions": 19173,
"nanny": 19174,
"pawn": 19175,
"naturalist": 19176,
"parma": 19177,
"apostles": 19178,
"awoke": 19179,
"ethel": 19180,
"wen": 19181,
"##bey": 19182,
"monsoon": 19183,
"overview": 19184,
"##inating": 19185,
"mccain": 19186,
"rendition": 19187,
"risky": 19188,
"adorned": 19189,
"##ih": 19190,
"equestrian": 19191,
"germain": 19192,
"nj": 19193,
"conspicuous": 19194,
"confirming": 19195,
"##yoshi": 19196,
"shivering": 19197,
"##imeter": 19198,
"milestone": 19199,
"rumours": 19200,
"flinched": 19201,
"bounds": 19202,
"smacked": 19203,
"token": 19204,
"##bei": 19205,
"lectured": 19206,
"automobiles": 19207,
"##shore": 19208,
"impacted": 19209,
"##iable": 19210,
"nouns": 19211,
"nero": 19212,
"##leaf": 19213,
"ismail": 19214,
"prostitute": 19215,
"trams": 19216,
"##lace": 19217,
"bridget": 19218,
"sud": 19219,
"stimulus": 19220,
"impressions": 19221,
"reins": 19222,
"revolves": 19223,
"##oud": 19224,
"##gned": 19225,
"giro": 19226,
"honeymoon": 19227,
"##swell": 19228,
"criterion": 19229,
"##sms": 19230,
"##uil": 19231,
"libyan": 19232,
"prefers": 19233,
"##osition": 19234,
"211": 19235,
"preview": 19236,
"sucks": 19237,
"accusation": 19238,
"bursts": 19239,
"metaphor": 19240,
"diffusion": 19241,
"tolerate": 19242,
"faye": 19243,
"betting": 19244,
"cinematographer": 19245,
"liturgical": 19246,
"specials": 19247,
"bitterly": 19248,
"humboldt": 19249,
"##ckle": 19250,
"flux": 19251,
"rattled": 19252,
"##itzer": 19253,
"archaeologists": 19254,
"odor": 19255,
"authorised": 19256,
"marshes": 19257,
"discretion": 19258,
"##ов": 19259,
"alarmed": 19260,
"archaic": 19261,
"inverse": 19262,
"##leton": 19263,
"explorers": 19264,
"##pine": 19265,
"drummond": 19266,
"tsunami": 19267,
"woodlands": 19268,
"##minate": 19269,
"##tland": 19270,
"booklet": 19271,
"insanity": 19272,
"owning": 19273,
"insert": 19274,
"crafted": 19275,
"calculus": 19276,
"##tore": 19277,
"receivers": 19278,
"##bt": 19279,
"stung": 19280,
"##eca": 19281,
"##nched": 19282,
"prevailing": 19283,
"travellers": 19284,
"eyeing": 19285,
"lila": 19286,
"graphs": 19287,
"##borne": 19288,
"178": 19289,
"julien": 19290,
"##won": 19291,
"morale": 19292,
"adaptive": 19293,
"therapist": 19294,
"erica": 19295,
"cw": 19296,
"libertarian": 19297,
"bowman": 19298,
"pitches": 19299,
"vita": 19300,
"##ional": 19301,
"crook": 19302,
"##ads": 19303,
"##entation": 19304,
"caledonia": 19305,
"mutiny": 19306,
"##sible": 19307,
"1840s": 19308,
"automation": 19309,
"##ß": 19310,
"flock": 19311,
"##pia": 19312,
"ironic": 19313,
"pathology": 19314,
"##imus": 19315,
"remarried": 19316,
"##22": 19317,
"joker": 19318,
"withstand": 19319,
"energies": 19320,
"##att": 19321,
"shropshire": 19322,
"hostages": 19323,
"madeleine": 19324,
"tentatively": 19325,
"conflicting": 19326,
"mateo": 19327,
"recipes": 19328,
"euros": 19329,
"ol": 19330,
"mercenaries": 19331,
"nico": 19332,
"##ndon": 19333,
"albuquerque": 19334,
"augmented": 19335,
"mythical": 19336,
"bel": 19337,
"freud": 19338,
"##child": 19339,
"cough": 19340,
"##lica": 19341,
"365": 19342,
"freddy": 19343,
"lillian": 19344,
"genetically": 19345,
"nuremberg": 19346,
"calder": 19347,
"209": 19348,
"bonn": 19349,
"outdoors": 19350,
"paste": 19351,
"suns": 19352,
"urgency": 19353,
"vin": 19354,
"restraint": 19355,
"tyson": 19356,
"##cera": 19357,
"##selle": 19358,
"barrage": 19359,
"bethlehem": 19360,
"kahn": 19361,
"##par": 19362,
"mounts": 19363,
"nippon": 19364,
"barony": 19365,
"happier": 19366,
"ryu": 19367,
"makeshift": 19368,
"sheldon": 19369,
"blushed": 19370,
"castillo": 19371,
"barking": 19372,
"listener": 19373,
"taped": 19374,
"bethel": 19375,
"fluent": 19376,
"headlines": 19377,
"pornography": 19378,
"rum": 19379,
"disclosure": 19380,
"sighing": 19381,
"mace": 19382,
"doubling": 19383,
"gunther": 19384,
"manly": 19385,
"##plex": 19386,
"rt": 19387,
"interventions": 19388,
"physiological": 19389,
"forwards": 19390,
"emerges": 19391,
"##tooth": 19392,
"##gny": 19393,
"compliment": 19394,
"rib": 19395,
"recession": 19396,
"visibly": 19397,
"barge": 19398,
"faults": 19399,
"connector": 19400,
"exquisite": 19401,
"prefect": 19402,
"##rlin": 19403,
"patio": 19404,
"##cured": 19405,
"elevators": 19406,
"brandt": 19407,
"italics": 19408,
"pena": 19409,
"173": 19410,
"wasp": 19411,
"satin": 19412,
"ea": 19413,
"botswana": 19414,
"graceful": 19415,
"respectable": 19416,
"##jima": 19417,
"##rter": 19418,
"##oic": 19419,
"franciscan": 19420,
"generates": 19421,
"##dl": 19422,
"alfredo": 19423,
"disgusting": 19424,
"##olate": 19425,
"##iously": 19426,
"sherwood": 19427,
"warns": 19428,
"cod": 19429,
"promo": 19430,
"cheryl": 19431,
"sino": 19432,
"##ة": 19433,
"##escu": 19434,
"twitch": 19435,
"##zhi": 19436,
"brownish": 19437,
"thom": 19438,
"ortiz": 19439,
"##dron": 19440,
"densely": 19441,
"##beat": 19442,
"carmel": 19443,
"reinforce": 19444,
"##bana": 19445,
"187": 19446,
"anastasia": 19447,
"downhill": 19448,
"vertex": 19449,
"contaminated": 19450,
"remembrance": 19451,
"harmonic": 19452,
"homework": 19453,
"##sol": 19454,
"fiancee": 19455,
"gears": 19456,
"olds": 19457,
"angelica": 19458,
"loft": 19459,
"ramsay": 19460,
"quiz": 19461,
"colliery": 19462,
"sevens": 19463,
"##cape": 19464,
"autism": 19465,
"##hil": 19466,
"walkway": 19467,
"##boats": 19468,
"ruben": 19469,
"abnormal": 19470,
"ounce": 19471,
"khmer": 19472,
"##bbe": 19473,
"zachary": 19474,
"bedside": 19475,
"morphology": 19476,
"punching": 19477,
"##olar": 19478,
"sparrow": 19479,
"convinces": 19480,
"##35": 19481,
"hewitt": 19482,
"queer": 19483,
"remastered": 19484,
"rods": 19485,
"mabel": 19486,
"solemn": 19487,
"notified": 19488,
"lyricist": 19489,
"symmetric": 19490,
"##xide": 19491,
"174": 19492,
"encore": 19493,
"passports": 19494,
"wildcats": 19495,
"##uni": 19496,
"baja": 19497,
"##pac": 19498,
"mildly": 19499,
"##ease": 19500,
"bleed": 19501,
"commodity": 19502,
"mounds": 19503,
"glossy": 19504,
"orchestras": 19505,
"##omo": 19506,
"damian": 19507,
"prelude": 19508,
"ambitions": 19509,
"##vet": 19510,
"awhile": 19511,
"remotely": 19512,
"##aud": 19513,
"asserts": 19514,
"imply": 19515,
"##iques": 19516,
"distinctly": 19517,
"modelling": 19518,
"remedy": 19519,
"##dded": 19520,
"windshield": 19521,
"dani": 19522,
"xiao": 19523,
"##endra": 19524,
"audible": 19525,
"powerplant": 19526,
"1300": 19527,
"invalid": 19528,
"elemental": 19529,
"acquisitions": 19530,
"##hala": 19531,
"immaculate": 19532,
"libby": 19533,
"plata": 19534,
"smuggling": 19535,
"ventilation": 19536,
"denoted": 19537,
"minh": 19538,
"##morphism": 19539,
"430": 19540,
"differed": 19541,
"dion": 19542,
"kelley": 19543,
"lore": 19544,
"mocking": 19545,
"sabbath": 19546,
"spikes": 19547,
"hygiene": 19548,
"drown": 19549,
"runoff": 19550,
"stylized": 19551,
"tally": 19552,
"liberated": 19553,
"aux": 19554,
"interpreter": 19555,
"righteous": 19556,
"aba": 19557,
"siren": 19558,
"reaper": 19559,
"pearce": 19560,
"millie": 19561,
"##cier": 19562,
"##yra": 19563,
"gaius": 19564,
"##iso": 19565,
"captures": 19566,
"##ttering": 19567,
"dorm": 19568,
"claudio": 19569,
"##sic": 19570,
"benches": 19571,
"knighted": 19572,
"blackness": 19573,
"##ored": 19574,
"discount": 19575,
"fumble": 19576,
"oxidation": 19577,
"routed": 19578,
"##ς": 19579,
"novak": 19580,
"perpendicular": 19581,
"spoiled": 19582,
"fracture": 19583,
"splits": 19584,
"##urt": 19585,
"pads": 19586,
"topology": 19587,
"##cats": 19588,
"axes": 19589,
"fortunate": 19590,
"offenders": 19591,
"protestants": 19592,
"esteem": 19593,
"221": 19594,
"broadband": 19595,
"convened": 19596,
"frankly": 19597,
"hound": 19598,
"prototypes": 19599,
"isil": 19600,
"facilitated": 19601,
"keel": 19602,
"##sher": 19603,
"sahara": 19604,
"awaited": 19605,
"bubba": 19606,
"orb": 19607,
"prosecutors": 19608,
"186": 19609,
"hem": 19610,
"520": 19611,
"##xing": 19612,
"relaxing": 19613,
"remnant": 19614,
"romney": 19615,
"sorted": 19616,
"slalom": 19617,
"stefano": 19618,
"ulrich": 19619,
"##active": 19620,
"exemption": 19621,
"folder": 19622,
"pauses": 19623,
"foliage": 19624,
"hitchcock": 19625,
"epithet": 19626,
"204": 19627,
"criticisms": 19628,
"##aca": 19629,
"ballistic": 19630,
"brody": 19631,
"hinduism": 19632,
"chaotic": 19633,
"youths": 19634,
"equals": 19635,
"##pala": 19636,
"pts": 19637,
"thicker": 19638,
"analogous": 19639,
"capitalist": 19640,
"improvised": 19641,
"overseeing": 19642,
"sinatra": 19643,
"ascended": 19644,
"beverage": 19645,
"##tl": 19646,
"straightforward": 19647,
"##kon": 19648,
"curran": 19649,
"##west": 19650,
"bois": 19651,
"325": 19652,
"induce": 19653,
"surveying": 19654,
"emperors": 19655,
"sax": 19656,
"unpopular": 19657,
"##kk": 19658,
"cartoonist": 19659,
"fused": 19660,
"##mble": 19661,
"unto": 19662,
"##yuki": 19663,
"localities": 19664,
"##cko": 19665,
"##ln": 19666,
"darlington": 19667,
"slain": 19668,
"academie": 19669,
"lobbying": 19670,
"sediment": 19671,
"puzzles": 19672,
"##grass": 19673,
"defiance": 19674,
"dickens": 19675,
"manifest": 19676,
"tongues": 19677,
"alumnus": 19678,
"arbor": 19679,
"coincide": 19680,
"184": 19681,
"appalachian": 19682,
"mustafa": 19683,
"examiner": 19684,
"cabaret": 19685,
"traumatic": 19686,
"yves": 19687,
"bracelet": 19688,
"draining": 19689,
"heroin": 19690,
"magnum": 19691,
"baths": 19692,
"odessa": 19693,
"consonants": 19694,
"mitsubishi": 19695,
"##gua": 19696,
"kellan": 19697,
"vaudeville": 19698,
"##fr": 19699,
"joked": 19700,
"null": 19701,
"straps": 19702,
"probation": 19703,
"##ław": 19704,
"ceded": 19705,
"interfaces": 19706,
"##pas": 19707,
"##zawa": 19708,
"blinding": 19709,
"viet": 19710,
"224": 19711,
"rothschild": 19712,
"museo": 19713,
"640": 19714,
"huddersfield": 19715,
"##vr": 19716,
"tactic": 19717,
"##storm": 19718,
"brackets": 19719,
"dazed": 19720,
"incorrectly": 19721,
"##vu": 19722,
"reg": 19723,
"glazed": 19724,
"fearful": 19725,
"manifold": 19726,
"benefited": 19727,
"irony": 19728,
"##sun": 19729,
"stumbling": 19730,
"##rte": 19731,
"willingness": 19732,
"balkans": 19733,
"mei": 19734,
"wraps": 19735,
"##aba": 19736,
"injected": 19737,
"##lea": 19738,
"gu": 19739,
"syed": 19740,
"harmless": 19741,
"##hammer": 19742,
"bray": 19743,
"takeoff": 19744,
"poppy": 19745,
"timor": 19746,
"cardboard": 19747,
"astronaut": 19748,
"purdue": 19749,
"weeping": 19750,
"southbound": 19751,
"cursing": 19752,
"stalls": 19753,
"diagonal": 19754,
"##neer": 19755,
"lamar": 19756,
"bryce": 19757,
"comte": 19758,
"weekdays": 19759,
"harrington": 19760,
"##uba": 19761,
"negatively": 19762,
"##see": 19763,
"lays": 19764,
"grouping": 19765,
"##cken": 19766,
"##henko": 19767,
"affirmed": 19768,
"halle": 19769,
"modernist": 19770,
"##lai": 19771,
"hodges": 19772,
"smelling": 19773,
"aristocratic": 19774,
"baptized": 19775,
"dismiss": 19776,
"justification": 19777,
"oilers": 19778,
"##now": 19779,
"coupling": 19780,
"qin": 19781,
"snack": 19782,
"healer": 19783,
"##qing": 19784,
"gardener": 19785,
"layla": 19786,
"battled": 19787,
"formulated": 19788,
"stephenson": 19789,
"gravitational": 19790,
"##gill": 19791,
"##jun": 19792,
"1768": 19793,
"granny": 19794,
"coordinating": 19795,
"suites": 19796,
"##cd": 19797,
"##ioned": 19798,
"monarchs": 19799,
"##cote": 19800,
"##hips": 19801,
"sep": 19802,
"blended": 19803,
"apr": 19804,
"barrister": 19805,
"deposition": 19806,
"fia": 19807,
"mina": 19808,
"policemen": 19809,
"paranoid": 19810,
"##pressed": 19811,
"churchyard": 19812,
"covert": 19813,
"crumpled": 19814,
"creep": 19815,
"abandoning": 19816,
"tr": 19817,
"transmit": 19818,
"conceal": 19819,
"barr": 19820,
"understands": 19821,
"readiness": 19822,
"spire": 19823,
"##cology": 19824,
"##enia": 19825,
"##erry": 19826,
"610": 19827,
"startling": 19828,
"unlock": 19829,
"vida": 19830,
"bowled": 19831,
"slots": 19832,
"##nat": 19833,
"##islav": 19834,
"spaced": 19835,
"trusting": 19836,
"admire": 19837,
"rig": 19838,
"##ink": 19839,
"slack": 19840,
"##70": 19841,
"mv": 19842,
"207": 19843,
"casualty": 19844,
"##wei": 19845,
"classmates": 19846,
"##odes": 19847,
"##rar": 19848,
"##rked": 19849,
"amherst": 19850,
"furnished": 19851,
"evolve": 19852,
"foundry": 19853,
"menace": 19854,
"mead": 19855,
"##lein": 19856,
"flu": 19857,
"wesleyan": 19858,
"##kled": 19859,
"monterey": 19860,
"webber": 19861,
"##vos": 19862,
"wil": 19863,
"##mith": 19864,
"##на": 19865,
"bartholomew": 19866,
"justices": 19867,
"restrained": 19868,
"##cke": 19869,
"amenities": 19870,
"191": 19871,
"mediated": 19872,
"sewage": 19873,
"trenches": 19874,
"ml": 19875,
"mainz": 19876,
"##thus": 19877,
"1800s": 19878,
"##cula": 19879,
"##inski": 19880,
"caine": 19881,
"bonding": 19882,
"213": 19883,
"converts": 19884,
"spheres": 19885,
"superseded": 19886,
"marianne": 19887,
"crypt": 19888,
"sweaty": 19889,
"ensign": 19890,
"historia": 19891,
"##br": 19892,
"spruce": 19893,
"##post": 19894,
"##ask": 19895,
"forks": 19896,
"thoughtfully": 19897,
"yukon": 19898,
"pamphlet": 19899,
"ames": 19900,
"##uter": 19901,
"karma": 19902,
"##yya": 19903,
"bryn": 19904,
"negotiation": 19905,
"sighs": 19906,
"incapable": 19907,
"##mbre": 19908,
"##ntial": 19909,
"actresses": 19910,
"taft": 19911,
"##mill": 19912,
"luce": 19913,
"prevailed": 19914,
"##amine": 19915,
"1773": 19916,
"motionless": 19917,
"envoy": 19918,
"testify": 19919,
"investing": 19920,
"sculpted": 19921,
"instructors": 19922,
"provence": 19923,
"kali": 19924,
"cullen": 19925,
"horseback": 19926,
"##while": 19927,
"goodwin": 19928,
"##jos": 19929,
"gaa": 19930,
"norte": 19931,
"##ldon": 19932,
"modify": 19933,
"wavelength": 19934,
"abd": 19935,
"214": 19936,
"skinned": 19937,
"sprinter": 19938,
"forecast": 19939,
"scheduling": 19940,
"marries": 19941,
"squared": 19942,
"tentative": 19943,
"##chman": 19944,
"boer": 19945,
"##isch": 19946,
"bolts": 19947,
"swap": 19948,
"fisherman": 19949,
"assyrian": 19950,
"impatiently": 19951,
"guthrie": 19952,
"martins": 19953,
"murdoch": 19954,
"194": 19955,
"tanya": 19956,
"nicely": 19957,
"dolly": 19958,
"lacy": 19959,
"med": 19960,
"##45": 19961,
"syn": 19962,
"decks": 19963,
"fashionable": 19964,
"millionaire": 19965,
"##ust": 19966,
"surfing": 19967,
"##ml": 19968,
"##ision": 19969,
"heaved": 19970,
"tammy": 19971,
"consulate": 19972,
"attendees": 19973,
"routinely": 19974,
"197": 19975,
"fuse": 19976,
"saxophonist": 19977,
"backseat": 19978,
"malaya": 19979,
"##lord": 19980,
"scowl": 19981,
"tau": 19982,
"##ishly": 19983,
"193": 19984,
"sighted": 19985,
"steaming": 19986,
"##rks": 19987,
"303": 19988,
"911": 19989,
"##holes": 19990,
"##hong": 19991,
"ching": 19992,
"##wife": 19993,
"bless": 19994,
"conserved": 19995,
"jurassic": 19996,
"stacey": 19997,
"unix": 19998,
"zion": 19999,
"chunk": 20000,
"rigorous": 20001,
"blaine": 20002,
"198": 20003,
"peabody": 20004,
"slayer": 20005,
"dismay": 20006,
"brewers": 20007,
"nz": 20008,
"##jer": 20009,
"det": 20010,
"##glia": 20011,
"glover": 20012,
"postwar": 20013,
"int": 20014,
"penetration": 20015,
"sylvester": 20016,
"imitation": 20017,
"vertically": 20018,
"airlift": 20019,
"heiress": 20020,
"knoxville": 20021,
"viva": 20022,
"##uin": 20023,
"390": 20024,
"macon": 20025,
"##rim": 20026,
"##fighter": 20027,
"##gonal": 20028,
"janice": 20029,
"##orescence": 20030,
"##wari": 20031,
"marius": 20032,
"belongings": 20033,
"leicestershire": 20034,
"196": 20035,
"blanco": 20036,
"inverted": 20037,
"preseason": 20038,
"sanity": 20039,
"sobbing": 20040,
"##due": 20041,
"##elt": 20042,
"##dled": 20043,
"collingwood": 20044,
"regeneration": 20045,
"flickering": 20046,
"shortest": 20047,
"##mount": 20048,
"##osi": 20049,
"feminism": 20050,
"##lat": 20051,
"sherlock": 20052,
"cabinets": 20053,
"fumbled": 20054,
"northbound": 20055,
"precedent": 20056,
"snaps": 20057,
"##mme": 20058,
"researching": 20059,
"##akes": 20060,
"guillaume": 20061,
"insights": 20062,
"manipulated": 20063,
"vapor": 20064,
"neighbour": 20065,
"sap": 20066,
"gangster": 20067,
"frey": 20068,
"f1": 20069,
"stalking": 20070,
"scarcely": 20071,
"callie": 20072,
"barnett": 20073,
"tendencies": 20074,
"audi": 20075,
"doomed": 20076,
"assessing": 20077,
"slung": 20078,
"panchayat": 20079,
"ambiguous": 20080,
"bartlett": 20081,
"##etto": 20082,
"distributing": 20083,
"violating": 20084,
"wolverhampton": 20085,
"##hetic": 20086,
"swami": 20087,
"histoire": 20088,
"##urus": 20089,
"liable": 20090,
"pounder": 20091,
"groin": 20092,
"hussain": 20093,
"larsen": 20094,
"popping": 20095,
"surprises": 20096,
"##atter": 20097,
"vie": 20098,
"curt": 20099,
"##station": 20100,
"mute": 20101,
"relocate": 20102,
"musicals": 20103,
"authorization": 20104,
"richter": 20105,
"##sef": 20106,
"immortality": 20107,
"tna": 20108,
"bombings": 20109,
"##press": 20110,
"deteriorated": 20111,
"yiddish": 20112,
"##acious": 20113,
"robbed": 20114,
"colchester": 20115,
"cs": 20116,
"pmid": 20117,
"ao": 20118,
"verified": 20119,
"balancing": 20120,
"apostle": 20121,
"swayed": 20122,
"recognizable": 20123,
"oxfordshire": 20124,
"retention": 20125,
"nottinghamshire": 20126,
"contender": 20127,
"judd": 20128,
"invitational": 20129,
"shrimp": 20130,
"uhf": 20131,
"##icient": 20132,
"cleaner": 20133,
"longitudinal": 20134,
"tanker": 20135,
"##mur": 20136,
"acronym": 20137,
"broker": 20138,
"koppen": 20139,
"sundance": 20140,
"suppliers": 20141,
"##gil": 20142,
"4000": 20143,
"clipped": 20144,
"fuels": 20145,
"petite": 20146,
"##anne": 20147,
"landslide": 20148,
"helene": 20149,
"diversion": 20150,
"populous": 20151,
"landowners": 20152,
"auspices": 20153,
"melville": 20154,
"quantitative": 20155,
"##xes": 20156,
"ferries": 20157,
"nicky": 20158,
"##llus": 20159,
"doo": 20160,
"haunting": 20161,
"roche": 20162,
"carver": 20163,
"downed": 20164,
"unavailable": 20165,
"##pathy": 20166,
"approximation": 20167,
"hiroshima": 20168,
"##hue": 20169,
"garfield": 20170,
"valle": 20171,
"comparatively": 20172,
"keyboardist": 20173,
"traveler": 20174,
"##eit": 20175,
"congestion": 20176,
"calculating": 20177,
"subsidiaries": 20178,
"##bate": 20179,
"serb": 20180,
"modernization": 20181,
"fairies": 20182,
"deepened": 20183,
"ville": 20184,
"averages": 20185,
"##lore": 20186,
"inflammatory": 20187,
"tonga": 20188,
"##itch": 20189,
"co₂": 20190,
"squads": 20191,
"##hea": 20192,
"gigantic": 20193,
"serum": 20194,
"enjoyment": 20195,
"retailer": 20196,
"verona": 20197,
"35th": 20198,
"cis": 20199,
"##phobic": 20200,
"magna": 20201,
"technicians": 20202,
"##vati": 20203,
"arithmetic": 20204,
"##sport": 20205,
"levin": 20206,
"##dation": 20207,
"amtrak": 20208,
"chow": 20209,
"sienna": 20210,
"##eyer": 20211,
"backstage": 20212,
"entrepreneurship": 20213,
"##otic": 20214,
"learnt": 20215,
"tao": 20216,
"##udy": 20217,
"worcestershire": 20218,
"formulation": 20219,
"baggage": 20220,
"hesitant": 20221,
"bali": 20222,
"sabotage": 20223,
"##kari": 20224,
"barren": 20225,
"enhancing": 20226,
"murmur": 20227,
"pl": 20228,
"freshly": 20229,
"putnam": 20230,
"syntax": 20231,
"aces": 20232,
"medicines": 20233,
"resentment": 20234,
"bandwidth": 20235,
"##sier": 20236,
"grins": 20237,
"chili": 20238,
"guido": 20239,
"##sei": 20240,
"framing": 20241,
"implying": 20242,
"gareth": 20243,
"lissa": 20244,
"genevieve": 20245,
"pertaining": 20246,
"admissions": 20247,
"geo": 20248,
"thorpe": 20249,
"proliferation": 20250,
"sato": 20251,
"bela": 20252,
"analyzing": 20253,
"parting": 20254,
"##gor": 20255,
"awakened": 20256,
"##isman": 20257,
"huddled": 20258,
"secrecy": 20259,
"##kling": 20260,
"hush": 20261,
"gentry": 20262,
"540": 20263,
"dungeons": 20264,
"##ego": 20265,
"coasts": 20266,
"##utz": 20267,
"sacrificed": 20268,
"##chule": 20269,
"landowner": 20270,
"mutually": 20271,
"prevalence": 20272,
"programmer": 20273,
"adolescent": 20274,
"disrupted": 20275,
"seaside": 20276,
"gee": 20277,
"trusts": 20278,
"vamp": 20279,
"georgie": 20280,
"##nesian": 20281,
"##iol": 20282,
"schedules": 20283,
"sindh": 20284,
"##market": 20285,
"etched": 20286,
"hm": 20287,
"sparse": 20288,
"bey": 20289,
"beaux": 20290,
"scratching": 20291,
"gliding": 20292,
"unidentified": 20293,
"216": 20294,
"collaborating": 20295,
"gems": 20296,
"jesuits": 20297,
"oro": 20298,
"accumulation": 20299,
"shaping": 20300,
"mbe": 20301,
"anal": 20302,
"##xin": 20303,
"231": 20304,
"enthusiasts": 20305,
"newscast": 20306,
"##egan": 20307,
"janata": 20308,
"dewey": 20309,
"parkinson": 20310,
"179": 20311,
"ankara": 20312,
"biennial": 20313,
"towering": 20314,
"dd": 20315,
"inconsistent": 20316,
"950": 20317,
"##chet": 20318,
"thriving": 20319,
"terminate": 20320,
"cabins": 20321,
"furiously": 20322,
"eats": 20323,
"advocating": 20324,
"donkey": 20325,
"marley": 20326,
"muster": 20327,
"phyllis": 20328,
"leiden": 20329,
"##user": 20330,
"grassland": 20331,
"glittering": 20332,
"iucn": 20333,
"loneliness": 20334,
"217": 20335,
"memorandum": 20336,
"armenians": 20337,
"##ddle": 20338,
"popularized": 20339,
"rhodesia": 20340,
"60s": 20341,
"lame": 20342,
"##illon": 20343,
"sans": 20344,
"bikini": 20345,
"header": 20346,
"orbits": 20347,
"##xx": 20348,
"##finger": 20349,
"##ulator": 20350,
"sharif": 20351,
"spines": 20352,
"biotechnology": 20353,
"strolled": 20354,
"naughty": 20355,
"yates": 20356,
"##wire": 20357,
"fremantle": 20358,
"milo": 20359,
"##mour": 20360,
"abducted": 20361,
"removes": 20362,
"##atin": 20363,
"humming": 20364,
"wonderland": 20365,
"##chrome": 20366,
"##ester": 20367,
"hume": 20368,
"pivotal": 20369,
"##rates": 20370,
"armand": 20371,
"grams": 20372,
"believers": 20373,
"elector": 20374,
"rte": 20375,
"apron": 20376,
"bis": 20377,
"scraped": 20378,
"##yria": 20379,
"endorsement": 20380,
"initials": 20381,
"##llation": 20382,
"eps": 20383,
"dotted": 20384,
"hints": 20385,
"buzzing": 20386,
"emigration": 20387,
"nearer": 20388,
"##tom": 20389,
"indicators": 20390,
"##ulu": 20391,
"coarse": 20392,
"neutron": 20393,
"protectorate": 20394,
"##uze": 20395,
"directional": 20396,
"exploits": 20397,
"pains": 20398,
"loire": 20399,
"1830s": 20400,
"proponents": 20401,
"guggenheim": 20402,
"rabbits": 20403,
"ritchie": 20404,
"305": 20405,
"hectare": 20406,
"inputs": 20407,
"hutton": 20408,
"##raz": 20409,
"verify": 20410,
"##ako": 20411,
"boilers": 20412,
"longitude": 20413,
"##lev": 20414,
"skeletal": 20415,
"yer": 20416,
"emilia": 20417,
"citrus": 20418,
"compromised": 20419,
"##gau": 20420,
"pokemon": 20421,
"prescription": 20422,
"paragraph": 20423,
"eduard": 20424,
"cadillac": 20425,
"attire": 20426,
"categorized": 20427,
"kenyan": 20428,
"weddings": 20429,
"charley": 20430,
"##bourg": 20431,
"entertain": 20432,
"monmouth": 20433,
"##lles": 20434,
"nutrients": 20435,
"davey": 20436,
"mesh": 20437,
"incentive": 20438,
"practised": 20439,
"ecosystems": 20440,
"kemp": 20441,
"subdued": 20442,
"overheard": 20443,
"##rya": 20444,
"bodily": 20445,
"maxim": 20446,
"##nius": 20447,
"apprenticeship": 20448,
"ursula": 20449,
"##fight": 20450,
"lodged": 20451,
"rug": 20452,
"silesian": 20453,
"unconstitutional": 20454,
"patel": 20455,
"inspected": 20456,
"coyote": 20457,
"unbeaten": 20458,
"##hak": 20459,
"34th": 20460,
"disruption": 20461,
"convict": 20462,
"parcel": 20463,
"##cl": 20464,
"##nham": 20465,
"collier": 20466,
"implicated": 20467,
"mallory": 20468,
"##iac": 20469,
"##lab": 20470,
"susannah": 20471,
"winkler": 20472,
"##rber": 20473,
"shia": 20474,
"phelps": 20475,
"sediments": 20476,
"graphical": 20477,
"robotic": 20478,
"##sner": 20479,
"adulthood": 20480,
"mart": 20481,
"smoked": 20482,
"##isto": 20483,
"kathryn": 20484,
"clarified": 20485,
"##aran": 20486,
"divides": 20487,
"convictions": 20488,
"oppression": 20489,
"pausing": 20490,
"burying": 20491,
"##mt": 20492,
"federico": 20493,
"mathias": 20494,
"eileen": 20495,
"##tana": 20496,
"kite": 20497,
"hunched": 20498,
"##acies": 20499,
"189": 20500,
"##atz": 20501,
"disadvantage": 20502,
"liza": 20503,
"kinetic": 20504,
"greedy": 20505,
"paradox": 20506,
"yokohama": 20507,
"dowager": 20508,
"trunks": 20509,
"ventured": 20510,
"##gement": 20511,
"gupta": 20512,
"vilnius": 20513,
"olaf": 20514,
"##thest": 20515,
"crimean": 20516,
"hopper": 20517,
"##ej": 20518,
"progressively": 20519,
"arturo": 20520,
"mouthed": 20521,
"arrondissement": 20522,
"##fusion": 20523,
"rubin": 20524,
"simulcast": 20525,
"oceania": 20526,
"##orum": 20527,
"##stra": 20528,
"##rred": 20529,
"busiest": 20530,
"intensely": 20531,
"navigator": 20532,
"cary": 20533,
"##vine": 20534,
"##hini": 20535,
"##bies": 20536,
"fife": 20537,
"rowe": 20538,
"rowland": 20539,
"posing": 20540,
"insurgents": 20541,
"shafts": 20542,
"lawsuits": 20543,
"activate": 20544,
"conor": 20545,
"inward": 20546,
"culturally": 20547,
"garlic": 20548,
"265": 20549,
"##eering": 20550,
"eclectic": 20551,
"##hui": 20552,
"##kee": 20553,
"##nl": 20554,
"furrowed": 20555,
"vargas": 20556,
"meteorological": 20557,
"rendezvous": 20558,
"##aus": 20559,
"culinary": 20560,
"commencement": 20561,
"##dition": 20562,
"quota": 20563,
"##notes": 20564,
"mommy": 20565,
"salaries": 20566,
"overlapping": 20567,
"mule": 20568,
"##iology": 20569,
"##mology": 20570,
"sums": 20571,
"wentworth": 20572,
"##isk": 20573,
"##zione": 20574,
"mainline": 20575,
"subgroup": 20576,
"##illy": 20577,
"hack": 20578,
"plaintiff": 20579,
"verdi": 20580,
"bulb": 20581,
"differentiation": 20582,
"engagements": 20583,
"multinational": 20584,
"supplemented": 20585,
"bertrand": 20586,
"caller": 20587,
"regis": 20588,
"##naire": 20589,
"##sler": 20590,
"##arts": 20591,
"##imated": 20592,
"blossom": 20593,
"propagation": 20594,
"kilometer": 20595,
"viaduct": 20596,
"vineyards": 20597,
"##uate": 20598,
"beckett": 20599,
"optimization": 20600,
"golfer": 20601,
"songwriters": 20602,
"seminal": 20603,
"semitic": 20604,
"thud": 20605,
"volatile": 20606,
"evolving": 20607,
"ridley": 20608,
"##wley": 20609,
"trivial": 20610,
"distributions": 20611,
"scandinavia": 20612,
"jiang": 20613,
"##ject": 20614,
"wrestled": 20615,
"insistence": 20616,
"##dio": 20617,
"emphasizes": 20618,
"napkin": 20619,
"##ods": 20620,
"adjunct": 20621,
"rhyme": 20622,
"##ricted": 20623,
"##eti": 20624,
"hopeless": 20625,
"surrounds": 20626,
"tremble": 20627,
"32nd": 20628,
"smoky": 20629,
"##ntly": 20630,
"oils": 20631,
"medicinal": 20632,
"padded": 20633,
"steer": 20634,
"wilkes": 20635,
"219": 20636,
"255": 20637,
"concessions": 20638,
"hue": 20639,
"uniquely": 20640,
"blinded": 20641,
"landon": 20642,
"yahoo": 20643,
"##lane": 20644,
"hendrix": 20645,
"commemorating": 20646,
"dex": 20647,
"specify": 20648,
"chicks": 20649,
"##ggio": 20650,
"intercity": 20651,
"1400": 20652,
"morley": 20653,
"##torm": 20654,
"highlighting": 20655,
"##oting": 20656,
"pang": 20657,
"oblique": 20658,
"stalled": 20659,
"##liner": 20660,
"flirting": 20661,
"newborn": 20662,
"1769": 20663,
"bishopric": 20664,
"shaved": 20665,
"232": 20666,
"currie": 20667,
"##ush": 20668,
"dharma": 20669,
"spartan": 20670,
"##ooped": 20671,
"favorites": 20672,
"smug": 20673,
"novella": 20674,
"sirens": 20675,
"abusive": 20676,
"creations": 20677,
"espana": 20678,
"##lage": 20679,
"paradigm": 20680,
"semiconductor": 20681,
"sheen": 20682,
"##rdo": 20683,
"##yen": 20684,
"##zak": 20685,
"nrl": 20686,
"renew": 20687,
"##pose": 20688,
"##tur": 20689,
"adjutant": 20690,
"marches": 20691,
"norma": 20692,
"##enity": 20693,
"ineffective": 20694,
"weimar": 20695,
"grunt": 20696,
"##gat": 20697,
"lordship": 20698,
"plotting": 20699,
"expenditure": 20700,
"infringement": 20701,
"lbs": 20702,
"refrain": 20703,
"av": 20704,
"mimi": 20705,
"mistakenly": 20706,
"postmaster": 20707,
"1771": 20708,
"##bara": 20709,
"ras": 20710,
"motorsports": 20711,
"tito": 20712,
"199": 20713,
"subjective": 20714,
"##zza": 20715,
"bully": 20716,
"stew": 20717,
"##kaya": 20718,
"prescott": 20719,
"1a": 20720,
"##raphic": 20721,
"##zam": 20722,
"bids": 20723,
"styling": 20724,
"paranormal": 20725,
"reeve": 20726,
"sneaking": 20727,
"exploding": 20728,
"katz": 20729,
"akbar": 20730,
"migrant": 20731,
"syllables": 20732,
"indefinitely": 20733,
"##ogical": 20734,
"destroys": 20735,
"replaces": 20736,
"applause": 20737,
"##phine": 20738,
"pest": 20739,
"##fide": 20740,
"218": 20741,
"articulated": 20742,
"bertie": 20743,
"##thing": 20744,
"##cars": 20745,
"##ptic": 20746,
"courtroom": 20747,
"crowley": 20748,
"aesthetics": 20749,
"cummings": 20750,
"tehsil": 20751,
"hormones": 20752,
"titanic": 20753,
"dangerously": 20754,
"##ibe": 20755,
"stadion": 20756,
"jaenelle": 20757,
"auguste": 20758,
"ciudad": 20759,
"##chu": 20760,
"mysore": 20761,
"partisans": 20762,
"##sio": 20763,
"lucan": 20764,
"philipp": 20765,
"##aly": 20766,
"debating": 20767,
"henley": 20768,
"interiors": 20769,
"##rano": 20770,
"##tious": 20771,
"homecoming": 20772,
"beyonce": 20773,
"usher": 20774,
"henrietta": 20775,
"prepares": 20776,
"weeds": 20777,
"##oman": 20778,
"ely": 20779,
"plucked": 20780,
"##pire": 20781,
"##dable": 20782,
"luxurious": 20783,
"##aq": 20784,
"artifact": 20785,
"password": 20786,
"pasture": 20787,
"juno": 20788,
"maddy": 20789,
"minsk": 20790,
"##dder": 20791,
"##ologies": 20792,
"##rone": 20793,
"assessments": 20794,
"martian": 20795,
"royalist": 20796,
"1765": 20797,
"examines": 20798,
"##mani": 20799,
"##rge": 20800,
"nino": 20801,
"223": 20802,
"parry": 20803,
"scooped": 20804,
"relativity": 20805,
"##eli": 20806,
"##uting": 20807,
"##cao": 20808,
"congregational": 20809,
"noisy": 20810,
"traverse": 20811,
"##agawa": 20812,
"strikeouts": 20813,
"nickelodeon": 20814,
"obituary": 20815,
"transylvania": 20816,
"binds": 20817,
"depictions": 20818,
"polk": 20819,
"trolley": 20820,
"##yed": 20821,
"##lard": 20822,
"breeders": 20823,
"##under": 20824,
"dryly": 20825,
"hokkaido": 20826,
"1762": 20827,
"strengths": 20828,
"stacks": 20829,
"bonaparte": 20830,
"connectivity": 20831,
"neared": 20832,
"prostitutes": 20833,
"stamped": 20834,
"anaheim": 20835,
"gutierrez": 20836,
"sinai": 20837,
"##zzling": 20838,
"bram": 20839,
"fresno": 20840,
"madhya": 20841,
"##86": 20842,
"proton": 20843,
"##lena": 20844,
"##llum": 20845,
"##phon": 20846,
"reelected": 20847,
"wanda": 20848,
"##anus": 20849,
"##lb": 20850,
"ample": 20851,
"distinguishing": 20852,
"##yler": 20853,
"grasping": 20854,
"sermons": 20855,
"tomato": 20856,
"bland": 20857,
"stimulation": 20858,
"avenues": 20859,
"##eux": 20860,
"spreads": 20861,
"scarlett": 20862,
"fern": 20863,
"pentagon": 20864,
"assert": 20865,
"baird": 20866,
"chesapeake": 20867,
"ir": 20868,
"calmed": 20869,
"distortion": 20870,
"fatalities": 20871,
"##olis": 20872,
"correctional": 20873,
"pricing": 20874,
"##astic": 20875,
"##gina": 20876,
"prom": 20877,
"dammit": 20878,
"ying": 20879,
"collaborate": 20880,
"##chia": 20881,
"welterweight": 20882,
"33rd": 20883,
"pointer": 20884,
"substitution": 20885,
"bonded": 20886,
"umpire": 20887,
"communicating": 20888,
"multitude": 20889,
"paddle": 20890,
"##obe": 20891,
"federally": 20892,
"intimacy": 20893,
"##insky": 20894,
"betray": 20895,
"ssr": 20896,
"##lett": 20897,
"##lean": 20898,
"##lves": 20899,
"##therapy": 20900,
"airbus": 20901,
"##tery": 20902,
"functioned": 20903,
"ud": 20904,
"bearer": 20905,
"biomedical": 20906,
"netflix": 20907,
"##hire": 20908,
"##nca": 20909,
"condom": 20910,
"brink": 20911,
"ik": 20912,
"##nical": 20913,
"macy": 20914,
"##bet": 20915,
"flap": 20916,
"gma": 20917,
"experimented": 20918,
"jelly": 20919,
"lavender": 20920,
"##icles": 20921,
"##ulia": 20922,
"munro": 20923,
"##mian": 20924,
"##tial": 20925,
"rye": 20926,
"##rle": 20927,
"60th": 20928,
"gigs": 20929,
"hottest": 20930,
"rotated": 20931,
"predictions": 20932,
"fuji": 20933,
"bu": 20934,
"##erence": 20935,
"##omi": 20936,
"barangay": 20937,
"##fulness": 20938,
"##sas": 20939,
"clocks": 20940,
"##rwood": 20941,
"##liness": 20942,
"cereal": 20943,
"roe": 20944,
"wight": 20945,
"decker": 20946,
"uttered": 20947,
"babu": 20948,
"onion": 20949,
"xml": 20950,
"forcibly": 20951,
"##df": 20952,
"petra": 20953,
"sarcasm": 20954,
"hartley": 20955,
"peeled": 20956,
"storytelling": 20957,
"##42": 20958,
"##xley": 20959,
"##ysis": 20960,
"##ffa": 20961,
"fibre": 20962,
"kiel": 20963,
"auditor": 20964,
"fig": 20965,
"harald": 20966,
"greenville": 20967,
"##berries": 20968,
"geographically": 20969,
"nell": 20970,
"quartz": 20971,
"##athic": 20972,
"cemeteries": 20973,
"##lr": 20974,
"crossings": 20975,
"nah": 20976,
"holloway": 20977,
"reptiles": 20978,
"chun": 20979,
"sichuan": 20980,
"snowy": 20981,
"660": 20982,
"corrections": 20983,
"##ivo": 20984,
"zheng": 20985,
"ambassadors": 20986,
"blacksmith": 20987,
"fielded": 20988,
"fluids": 20989,
"hardcover": 20990,
"turnover": 20991,
"medications": 20992,
"melvin": 20993,
"academies": 20994,
"##erton": 20995,
"ro": 20996,
"roach": 20997,
"absorbing": 20998,
"spaniards": 20999,
"colton": 21000,
"##founded": 21001,
"outsider": 21002,
"espionage": 21003,
"kelsey": 21004,
"245": 21005,
"edible": 21006,
"##ulf": 21007,
"dora": 21008,
"establishes": 21009,
"##sham": 21010,
"##tries": 21011,
"contracting": 21012,
"##tania": 21013,
"cinematic": 21014,
"costello": 21015,
"nesting": 21016,
"##uron": 21017,
"connolly": 21018,
"duff": 21019,
"##nology": 21020,
"mma": 21021,
"##mata": 21022,
"fergus": 21023,
"sexes": 21024,
"gi": 21025,
"optics": 21026,
"spectator": 21027,
"woodstock": 21028,
"banning": 21029,
"##hee": 21030,
"##fle": 21031,
"differentiate": 21032,
"outfielder": 21033,
"refinery": 21034,
"226": 21035,
"312": 21036,
"gerhard": 21037,
"horde": 21038,
"lair": 21039,
"drastically": 21040,
"##udi": 21041,
"landfall": 21042,
"##cheng": 21043,
"motorsport": 21044,
"odi": 21045,
"##achi": 21046,
"predominant": 21047,
"quay": 21048,
"skins": 21049,
"##ental": 21050,
"edna": 21051,
"harshly": 21052,
"complementary": 21053,
"murdering": 21054,
"##aves": 21055,
"wreckage": 21056,
"##90": 21057,
"ono": 21058,
"outstretched": 21059,
"lennox": 21060,
"munitions": 21061,
"galen": 21062,
"reconcile": 21063,
"470": 21064,
"scalp": 21065,
"bicycles": 21066,
"gillespie": 21067,
"questionable": 21068,
"rosenberg": 21069,
"guillermo": 21070,
"hostel": 21071,
"jarvis": 21072,
"kabul": 21073,
"volvo": 21074,
"opium": 21075,
"yd": 21076,
"##twined": 21077,
"abuses": 21078,
"decca": 21079,
"outpost": 21080,
"##cino": 21081,
"sensible": 21082,
"neutrality": 21083,
"##64": 21084,
"ponce": 21085,
"anchorage": 21086,
"atkins": 21087,
"turrets": 21088,
"inadvertently": 21089,
"disagree": 21090,
"libre": 21091,
"vodka": 21092,
"reassuring": 21093,
"weighs": 21094,
"##yal": 21095,
"glide": 21096,
"jumper": 21097,
"ceilings": 21098,
"repertory": 21099,
"outs": 21100,
"stain": 21101,
"##bial": 21102,
"envy": 21103,
"##ucible": 21104,
"smashing": 21105,
"heightened": 21106,
"policing": 21107,
"hyun": 21108,
"mixes": 21109,
"lai": 21110,
"prima": 21111,
"##ples": 21112,
"celeste": 21113,
"##bina": 21114,
"lucrative": 21115,
"intervened": 21116,
"kc": 21117,
"manually": 21118,
"##rned": 21119,
"stature": 21120,
"staffed": 21121,
"bun": 21122,
"bastards": 21123,
"nairobi": 21124,
"priced": 21125,
"##auer": 21126,
"thatcher": 21127,
"##kia": 21128,
"tripped": 21129,
"comune": 21130,
"##ogan": 21131,
"##pled": 21132,
"brasil": 21133,
"incentives": 21134,
"emanuel": 21135,
"hereford": 21136,
"musica": 21137,
"##kim": 21138,
"benedictine": 21139,
"biennale": 21140,
"##lani": 21141,
"eureka": 21142,
"gardiner": 21143,
"rb": 21144,
"knocks": 21145,
"sha": 21146,
"##ael": 21147,
"##elled": 21148,
"##onate": 21149,
"efficacy": 21150,
"ventura": 21151,
"masonic": 21152,
"sanford": 21153,
"maize": 21154,
"leverage": 21155,
"##feit": 21156,
"capacities": 21157,
"santana": 21158,
"##aur": 21159,
"novelty": 21160,
"vanilla": 21161,
"##cter": 21162,
"##tour": 21163,
"benin": 21164,
"##oir": 21165,
"##rain": 21166,
"neptune": 21167,
"drafting": 21168,
"tallinn": 21169,
"##cable": 21170,
"humiliation": 21171,
"##boarding": 21172,
"schleswig": 21173,
"fabian": 21174,
"bernardo": 21175,
"liturgy": 21176,
"spectacle": 21177,
"sweeney": 21178,
"pont": 21179,
"routledge": 21180,
"##tment": 21181,
"cosmos": 21182,
"ut": 21183,
"hilt": 21184,
"sleek": 21185,
"universally": 21186,
"##eville": 21187,
"##gawa": 21188,
"typed": 21189,
"##dry": 21190,
"favors": 21191,
"allegheny": 21192,
"glaciers": 21193,
"##rly": 21194,
"recalling": 21195,
"aziz": 21196,
"##log": 21197,
"parasite": 21198,
"requiem": 21199,
"auf": 21200,
"##berto": 21201,
"##llin": 21202,
"illumination": 21203,
"##breaker": 21204,
"##issa": 21205,
"festivities": 21206,
"bows": 21207,
"govern": 21208,
"vibe": 21209,
"vp": 21210,
"333": 21211,
"sprawled": 21212,
"larson": 21213,
"pilgrim": 21214,
"bwf": 21215,
"leaping": 21216,
"##rts": 21217,
"##ssel": 21218,
"alexei": 21219,
"greyhound": 21220,
"hoarse": 21221,
"##dler": 21222,
"##oration": 21223,
"seneca": 21224,
"##cule": 21225,
"gaping": 21226,
"##ulously": 21227,
"##pura": 21228,
"cinnamon": 21229,
"##gens": 21230,
"##rricular": 21231,
"craven": 21232,
"fantasies": 21233,
"houghton": 21234,
"engined": 21235,
"reigned": 21236,
"dictator": 21237,
"supervising": 21238,
"##oris": 21239,
"bogota": 21240,
"commentaries": 21241,
"unnatural": 21242,
"fingernails": 21243,
"spirituality": 21244,
"tighten": 21245,
"##tm": 21246,
"canadiens": 21247,
"protesting": 21248,
"intentional": 21249,
"cheers": 21250,
"sparta": 21251,
"##ytic": 21252,
"##iere": 21253,
"##zine": 21254,
"widen": 21255,
"belgarath": 21256,
"controllers": 21257,
"dodd": 21258,
"iaaf": 21259,
"navarre": 21260,
"##ication": 21261,
"defect": 21262,
"squire": 21263,
"steiner": 21264,
"whisky": 21265,
"##mins": 21266,
"560": 21267,
"inevitably": 21268,
"tome": 21269,
"##gold": 21270,
"chew": 21271,
"##uid": 21272,
"##lid": 21273,
"elastic": 21274,
"##aby": 21275,
"streaked": 21276,
"alliances": 21277,
"jailed": 21278,
"regal": 21279,
"##ined": 21280,
"##phy": 21281,
"czechoslovak": 21282,
"narration": 21283,
"absently": 21284,
"##uld": 21285,
"bluegrass": 21286,
"guangdong": 21287,
"quran": 21288,
"criticizing": 21289,
"hose": 21290,
"hari": 21291,
"##liest": 21292,
"##owa": 21293,
"skier": 21294,
"streaks": 21295,
"deploy": 21296,
"##lom": 21297,
"raft": 21298,
"bose": 21299,
"dialed": 21300,
"huff": 21301,
"##eira": 21302,
"haifa": 21303,
"simplest": 21304,
"bursting": 21305,
"endings": 21306,
"ib": 21307,
"sultanate": 21308,
"##titled": 21309,
"franks": 21310,
"whitman": 21311,
"ensures": 21312,
"sven": 21313,
"##ggs": 21314,
"collaborators": 21315,
"forster": 21316,
"organising": 21317,
"ui": 21318,
"banished": 21319,
"napier": 21320,
"injustice": 21321,
"teller": 21322,
"layered": 21323,
"thump": 21324,
"##otti": 21325,
"roc": 21326,
"battleships": 21327,
"evidenced": 21328,
"fugitive": 21329,
"sadie": 21330,
"robotics": 21331,
"##roud": 21332,
"equatorial": 21333,
"geologist": 21334,
"##iza": 21335,
"yielding": 21336,
"##bron": 21337,
"##sr": 21338,
"internationale": 21339,
"mecca": 21340,
"##diment": 21341,
"sbs": 21342,
"skyline": 21343,
"toad": 21344,
"uploaded": 21345,
"reflective": 21346,
"undrafted": 21347,
"lal": 21348,
"leafs": 21349,
"bayern": 21350,
"##dai": 21351,
"lakshmi": 21352,
"shortlisted": 21353,
"##stick": 21354,
"##wicz": 21355,
"camouflage": 21356,
"donate": 21357,
"af": 21358,
"christi": 21359,
"lau": 21360,
"##acio": 21361,
"disclosed": 21362,
"nemesis": 21363,
"1761": 21364,
"assemble": 21365,
"straining": 21366,
"northamptonshire": 21367,
"tal": 21368,
"##asi": 21369,
"bernardino": 21370,
"premature": 21371,
"heidi": 21372,
"42nd": 21373,
"coefficients": 21374,
"galactic": 21375,
"reproduce": 21376,
"buzzed": 21377,
"sensations": 21378,
"zionist": 21379,
"monsieur": 21380,
"myrtle": 21381,
"##eme": 21382,
"archery": 21383,
"strangled": 21384,
"musically": 21385,
"viewpoint": 21386,
"antiquities": 21387,
"bei": 21388,
"trailers": 21389,
"seahawks": 21390,
"cured": 21391,
"pee": 21392,
"preferring": 21393,
"tasmanian": 21394,
"lange": 21395,
"sul": 21396,
"##mail": 21397,
"##working": 21398,
"colder": 21399,
"overland": 21400,
"lucivar": 21401,
"massey": 21402,
"gatherings": 21403,
"haitian": 21404,
"##smith": 21405,
"disapproval": 21406,
"flaws": 21407,
"##cco": 21408,
"##enbach": 21409,
"1766": 21410,
"npr": 21411,
"##icular": 21412,
"boroughs": 21413,
"creole": 21414,
"forums": 21415,
"techno": 21416,
"1755": 21417,
"dent": 21418,
"abdominal": 21419,
"streetcar": 21420,
"##eson": 21421,
"##stream": 21422,
"procurement": 21423,
"gemini": 21424,
"predictable": 21425,
"##tya": 21426,
"acheron": 21427,
"christoph": 21428,
"feeder": 21429,
"fronts": 21430,
"vendor": 21431,
"bernhard": 21432,
"jammu": 21433,
"tumors": 21434,
"slang": 21435,
"##uber": 21436,
"goaltender": 21437,
"twists": 21438,
"curving": 21439,
"manson": 21440,
"vuelta": 21441,
"mer": 21442,
"peanut": 21443,
"confessions": 21444,
"pouch": 21445,
"unpredictable": 21446,
"allowance": 21447,
"theodor": 21448,
"vascular": 21449,
"##factory": 21450,
"bala": 21451,
"authenticity": 21452,
"metabolic": 21453,
"coughing": 21454,
"nanjing": 21455,
"##cea": 21456,
"pembroke": 21457,
"##bard": 21458,
"splendid": 21459,
"36th": 21460,
"ff": 21461,
"hourly": 21462,
"##ahu": 21463,
"elmer": 21464,
"handel": 21465,
"##ivate": 21466,
"awarding": 21467,
"thrusting": 21468,
"dl": 21469,
"experimentation": 21470,
"##hesion": 21471,
"##46": 21472,
"caressed": 21473,
"entertained": 21474,
"steak": 21475,
"##rangle": 21476,
"biologist": 21477,
"orphans": 21478,
"baroness": 21479,
"oyster": 21480,
"stepfather": 21481,
"##dridge": 21482,
"mirage": 21483,
"reefs": 21484,
"speeding": 21485,
"##31": 21486,
"barons": 21487,
"1764": 21488,
"227": 21489,
"inhabit": 21490,
"preached": 21491,
"repealed": 21492,
"##tral": 21493,
"honoring": 21494,
"boogie": 21495,
"captives": 21496,
"administer": 21497,
"johanna": 21498,
"##imate": 21499,
"gel": 21500,
"suspiciously": 21501,
"1767": 21502,
"sobs": 21503,
"##dington": 21504,
"backbone": 21505,
"hayward": 21506,
"garry": 21507,
"##folding": 21508,
"##nesia": 21509,
"maxi": 21510,
"##oof": 21511,
"##ppe": 21512,
"ellison": 21513,
"galileo": 21514,
"##stand": 21515,
"crimea": 21516,
"frenzy": 21517,
"amour": 21518,
"bumper": 21519,
"matrices": 21520,
"natalia": 21521,
"baking": 21522,
"garth": 21523,
"palestinians": 21524,
"##grove": 21525,
"smack": 21526,
"conveyed": 21527,
"ensembles": 21528,
"gardening": 21529,
"##manship": 21530,
"##rup": 21531,
"##stituting": 21532,
"1640": 21533,
"harvesting": 21534,
"topography": 21535,
"jing": 21536,
"shifters": 21537,
"dormitory": 21538,
"##carriage": 21539,
"##lston": 21540,
"ist": 21541,
"skulls": 21542,
"##stadt": 21543,
"dolores": 21544,
"jewellery": 21545,
"sarawak": 21546,
"##wai": 21547,
"##zier": 21548,
"fences": 21549,
"christy": 21550,
"confinement": 21551,
"tumbling": 21552,
"credibility": 21553,
"fir": 21554,
"stench": 21555,
"##bria": 21556,
"##plication": 21557,
"##nged": 21558,
"##sam": 21559,
"virtues": 21560,
"##belt": 21561,
"marjorie": 21562,
"pba": 21563,
"##eem": 21564,
"##made": 21565,
"celebrates": 21566,
"schooner": 21567,
"agitated": 21568,
"barley": 21569,
"fulfilling": 21570,
"anthropologist": 21571,
"##pro": 21572,
"restrict": 21573,
"novi": 21574,
"regulating": 21575,
"##nent": 21576,
"padres": 21577,
"##rani": 21578,
"##hesive": 21579,
"loyola": 21580,
"tabitha": 21581,
"milky": 21582,
"olson": 21583,
"proprietor": 21584,
"crambidae": 21585,
"guarantees": 21586,
"intercollegiate": 21587,
"ljubljana": 21588,
"hilda": 21589,
"##sko": 21590,
"ignorant": 21591,
"hooded": 21592,
"##lts": 21593,
"sardinia": 21594,
"##lidae": 21595,
"##vation": 21596,
"frontman": 21597,
"privileged": 21598,
"witchcraft": 21599,
"##gp": 21600,
"jammed": 21601,
"laude": 21602,
"poking": 21603,
"##than": 21604,
"bracket": 21605,
"amazement": 21606,
"yunnan": 21607,
"##erus": 21608,
"maharaja": 21609,
"linnaeus": 21610,
"264": 21611,
"commissioning": 21612,
"milano": 21613,
"peacefully": 21614,
"##logies": 21615,
"akira": 21616,
"rani": 21617,
"regulator": 21618,
"##36": 21619,
"grasses": 21620,
"##rance": 21621,
"luzon": 21622,
"crows": 21623,
"compiler": 21624,
"gretchen": 21625,
"seaman": 21626,
"edouard": 21627,
"tab": 21628,
"buccaneers": 21629,
"ellington": 21630,
"hamlets": 21631,
"whig": 21632,
"socialists": 21633,
"##anto": 21634,
"directorial": 21635,
"easton": 21636,
"mythological": 21637,
"##kr": 21638,
"##vary": 21639,
"rhineland": 21640,
"semantic": 21641,
"taut": 21642,
"dune": 21643,
"inventions": 21644,
"succeeds": 21645,
"##iter": 21646,
"replication": 21647,
"branched": 21648,
"##pired": 21649,
"jul": 21650,
"prosecuted": 21651,
"kangaroo": 21652,
"penetrated": 21653,
"##avian": 21654,
"middlesbrough": 21655,
"doses": 21656,
"bleak": 21657,
"madam": 21658,
"predatory": 21659,
"relentless": 21660,
"##vili": 21661,
"reluctance": 21662,
"##vir": 21663,
"hailey": 21664,
"crore": 21665,
"silvery": 21666,
"1759": 21667,
"monstrous": 21668,
"swimmers": 21669,
"transmissions": 21670,
"hawthorn": 21671,
"informing": 21672,
"##eral": 21673,
"toilets": 21674,
"caracas": 21675,
"crouch": 21676,
"kb": 21677,
"##sett": 21678,
"295": 21679,
"cartel": 21680,
"hadley": 21681,
"##aling": 21682,
"alexia": 21683,
"yvonne": 21684,
"##biology": 21685,
"cinderella": 21686,
"eton": 21687,
"superb": 21688,
"blizzard": 21689,
"stabbing": 21690,
"industrialist": 21691,
"maximus": 21692,
"##gm": 21693,
"##orus": 21694,
"groves": 21695,
"maud": 21696,
"clade": 21697,
"oversized": 21698,
"comedic": 21699,
"##bella": 21700,
"rosen": 21701,
"nomadic": 21702,
"fulham": 21703,
"montane": 21704,
"beverages": 21705,
"galaxies": 21706,
"redundant": 21707,
"swarm": 21708,
"##rot": 21709,
"##folia": 21710,
"##llis": 21711,
"buckinghamshire": 21712,
"fen": 21713,
"bearings": 21714,
"bahadur": 21715,
"##rom": 21716,
"gilles": 21717,
"phased": 21718,
"dynamite": 21719,
"faber": 21720,
"benoit": 21721,
"vip": 21722,
"##ount": 21723,
"##wd": 21724,
"booking": 21725,
"fractured": 21726,
"tailored": 21727,
"anya": 21728,
"spices": 21729,
"westwood": 21730,
"cairns": 21731,
"auditions": 21732,
"inflammation": 21733,
"steamed": 21734,
"##rocity": 21735,
"##acion": 21736,
"##urne": 21737,
"skyla": 21738,
"thereof": 21739,
"watford": 21740,
"torment": 21741,
"archdeacon": 21742,
"transforms": 21743,
"lulu": 21744,
"demeanor": 21745,
"fucked": 21746,
"serge": 21747,
"##sor": 21748,
"mckenna": 21749,
"minas": 21750,
"entertainer": 21751,
"##icide": 21752,
"caress": 21753,
"originate": 21754,
"residue": 21755,
"##sty": 21756,
"1740": 21757,
"##ilised": 21758,
"##org": 21759,
"beech": 21760,
"##wana": 21761,
"subsidies": 21762,
"##ghton": 21763,
"emptied": 21764,
"gladstone": 21765,
"ru": 21766,
"firefighters": 21767,
"voodoo": 21768,
"##rcle": 21769,
"het": 21770,
"nightingale": 21771,
"tamara": 21772,
"edmond": 21773,
"ingredient": 21774,
"weaknesses": 21775,
"silhouette": 21776,
"285": 21777,
"compatibility": 21778,
"withdrawing": 21779,
"hampson": 21780,
"##mona": 21781,
"anguish": 21782,
"giggling": 21783,
"##mber": 21784,
"bookstore": 21785,
"##jiang": 21786,
"southernmost": 21787,
"tilting": 21788,
"##vance": 21789,
"bai": 21790,
"economical": 21791,
"rf": 21792,
"briefcase": 21793,
"dreadful": 21794,
"hinted": 21795,
"projections": 21796,
"shattering": 21797,
"totaling": 21798,
"##rogate": 21799,
"analogue": 21800,
"indicted": 21801,
"periodical": 21802,
"fullback": 21803,
"##dman": 21804,
"haynes": 21805,
"##tenberg": 21806,
"##ffs": 21807,
"##ishment": 21808,
"1745": 21809,
"thirst": 21810,
"stumble": 21811,
"penang": 21812,
"vigorous": 21813,
"##ddling": 21814,
"##kor": 21815,
"##lium": 21816,
"octave": 21817,
"##ove": 21818,
"##enstein": 21819,
"##inen": 21820,
"##ones": 21821,
"siberian": 21822,
"##uti": 21823,
"cbn": 21824,
"repeal": 21825,
"swaying": 21826,
"##vington": 21827,
"khalid": 21828,
"tanaka": 21829,
"unicorn": 21830,
"otago": 21831,
"plastered": 21832,
"lobe": 21833,
"riddle": 21834,
"##rella": 21835,
"perch": 21836,
"##ishing": 21837,
"croydon": 21838,
"filtered": 21839,
"graeme": 21840,
"tripoli": 21841,
"##ossa": 21842,
"crocodile": 21843,
"##chers": 21844,
"sufi": 21845,
"mined": 21846,
"##tung": 21847,
"inferno": 21848,
"lsu": 21849,
"##phi": 21850,
"swelled": 21851,
"utilizes": 21852,
"£2": 21853,
"cale": 21854,
"periodicals": 21855,
"styx": 21856,
"hike": 21857,
"informally": 21858,
"coop": 21859,
"lund": 21860,
"##tidae": 21861,
"ala": 21862,
"hen": 21863,
"qui": 21864,
"transformations": 21865,
"disposed": 21866,
"sheath": 21867,
"chickens": 21868,
"##cade": 21869,
"fitzroy": 21870,
"sas": 21871,
"silesia": 21872,
"unacceptable": 21873,
"odisha": 21874,
"1650": 21875,
"sabrina": 21876,
"pe": 21877,
"spokane": 21878,
"ratios": 21879,
"athena": 21880,
"massage": 21881,
"shen": 21882,
"dilemma": 21883,
"##drum": 21884,
"##riz": 21885,
"##hul": 21886,
"corona": 21887,
"doubtful": 21888,
"niall": 21889,
"##pha": 21890,
"##bino": 21891,
"fines": 21892,
"cite": 21893,
"acknowledging": 21894,
"bangor": 21895,
"ballard": 21896,
"bathurst": 21897,
"##resh": 21898,
"huron": 21899,
"mustered": 21900,
"alzheimer": 21901,
"garments": 21902,
"kinase": 21903,
"tyre": 21904,
"warship": 21905,
"##cp": 21906,
"flashback": 21907,
"pulmonary": 21908,
"braun": 21909,
"cheat": 21910,
"kamal": 21911,
"cyclists": 21912,
"constructions": 21913,
"grenades": 21914,
"ndp": 21915,
"traveller": 21916,
"excuses": 21917,
"stomped": 21918,
"signalling": 21919,
"trimmed": 21920,
"futsal": 21921,
"mosques": 21922,
"relevance": 21923,
"##wine": 21924,
"wta": 21925,
"##23": 21926,
"##vah": 21927,
"##lter": 21928,
"hoc": 21929,
"##riding": 21930,
"optimistic": 21931,
"##´s": 21932,
"deco": 21933,
"sim": 21934,
"interacting": 21935,
"rejecting": 21936,
"moniker": 21937,
"waterways": 21938,
"##ieri": 21939,
"##oku": 21940,
"mayors": 21941,
"gdansk": 21942,
"outnumbered": 21943,
"pearls": 21944,
"##ended": 21945,
"##hampton": 21946,
"fairs": 21947,
"totals": 21948,
"dominating": 21949,
"262": 21950,
"notions": 21951,
"stairway": 21952,
"compiling": 21953,
"pursed": 21954,
"commodities": 21955,
"grease": 21956,
"yeast": 21957,
"##jong": 21958,
"carthage": 21959,
"griffiths": 21960,
"residual": 21961,
"amc": 21962,
"contraction": 21963,
"laird": 21964,
"sapphire": 21965,
"##marine": 21966,
"##ivated": 21967,
"amalgamation": 21968,
"dissolve": 21969,
"inclination": 21970,
"lyle": 21971,
"packaged": 21972,
"altitudes": 21973,
"suez": 21974,
"canons": 21975,
"graded": 21976,
"lurched": 21977,
"narrowing": 21978,
"boasts": 21979,
"guise": 21980,
"wed": 21981,
"enrico": 21982,
"##ovsky": 21983,
"rower": 21984,
"scarred": 21985,
"bree": 21986,
"cub": 21987,
"iberian": 21988,
"protagonists": 21989,
"bargaining": 21990,
"proposing": 21991,
"trainers": 21992,
"voyages": 21993,
"vans": 21994,
"fishes": 21995,
"##aea": 21996,
"##ivist": 21997,
"##verance": 21998,
"encryption": 21999,
"artworks": 22000,
"kazan": 22001,
"sabre": 22002,
"cleopatra": 22003,
"hepburn": 22004,
"rotting": 22005,
"supremacy": 22006,
"mecklenburg": 22007,
"##brate": 22008,
"burrows": 22009,
"hazards": 22010,
"outgoing": 22011,
"flair": 22012,
"organizes": 22013,
"##ctions": 22014,
"scorpion": 22015,
"##usions": 22016,
"boo": 22017,
"234": 22018,
"chevalier": 22019,
"dunedin": 22020,
"slapping": 22021,
"##34": 22022,
"ineligible": 22023,
"pensions": 22024,
"##38": 22025,
"##omic": 22026,
"manufactures": 22027,
"emails": 22028,
"bismarck": 22029,
"238": 22030,
"weakening": 22031,
"blackish": 22032,
"ding": 22033,
"mcgee": 22034,
"quo": 22035,
"##rling": 22036,
"northernmost": 22037,
"xx": 22038,
"manpower": 22039,
"greed": 22040,
"sampson": 22041,
"clicking": 22042,
"##ange": 22043,
"##horpe": 22044,
"##inations": 22045,
"##roving": 22046,
"torre": 22047,
"##eptive": 22048,
"##moral": 22049,
"symbolism": 22050,
"38th": 22051,
"asshole": 22052,
"meritorious": 22053,
"outfits": 22054,
"splashed": 22055,
"biographies": 22056,
"sprung": 22057,
"astros": 22058,
"##tale": 22059,
"302": 22060,
"737": 22061,
"filly": 22062,
"raoul": 22063,
"nw": 22064,
"tokugawa": 22065,
"linden": 22066,
"clubhouse": 22067,
"##apa": 22068,
"tracts": 22069,
"romano": 22070,
"##pio": 22071,
"putin": 22072,
"tags": 22073,
"##note": 22074,
"chained": 22075,
"dickson": 22076,
"gunshot": 22077,
"moe": 22078,
"gunn": 22079,
"rashid": 22080,
"##tails": 22081,
"zipper": 22082,
"##bas": 22083,
"##nea": 22084,
"contrasted": 22085,
"##ply": 22086,
"##udes": 22087,
"plum": 22088,
"pharaoh": 22089,
"##pile": 22090,
"aw": 22091,
"comedies": 22092,
"ingrid": 22093,
"sandwiches": 22094,
"subdivisions": 22095,
"1100": 22096,
"mariana": 22097,
"nokia": 22098,
"kamen": 22099,
"hz": 22100,
"delaney": 22101,
"veto": 22102,
"herring": 22103,
"##words": 22104,
"possessive": 22105,
"outlines": 22106,
"##roup": 22107,
"siemens": 22108,
"stairwell": 22109,
"rc": 22110,
"gallantry": 22111,
"messiah": 22112,
"palais": 22113,
"yells": 22114,
"233": 22115,
"zeppelin": 22116,
"##dm": 22117,
"bolivar": 22118,
"##cede": 22119,
"smackdown": 22120,
"mckinley": 22121,
"##mora": 22122,
"##yt": 22123,
"muted": 22124,
"geologic": 22125,
"finely": 22126,
"unitary": 22127,
"avatar": 22128,
"hamas": 22129,
"maynard": 22130,
"rees": 22131,
"bog": 22132,
"contrasting": 22133,
"##rut": 22134,
"liv": 22135,
"chico": 22136,
"disposition": 22137,
"pixel": 22138,
"##erate": 22139,
"becca": 22140,
"dmitry": 22141,
"yeshiva": 22142,
"narratives": 22143,
"##lva": 22144,
"##ulton": 22145,
"mercenary": 22146,
"sharpe": 22147,
"tempered": 22148,
"navigate": 22149,
"stealth": 22150,
"amassed": 22151,
"keynes": 22152,
"##lini": 22153,
"untouched": 22154,
"##rrie": 22155,
"havoc": 22156,
"lithium": 22157,
"##fighting": 22158,
"abyss": 22159,
"graf": 22160,
"southward": 22161,
"wolverine": 22162,
"balloons": 22163,
"implements": 22164,
"ngos": 22165,
"transitions": 22166,
"##icum": 22167,
"ambushed": 22168,
"concacaf": 22169,
"dormant": 22170,
"economists": 22171,
"##dim": 22172,
"costing": 22173,
"csi": 22174,
"rana": 22175,
"universite": 22176,
"boulders": 22177,
"verity": 22178,
"##llon": 22179,
"collin": 22180,
"mellon": 22181,
"misses": 22182,
"cypress": 22183,
"fluorescent": 22184,
"lifeless": 22185,
"spence": 22186,
"##ulla": 22187,
"crewe": 22188,
"shepard": 22189,
"pak": 22190,
"revelations": 22191,
"##م": 22192,
"jolly": 22193,
"gibbons": 22194,
"paw": 22195,
"##dro": 22196,
"##quel": 22197,
"freeing": 22198,
"##test": 22199,
"shack": 22200,
"fries": 22201,
"palatine": 22202,
"##51": 22203,
"##hiko": 22204,
"accompaniment": 22205,
"cruising": 22206,
"recycled": 22207,
"##aver": 22208,
"erwin": 22209,
"sorting": 22210,
"synthesizers": 22211,
"dyke": 22212,
"realities": 22213,
"sg": 22214,
"strides": 22215,
"enslaved": 22216,
"wetland": 22217,
"##ghan": 22218,
"competence": 22219,
"gunpowder": 22220,
"grassy": 22221,
"maroon": 22222,
"reactors": 22223,
"objection": 22224,
"##oms": 22225,
"carlson": 22226,
"gearbox": 22227,
"macintosh": 22228,
"radios": 22229,
"shelton": 22230,
"##sho": 22231,
"clergyman": 22232,
"prakash": 22233,
"254": 22234,
"mongols": 22235,
"trophies": 22236,
"oricon": 22237,
"228": 22238,
"stimuli": 22239,
"twenty20": 22240,
"cantonese": 22241,
"cortes": 22242,
"mirrored": 22243,
"##saurus": 22244,
"bhp": 22245,
"cristina": 22246,
"melancholy": 22247,
"##lating": 22248,
"enjoyable": 22249,
"nuevo": 22250,
"##wny": 22251,
"downfall": 22252,
"schumacher": 22253,
"##ind": 22254,
"banging": 22255,
"lausanne": 22256,
"rumbled": 22257,
"paramilitary": 22258,
"reflex": 22259,
"ax": 22260,
"amplitude": 22261,
"migratory": 22262,
"##gall": 22263,
"##ups": 22264,
"midi": 22265,
"barnard": 22266,
"lastly": 22267,
"sherry": 22268,
"##hp": 22269,
"##nall": 22270,
"keystone": 22271,
"##kra": 22272,
"carleton": 22273,
"slippery": 22274,
"##53": 22275,
"coloring": 22276,
"foe": 22277,
"socket": 22278,
"otter": 22279,
"##rgos": 22280,
"mats": 22281,
"##tose": 22282,
"consultants": 22283,
"bafta": 22284,
"bison": 22285,
"topping": 22286,
"##km": 22287,
"490": 22288,
"primal": 22289,
"abandonment": 22290,
"transplant": 22291,
"atoll": 22292,
"hideous": 22293,
"mort": 22294,
"pained": 22295,
"reproduced": 22296,
"tae": 22297,
"howling": 22298,
"##turn": 22299,
"unlawful": 22300,
"billionaire": 22301,
"hotter": 22302,
"poised": 22303,
"lansing": 22304,
"##chang": 22305,
"dinamo": 22306,
"retro": 22307,
"messing": 22308,
"nfc": 22309,
"domesday": 22310,
"##mina": 22311,
"blitz": 22312,
"timed": 22313,
"##athing": 22314,
"##kley": 22315,
"ascending": 22316,
"gesturing": 22317,
"##izations": 22318,
"signaled": 22319,
"tis": 22320,
"chinatown": 22321,
"mermaid": 22322,
"savanna": 22323,
"jameson": 22324,
"##aint": 22325,
"catalina": 22326,
"##pet": 22327,
"##hers": 22328,
"cochrane": 22329,
"cy": 22330,
"chatting": 22331,
"##kus": 22332,
"alerted": 22333,
"computation": 22334,
"mused": 22335,
"noelle": 22336,
"majestic": 22337,
"mohawk": 22338,
"campo": 22339,
"octagonal": 22340,
"##sant": 22341,
"##hend": 22342,
"241": 22343,
"aspiring": 22344,
"##mart": 22345,
"comprehend": 22346,
"iona": 22347,
"paralyzed": 22348,
"shimmering": 22349,
"swindon": 22350,
"rhone": 22351,
"##eley": 22352,
"reputed": 22353,
"configurations": 22354,
"pitchfork": 22355,
"agitation": 22356,
"francais": 22357,
"gillian": 22358,
"lipstick": 22359,
"##ilo": 22360,
"outsiders": 22361,
"pontifical": 22362,
"resisting": 22363,
"bitterness": 22364,
"sewer": 22365,
"rockies": 22366,
"##edd": 22367,
"##ucher": 22368,
"misleading": 22369,
"1756": 22370,
"exiting": 22371,
"galloway": 22372,
"##nging": 22373,
"risked": 22374,
"##heart": 22375,
"246": 22376,
"commemoration": 22377,
"schultz": 22378,
"##rka": 22379,
"integrating": 22380,
"##rsa": 22381,
"poses": 22382,
"shrieked": 22383,
"##weiler": 22384,
"guineas": 22385,
"gladys": 22386,
"jerking": 22387,
"owls": 22388,
"goldsmith": 22389,
"nightly": 22390,
"penetrating": 22391,
"##unced": 22392,
"lia": 22393,
"##33": 22394,
"ignited": 22395,
"betsy": 22396,
"##aring": 22397,
"##thorpe": 22398,
"follower": 22399,
"vigorously": 22400,
"##rave": 22401,
"coded": 22402,
"kiran": 22403,
"knit": 22404,
"zoology": 22405,
"tbilisi": 22406,
"##28": 22407,
"##bered": 22408,
"repository": 22409,
"govt": 22410,
"deciduous": 22411,
"dino": 22412,
"growling": 22413,
"##bba": 22414,
"enhancement": 22415,
"unleashed": 22416,
"chanting": 22417,
"pussy": 22418,
"biochemistry": 22419,
"##eric": 22420,
"kettle": 22421,
"repression": 22422,
"toxicity": 22423,
"nrhp": 22424,
"##arth": 22425,
"##kko": 22426,
"##bush": 22427,
"ernesto": 22428,
"commended": 22429,
"outspoken": 22430,
"242": 22431,
"mca": 22432,
"parchment": 22433,
"sms": 22434,
"kristen": 22435,
"##aton": 22436,
"bisexual": 22437,
"raked": 22438,
"glamour": 22439,
"navajo": 22440,
"a2": 22441,
"conditioned": 22442,
"showcased": 22443,
"##hma": 22444,
"spacious": 22445,
"youthful": 22446,
"##esa": 22447,
"usl": 22448,
"appliances": 22449,
"junta": 22450,
"brest": 22451,
"layne": 22452,
"conglomerate": 22453,
"enchanted": 22454,
"chao": 22455,
"loosened": 22456,
"picasso": 22457,
"circulating": 22458,
"inspect": 22459,
"montevideo": 22460,
"##centric": 22461,
"##kti": 22462,
"piazza": 22463,
"spurred": 22464,
"##aith": 22465,
"bari": 22466,
"freedoms": 22467,
"poultry": 22468,
"stamford": 22469,
"lieu": 22470,
"##ect": 22471,
"indigo": 22472,
"sarcastic": 22473,
"bahia": 22474,
"stump": 22475,
"attach": 22476,
"dvds": 22477,
"frankenstein": 22478,
"lille": 22479,
"approx": 22480,
"scriptures": 22481,
"pollen": 22482,
"##script": 22483,
"nmi": 22484,
"overseen": 22485,
"##ivism": 22486,
"tides": 22487,
"proponent": 22488,
"newmarket": 22489,
"inherit": 22490,
"milling": 22491,
"##erland": 22492,
"centralized": 22493,
"##rou": 22494,
"distributors": 22495,
"credentials": 22496,
"drawers": 22497,
"abbreviation": 22498,
"##lco": 22499,
"##xon": 22500,
"downing": 22501,
"uncomfortably": 22502,
"ripe": 22503,
"##oes": 22504,
"erase": 22505,
"franchises": 22506,
"##ever": 22507,
"populace": 22508,
"##bery": 22509,
"##khar": 22510,
"decomposition": 22511,
"pleas": 22512,
"##tet": 22513,
"daryl": 22514,
"sabah": 22515,
"##stle": 22516,
"##wide": 22517,
"fearless": 22518,
"genie": 22519,
"lesions": 22520,
"annette": 22521,
"##ogist": 22522,
"oboe": 22523,
"appendix": 22524,
"nair": 22525,
"dripped": 22526,
"petitioned": 22527,
"maclean": 22528,
"mosquito": 22529,
"parrot": 22530,
"rpg": 22531,
"hampered": 22532,
"1648": 22533,
"operatic": 22534,
"reservoirs": 22535,
"##tham": 22536,
"irrelevant": 22537,
"jolt": 22538,
"summarized": 22539,
"##fp": 22540,
"medallion": 22541,
"##taff": 22542,
"##−": 22543,
"clawed": 22544,
"harlow": 22545,
"narrower": 22546,
"goddard": 22547,
"marcia": 22548,
"bodied": 22549,
"fremont": 22550,
"suarez": 22551,
"altering": 22552,
"tempest": 22553,
"mussolini": 22554,
"porn": 22555,
"##isms": 22556,
"sweetly": 22557,
"oversees": 22558,
"walkers": 22559,
"solitude": 22560,
"grimly": 22561,
"shrines": 22562,
"hk": 22563,
"ich": 22564,
"supervisors": 22565,
"hostess": 22566,
"dietrich": 22567,
"legitimacy": 22568,
"brushes": 22569,
"expressive": 22570,
"##yp": 22571,
"dissipated": 22572,
"##rse": 22573,
"localized": 22574,
"systemic": 22575,
"##nikov": 22576,
"gettysburg": 22577,
"##js": 22578,
"##uaries": 22579,
"dialogues": 22580,
"muttering": 22581,
"251": 22582,
"housekeeper": 22583,
"sicilian": 22584,
"discouraged": 22585,
"##frey": 22586,
"beamed": 22587,
"kaladin": 22588,
"halftime": 22589,
"kidnap": 22590,
"##amo": 22591,
"##llet": 22592,
"1754": 22593,
"synonymous": 22594,
"depleted": 22595,
"instituto": 22596,
"insulin": 22597,
"reprised": 22598,
"##opsis": 22599,
"clashed": 22600,
"##ctric": 22601,
"interrupting": 22602,
"radcliffe": 22603,
"insisting": 22604,
"medici": 22605,
"1715": 22606,
"ejected": 22607,
"playfully": 22608,
"turbulent": 22609,
"##47": 22610,
"starvation": 22611,
"##rini": 22612,
"shipment": 22613,
"rebellious": 22614,
"petersen": 22615,
"verification": 22616,
"merits": 22617,
"##rified": 22618,
"cakes": 22619,
"##charged": 22620,
"1757": 22621,
"milford": 22622,
"shortages": 22623,
"spying": 22624,
"fidelity": 22625,
"##aker": 22626,
"emitted": 22627,
"storylines": 22628,
"harvested": 22629,
"seismic": 22630,
"##iform": 22631,
"cheung": 22632,
"kilda": 22633,
"theoretically": 22634,
"barbie": 22635,
"lynx": 22636,
"##rgy": 22637,
"##tius": 22638,
"goblin": 22639,
"mata": 22640,
"poisonous": 22641,
"##nburg": 22642,
"reactive": 22643,
"residues": 22644,
"obedience": 22645,
"##евич": 22646,
"conjecture": 22647,
"##rac": 22648,
"401": 22649,
"hating": 22650,
"sixties": 22651,
"kicker": 22652,
"moaning": 22653,
"motown": 22654,
"##bha": 22655,
"emancipation": 22656,
"neoclassical": 22657,
"##hering": 22658,
"consoles": 22659,
"ebert": 22660,
"professorship": 22661,
"##tures": 22662,
"sustaining": 22663,
"assaults": 22664,
"obeyed": 22665,
"affluent": 22666,
"incurred": 22667,
"tornadoes": 22668,
"##eber": 22669,
"##zow": 22670,
"emphasizing": 22671,
"highlanders": 22672,
"cheated": 22673,
"helmets": 22674,
"##ctus": 22675,
"internship": 22676,
"terence": 22677,
"bony": 22678,
"executions": 22679,
"legislators": 22680,
"berries": 22681,
"peninsular": 22682,
"tinged": 22683,
"##aco": 22684,
"1689": 22685,
"amplifier": 22686,
"corvette": 22687,
"ribbons": 22688,
"lavish": 22689,
"pennant": 22690,
"##lander": 22691,
"worthless": 22692,
"##chfield": 22693,
"##forms": 22694,
"mariano": 22695,
"pyrenees": 22696,
"expenditures": 22697,
"##icides": 22698,
"chesterfield": 22699,
"mandir": 22700,
"tailor": 22701,
"39th": 22702,
"sergey": 22703,
"nestled": 22704,
"willed": 22705,
"aristocracy": 22706,
"devotees": 22707,
"goodnight": 22708,
"raaf": 22709,
"rumored": 22710,
"weaponry": 22711,
"remy": 22712,
"appropriations": 22713,
"harcourt": 22714,
"burr": 22715,
"riaa": 22716,
"##lence": 22717,
"limitation": 22718,
"unnoticed": 22719,
"guo": 22720,
"soaking": 22721,
"swamps": 22722,
"##tica": 22723,
"collapsing": 22724,
"tatiana": 22725,
"descriptive": 22726,
"brigham": 22727,
"psalm": 22728,
"##chment": 22729,
"maddox": 22730,
"##lization": 22731,
"patti": 22732,
"caliph": 22733,
"##aja": 22734,
"akron": 22735,
"injuring": 22736,
"serra": 22737,
"##ganj": 22738,
"basins": 22739,
"##sari": 22740,
"astonished": 22741,
"launcher": 22742,
"##church": 22743,
"hilary": 22744,
"wilkins": 22745,
"sewing": 22746,
"##sf": 22747,
"stinging": 22748,
"##fia": 22749,
"##ncia": 22750,
"underwood": 22751,
"startup": 22752,
"##ition": 22753,
"compilations": 22754,
"vibrations": 22755,
"embankment": 22756,
"jurist": 22757,
"##nity": 22758,
"bard": 22759,
"juventus": 22760,
"groundwater": 22761,
"kern": 22762,
"palaces": 22763,
"helium": 22764,
"boca": 22765,
"cramped": 22766,
"marissa": 22767,
"soto": 22768,
"##worm": 22769,
"jae": 22770,
"princely": 22771,
"##ggy": 22772,
"faso": 22773,
"bazaar": 22774,
"warmly": 22775,
"##voking": 22776,
"229": 22777,
"pairing": 22778,
"##lite": 22779,
"##grate": 22780,
"##nets": 22781,
"wien": 22782,
"freaked": 22783,
"ulysses": 22784,
"rebirth": 22785,
"##alia": 22786,
"##rent": 22787,
"mummy": 22788,
"guzman": 22789,
"jimenez": 22790,
"stilled": 22791,
"##nitz": 22792,
"trajectory": 22793,
"tha": 22794,
"woken": 22795,
"archival": 22796,
"professions": 22797,
"##pts": 22798,
"##pta": 22799,
"hilly": 22800,
"shadowy": 22801,
"shrink": 22802,
"##bolt": 22803,
"norwood": 22804,
"glued": 22805,
"migrate": 22806,
"stereotypes": 22807,
"devoid": 22808,
"##pheus": 22809,
"625": 22810,
"evacuate": 22811,
"horrors": 22812,
"infancy": 22813,
"gotham": 22814,
"knowles": 22815,
"optic": 22816,
"downloaded": 22817,
"sachs": 22818,
"kingsley": 22819,
"parramatta": 22820,
"darryl": 22821,
"mor": 22822,
"##onale": 22823,
"shady": 22824,
"commence": 22825,
"confesses": 22826,
"kan": 22827,
"##meter": 22828,
"##placed": 22829,
"marlborough": 22830,
"roundabout": 22831,
"regents": 22832,
"frigates": 22833,
"io": 22834,
"##imating": 22835,
"gothenburg": 22836,
"revoked": 22837,
"carvings": 22838,
"clockwise": 22839,
"convertible": 22840,
"intruder": 22841,
"##sche": 22842,
"banged": 22843,
"##ogo": 22844,
"vicky": 22845,
"bourgeois": 22846,
"##mony": 22847,
"dupont": 22848,
"footing": 22849,
"##gum": 22850,
"pd": 22851,
"##real": 22852,
"buckle": 22853,
"yun": 22854,
"penthouse": 22855,
"sane": 22856,
"720": 22857,
"serviced": 22858,
"stakeholders": 22859,
"neumann": 22860,
"bb": 22861,
"##eers": 22862,
"comb": 22863,
"##gam": 22864,
"catchment": 22865,
"pinning": 22866,
"rallies": 22867,
"typing": 22868,
"##elles": 22869,
"forefront": 22870,
"freiburg": 22871,
"sweetie": 22872,
"giacomo": 22873,
"widowed": 22874,
"goodwill": 22875,
"worshipped": 22876,
"aspirations": 22877,
"midday": 22878,
"##vat": 22879,
"fishery": 22880,
"##trick": 22881,
"bournemouth": 22882,
"turk": 22883,
"243": 22884,
"hearth": 22885,
"ethanol": 22886,
"guadalajara": 22887,
"murmurs": 22888,
"sl": 22889,
"##uge": 22890,
"afforded": 22891,
"scripted": 22892,
"##hta": 22893,
"wah": 22894,
"##jn": 22895,
"coroner": 22896,
"translucent": 22897,
"252": 22898,
"memorials": 22899,
"puck": 22900,
"progresses": 22901,
"clumsy": 22902,
"##race": 22903,
"315": 22904,
"candace": 22905,
"recounted": 22906,
"##27": 22907,
"##slin": 22908,
"##uve": 22909,
"filtering": 22910,
"##mac": 22911,
"howl": 22912,
"strata": 22913,
"heron": 22914,
"leveled": 22915,
"##ays": 22916,
"dubious": 22917,
"##oja": 22918,
"##т": 22919,
"##wheel": 22920,
"citations": 22921,
"exhibiting": 22922,
"##laya": 22923,
"##mics": 22924,
"##pods": 22925,
"turkic": 22926,
"##lberg": 22927,
"injunction": 22928,
"##ennial": 22929,
"##mit": 22930,
"antibodies": 22931,
"##44": 22932,
"organise": 22933,
"##rigues": 22934,
"cardiovascular": 22935,
"cushion": 22936,
"inverness": 22937,
"##zquez": 22938,
"dia": 22939,
"cocoa": 22940,
"sibling": 22941,
"##tman": 22942,
"##roid": 22943,
"expanse": 22944,
"feasible": 22945,
"tunisian": 22946,
"algiers": 22947,
"##relli": 22948,
"rus": 22949,
"bloomberg": 22950,
"dso": 22951,
"westphalia": 22952,
"bro": 22953,
"tacoma": 22954,
"281": 22955,
"downloads": 22956,
"##ours": 22957,
"konrad": 22958,
"duran": 22959,
"##hdi": 22960,
"continuum": 22961,
"jett": 22962,
"compares": 22963,
"legislator": 22964,
"secession": 22965,
"##nable": 22966,
"##gues": 22967,
"##zuka": 22968,
"translating": 22969,
"reacher": 22970,
"##gley": 22971,
"##ła": 22972,
"aleppo": 22973,
"##agi": 22974,
"tc": 22975,
"orchards": 22976,
"trapping": 22977,
"linguist": 22978,
"versatile": 22979,
"drumming": 22980,
"postage": 22981,
"calhoun": 22982,
"superiors": 22983,
"##mx": 22984,
"barefoot": 22985,
"leary": 22986,
"##cis": 22987,
"ignacio": 22988,
"alfa": 22989,
"kaplan": 22990,
"##rogen": 22991,
"bratislava": 22992,
"mori": 22993,
"##vot": 22994,
"disturb": 22995,
"haas": 22996,
"313": 22997,
"cartridges": 22998,
"gilmore": 22999,
"radiated": 23000,
"salford": 23001,
"tunic": 23002,
"hades": 23003,
"##ulsive": 23004,
"archeological": 23005,
"delilah": 23006,
"magistrates": 23007,
"auditioned": 23008,
"brewster": 23009,
"charters": 23010,
"empowerment": 23011,
"blogs": 23012,
"cappella": 23013,
"dynasties": 23014,
"iroquois": 23015,
"whipping": 23016,
"##krishna": 23017,
"raceway": 23018,
"truths": 23019,
"myra": 23020,
"weaken": 23021,
"judah": 23022,
"mcgregor": 23023,
"##horse": 23024,
"mic": 23025,
"refueling": 23026,
"37th": 23027,
"burnley": 23028,
"bosses": 23029,
"markus": 23030,
"premio": 23031,
"query": 23032,
"##gga": 23033,
"dunbar": 23034,
"##economic": 23035,
"darkest": 23036,
"lyndon": 23037,
"sealing": 23038,
"commendation": 23039,
"reappeared": 23040,
"##mun": 23041,
"addicted": 23042,
"ezio": 23043,
"slaughtered": 23044,
"satisfactory": 23045,
"shuffle": 23046,
"##eves": 23047,
"##thic": 23048,
"##uj": 23049,
"fortification": 23050,
"warrington": 23051,
"##otto": 23052,
"resurrected": 23053,
"fargo": 23054,
"mane": 23055,
"##utable": 23056,
"##lei": 23057,
"##space": 23058,
"foreword": 23059,
"ox": 23060,
"##aris": 23061,
"##vern": 23062,
"abrams": 23063,
"hua": 23064,
"##mento": 23065,
"sakura": 23066,
"##alo": 23067,
"uv": 23068,
"sentimental": 23069,
"##skaya": 23070,
"midfield": 23071,
"##eses": 23072,
"sturdy": 23073,
"scrolls": 23074,
"macleod": 23075,
"##kyu": 23076,
"entropy": 23077,
"##lance": 23078,
"mitochondrial": 23079,
"cicero": 23080,
"excelled": 23081,
"thinner": 23082,
"convoys": 23083,
"perceive": 23084,
"##oslav": 23085,
"##urable": 23086,
"systematically": 23087,
"grind": 23088,
"burkina": 23089,
"287": 23090,
"##tagram": 23091,
"ops": 23092,
"##aman": 23093,
"guantanamo": 23094,
"##cloth": 23095,
"##tite": 23096,
"forcefully": 23097,
"wavy": 23098,
"##jou": 23099,
"pointless": 23100,
"##linger": 23101,
"##tze": 23102,
"layton": 23103,
"portico": 23104,
"superficial": 23105,
"clerical": 23106,
"outlaws": 23107,
"##hism": 23108,
"burials": 23109,
"muir": 23110,
"##inn": 23111,
"creditors": 23112,
"hauling": 23113,
"rattle": 23114,
"##leg": 23115,
"calais": 23116,
"monde": 23117,
"archers": 23118,
"reclaimed": 23119,
"dwell": 23120,
"wexford": 23121,
"hellenic": 23122,
"falsely": 23123,
"remorse": 23124,
"##tek": 23125,
"dough": 23126,
"furnishings": 23127,
"##uttered": 23128,
"gabon": 23129,
"neurological": 23130,
"novice": 23131,
"##igraphy": 23132,
"contemplated": 23133,
"pulpit": 23134,
"nightstand": 23135,
"saratoga": 23136,
"##istan": 23137,
"documenting": 23138,
"pulsing": 23139,
"taluk": 23140,
"##firmed": 23141,
"busted": 23142,
"marital": 23143,
"##rien": 23144,
"disagreements": 23145,
"wasps": 23146,
"##yes": 23147,
"hodge": 23148,
"mcdonnell": 23149,
"mimic": 23150,
"fran": 23151,
"pendant": 23152,
"dhabi": 23153,
"musa": 23154,
"##nington": 23155,
"congratulations": 23156,
"argent": 23157,
"darrell": 23158,
"concussion": 23159,
"losers": 23160,
"regrets": 23161,
"thessaloniki": 23162,
"reversal": 23163,
"donaldson": 23164,
"hardwood": 23165,
"thence": 23166,
"achilles": 23167,
"ritter": 23168,
"##eran": 23169,
"demonic": 23170,
"jurgen": 23171,
"prophets": 23172,
"goethe": 23173,
"eki": 23174,
"classmate": 23175,
"buff": 23176,
"##cking": 23177,
"yank": 23178,
"irrational": 23179,
"##inging": 23180,
"perished": 23181,
"seductive": 23182,
"qur": 23183,
"sourced": 23184,
"##crat": 23185,
"##typic": 23186,
"mustard": 23187,
"ravine": 23188,
"barre": 23189,
"horizontally": 23190,
"characterization": 23191,
"phylogenetic": 23192,
"boise": 23193,
"##dit": 23194,
"##runner": 23195,
"##tower": 23196,
"brutally": 23197,
"intercourse": 23198,
"seduce": 23199,
"##bbing": 23200,
"fay": 23201,
"ferris": 23202,
"ogden": 23203,
"amar": 23204,
"nik": 23205,
"unarmed": 23206,
"##inator": 23207,
"evaluating": 23208,
"kyrgyzstan": 23209,
"sweetness": 23210,
"##lford": 23211,
"##oki": 23212,
"mccormick": 23213,
"meiji": 23214,
"notoriety": 23215,
"stimulate": 23216,
"disrupt": 23217,
"figuring": 23218,
"instructional": 23219,
"mcgrath": 23220,
"##zoo": 23221,
"groundbreaking": 23222,
"##lto": 23223,
"flinch": 23224,
"khorasan": 23225,
"agrarian": 23226,
"bengals": 23227,
"mixer": 23228,
"radiating": 23229,
"##sov": 23230,
"ingram": 23231,
"pitchers": 23232,
"nad": 23233,
"tariff": 23234,
"##cript": 23235,
"tata": 23236,
"##codes": 23237,
"##emi": 23238,
"##ungen": 23239,
"appellate": 23240,
"lehigh": 23241,
"##bled": 23242,
"##giri": 23243,
"brawl": 23244,
"duct": 23245,
"texans": 23246,
"##ciation": 23247,
"##ropolis": 23248,
"skipper": 23249,
"speculative": 23250,
"vomit": 23251,
"doctrines": 23252,
"stresses": 23253,
"253": 23254,
"davy": 23255,
"graders": 23256,
"whitehead": 23257,
"jozef": 23258,
"timely": 23259,
"cumulative": 23260,
"haryana": 23261,
"paints": 23262,
"appropriately": 23263,
"boon": 23264,
"cactus": 23265,
"##ales": 23266,
"##pid": 23267,
"dow": 23268,
"legions": 23269,
"##pit": 23270,
"perceptions": 23271,
"1730": 23272,
"picturesque": 23273,
"##yse": 23274,
"periphery": 23275,
"rune": 23276,
"wr": 23277,
"##aha": 23278,
"celtics": 23279,
"sentencing": 23280,
"whoa": 23281,
"##erin": 23282,
"confirms": 23283,
"variance": 23284,
"425": 23285,
"moines": 23286,
"mathews": 23287,
"spade": 23288,
"rave": 23289,
"m1": 23290,
"fronted": 23291,
"fx": 23292,
"blending": 23293,
"alleging": 23294,
"reared": 23295,
"##gl": 23296,
"237": 23297,
"##paper": 23298,
"grassroots": 23299,
"eroded": 23300,
"##free": 23301,
"##physical": 23302,
"directs": 23303,
"ordeal": 23304,
"##sław": 23305,
"accelerate": 23306,
"hacker": 23307,
"rooftop": 23308,
"##inia": 23309,
"lev": 23310,
"buys": 23311,
"cebu": 23312,
"devote": 23313,
"##lce": 23314,
"specialising": 23315,
"##ulsion": 23316,
"choreographed": 23317,
"repetition": 23318,
"warehouses": 23319,
"##ryl": 23320,
"paisley": 23321,
"tuscany": 23322,
"analogy": 23323,
"sorcerer": 23324,
"hash": 23325,
"huts": 23326,
"shards": 23327,
"descends": 23328,
"exclude": 23329,
"nix": 23330,
"chaplin": 23331,
"gaga": 23332,
"ito": 23333,
"vane": 23334,
"##drich": 23335,
"causeway": 23336,
"misconduct": 23337,
"limo": 23338,
"orchestrated": 23339,
"glands": 23340,
"jana": 23341,
"##kot": 23342,
"u2": 23343,
"##mple": 23344,
"##sons": 23345,
"branching": 23346,
"contrasts": 23347,
"scoop": 23348,
"longed": 23349,
"##virus": 23350,
"chattanooga": 23351,
"##75": 23352,
"syrup": 23353,
"cornerstone": 23354,
"##tized": 23355,
"##mind": 23356,
"##iaceae": 23357,
"careless": 23358,
"precedence": 23359,
"frescoes": 23360,
"##uet": 23361,
"chilled": 23362,
"consult": 23363,
"modelled": 23364,
"snatch": 23365,
"peat": 23366,
"##thermal": 23367,
"caucasian": 23368,
"humane": 23369,
"relaxation": 23370,
"spins": 23371,
"temperance": 23372,
"##lbert": 23373,
"occupations": 23374,
"lambda": 23375,
"hybrids": 23376,
"moons": 23377,
"mp3": 23378,
"##oese": 23379,
"247": 23380,
"rolf": 23381,
"societal": 23382,
"yerevan": 23383,
"ness": 23384,
"##ssler": 23385,
"befriended": 23386,
"mechanized": 23387,
"nominate": 23388,
"trough": 23389,
"boasted": 23390,
"cues": 23391,
"seater": 23392,
"##hom": 23393,
"bends": 23394,
"##tangle": 23395,
"conductors": 23396,
"emptiness": 23397,
"##lmer": 23398,
"eurasian": 23399,
"adriatic": 23400,
"tian": 23401,
"##cie": 23402,
"anxiously": 23403,
"lark": 23404,
"propellers": 23405,
"chichester": 23406,
"jock": 23407,
"ev": 23408,
"2a": 23409,
"##holding": 23410,
"credible": 23411,
"recounts": 23412,
"tori": 23413,
"loyalist": 23414,
"abduction": 23415,
"##hoot": 23416,
"##redo": 23417,
"nepali": 23418,
"##mite": 23419,
"ventral": 23420,
"tempting": 23421,
"##ango": 23422,
"##crats": 23423,
"steered": 23424,
"##wice": 23425,
"javelin": 23426,
"dipping": 23427,
"laborers": 23428,
"prentice": 23429,
"looming": 23430,
"titanium": 23431,
"##ː": 23432,
"badges": 23433,
"emir": 23434,
"tensor": 23435,
"##ntation": 23436,
"egyptians": 23437,
"rash": 23438,
"denies": 23439,
"hawthorne": 23440,
"lombard": 23441,
"showers": 23442,
"wehrmacht": 23443,
"dietary": 23444,
"trojan": 23445,
"##reus": 23446,
"welles": 23447,
"executing": 23448,
"horseshoe": 23449,
"lifeboat": 23450,
"##lak": 23451,
"elsa": 23452,
"infirmary": 23453,
"nearing": 23454,
"roberta": 23455,
"boyer": 23456,
"mutter": 23457,
"trillion": 23458,
"joanne": 23459,
"##fine": 23460,
"##oked": 23461,
"sinks": 23462,
"vortex": 23463,
"uruguayan": 23464,
"clasp": 23465,
"sirius": 23466,
"##block": 23467,
"accelerator": 23468,
"prohibit": 23469,
"sunken": 23470,
"byu": 23471,
"chronological": 23472,
"diplomats": 23473,
"ochreous": 23474,
"510": 23475,
"symmetrical": 23476,
"1644": 23477,
"maia": 23478,
"##tology": 23479,
"salts": 23480,
"reigns": 23481,
"atrocities": 23482,
"##ия": 23483,
"hess": 23484,
"bared": 23485,
"issn": 23486,
"##vyn": 23487,
"cater": 23488,
"saturated": 23489,
"##cycle": 23490,
"##isse": 23491,
"sable": 23492,
"voyager": 23493,
"dyer": 23494,
"yusuf": 23495,
"##inge": 23496,
"fountains": 23497,
"wolff": 23498,
"##39": 23499,
"##nni": 23500,
"engraving": 23501,
"rollins": 23502,
"atheist": 23503,
"ominous": 23504,
"##ault": 23505,
"herr": 23506,
"chariot": 23507,
"martina": 23508,
"strung": 23509,
"##fell": 23510,
"##farlane": 23511,
"horrific": 23512,
"sahib": 23513,
"gazes": 23514,
"saetan": 23515,
"erased": 23516,
"ptolemy": 23517,
"##olic": 23518,
"flushing": 23519,
"lauderdale": 23520,
"analytic": 23521,
"##ices": 23522,
"530": 23523,
"navarro": 23524,
"beak": 23525,
"gorilla": 23526,
"herrera": 23527,
"broom": 23528,
"guadalupe": 23529,
"raiding": 23530,
"sykes": 23531,
"311": 23532,
"bsc": 23533,
"deliveries": 23534,
"1720": 23535,
"invasions": 23536,
"carmichael": 23537,
"tajikistan": 23538,
"thematic": 23539,
"ecumenical": 23540,
"sentiments": 23541,
"onstage": 23542,
"##rians": 23543,
"##brand": 23544,
"##sume": 23545,
"catastrophic": 23546,
"flanks": 23547,
"molten": 23548,
"##arns": 23549,
"waller": 23550,
"aimee": 23551,
"terminating": 23552,
"##icing": 23553,
"alternately": 23554,
"##oche": 23555,
"nehru": 23556,
"printers": 23557,
"outraged": 23558,
"##eving": 23559,
"empires": 23560,
"template": 23561,
"banners": 23562,
"repetitive": 23563,
"za": 23564,
"##oise": 23565,
"vegetarian": 23566,
"##tell": 23567,
"guiana": 23568,
"opt": 23569,
"cavendish": 23570,
"lucknow": 23571,
"synthesized": 23572,
"##hani": 23573,
"##mada": 23574,
"finalized": 23575,
"##ctable": 23576,
"fictitious": 23577,
"mayoral": 23578,
"unreliable": 23579,
"##enham": 23580,
"embracing": 23581,
"peppers": 23582,
"rbis": 23583,
"##chio": 23584,
"##neo": 23585,
"inhibition": 23586,
"slashed": 23587,
"togo": 23588,
"orderly": 23589,
"embroidered": 23590,
"safari": 23591,
"salty": 23592,
"236": 23593,
"barron": 23594,
"benito": 23595,
"totaled": 23596,
"##dak": 23597,
"pubs": 23598,
"simulated": 23599,
"caden": 23600,
"devin": 23601,
"tolkien": 23602,
"momma": 23603,
"welding": 23604,
"sesame": 23605,
"##ept": 23606,
"gottingen": 23607,
"hardness": 23608,
"630": 23609,
"shaman": 23610,
"temeraire": 23611,
"620": 23612,
"adequately": 23613,
"pediatric": 23614,
"##kit": 23615,
"ck": 23616,
"assertion": 23617,
"radicals": 23618,
"composure": 23619,
"cadence": 23620,
"seafood": 23621,
"beaufort": 23622,
"lazarus": 23623,
"mani": 23624,
"warily": 23625,
"cunning": 23626,
"kurdistan": 23627,
"249": 23628,
"cantata": 23629,
"##kir": 23630,
"ares": 23631,
"##41": 23632,
"##clusive": 23633,
"nape": 23634,
"townland": 23635,
"geared": 23636,
"insulted": 23637,
"flutter": 23638,
"boating": 23639,
"violate": 23640,
"draper": 23641,
"dumping": 23642,
"malmo": 23643,
"##hh": 23644,
"##romatic": 23645,
"firearm": 23646,
"alta": 23647,
"bono": 23648,
"obscured": 23649,
"##clave": 23650,
"exceeds": 23651,
"panorama": 23652,
"unbelievable": 23653,
"##train": 23654,
"preschool": 23655,
"##essed": 23656,
"disconnected": 23657,
"installing": 23658,
"rescuing": 23659,
"secretaries": 23660,
"accessibility": 23661,
"##castle": 23662,
"##drive": 23663,
"##ifice": 23664,
"##film": 23665,
"bouts": 23666,
"slug": 23667,
"waterway": 23668,
"mindanao": 23669,
"##buro": 23670,
"##ratic": 23671,
"halves": 23672,
"##ل": 23673,
"calming": 23674,
"liter": 23675,
"maternity": 23676,
"adorable": 23677,
"bragg": 23678,
"electrification": 23679,
"mcc": 23680,
"##dote": 23681,
"roxy": 23682,
"schizophrenia": 23683,
"##body": 23684,
"munoz": 23685,
"kaye": 23686,
"whaling": 23687,
"239": 23688,
"mil": 23689,
"tingling": 23690,
"tolerant": 23691,
"##ago": 23692,
"unconventional": 23693,
"volcanoes": 23694,
"##finder": 23695,
"deportivo": 23696,
"##llie": 23697,
"robson": 23698,
"kaufman": 23699,
"neuroscience": 23700,
"wai": 23701,
"deportation": 23702,
"masovian": 23703,
"scraping": 23704,
"converse": 23705,
"##bh": 23706,
"hacking": 23707,
"bulge": 23708,
"##oun": 23709,
"administratively": 23710,
"yao": 23711,
"580": 23712,
"amp": 23713,
"mammoth": 23714,
"booster": 23715,
"claremont": 23716,
"hooper": 23717,
"nomenclature": 23718,
"pursuits": 23719,
"mclaughlin": 23720,
"melinda": 23721,
"##sul": 23722,
"catfish": 23723,
"barclay": 23724,
"substrates": 23725,
"taxa": 23726,
"zee": 23727,
"originals": 23728,
"kimberly": 23729,
"packets": 23730,
"padma": 23731,
"##ality": 23732,
"borrowing": 23733,
"ostensibly": 23734,
"solvent": 23735,
"##bri": 23736,
"##genesis": 23737,
"##mist": 23738,
"lukas": 23739,
"shreveport": 23740,
"veracruz": 23741,
"##ь": 23742,
"##lou": 23743,
"##wives": 23744,
"cheney": 23745,
"tt": 23746,
"anatolia": 23747,
"hobbs": 23748,
"##zyn": 23749,
"cyclic": 23750,
"radiant": 23751,
"alistair": 23752,
"greenish": 23753,
"siena": 23754,
"dat": 23755,
"independents": 23756,
"##bation": 23757,
"conform": 23758,
"pieter": 23759,
"hyper": 23760,
"applicant": 23761,
"bradshaw": 23762,
"spores": 23763,
"telangana": 23764,
"vinci": 23765,
"inexpensive": 23766,
"nuclei": 23767,
"322": 23768,
"jang": 23769,
"nme": 23770,
"soho": 23771,
"spd": 23772,
"##ign": 23773,
"cradled": 23774,
"receptionist": 23775,
"pow": 23776,
"##43": 23777,
"##rika": 23778,
"fascism": 23779,
"##ifer": 23780,
"experimenting": 23781,
"##ading": 23782,
"##iec": 23783,
"##region": 23784,
"345": 23785,
"jocelyn": 23786,
"maris": 23787,
"stair": 23788,
"nocturnal": 23789,
"toro": 23790,
"constabulary": 23791,
"elgin": 23792,
"##kker": 23793,
"msc": 23794,
"##giving": 23795,
"##schen": 23796,
"##rase": 23797,
"doherty": 23798,
"doping": 23799,
"sarcastically": 23800,
"batter": 23801,
"maneuvers": 23802,
"##cano": 23803,
"##apple": 23804,
"##gai": 23805,
"##git": 23806,
"intrinsic": 23807,
"##nst": 23808,
"##stor": 23809,
"1753": 23810,
"showtime": 23811,
"cafes": 23812,
"gasps": 23813,
"lviv": 23814,
"ushered": 23815,
"##thed": 23816,
"fours": 23817,
"restart": 23818,
"astonishment": 23819,
"transmitting": 23820,
"flyer": 23821,
"shrugs": 23822,
"##sau": 23823,
"intriguing": 23824,
"cones": 23825,
"dictated": 23826,
"mushrooms": 23827,
"medial": 23828,
"##kovsky": 23829,
"##elman": 23830,
"escorting": 23831,
"gaped": 23832,
"##26": 23833,
"godfather": 23834,
"##door": 23835,
"##sell": 23836,
"djs": 23837,
"recaptured": 23838,
"timetable": 23839,
"vila": 23840,
"1710": 23841,
"3a": 23842,
"aerodrome": 23843,
"mortals": 23844,
"scientology": 23845,
"##orne": 23846,
"angelina": 23847,
"mag": 23848,
"convection": 23849,
"unpaid": 23850,
"insertion": 23851,
"intermittent": 23852,
"lego": 23853,
"##nated": 23854,
"endeavor": 23855,
"kota": 23856,
"pereira": 23857,
"##lz": 23858,
"304": 23859,
"bwv": 23860,
"glamorgan": 23861,
"insults": 23862,
"agatha": 23863,
"fey": 23864,
"##cend": 23865,
"fleetwood": 23866,
"mahogany": 23867,
"protruding": 23868,
"steamship": 23869,
"zeta": 23870,
"##arty": 23871,
"mcguire": 23872,
"suspense": 23873,
"##sphere": 23874,
"advising": 23875,
"urges": 23876,
"##wala": 23877,
"hurriedly": 23878,
"meteor": 23879,
"gilded": 23880,
"inline": 23881,
"arroyo": 23882,
"stalker": 23883,
"##oge": 23884,
"excitedly": 23885,
"revered": 23886,
"##cure": 23887,
"earle": 23888,
"introductory": 23889,
"##break": 23890,
"##ilde": 23891,
"mutants": 23892,
"puff": 23893,
"pulses": 23894,
"reinforcement": 23895,
"##haling": 23896,
"curses": 23897,
"lizards": 23898,
"stalk": 23899,
"correlated": 23900,
"##fixed": 23901,
"fallout": 23902,
"macquarie": 23903,
"##unas": 23904,
"bearded": 23905,
"denton": 23906,
"heaving": 23907,
"802": 23908,
"##ocation": 23909,
"winery": 23910,
"assign": 23911,
"dortmund": 23912,
"##lkirk": 23913,
"everest": 23914,
"invariant": 23915,
"charismatic": 23916,
"susie": 23917,
"##elling": 23918,
"bled": 23919,
"lesley": 23920,
"telegram": 23921,
"sumner": 23922,
"bk": 23923,
"##ogen": 23924,
"##к": 23925,
"wilcox": 23926,
"needy": 23927,
"colbert": 23928,
"duval": 23929,
"##iferous": 23930,
"##mbled": 23931,
"allotted": 23932,
"attends": 23933,
"imperative": 23934,
"##hita": 23935,
"replacements": 23936,
"hawker": 23937,
"##inda": 23938,
"insurgency": 23939,
"##zee": 23940,
"##eke": 23941,
"casts": 23942,
"##yla": 23943,
"680": 23944,
"ives": 23945,
"transitioned": 23946,
"##pack": 23947,
"##powering": 23948,
"authoritative": 23949,
"baylor": 23950,
"flex": 23951,
"cringed": 23952,
"plaintiffs": 23953,
"woodrow": 23954,
"##skie": 23955,
"drastic": 23956,
"ape": 23957,
"aroma": 23958,
"unfolded": 23959,
"commotion": 23960,
"nt": 23961,
"preoccupied": 23962,
"theta": 23963,
"routines": 23964,
"lasers": 23965,
"privatization": 23966,
"wand": 23967,
"domino": 23968,
"ek": 23969,
"clenching": 23970,
"nsa": 23971,
"strategically": 23972,
"showered": 23973,
"bile": 23974,
"handkerchief": 23975,
"pere": 23976,
"storing": 23977,
"christophe": 23978,
"insulting": 23979,
"316": 23980,
"nakamura": 23981,
"romani": 23982,
"asiatic": 23983,
"magdalena": 23984,
"palma": 23985,
"cruises": 23986,
"stripping": 23987,
"405": 23988,
"konstantin": 23989,
"soaring": 23990,
"##berman": 23991,
"colloquially": 23992,
"forerunner": 23993,
"havilland": 23994,
"incarcerated": 23995,
"parasites": 23996,
"sincerity": 23997,
"##utus": 23998,
"disks": 23999,
"plank": 24000,
"saigon": 24001,
"##ining": 24002,
"corbin": 24003,
"homo": 24004,
"ornaments": 24005,
"powerhouse": 24006,
"##tlement": 24007,
"chong": 24008,
"fastened": 24009,
"feasibility": 24010,
"idf": 24011,
"morphological": 24012,
"usable": 24013,
"##nish": 24014,
"##zuki": 24015,
"aqueduct": 24016,
"jaguars": 24017,
"keepers": 24018,
"##flies": 24019,
"aleksandr": 24020,
"faust": 24021,
"assigns": 24022,
"ewing": 24023,
"bacterium": 24024,
"hurled": 24025,
"tricky": 24026,
"hungarians": 24027,
"integers": 24028,
"wallis": 24029,
"321": 24030,
"yamaha": 24031,
"##isha": 24032,
"hushed": 24033,
"oblivion": 24034,
"aviator": 24035,
"evangelist": 24036,
"friars": 24037,
"##eller": 24038,
"monograph": 24039,
"ode": 24040,
"##nary": 24041,
"airplanes": 24042,
"labourers": 24043,
"charms": 24044,
"##nee": 24045,
"1661": 24046,
"hagen": 24047,
"tnt": 24048,
"rudder": 24049,
"fiesta": 24050,
"transcript": 24051,
"dorothea": 24052,
"ska": 24053,
"inhibitor": 24054,
"maccabi": 24055,
"retorted": 24056,
"raining": 24057,
"encompassed": 24058,
"clauses": 24059,
"menacing": 24060,
"1642": 24061,
"lineman": 24062,
"##gist": 24063,
"vamps": 24064,
"##ape": 24065,
"##dick": 24066,
"gloom": 24067,
"##rera": 24068,
"dealings": 24069,
"easing": 24070,
"seekers": 24071,
"##nut": 24072,
"##pment": 24073,
"helens": 24074,
"unmanned": 24075,
"##anu": 24076,
"##isson": 24077,
"basics": 24078,
"##amy": 24079,
"##ckman": 24080,
"adjustments": 24081,
"1688": 24082,
"brutality": 24083,
"horne": 24084,
"##zell": 24085,
"sui": 24086,
"##55": 24087,
"##mable": 24088,
"aggregator": 24089,
"##thal": 24090,
"rhino": 24091,
"##drick": 24092,
"##vira": 24093,
"counters": 24094,
"zoom": 24095,
"##01": 24096,
"##rting": 24097,
"mn": 24098,
"montenegrin": 24099,
"packard": 24100,
"##unciation": 24101,
"##♭": 24102,
"##kki": 24103,
"reclaim": 24104,
"scholastic": 24105,
"thugs": 24106,
"pulsed": 24107,
"##icia": 24108,
"syriac": 24109,
"quan": 24110,
"saddam": 24111,
"banda": 24112,
"kobe": 24113,
"blaming": 24114,
"buddies": 24115,
"dissent": 24116,
"##lusion": 24117,
"##usia": 24118,
"corbett": 24119,
"jaya": 24120,
"delle": 24121,
"erratic": 24122,
"lexie": 24123,
"##hesis": 24124,
"435": 24125,
"amiga": 24126,
"hermes": 24127,
"##pressing": 24128,
"##leen": 24129,
"chapels": 24130,
"gospels": 24131,
"jamal": 24132,
"##uating": 24133,
"compute": 24134,
"revolving": 24135,
"warp": 24136,
"##sso": 24137,
"##thes": 24138,
"armory": 24139,
"##eras": 24140,
"##gol": 24141,
"antrim": 24142,
"loki": 24143,
"##kow": 24144,
"##asian": 24145,
"##good": 24146,
"##zano": 24147,
"braid": 24148,
"handwriting": 24149,
"subdistrict": 24150,
"funky": 24151,
"pantheon": 24152,
"##iculate": 24153,
"concurrency": 24154,
"estimation": 24155,
"improper": 24156,
"juliana": 24157,
"##his": 24158,
"newcomers": 24159,
"johnstone": 24160,
"staten": 24161,
"communicated": 24162,
"##oco": 24163,
"##alle": 24164,
"sausage": 24165,
"stormy": 24166,
"##stered": 24167,
"##tters": 24168,
"superfamily": 24169,
"##grade": 24170,
"acidic": 24171,
"collateral": 24172,
"tabloid": 24173,
"##oped": 24174,
"##rza": 24175,
"bladder": 24176,
"austen": 24177,
"##ellant": 24178,
"mcgraw": 24179,
"##hay": 24180,
"hannibal": 24181,
"mein": 24182,
"aquino": 24183,
"lucifer": 24184,
"wo": 24185,
"badger": 24186,
"boar": 24187,
"cher": 24188,
"christensen": 24189,
"greenberg": 24190,
"interruption": 24191,
"##kken": 24192,
"jem": 24193,
"244": 24194,
"mocked": 24195,
"bottoms": 24196,
"cambridgeshire": 24197,
"##lide": 24198,
"sprawling": 24199,
"##bbly": 24200,
"eastwood": 24201,
"ghent": 24202,
"synth": 24203,
"##buck": 24204,
"advisers": 24205,
"##bah": 24206,
"nominally": 24207,
"hapoel": 24208,
"qu": 24209,
"daggers": 24210,
"estranged": 24211,
"fabricated": 24212,
"towels": 24213,
"vinnie": 24214,
"wcw": 24215,
"misunderstanding": 24216,
"anglia": 24217,
"nothin": 24218,
"unmistakable": 24219,
"##dust": 24220,
"##lova": 24221,
"chilly": 24222,
"marquette": 24223,
"truss": 24224,
"##edge": 24225,
"##erine": 24226,
"reece": 24227,
"##lty": 24228,
"##chemist": 24229,
"##connected": 24230,
"272": 24231,
"308": 24232,
"41st": 24233,
"bash": 24234,
"raion": 24235,
"waterfalls": 24236,
"##ump": 24237,
"##main": 24238,
"labyrinth": 24239,
"queue": 24240,
"theorist": 24241,
"##istle": 24242,
"bharatiya": 24243,
"flexed": 24244,
"soundtracks": 24245,
"rooney": 24246,
"leftist": 24247,
"patrolling": 24248,
"wharton": 24249,
"plainly": 24250,
"alleviate": 24251,
"eastman": 24252,
"schuster": 24253,
"topographic": 24254,
"engages": 24255,
"immensely": 24256,
"unbearable": 24257,
"fairchild": 24258,
"1620": 24259,
"dona": 24260,
"lurking": 24261,
"parisian": 24262,
"oliveira": 24263,
"ia": 24264,
"indictment": 24265,
"hahn": 24266,
"bangladeshi": 24267,
"##aster": 24268,
"vivo": 24269,
"##uming": 24270,
"##ential": 24271,
"antonia": 24272,
"expects": 24273,
"indoors": 24274,
"kildare": 24275,
"harlan": 24276,
"##logue": 24277,
"##ogenic": 24278,
"##sities": 24279,
"forgiven": 24280,
"##wat": 24281,
"childish": 24282,
"tavi": 24283,
"##mide": 24284,
"##orra": 24285,
"plausible": 24286,
"grimm": 24287,
"successively": 24288,
"scooted": 24289,
"##bola": 24290,
"##dget": 24291,
"##rith": 24292,
"spartans": 24293,
"emery": 24294,
"flatly": 24295,
"azure": 24296,
"epilogue": 24297,
"##wark": 24298,
"flourish": 24299,
"##iny": 24300,
"##tracted": 24301,
"##overs": 24302,
"##oshi": 24303,
"bestseller": 24304,
"distressed": 24305,
"receipt": 24306,
"spitting": 24307,
"hermit": 24308,
"topological": 24309,
"##cot": 24310,
"drilled": 24311,
"subunit": 24312,
"francs": 24313,
"##layer": 24314,
"eel": 24315,
"##fk": 24316,
"##itas": 24317,
"octopus": 24318,
"footprint": 24319,
"petitions": 24320,
"ufo": 24321,
"##say": 24322,
"##foil": 24323,
"interfering": 24324,
"leaking": 24325,
"palo": 24326,
"##metry": 24327,
"thistle": 24328,
"valiant": 24329,
"##pic": 24330,
"narayan": 24331,
"mcpherson": 24332,
"##fast": 24333,
"gonzales": 24334,
"##ym": 24335,
"##enne": 24336,
"dustin": 24337,
"novgorod": 24338,
"solos": 24339,
"##zman": 24340,
"doin": 24341,
"##raph": 24342,
"##patient": 24343,
"##meyer": 24344,
"soluble": 24345,
"ashland": 24346,
"cuffs": 24347,
"carole": 24348,
"pendleton": 24349,
"whistling": 24350,
"vassal": 24351,
"##river": 24352,
"deviation": 24353,
"revisited": 24354,
"constituents": 24355,
"rallied": 24356,
"rotate": 24357,
"loomed": 24358,
"##eil": 24359,
"##nting": 24360,
"amateurs": 24361,
"augsburg": 24362,
"auschwitz": 24363,
"crowns": 24364,
"skeletons": 24365,
"##cona": 24366,
"bonnet": 24367,
"257": 24368,
"dummy": 24369,
"globalization": 24370,
"simeon": 24371,
"sleeper": 24372,
"mandal": 24373,
"differentiated": 24374,
"##crow": 24375,
"##mare": 24376,
"milne": 24377,
"bundled": 24378,
"exasperated": 24379,
"talmud": 24380,
"owes": 24381,
"segregated": 24382,
"##feng": 24383,
"##uary": 24384,
"dentist": 24385,
"piracy": 24386,
"props": 24387,
"##rang": 24388,
"devlin": 24389,
"##torium": 24390,
"malicious": 24391,
"paws": 24392,
"##laid": 24393,
"dependency": 24394,
"##ergy": 24395,
"##fers": 24396,
"##enna": 24397,
"258": 24398,
"pistons": 24399,
"rourke": 24400,
"jed": 24401,
"grammatical": 24402,
"tres": 24403,
"maha": 24404,
"wig": 24405,
"512": 24406,
"ghostly": 24407,
"jayne": 24408,
"##achal": 24409,
"##creen": 24410,
"##ilis": 24411,
"##lins": 24412,
"##rence": 24413,
"designate": 24414,
"##with": 24415,
"arrogance": 24416,
"cambodian": 24417,
"clones": 24418,
"showdown": 24419,
"throttle": 24420,
"twain": 24421,
"##ception": 24422,
"lobes": 24423,
"metz": 24424,
"nagoya": 24425,
"335": 24426,
"braking": 24427,
"##furt": 24428,
"385": 24429,
"roaming": 24430,
"##minster": 24431,
"amin": 24432,
"crippled": 24433,
"##37": 24434,
"##llary": 24435,
"indifferent": 24436,
"hoffmann": 24437,
"idols": 24438,
"intimidating": 24439,
"1751": 24440,
"261": 24441,
"influenza": 24442,
"memo": 24443,
"onions": 24444,
"1748": 24445,
"bandage": 24446,
"consciously": 24447,
"##landa": 24448,
"##rage": 24449,
"clandestine": 24450,
"observes": 24451,
"swiped": 24452,
"tangle": 24453,
"##ener": 24454,
"##jected": 24455,
"##trum": 24456,
"##bill": 24457,
"##lta": 24458,
"hugs": 24459,
"congresses": 24460,
"josiah": 24461,
"spirited": 24462,
"##dek": 24463,
"humanist": 24464,
"managerial": 24465,
"filmmaking": 24466,
"inmate": 24467,
"rhymes": 24468,
"debuting": 24469,
"grimsby": 24470,
"ur": 24471,
"##laze": 24472,
"duplicate": 24473,
"vigor": 24474,
"##tf": 24475,
"republished": 24476,
"bolshevik": 24477,
"refurbishment": 24478,
"antibiotics": 24479,
"martini": 24480,
"methane": 24481,
"newscasts": 24482,
"royale": 24483,
"horizons": 24484,
"levant": 24485,
"iain": 24486,
"visas": 24487,
"##ischen": 24488,
"paler": 24489,
"##around": 24490,
"manifestation": 24491,
"snuck": 24492,
"alf": 24493,
"chop": 24494,
"futile": 24495,
"pedestal": 24496,
"rehab": 24497,
"##kat": 24498,
"bmg": 24499,
"kerman": 24500,
"res": 24501,
"fairbanks": 24502,
"jarrett": 24503,
"abstraction": 24504,
"saharan": 24505,
"##zek": 24506,
"1746": 24507,
"procedural": 24508,
"clearer": 24509,
"kincaid": 24510,
"sash": 24511,
"luciano": 24512,
"##ffey": 24513,
"crunch": 24514,
"helmut": 24515,
"##vara": 24516,
"revolutionaries": 24517,
"##tute": 24518,
"creamy": 24519,
"leach": 24520,
"##mmon": 24521,
"1747": 24522,
"permitting": 24523,
"nes": 24524,
"plight": 24525,
"wendell": 24526,
"##lese": 24527,
"contra": 24528,
"ts": 24529,
"clancy": 24530,
"ipa": 24531,
"mach": 24532,
"staples": 24533,
"autopsy": 24534,
"disturbances": 24535,
"nueva": 24536,
"karin": 24537,
"pontiac": 24538,
"##uding": 24539,
"proxy": 24540,
"venerable": 24541,
"haunt": 24542,
"leto": 24543,
"bergman": 24544,
"expands": 24545,
"##helm": 24546,
"wal": 24547,
"##pipe": 24548,
"canning": 24549,
"celine": 24550,
"cords": 24551,
"obesity": 24552,
"##enary": 24553,
"intrusion": 24554,
"planner": 24555,
"##phate": 24556,
"reasoned": 24557,
"sequencing": 24558,
"307": 24559,
"harrow": 24560,
"##chon": 24561,
"##dora": 24562,
"marred": 24563,
"mcintyre": 24564,
"repay": 24565,
"tarzan": 24566,
"darting": 24567,
"248": 24568,
"harrisburg": 24569,
"margarita": 24570,
"repulsed": 24571,
"##hur": 24572,
"##lding": 24573,
"belinda": 24574,
"hamburger": 24575,
"novo": 24576,
"compliant": 24577,
"runways": 24578,
"bingham": 24579,
"registrar": 24580,
"skyscraper": 24581,
"ic": 24582,
"cuthbert": 24583,
"improvisation": 24584,
"livelihood": 24585,
"##corp": 24586,
"##elial": 24587,
"admiring": 24588,
"##dened": 24589,
"sporadic": 24590,
"believer": 24591,
"casablanca": 24592,
"popcorn": 24593,
"##29": 24594,
"asha": 24595,
"shovel": 24596,
"##bek": 24597,
"##dice": 24598,
"coiled": 24599,
"tangible": 24600,
"##dez": 24601,
"casper": 24602,
"elsie": 24603,
"resin": 24604,
"tenderness": 24605,
"rectory": 24606,
"##ivision": 24607,
"avail": 24608,
"sonar": 24609,
"##mori": 24610,
"boutique": 24611,
"##dier": 24612,
"guerre": 24613,
"bathed": 24614,
"upbringing": 24615,
"vaulted": 24616,
"sandals": 24617,
"blessings": 24618,
"##naut": 24619,
"##utnant": 24620,
"1680": 24621,
"306": 24622,
"foxes": 24623,
"pia": 24624,
"corrosion": 24625,
"hesitantly": 24626,
"confederates": 24627,
"crystalline": 24628,
"footprints": 24629,
"shapiro": 24630,
"tirana": 24631,
"valentin": 24632,
"drones": 24633,
"45th": 24634,
"microscope": 24635,
"shipments": 24636,
"texted": 24637,
"inquisition": 24638,
"wry": 24639,
"guernsey": 24640,
"unauthorized": 24641,
"resigning": 24642,
"760": 24643,
"ripple": 24644,
"schubert": 24645,
"stu": 24646,
"reassure": 24647,
"felony": 24648,
"##ardo": 24649,
"brittle": 24650,
"koreans": 24651,
"##havan": 24652,
"##ives": 24653,
"dun": 24654,
"implicit": 24655,
"tyres": 24656,
"##aldi": 24657,
"##lth": 24658,
"magnolia": 24659,
"##ehan": 24660,
"##puri": 24661,
"##poulos": 24662,
"aggressively": 24663,
"fei": 24664,
"gr": 24665,
"familiarity": 24666,
"##poo": 24667,
"indicative": 24668,
"##trust": 24669,
"fundamentally": 24670,
"jimmie": 24671,
"overrun": 24672,
"395": 24673,
"anchors": 24674,
"moans": 24675,
"##opus": 24676,
"britannia": 24677,
"armagh": 24678,
"##ggle": 24679,
"purposely": 24680,
"seizing": 24681,
"##vao": 24682,
"bewildered": 24683,
"mundane": 24684,
"avoidance": 24685,
"cosmopolitan": 24686,
"geometridae": 24687,
"quartermaster": 24688,
"caf": 24689,
"415": 24690,
"chatter": 24691,
"engulfed": 24692,
"gleam": 24693,
"purge": 24694,
"##icate": 24695,
"juliette": 24696,
"jurisprudence": 24697,
"guerra": 24698,
"revisions": 24699,
"##bn": 24700,
"casimir": 24701,
"brew": 24702,
"##jm": 24703,
"1749": 24704,
"clapton": 24705,
"cloudy": 24706,
"conde": 24707,
"hermitage": 24708,
"278": 24709,
"simulations": 24710,
"torches": 24711,
"vincenzo": 24712,
"matteo": 24713,
"##rill": 24714,
"hidalgo": 24715,
"booming": 24716,
"westbound": 24717,
"accomplishment": 24718,
"tentacles": 24719,
"unaffected": 24720,
"##sius": 24721,
"annabelle": 24722,
"flopped": 24723,
"sloping": 24724,
"##litz": 24725,
"dreamer": 24726,
"interceptor": 24727,
"vu": 24728,
"##loh": 24729,
"consecration": 24730,
"copying": 24731,
"messaging": 24732,
"breaker": 24733,
"climates": 24734,
"hospitalized": 24735,
"1752": 24736,
"torino": 24737,
"afternoons": 24738,
"winfield": 24739,
"witnessing": 24740,
"##teacher": 24741,
"breakers": 24742,
"choirs": 24743,
"sawmill": 24744,
"coldly": 24745,
"##ege": 24746,
"sipping": 24747,
"haste": 24748,
"uninhabited": 24749,
"conical": 24750,
"bibliography": 24751,
"pamphlets": 24752,
"severn": 24753,
"edict": 24754,
"##oca": 24755,
"deux": 24756,
"illnesses": 24757,
"grips": 24758,
"##pl": 24759,
"rehearsals": 24760,
"sis": 24761,
"thinkers": 24762,
"tame": 24763,
"##keepers": 24764,
"1690": 24765,
"acacia": 24766,
"reformer": 24767,
"##osed": 24768,
"##rys": 24769,
"shuffling": 24770,
"##iring": 24771,
"##shima": 24772,
"eastbound": 24773,
"ionic": 24774,
"rhea": 24775,
"flees": 24776,
"littered": 24777,
"##oum": 24778,
"rocker": 24779,
"vomiting": 24780,
"groaning": 24781,
"champ": 24782,
"overwhelmingly": 24783,
"civilizations": 24784,
"paces": 24785,
"sloop": 24786,
"adoptive": 24787,
"##tish": 24788,
"skaters": 24789,
"##vres": 24790,
"aiding": 24791,
"mango": 24792,
"##joy": 24793,
"nikola": 24794,
"shriek": 24795,
"##ignon": 24796,
"pharmaceuticals": 24797,
"##mg": 24798,
"tuna": 24799,
"calvert": 24800,
"gustavo": 24801,
"stocked": 24802,
"yearbook": 24803,
"##urai": 24804,
"##mana": 24805,
"computed": 24806,
"subsp": 24807,
"riff": 24808,
"hanoi": 24809,
"kelvin": 24810,
"hamid": 24811,
"moors": 24812,
"pastures": 24813,
"summons": 24814,
"jihad": 24815,
"nectar": 24816,
"##ctors": 24817,
"bayou": 24818,
"untitled": 24819,
"pleasing": 24820,
"vastly": 24821,
"republics": 24822,
"intellect": 24823,
"##η": 24824,
"##ulio": 24825,
"##tou": 24826,
"crumbling": 24827,
"stylistic": 24828,
"sb": 24829,
"##ی": 24830,
"consolation": 24831,
"frequented": 24832,
"h₂o": 24833,
"walden": 24834,
"widows": 24835,
"##iens": 24836,
"404": 24837,
"##ignment": 24838,
"chunks": 24839,
"improves": 24840,
"288": 24841,
"grit": 24842,
"recited": 24843,
"##dev": 24844,
"snarl": 24845,
"sociological": 24846,
"##arte": 24847,
"##gul": 24848,
"inquired": 24849,
"##held": 24850,
"bruise": 24851,
"clube": 24852,
"consultancy": 24853,
"homogeneous": 24854,
"hornets": 24855,
"multiplication": 24856,
"pasta": 24857,
"prick": 24858,
"savior": 24859,
"##grin": 24860,
"##kou": 24861,
"##phile": 24862,
"yoon": 24863,
"##gara": 24864,
"grimes": 24865,
"vanishing": 24866,
"cheering": 24867,
"reacting": 24868,
"bn": 24869,
"distillery": 24870,
"##quisite": 24871,
"##vity": 24872,
"coe": 24873,
"dockyard": 24874,
"massif": 24875,
"##jord": 24876,
"escorts": 24877,
"voss": 24878,
"##valent": 24879,
"byte": 24880,
"chopped": 24881,
"hawke": 24882,
"illusions": 24883,
"workings": 24884,
"floats": 24885,
"##koto": 24886,
"##vac": 24887,
"kv": 24888,
"annapolis": 24889,
"madden": 24890,
"##onus": 24891,
"alvaro": 24892,
"noctuidae": 24893,
"##cum": 24894,
"##scopic": 24895,
"avenge": 24896,
"steamboat": 24897,
"forte": 24898,
"illustrates": 24899,
"erika": 24900,
"##trip": 24901,
"570": 24902,
"dew": 24903,
"nationalities": 24904,
"bran": 24905,
"manifested": 24906,
"thirsty": 24907,
"diversified": 24908,
"muscled": 24909,
"reborn": 24910,
"##standing": 24911,
"arson": 24912,
"##lessness": 24913,
"##dran": 24914,
"##logram": 24915,
"##boys": 24916,
"##kushima": 24917,
"##vious": 24918,
"willoughby": 24919,
"##phobia": 24920,
"286": 24921,
"alsace": 24922,
"dashboard": 24923,
"yuki": 24924,
"##chai": 24925,
"granville": 24926,
"myspace": 24927,
"publicized": 24928,
"tricked": 24929,
"##gang": 24930,
"adjective": 24931,
"##ater": 24932,
"relic": 24933,
"reorganisation": 24934,
"enthusiastically": 24935,
"indications": 24936,
"saxe": 24937,
"##lassified": 24938,
"consolidate": 24939,
"iec": 24940,
"padua": 24941,
"helplessly": 24942,
"ramps": 24943,
"renaming": 24944,
"regulars": 24945,
"pedestrians": 24946,
"accents": 24947,
"convicts": 24948,
"inaccurate": 24949,
"lowers": 24950,
"mana": 24951,
"##pati": 24952,
"barrie": 24953,
"bjp": 24954,
"outta": 24955,
"someplace": 24956,
"berwick": 24957,
"flanking": 24958,
"invoked": 24959,
"marrow": 24960,
"sparsely": 24961,
"excerpts": 24962,
"clothed": 24963,
"rei": 24964,
"##ginal": 24965,
"wept": 24966,
"##straße": 24967,
"##vish": 24968,
"alexa": 24969,
"excel": 24970,
"##ptive": 24971,
"membranes": 24972,
"aquitaine": 24973,
"creeks": 24974,
"cutler": 24975,
"sheppard": 24976,
"implementations": 24977,
"ns": 24978,
"##dur": 24979,
"fragrance": 24980,
"budge": 24981,
"concordia": 24982,
"magnesium": 24983,
"marcelo": 24984,
"##antes": 24985,
"gladly": 24986,
"vibrating": 24987,
"##rral": 24988,
"##ggles": 24989,
"montrose": 24990,
"##omba": 24991,
"lew": 24992,
"seamus": 24993,
"1630": 24994,
"cocky": 24995,
"##ament": 24996,
"##uen": 24997,
"bjorn": 24998,
"##rrick": 24999,
"fielder": 25000,
"fluttering": 25001,
"##lase": 25002,
"methyl": 25003,
"kimberley": 25004,
"mcdowell": 25005,
"reductions": 25006,
"barbed": 25007,
"##jic": 25008,
"##tonic": 25009,
"aeronautical": 25010,
"condensed": 25011,
"distracting": 25012,
"##promising": 25013,
"huffed": 25014,
"##cala": 25015,
"##sle": 25016,
"claudius": 25017,
"invincible": 25018,
"missy": 25019,
"pious": 25020,
"balthazar": 25021,
"ci": 25022,
"##lang": 25023,
"butte": 25024,
"combo": 25025,
"orson": 25026,
"##dication": 25027,
"myriad": 25028,
"1707": 25029,
"silenced": 25030,
"##fed": 25031,
"##rh": 25032,
"coco": 25033,
"netball": 25034,
"yourselves": 25035,
"##oza": 25036,
"clarify": 25037,
"heller": 25038,
"peg": 25039,
"durban": 25040,
"etudes": 25041,
"offender": 25042,
"roast": 25043,
"blackmail": 25044,
"curvature": 25045,
"##woods": 25046,
"vile": 25047,
"309": 25048,
"illicit": 25049,
"suriname": 25050,
"##linson": 25051,
"overture": 25052,
"1685": 25053,
"bubbling": 25054,
"gymnast": 25055,
"tucking": 25056,
"##mming": 25057,
"##ouin": 25058,
"maldives": 25059,
"##bala": 25060,
"gurney": 25061,
"##dda": 25062,
"##eased": 25063,
"##oides": 25064,
"backside": 25065,
"pinto": 25066,
"jars": 25067,
"racehorse": 25068,
"tending": 25069,
"##rdial": 25070,
"baronetcy": 25071,
"wiener": 25072,
"duly": 25073,
"##rke": 25074,
"barbarian": 25075,
"cupping": 25076,
"flawed": 25077,
"##thesis": 25078,
"bertha": 25079,
"pleistocene": 25080,
"puddle": 25081,
"swearing": 25082,
"##nob": 25083,
"##tically": 25084,
"fleeting": 25085,
"prostate": 25086,
"amulet": 25087,
"educating": 25088,
"##mined": 25089,
"##iti": 25090,
"##tler": 25091,
"75th": 25092,
"jens": 25093,
"respondents": 25094,
"analytics": 25095,
"cavaliers": 25096,
"papacy": 25097,
"raju": 25098,
"##iente": 25099,
"##ulum": 25100,
"##tip": 25101,
"funnel": 25102,
"271": 25103,
"disneyland": 25104,
"##lley": 25105,
"sociologist": 25106,
"##iam": 25107,
"2500": 25108,
"faulkner": 25109,
"louvre": 25110,
"menon": 25111,
"##dson": 25112,
"276": 25113,
"##ower": 25114,
"afterlife": 25115,
"mannheim": 25116,
"peptide": 25117,
"referees": 25118,
"comedians": 25119,
"meaningless": 25120,
"##anger": 25121,
"##laise": 25122,
"fabrics": 25123,
"hurley": 25124,
"renal": 25125,
"sleeps": 25126,
"##bour": 25127,
"##icle": 25128,
"breakout": 25129,
"kristin": 25130,
"roadside": 25131,
"animator": 25132,
"clover": 25133,
"disdain": 25134,
"unsafe": 25135,
"redesign": 25136,
"##urity": 25137,
"firth": 25138,
"barnsley": 25139,
"portage": 25140,
"reset": 25141,
"narrows": 25142,
"268": 25143,
"commandos": 25144,
"expansive": 25145,
"speechless": 25146,
"tubular": 25147,
"##lux": 25148,
"essendon": 25149,
"eyelashes": 25150,
"smashwords": 25151,
"##yad": 25152,
"##bang": 25153,
"##claim": 25154,
"craved": 25155,
"sprinted": 25156,
"chet": 25157,
"somme": 25158,
"astor": 25159,
"wrocław": 25160,
"orton": 25161,
"266": 25162,
"bane": 25163,
"##erving": 25164,
"##uing": 25165,
"mischief": 25166,
"##amps": 25167,
"##sund": 25168,
"scaling": 25169,
"terre": 25170,
"##xious": 25171,
"impairment": 25172,
"offenses": 25173,
"undermine": 25174,
"moi": 25175,
"soy": 25176,
"contiguous": 25177,
"arcadia": 25178,
"inuit": 25179,
"seam": 25180,
"##tops": 25181,
"macbeth": 25182,
"rebelled": 25183,
"##icative": 25184,
"##iot": 25185,
"590": 25186,
"elaborated": 25187,
"frs": 25188,
"uniformed": 25189,
"##dberg": 25190,
"259": 25191,
"powerless": 25192,
"priscilla": 25193,
"stimulated": 25194,
"980": 25195,
"qc": 25196,
"arboretum": 25197,
"frustrating": 25198,
"trieste": 25199,
"bullock": 25200,
"##nified": 25201,
"enriched": 25202,
"glistening": 25203,
"intern": 25204,
"##adia": 25205,
"locus": 25206,
"nouvelle": 25207,
"ollie": 25208,
"ike": 25209,
"lash": 25210,
"starboard": 25211,
"ee": 25212,
"tapestry": 25213,
"headlined": 25214,
"hove": 25215,
"rigged": 25216,
"##vite": 25217,
"pollock": 25218,
"##yme": 25219,
"thrive": 25220,
"clustered": 25221,
"cas": 25222,
"roi": 25223,
"gleamed": 25224,
"olympiad": 25225,
"##lino": 25226,
"pressured": 25227,
"regimes": 25228,
"##hosis": 25229,
"##lick": 25230,
"ripley": 25231,
"##ophone": 25232,
"kickoff": 25233,
"gallon": 25234,
"rockwell": 25235,
"##arable": 25236,
"crusader": 25237,
"glue": 25238,
"revolutions": 25239,
"scrambling": 25240,
"1714": 25241,
"grover": 25242,
"##jure": 25243,
"englishman": 25244,
"aztec": 25245,
"263": 25246,
"contemplating": 25247,
"coven": 25248,
"ipad": 25249,
"preach": 25250,
"triumphant": 25251,
"tufts": 25252,
"##esian": 25253,
"rotational": 25254,
"##phus": 25255,
"328": 25256,
"falkland": 25257,
"##brates": 25258,
"strewn": 25259,
"clarissa": 25260,
"rejoin": 25261,
"environmentally": 25262,
"glint": 25263,
"banded": 25264,
"drenched": 25265,
"moat": 25266,
"albanians": 25267,
"johor": 25268,
"rr": 25269,
"maestro": 25270,
"malley": 25271,
"nouveau": 25272,
"shaded": 25273,
"taxonomy": 25274,
"v6": 25275,
"adhere": 25276,
"bunk": 25277,
"airfields": 25278,
"##ritan": 25279,
"1741": 25280,
"encompass": 25281,
"remington": 25282,
"tran": 25283,
"##erative": 25284,
"amelie": 25285,
"mazda": 25286,
"friar": 25287,
"morals": 25288,
"passions": 25289,
"##zai": 25290,
"breadth": 25291,
"vis": 25292,
"##hae": 25293,
"argus": 25294,
"burnham": 25295,
"caressing": 25296,
"insider": 25297,
"rudd": 25298,
"##imov": 25299,
"##mini": 25300,
"##rso": 25301,
"italianate": 25302,
"murderous": 25303,
"textual": 25304,
"wainwright": 25305,
"armada": 25306,
"bam": 25307,
"weave": 25308,
"timer": 25309,
"##taken": 25310,
"##nh": 25311,
"fra": 25312,
"##crest": 25313,
"ardent": 25314,
"salazar": 25315,
"taps": 25316,
"tunis": 25317,
"##ntino": 25318,
"allegro": 25319,
"gland": 25320,
"philanthropic": 25321,
"##chester": 25322,
"implication": 25323,
"##optera": 25324,
"esq": 25325,
"judas": 25326,
"noticeably": 25327,
"wynn": 25328,
"##dara": 25329,
"inched": 25330,
"indexed": 25331,
"crises": 25332,
"villiers": 25333,
"bandit": 25334,
"royalties": 25335,
"patterned": 25336,
"cupboard": 25337,
"interspersed": 25338,
"accessory": 25339,
"isla": 25340,
"kendrick": 25341,
"entourage": 25342,
"stitches": 25343,
"##esthesia": 25344,
"headwaters": 25345,
"##ior": 25346,
"interlude": 25347,
"distraught": 25348,
"draught": 25349,
"1727": 25350,
"##basket": 25351,
"biased": 25352,
"sy": 25353,
"transient": 25354,
"triad": 25355,
"subgenus": 25356,
"adapting": 25357,
"kidd": 25358,
"shortstop": 25359,
"##umatic": 25360,
"dimly": 25361,
"spiked": 25362,
"mcleod": 25363,
"reprint": 25364,
"nellie": 25365,
"pretoria": 25366,
"windmill": 25367,
"##cek": 25368,
"singled": 25369,
"##mps": 25370,
"273": 25371,
"reunite": 25372,
"##orous": 25373,
"747": 25374,
"bankers": 25375,
"outlying": 25376,
"##omp": 25377,
"##ports": 25378,
"##tream": 25379,
"apologies": 25380,
"cosmetics": 25381,
"patsy": 25382,
"##deh": 25383,
"##ocks": 25384,
"##yson": 25385,
"bender": 25386,
"nantes": 25387,
"serene": 25388,
"##nad": 25389,
"lucha": 25390,
"mmm": 25391,
"323": 25392,
"##cius": 25393,
"##gli": 25394,
"cmll": 25395,
"coinage": 25396,
"nestor": 25397,
"juarez": 25398,
"##rook": 25399,
"smeared": 25400,
"sprayed": 25401,
"twitching": 25402,
"sterile": 25403,
"irina": 25404,
"embodied": 25405,
"juveniles": 25406,
"enveloped": 25407,
"miscellaneous": 25408,
"cancers": 25409,
"dq": 25410,
"gulped": 25411,
"luisa": 25412,
"crested": 25413,
"swat": 25414,
"donegal": 25415,
"ref": 25416,
"##anov": 25417,
"##acker": 25418,
"hearst": 25419,
"mercantile": 25420,
"##lika": 25421,
"doorbell": 25422,
"ua": 25423,
"vicki": 25424,
"##alla": 25425,
"##som": 25426,
"bilbao": 25427,
"psychologists": 25428,
"stryker": 25429,
"sw": 25430,
"horsemen": 25431,
"turkmenistan": 25432,
"wits": 25433,
"##national": 25434,
"anson": 25435,
"mathew": 25436,
"screenings": 25437,
"##umb": 25438,
"rihanna": 25439,
"##agne": 25440,
"##nessy": 25441,
"aisles": 25442,
"##iani": 25443,
"##osphere": 25444,
"hines": 25445,
"kenton": 25446,
"saskatoon": 25447,
"tasha": 25448,
"truncated": 25449,
"##champ": 25450,
"##itan": 25451,
"mildred": 25452,
"advises": 25453,
"fredrik": 25454,
"interpreting": 25455,
"inhibitors": 25456,
"##athi": 25457,
"spectroscopy": 25458,
"##hab": 25459,
"##kong": 25460,
"karim": 25461,
"panda": 25462,
"##oia": 25463,
"##nail": 25464,
"##vc": 25465,
"conqueror": 25466,
"kgb": 25467,
"leukemia": 25468,
"##dity": 25469,
"arrivals": 25470,
"cheered": 25471,
"pisa": 25472,
"phosphorus": 25473,
"shielded": 25474,
"##riated": 25475,
"mammal": 25476,
"unitarian": 25477,
"urgently": 25478,
"chopin": 25479,
"sanitary": 25480,
"##mission": 25481,
"spicy": 25482,
"drugged": 25483,
"hinges": 25484,
"##tort": 25485,
"tipping": 25486,
"trier": 25487,
"impoverished": 25488,
"westchester": 25489,
"##caster": 25490,
"267": 25491,
"epoch": 25492,
"nonstop": 25493,
"##gman": 25494,
"##khov": 25495,
"aromatic": 25496,
"centrally": 25497,
"cerro": 25498,
"##tively": 25499,
"##vio": 25500,
"billions": 25501,
"modulation": 25502,
"sedimentary": 25503,
"283": 25504,
"facilitating": 25505,
"outrageous": 25506,
"goldstein": 25507,
"##eak": 25508,
"##kt": 25509,
"ld": 25510,
"maitland": 25511,
"penultimate": 25512,
"pollard": 25513,
"##dance": 25514,
"fleets": 25515,
"spaceship": 25516,
"vertebrae": 25517,
"##nig": 25518,
"alcoholism": 25519,
"als": 25520,
"recital": 25521,
"##bham": 25522,
"##ference": 25523,
"##omics": 25524,
"m2": 25525,
"##bm": 25526,
"trois": 25527,
"##tropical": 25528,
"##в": 25529,
"commemorates": 25530,
"##meric": 25531,
"marge": 25532,
"##raction": 25533,
"1643": 25534,
"670": 25535,
"cosmetic": 25536,
"ravaged": 25537,
"##ige": 25538,
"catastrophe": 25539,
"eng": 25540,
"##shida": 25541,
"albrecht": 25542,
"arterial": 25543,
"bellamy": 25544,
"decor": 25545,
"harmon": 25546,
"##rde": 25547,
"bulbs": 25548,
"synchronized": 25549,
"vito": 25550,
"easiest": 25551,
"shetland": 25552,
"shielding": 25553,
"wnba": 25554,
"##glers": 25555,
"##ssar": 25556,
"##riam": 25557,
"brianna": 25558,
"cumbria": 25559,
"##aceous": 25560,
"##rard": 25561,
"cores": 25562,
"thayer": 25563,
"##nsk": 25564,
"brood": 25565,
"hilltop": 25566,
"luminous": 25567,
"carts": 25568,
"keynote": 25569,
"larkin": 25570,
"logos": 25571,
"##cta": 25572,
"##ا": 25573,
"##mund": 25574,
"##quay": 25575,
"lilith": 25576,
"tinted": 25577,
"277": 25578,
"wrestle": 25579,
"mobilization": 25580,
"##uses": 25581,
"sequential": 25582,
"siam": 25583,
"bloomfield": 25584,
"takahashi": 25585,
"274": 25586,
"##ieving": 25587,
"presenters": 25588,
"ringo": 25589,
"blazed": 25590,
"witty": 25591,
"##oven": 25592,
"##ignant": 25593,
"devastation": 25594,
"haydn": 25595,
"harmed": 25596,
"newt": 25597,
"therese": 25598,
"##peed": 25599,
"gershwin": 25600,
"molina": 25601,
"rabbis": 25602,
"sudanese": 25603,
"001": 25604,
"innate": 25605,
"restarted": 25606,
"##sack": 25607,
"##fus": 25608,
"slices": 25609,
"wb": 25610,
"##shah": 25611,
"enroll": 25612,
"hypothetical": 25613,
"hysterical": 25614,
"1743": 25615,
"fabio": 25616,
"indefinite": 25617,
"warped": 25618,
"##hg": 25619,
"exchanging": 25620,
"525": 25621,
"unsuitable": 25622,
"##sboro": 25623,
"gallo": 25624,
"1603": 25625,
"bret": 25626,
"cobalt": 25627,
"homemade": 25628,
"##hunter": 25629,
"mx": 25630,
"operatives": 25631,
"##dhar": 25632,
"terraces": 25633,
"durable": 25634,
"latch": 25635,
"pens": 25636,
"whorls": 25637,
"##ctuated": 25638,
"##eaux": 25639,
"billing": 25640,
"ligament": 25641,
"succumbed": 25642,
"##gly": 25643,
"regulators": 25644,
"spawn": 25645,
"##brick": 25646,
"##stead": 25647,
"filmfare": 25648,
"rochelle": 25649,
"##nzo": 25650,
"1725": 25651,
"circumstance": 25652,
"saber": 25653,
"supplements": 25654,
"##nsky": 25655,
"##tson": 25656,
"crowe": 25657,
"wellesley": 25658,
"carrot": 25659,
"##9th": 25660,
"##movable": 25661,
"primate": 25662,
"drury": 25663,
"sincerely": 25664,
"topical": 25665,
"##mad": 25666,
"##rao": 25667,
"callahan": 25668,
"kyiv": 25669,
"smarter": 25670,
"tits": 25671,
"undo": 25672,
"##yeh": 25673,
"announcements": 25674,
"anthologies": 25675,
"barrio": 25676,
"nebula": 25677,
"##islaus": 25678,
"##shaft": 25679,
"##tyn": 25680,
"bodyguards": 25681,
"2021": 25682,
"assassinate": 25683,
"barns": 25684,
"emmett": 25685,
"scully": 25686,
"##mah": 25687,
"##yd": 25688,
"##eland": 25689,
"##tino": 25690,
"##itarian": 25691,
"demoted": 25692,
"gorman": 25693,
"lashed": 25694,
"prized": 25695,
"adventist": 25696,
"writ": 25697,
"##gui": 25698,
"alla": 25699,
"invertebrates": 25700,
"##ausen": 25701,
"1641": 25702,
"amman": 25703,
"1742": 25704,
"align": 25705,
"healy": 25706,
"redistribution": 25707,
"##gf": 25708,
"##rize": 25709,
"insulation": 25710,
"##drop": 25711,
"adherents": 25712,
"hezbollah": 25713,
"vitro": 25714,
"ferns": 25715,
"yanking": 25716,
"269": 25717,
"php": 25718,
"registering": 25719,
"uppsala": 25720,
"cheerleading": 25721,
"confines": 25722,
"mischievous": 25723,
"tully": 25724,
"##ross": 25725,
"49th": 25726,
"docked": 25727,
"roam": 25728,
"stipulated": 25729,
"pumpkin": 25730,
"##bry": 25731,
"prompt": 25732,
"##ezer": 25733,
"blindly": 25734,
"shuddering": 25735,
"craftsmen": 25736,
"frail": 25737,
"scented": 25738,
"katharine": 25739,
"scramble": 25740,
"shaggy": 25741,
"sponge": 25742,
"helix": 25743,
"zaragoza": 25744,
"279": 25745,
"##52": 25746,
"43rd": 25747,
"backlash": 25748,
"fontaine": 25749,
"seizures": 25750,
"posse": 25751,
"cowan": 25752,
"nonfiction": 25753,
"telenovela": 25754,
"wwii": 25755,
"hammered": 25756,
"undone": 25757,
"##gpur": 25758,
"encircled": 25759,
"irs": 25760,
"##ivation": 25761,
"artefacts": 25762,
"oneself": 25763,
"searing": 25764,
"smallpox": 25765,
"##belle": 25766,
"##osaurus": 25767,
"shandong": 25768,
"breached": 25769,
"upland": 25770,
"blushing": 25771,
"rankin": 25772,
"infinitely": 25773,
"psyche": 25774,
"tolerated": 25775,
"docking": 25776,
"evicted": 25777,
"##col": 25778,
"unmarked": 25779,
"##lving": 25780,
"gnome": 25781,
"lettering": 25782,
"litres": 25783,
"musique": 25784,
"##oint": 25785,
"benevolent": 25786,
"##jal": 25787,
"blackened": 25788,
"##anna": 25789,
"mccall": 25790,
"racers": 25791,
"tingle": 25792,
"##ocene": 25793,
"##orestation": 25794,
"introductions": 25795,
"radically": 25796,
"292": 25797,
"##hiff": 25798,
"##باد": 25799,
"1610": 25800,
"1739": 25801,
"munchen": 25802,
"plead": 25803,
"##nka": 25804,
"condo": 25805,
"scissors": 25806,
"##sight": 25807,
"##tens": 25808,
"apprehension": 25809,
"##cey": 25810,
"##yin": 25811,
"hallmark": 25812,
"watering": 25813,
"formulas": 25814,
"sequels": 25815,
"##llas": 25816,
"aggravated": 25817,
"bae": 25818,
"commencing": 25819,
"##building": 25820,
"enfield": 25821,
"prohibits": 25822,
"marne": 25823,
"vedic": 25824,
"civilized": 25825,
"euclidean": 25826,
"jagger": 25827,
"beforehand": 25828,
"blasts": 25829,
"dumont": 25830,
"##arney": 25831,
"##nem": 25832,
"740": 25833,
"conversions": 25834,
"hierarchical": 25835,
"rios": 25836,
"simulator": 25837,
"##dya": 25838,
"##lellan": 25839,
"hedges": 25840,
"oleg": 25841,
"thrusts": 25842,
"shadowed": 25843,
"darby": 25844,
"maximize": 25845,
"1744": 25846,
"gregorian": 25847,
"##nded": 25848,
"##routed": 25849,
"sham": 25850,
"unspecified": 25851,
"##hog": 25852,
"emory": 25853,
"factual": 25854,
"##smo": 25855,
"##tp": 25856,
"fooled": 25857,
"##rger": 25858,
"ortega": 25859,
"wellness": 25860,
"marlon": 25861,
"##oton": 25862,
"##urance": 25863,
"casket": 25864,
"keating": 25865,
"ley": 25866,
"enclave": 25867,
"##ayan": 25868,
"char": 25869,
"influencing": 25870,
"jia": 25871,
"##chenko": 25872,
"412": 25873,
"ammonia": 25874,
"erebidae": 25875,
"incompatible": 25876,
"violins": 25877,
"cornered": 25878,
"##arat": 25879,
"grooves": 25880,
"astronauts": 25881,
"columbian": 25882,
"rampant": 25883,
"fabrication": 25884,
"kyushu": 25885,
"mahmud": 25886,
"vanish": 25887,
"##dern": 25888,
"mesopotamia": 25889,
"##lete": 25890,
"ict": 25891,
"##rgen": 25892,
"caspian": 25893,
"kenji": 25894,
"pitted": 25895,
"##vered": 25896,
"999": 25897,
"grimace": 25898,
"roanoke": 25899,
"tchaikovsky": 25900,
"twinned": 25901,
"##analysis": 25902,
"##awan": 25903,
"xinjiang": 25904,
"arias": 25905,
"clemson": 25906,
"kazakh": 25907,
"sizable": 25908,
"1662": 25909,
"##khand": 25910,
"##vard": 25911,
"plunge": 25912,
"tatum": 25913,
"vittorio": 25914,
"##nden": 25915,
"cholera": 25916,
"##dana": 25917,
"##oper": 25918,
"bracing": 25919,
"indifference": 25920,
"projectile": 25921,
"superliga": 25922,
"##chee": 25923,
"realises": 25924,
"upgrading": 25925,
"299": 25926,
"porte": 25927,
"retribution": 25928,
"##vies": 25929,
"nk": 25930,
"stil": 25931,
"##resses": 25932,
"ama": 25933,
"bureaucracy": 25934,
"blackberry": 25935,
"bosch": 25936,
"testosterone": 25937,
"collapses": 25938,
"greer": 25939,
"##pathic": 25940,
"ioc": 25941,
"fifties": 25942,
"malls": 25943,
"##erved": 25944,
"bao": 25945,
"baskets": 25946,
"adolescents": 25947,
"siegfried": 25948,
"##osity": 25949,
"##tosis": 25950,
"mantra": 25951,
"detecting": 25952,
"existent": 25953,
"fledgling": 25954,
"##cchi": 25955,
"dissatisfied": 25956,
"gan": 25957,
"telecommunication": 25958,
"mingled": 25959,
"sobbed": 25960,
"6000": 25961,
"controversies": 25962,
"outdated": 25963,
"taxis": 25964,
"##raus": 25965,
"fright": 25966,
"slams": 25967,
"##lham": 25968,
"##fect": 25969,
"##tten": 25970,
"detectors": 25971,
"fetal": 25972,
"tanned": 25973,
"##uw": 25974,
"fray": 25975,
"goth": 25976,
"olympian": 25977,
"skipping": 25978,
"mandates": 25979,
"scratches": 25980,
"sheng": 25981,
"unspoken": 25982,
"hyundai": 25983,
"tracey": 25984,
"hotspur": 25985,
"restrictive": 25986,
"##buch": 25987,
"americana": 25988,
"mundo": 25989,
"##bari": 25990,
"burroughs": 25991,
"diva": 25992,
"vulcan": 25993,
"##6th": 25994,
"distinctions": 25995,
"thumping": 25996,
"##ngen": 25997,
"mikey": 25998,
"sheds": 25999,
"fide": 26000,
"rescues": 26001,
"springsteen": 26002,
"vested": 26003,
"valuation": 26004,
"##ece": 26005,
"##ely": 26006,
"pinnacle": 26007,
"rake": 26008,
"sylvie": 26009,
"##edo": 26010,
"almond": 26011,
"quivering": 26012,
"##irus": 26013,
"alteration": 26014,
"faltered": 26015,
"##wad": 26016,
"51st": 26017,
"hydra": 26018,
"ticked": 26019,
"##kato": 26020,
"recommends": 26021,
"##dicated": 26022,
"antigua": 26023,
"arjun": 26024,
"stagecoach": 26025,
"wilfred": 26026,
"trickle": 26027,
"pronouns": 26028,
"##pon": 26029,
"aryan": 26030,
"nighttime": 26031,
"##anian": 26032,
"gall": 26033,
"pea": 26034,
"stitch": 26035,
"##hei": 26036,
"leung": 26037,
"milos": 26038,
"##dini": 26039,
"eritrea": 26040,
"nexus": 26041,
"starved": 26042,
"snowfall": 26043,
"kant": 26044,
"parasitic": 26045,
"cot": 26046,
"discus": 26047,
"hana": 26048,
"strikers": 26049,
"appleton": 26050,
"kitchens": 26051,
"##erina": 26052,
"##partisan": 26053,
"##itha": 26054,
"##vius": 26055,
"disclose": 26056,
"metis": 26057,
"##channel": 26058,
"1701": 26059,
"tesla": 26060,
"##vera": 26061,
"fitch": 26062,
"1735": 26063,
"blooded": 26064,
"##tila": 26065,
"decimal": 26066,
"##tang": 26067,
"##bai": 26068,
"cyclones": 26069,
"eun": 26070,
"bottled": 26071,
"peas": 26072,
"pensacola": 26073,
"basha": 26074,
"bolivian": 26075,
"crabs": 26076,
"boil": 26077,
"lanterns": 26078,
"partridge": 26079,
"roofed": 26080,
"1645": 26081,
"necks": 26082,
"##phila": 26083,
"opined": 26084,
"patting": 26085,
"##kla": 26086,
"##lland": 26087,
"chuckles": 26088,
"volta": 26089,
"whereupon": 26090,
"##nche": 26091,
"devout": 26092,
"euroleague": 26093,
"suicidal": 26094,
"##dee": 26095,
"inherently": 26096,
"involuntary": 26097,
"knitting": 26098,
"nasser": 26099,
"##hide": 26100,
"puppets": 26101,
"colourful": 26102,
"courageous": 26103,
"southend": 26104,
"stills": 26105,
"miraculous": 26106,
"hodgson": 26107,
"richer": 26108,
"rochdale": 26109,
"ethernet": 26110,
"greta": 26111,
"uniting": 26112,
"prism": 26113,
"umm": 26114,
"##haya": 26115,
"##itical": 26116,
"##utation": 26117,
"deterioration": 26118,
"pointe": 26119,
"prowess": 26120,
"##ropriation": 26121,
"lids": 26122,
"scranton": 26123,
"billings": 26124,
"subcontinent": 26125,
"##koff": 26126,
"##scope": 26127,
"brute": 26128,
"kellogg": 26129,
"psalms": 26130,
"degraded": 26131,
"##vez": 26132,
"stanisław": 26133,
"##ructured": 26134,
"ferreira": 26135,
"pun": 26136,
"astonishing": 26137,
"gunnar": 26138,
"##yat": 26139,
"arya": 26140,
"prc": 26141,
"gottfried": 26142,
"##tight": 26143,
"excursion": 26144,
"##ographer": 26145,
"dina": 26146,
"##quil": 26147,
"##nare": 26148,
"huffington": 26149,
"illustrious": 26150,
"wilbur": 26151,
"gundam": 26152,
"verandah": 26153,
"##zard": 26154,
"naacp": 26155,
"##odle": 26156,
"constructive": 26157,
"fjord": 26158,
"kade": 26159,
"##naud": 26160,
"generosity": 26161,
"thrilling": 26162,
"baseline": 26163,
"cayman": 26164,
"frankish": 26165,
"plastics": 26166,
"accommodations": 26167,
"zoological": 26168,
"##fting": 26169,
"cedric": 26170,
"qb": 26171,
"motorized": 26172,
"##dome": 26173,
"##otted": 26174,
"squealed": 26175,
"tackled": 26176,
"canucks": 26177,
"budgets": 26178,
"situ": 26179,
"asthma": 26180,
"dail": 26181,
"gabled": 26182,
"grasslands": 26183,
"whimpered": 26184,
"writhing": 26185,
"judgments": 26186,
"##65": 26187,
"minnie": 26188,
"pv": 26189,
"##carbon": 26190,
"bananas": 26191,
"grille": 26192,
"domes": 26193,
"monique": 26194,
"odin": 26195,
"maguire": 26196,
"markham": 26197,
"tierney": 26198,
"##estra": 26199,
"##chua": 26200,
"libel": 26201,
"poke": 26202,
"speedy": 26203,
"atrium": 26204,
"laval": 26205,
"notwithstanding": 26206,
"##edly": 26207,
"fai": 26208,
"kala": 26209,
"##sur": 26210,
"robb": 26211,
"##sma": 26212,
"listings": 26213,
"luz": 26214,
"supplementary": 26215,
"tianjin": 26216,
"##acing": 26217,
"enzo": 26218,
"jd": 26219,
"ric": 26220,
"scanner": 26221,
"croats": 26222,
"transcribed": 26223,
"##49": 26224,
"arden": 26225,
"cv": 26226,
"##hair": 26227,
"##raphy": 26228,
"##lver": 26229,
"##uy": 26230,
"357": 26231,
"seventies": 26232,
"staggering": 26233,
"alam": 26234,
"horticultural": 26235,
"hs": 26236,
"regression": 26237,
"timbers": 26238,
"blasting": 26239,
"##ounded": 26240,
"montagu": 26241,
"manipulating": 26242,
"##cit": 26243,
"catalytic": 26244,
"1550": 26245,
"troopers": 26246,
"##meo": 26247,
"condemnation": 26248,
"fitzpatrick": 26249,
"##oire": 26250,
"##roved": 26251,
"inexperienced": 26252,
"1670": 26253,
"castes": 26254,
"##lative": 26255,
"outing": 26256,
"314": 26257,
"dubois": 26258,
"flicking": 26259,
"quarrel": 26260,
"ste": 26261,
"learners": 26262,
"1625": 26263,
"iq": 26264,
"whistled": 26265,
"##class": 26266,
"282": 26267,
"classify": 26268,
"tariffs": 26269,
"temperament": 26270,
"355": 26271,
"folly": 26272,
"liszt": 26273,
"##yles": 26274,
"immersed": 26275,
"jordanian": 26276,
"ceasefire": 26277,
"apparel": 26278,
"extras": 26279,
"maru": 26280,
"fished": 26281,
"##bio": 26282,
"harta": 26283,
"stockport": 26284,
"assortment": 26285,
"craftsman": 26286,
"paralysis": 26287,
"transmitters": 26288,
"##cola": 26289,
"blindness": 26290,
"##wk": 26291,
"fatally": 26292,
"proficiency": 26293,
"solemnly": 26294,
"##orno": 26295,
"repairing": 26296,
"amore": 26297,
"groceries": 26298,
"ultraviolet": 26299,
"##chase": 26300,
"schoolhouse": 26301,
"##tua": 26302,
"resurgence": 26303,
"nailed": 26304,
"##otype": 26305,
"##×": 26306,
"ruse": 26307,
"saliva": 26308,
"diagrams": 26309,
"##tructing": 26310,
"albans": 26311,
"rann": 26312,
"thirties": 26313,
"1b": 26314,
"antennas": 26315,
"hilarious": 26316,
"cougars": 26317,
"paddington": 26318,
"stats": 26319,
"##eger": 26320,
"breakaway": 26321,
"ipod": 26322,
"reza": 26323,
"authorship": 26324,
"prohibiting": 26325,
"scoffed": 26326,
"##etz": 26327,
"##ttle": 26328,
"conscription": 26329,
"defected": 26330,
"trondheim": 26331,
"##fires": 26332,
"ivanov": 26333,
"keenan": 26334,
"##adan": 26335,
"##ciful": 26336,
"##fb": 26337,
"##slow": 26338,
"locating": 26339,
"##ials": 26340,
"##tford": 26341,
"cadiz": 26342,
"basalt": 26343,
"blankly": 26344,
"interned": 26345,
"rags": 26346,
"rattling": 26347,
"##tick": 26348,
"carpathian": 26349,
"reassured": 26350,
"sync": 26351,
"bum": 26352,
"guildford": 26353,
"iss": 26354,
"staunch": 26355,
"##onga": 26356,
"astronomers": 26357,
"sera": 26358,
"sofie": 26359,
"emergencies": 26360,
"susquehanna": 26361,
"##heard": 26362,
"duc": 26363,
"mastery": 26364,
"vh1": 26365,
"williamsburg": 26366,
"bayer": 26367,
"buckled": 26368,
"craving": 26369,
"##khan": 26370,
"##rdes": 26371,
"bloomington": 26372,
"##write": 26373,
"alton": 26374,
"barbecue": 26375,
"##bians": 26376,
"justine": 26377,
"##hri": 26378,
"##ndt": 26379,
"delightful": 26380,
"smartphone": 26381,
"newtown": 26382,
"photon": 26383,
"retrieval": 26384,
"peugeot": 26385,
"hissing": 26386,
"##monium": 26387,
"##orough": 26388,
"flavors": 26389,
"lighted": 26390,
"relaunched": 26391,
"tainted": 26392,
"##games": 26393,
"##lysis": 26394,
"anarchy": 26395,
"microscopic": 26396,
"hopping": 26397,
"adept": 26398,
"evade": 26399,
"evie": 26400,
"##beau": 26401,
"inhibit": 26402,
"sinn": 26403,
"adjustable": 26404,
"hurst": 26405,
"intuition": 26406,
"wilton": 26407,
"cisco": 26408,
"44th": 26409,
"lawful": 26410,
"lowlands": 26411,
"stockings": 26412,
"thierry": 26413,
"##dalen": 26414,
"##hila": 26415,
"##nai": 26416,
"fates": 26417,
"prank": 26418,
"tb": 26419,
"maison": 26420,
"lobbied": 26421,
"provocative": 26422,
"1724": 26423,
"4a": 26424,
"utopia": 26425,
"##qual": 26426,
"carbonate": 26427,
"gujarati": 26428,
"purcell": 26429,
"##rford": 26430,
"curtiss": 26431,
"##mei": 26432,
"overgrown": 26433,
"arenas": 26434,
"mediation": 26435,
"swallows": 26436,
"##rnik": 26437,
"respectful": 26438,
"turnbull": 26439,
"##hedron": 26440,
"##hope": 26441,
"alyssa": 26442,
"ozone": 26443,
"##ʻi": 26444,
"ami": 26445,
"gestapo": 26446,
"johansson": 26447,
"snooker": 26448,
"canteen": 26449,
"cuff": 26450,
"declines": 26451,
"empathy": 26452,
"stigma": 26453,
"##ags": 26454,
"##iner": 26455,
"##raine": 26456,
"taxpayers": 26457,
"gui": 26458,
"volga": 26459,
"##wright": 26460,
"##copic": 26461,
"lifespan": 26462,
"overcame": 26463,
"tattooed": 26464,
"enactment": 26465,
"giggles": 26466,
"##ador": 26467,
"##camp": 26468,
"barrington": 26469,
"bribe": 26470,
"obligatory": 26471,
"orbiting": 26472,
"peng": 26473,
"##enas": 26474,
"elusive": 26475,
"sucker": 26476,
"##vating": 26477,
"cong": 26478,
"hardship": 26479,
"empowered": 26480,
"anticipating": 26481,
"estrada": 26482,
"cryptic": 26483,
"greasy": 26484,
"detainees": 26485,
"planck": 26486,
"sudbury": 26487,
"plaid": 26488,
"dod": 26489,
"marriott": 26490,
"kayla": 26491,
"##ears": 26492,
"##vb": 26493,
"##zd": 26494,
"mortally": 26495,
"##hein": 26496,
"cognition": 26497,
"radha": 26498,
"319": 26499,
"liechtenstein": 26500,
"meade": 26501,
"richly": 26502,
"argyle": 26503,
"harpsichord": 26504,
"liberalism": 26505,
"trumpets": 26506,
"lauded": 26507,
"tyrant": 26508,
"salsa": 26509,
"tiled": 26510,
"lear": 26511,
"promoters": 26512,
"reused": 26513,
"slicing": 26514,
"trident": 26515,
"##chuk": 26516,
"##gami": 26517,
"##lka": 26518,
"cantor": 26519,
"checkpoint": 26520,
"##points": 26521,
"gaul": 26522,
"leger": 26523,
"mammalian": 26524,
"##tov": 26525,
"##aar": 26526,
"##schaft": 26527,
"doha": 26528,
"frenchman": 26529,
"nirvana": 26530,
"##vino": 26531,
"delgado": 26532,
"headlining": 26533,
"##eron": 26534,
"##iography": 26535,
"jug": 26536,
"tko": 26537,
"1649": 26538,
"naga": 26539,
"intersections": 26540,
"##jia": 26541,
"benfica": 26542,
"nawab": 26543,
"##suka": 26544,
"ashford": 26545,
"gulp": 26546,
"##deck": 26547,
"##vill": 26548,
"##rug": 26549,
"brentford": 26550,
"frazier": 26551,
"pleasures": 26552,
"dunne": 26553,
"potsdam": 26554,
"shenzhen": 26555,
"dentistry": 26556,
"##tec": 26557,
"flanagan": 26558,
"##dorff": 26559,
"##hear": 26560,
"chorale": 26561,
"dinah": 26562,
"prem": 26563,
"quezon": 26564,
"##rogated": 26565,
"relinquished": 26566,
"sutra": 26567,
"terri": 26568,
"##pani": 26569,
"flaps": 26570,
"##rissa": 26571,
"poly": 26572,
"##rnet": 26573,
"homme": 26574,
"aback": 26575,
"##eki": 26576,
"linger": 26577,
"womb": 26578,
"##kson": 26579,
"##lewood": 26580,
"doorstep": 26581,
"orthodoxy": 26582,
"threaded": 26583,
"westfield": 26584,
"##rval": 26585,
"dioceses": 26586,
"fridays": 26587,
"subsided": 26588,
"##gata": 26589,
"loyalists": 26590,
"##biotic": 26591,
"##ettes": 26592,
"letterman": 26593,
"lunatic": 26594,
"prelate": 26595,
"tenderly": 26596,
"invariably": 26597,
"souza": 26598,
"thug": 26599,
"winslow": 26600,
"##otide": 26601,
"furlongs": 26602,
"gogh": 26603,
"jeopardy": 26604,
"##runa": 26605,
"pegasus": 26606,
"##umble": 26607,
"humiliated": 26608,
"standalone": 26609,
"tagged": 26610,
"##roller": 26611,
"freshmen": 26612,
"klan": 26613,
"##bright": 26614,
"attaining": 26615,
"initiating": 26616,
"transatlantic": 26617,
"logged": 26618,
"viz": 26619,
"##uance": 26620,
"1723": 26621,
"combatants": 26622,
"intervening": 26623,
"stephane": 26624,
"chieftain": 26625,
"despised": 26626,
"grazed": 26627,
"317": 26628,
"cdc": 26629,
"galveston": 26630,
"godzilla": 26631,
"macro": 26632,
"simulate": 26633,
"##planes": 26634,
"parades": 26635,
"##esses": 26636,
"960": 26637,
"##ductive": 26638,
"##unes": 26639,
"equator": 26640,
"overdose": 26641,
"##cans": 26642,
"##hosh": 26643,
"##lifting": 26644,
"joshi": 26645,
"epstein": 26646,
"sonora": 26647,
"treacherous": 26648,
"aquatics": 26649,
"manchu": 26650,
"responsive": 26651,
"##sation": 26652,
"supervisory": 26653,
"##christ": 26654,
"##llins": 26655,
"##ibar": 26656,
"##balance": 26657,
"##uso": 26658,
"kimball": 26659,
"karlsruhe": 26660,
"mab": 26661,
"##emy": 26662,
"ignores": 26663,
"phonetic": 26664,
"reuters": 26665,
"spaghetti": 26666,
"820": 26667,
"almighty": 26668,
"danzig": 26669,
"rumbling": 26670,
"tombstone": 26671,
"designations": 26672,
"lured": 26673,
"outset": 26674,
"##felt": 26675,
"supermarkets": 26676,
"##wt": 26677,
"grupo": 26678,
"kei": 26679,
"kraft": 26680,
"susanna": 26681,
"##blood": 26682,
"comprehension": 26683,
"genealogy": 26684,
"##aghan": 26685,
"##verted": 26686,
"redding": 26687,
"##ythe": 26688,
"1722": 26689,
"bowing": 26690,
"##pore": 26691,
"##roi": 26692,
"lest": 26693,
"sharpened": 26694,
"fulbright": 26695,
"valkyrie": 26696,
"sikhs": 26697,
"##unds": 26698,
"swans": 26699,
"bouquet": 26700,
"merritt": 26701,
"##tage": 26702,
"##venting": 26703,
"commuted": 26704,
"redhead": 26705,
"clerks": 26706,
"leasing": 26707,
"cesare": 26708,
"dea": 26709,
"hazy": 26710,
"##vances": 26711,
"fledged": 26712,
"greenfield": 26713,
"servicemen": 26714,
"##gical": 26715,
"armando": 26716,
"blackout": 26717,
"dt": 26718,
"sagged": 26719,
"downloadable": 26720,
"intra": 26721,
"potion": 26722,
"pods": 26723,
"##4th": 26724,
"##mism": 26725,
"xp": 26726,
"attendants": 26727,
"gambia": 26728,
"stale": 26729,
"##ntine": 26730,
"plump": 26731,
"asteroids": 26732,
"rediscovered": 26733,
"buds": 26734,
"flea": 26735,
"hive": 26736,
"##neas": 26737,
"1737": 26738,
"classifications": 26739,
"debuts": 26740,
"##eles": 26741,
"olympus": 26742,
"scala": 26743,
"##eurs": 26744,
"##gno": 26745,
"##mute": 26746,
"hummed": 26747,
"sigismund": 26748,
"visuals": 26749,
"wiggled": 26750,
"await": 26751,
"pilasters": 26752,
"clench": 26753,
"sulfate": 26754,
"##ances": 26755,
"bellevue": 26756,
"enigma": 26757,
"trainee": 26758,
"snort": 26759,
"##sw": 26760,
"clouded": 26761,
"denim": 26762,
"##rank": 26763,
"##rder": 26764,
"churning": 26765,
"hartman": 26766,
"lodges": 26767,
"riches": 26768,
"sima": 26769,
"##missible": 26770,
"accountable": 26771,
"socrates": 26772,
"regulates": 26773,
"mueller": 26774,
"##cr": 26775,
"1702": 26776,
"avoids": 26777,
"solids": 26778,
"himalayas": 26779,
"nutrient": 26780,
"pup": 26781,
"##jevic": 26782,
"squat": 26783,
"fades": 26784,
"nec": 26785,
"##lates": 26786,
"##pina": 26787,
"##rona": 26788,
"##ου": 26789,
"privateer": 26790,
"tequila": 26791,
"##gative": 26792,
"##mpton": 26793,
"apt": 26794,
"hornet": 26795,
"immortals": 26796,
"##dou": 26797,
"asturias": 26798,
"cleansing": 26799,
"dario": 26800,
"##rries": 26801,
"##anta": 26802,
"etymology": 26803,
"servicing": 26804,
"zhejiang": 26805,
"##venor": 26806,
"##nx": 26807,
"horned": 26808,
"erasmus": 26809,
"rayon": 26810,
"relocating": 26811,
"£10": 26812,
"##bags": 26813,
"escalated": 26814,
"promenade": 26815,
"stubble": 26816,
"2010s": 26817,
"artisans": 26818,
"axial": 26819,
"liquids": 26820,
"mora": 26821,
"sho": 26822,
"yoo": 26823,
"##tsky": 26824,
"bundles": 26825,
"oldies": 26826,
"##nally": 26827,
"notification": 26828,
"bastion": 26829,
"##ths": 26830,
"sparkle": 26831,
"##lved": 26832,
"1728": 26833,
"leash": 26834,
"pathogen": 26835,
"highs": 26836,
"##hmi": 26837,
"immature": 26838,
"880": 26839,
"gonzaga": 26840,
"ignatius": 26841,
"mansions": 26842,
"monterrey": 26843,
"sweets": 26844,
"bryson": 26845,
"##loe": 26846,
"polled": 26847,
"regatta": 26848,
"brightest": 26849,
"pei": 26850,
"rosy": 26851,
"squid": 26852,
"hatfield": 26853,
"payroll": 26854,
"addict": 26855,
"meath": 26856,
"cornerback": 26857,
"heaviest": 26858,
"lodging": 26859,
"##mage": 26860,
"capcom": 26861,
"rippled": 26862,
"##sily": 26863,
"barnet": 26864,
"mayhem": 26865,
"ymca": 26866,
"snuggled": 26867,
"rousseau": 26868,
"##cute": 26869,
"blanchard": 26870,
"284": 26871,
"fragmented": 26872,
"leighton": 26873,
"chromosomes": 26874,
"risking": 26875,
"##md": 26876,
"##strel": 26877,
"##utter": 26878,
"corinne": 26879,
"coyotes": 26880,
"cynical": 26881,
"hiroshi": 26882,
"yeomanry": 26883,
"##ractive": 26884,
"ebook": 26885,
"grading": 26886,
"mandela": 26887,
"plume": 26888,
"agustin": 26889,
"magdalene": 26890,
"##rkin": 26891,
"bea": 26892,
"femme": 26893,
"trafford": 26894,
"##coll": 26895,
"##lun": 26896,
"##tance": 26897,
"52nd": 26898,
"fourier": 26899,
"upton": 26900,
"##mental": 26901,
"camilla": 26902,
"gust": 26903,
"iihf": 26904,
"islamabad": 26905,
"longevity": 26906,
"##kala": 26907,
"feldman": 26908,
"netting": 26909,
"##rization": 26910,
"endeavour": 26911,
"foraging": 26912,
"mfa": 26913,
"orr": 26914,
"##open": 26915,
"greyish": 26916,
"contradiction": 26917,
"graz": 26918,
"##ruff": 26919,
"handicapped": 26920,
"marlene": 26921,
"tweed": 26922,
"oaxaca": 26923,
"spp": 26924,
"campos": 26925,
"miocene": 26926,
"pri": 26927,
"configured": 26928,
"cooks": 26929,
"pluto": 26930,
"cozy": 26931,
"pornographic": 26932,
"##entes": 26933,
"70th": 26934,
"fairness": 26935,
"glided": 26936,
"jonny": 26937,
"lynne": 26938,
"rounding": 26939,
"sired": 26940,
"##emon": 26941,
"##nist": 26942,
"remade": 26943,
"uncover": 26944,
"##mack": 26945,
"complied": 26946,
"lei": 26947,
"newsweek": 26948,
"##jured": 26949,
"##parts": 26950,
"##enting": 26951,
"##pg": 26952,
"293": 26953,
"finer": 26954,
"guerrillas": 26955,
"athenian": 26956,
"deng": 26957,
"disused": 26958,
"stepmother": 26959,
"accuse": 26960,
"gingerly": 26961,
"seduction": 26962,
"521": 26963,
"confronting": 26964,
"##walker": 26965,
"##going": 26966,
"gora": 26967,
"nostalgia": 26968,
"sabres": 26969,
"virginity": 26970,
"wrenched": 26971,
"##minated": 26972,
"syndication": 26973,
"wielding": 26974,
"eyre": 26975,
"##56": 26976,
"##gnon": 26977,
"##igny": 26978,
"behaved": 26979,
"taxpayer": 26980,
"sweeps": 26981,
"##growth": 26982,
"childless": 26983,
"gallant": 26984,
"##ywood": 26985,
"amplified": 26986,
"geraldine": 26987,
"scrape": 26988,
"##ffi": 26989,
"babylonian": 26990,
"fresco": 26991,
"##rdan": 26992,
"##kney": 26993,
"##position": 26994,
"1718": 26995,
"restricting": 26996,
"tack": 26997,
"fukuoka": 26998,
"osborn": 26999,
"selector": 27000,
"partnering": 27001,
"##dlow": 27002,
"318": 27003,
"gnu": 27004,
"kia": 27005,
"tak": 27006,
"whitley": 27007,
"gables": 27008,
"##54": 27009,
"##mania": 27010,
"mri": 27011,
"softness": 27012,
"immersion": 27013,
"##bots": 27014,
"##evsky": 27015,
"1713": 27016,
"chilling": 27017,
"insignificant": 27018,
"pcs": 27019,
"##uis": 27020,
"elites": 27021,
"lina": 27022,
"purported": 27023,
"supplemental": 27024,
"teaming": 27025,
"##americana": 27026,
"##dding": 27027,
"##inton": 27028,
"proficient": 27029,
"rouen": 27030,
"##nage": 27031,
"##rret": 27032,
"niccolo": 27033,
"selects": 27034,
"##bread": 27035,
"fluffy": 27036,
"1621": 27037,
"gruff": 27038,
"knotted": 27039,
"mukherjee": 27040,
"polgara": 27041,
"thrash": 27042,
"nicholls": 27043,
"secluded": 27044,
"smoothing": 27045,
"thru": 27046,
"corsica": 27047,
"loaf": 27048,
"whitaker": 27049,
"inquiries": 27050,
"##rrier": 27051,
"##kam": 27052,
"indochina": 27053,
"289": 27054,
"marlins": 27055,
"myles": 27056,
"peking": 27057,
"##tea": 27058,
"extracts": 27059,
"pastry": 27060,
"superhuman": 27061,
"connacht": 27062,
"vogel": 27063,
"##ditional": 27064,
"##het": 27065,
"##udged": 27066,
"##lash": 27067,
"gloss": 27068,
"quarries": 27069,
"refit": 27070,
"teaser": 27071,
"##alic": 27072,
"##gaon": 27073,
"20s": 27074,
"materialized": 27075,
"sling": 27076,
"camped": 27077,
"pickering": 27078,
"tung": 27079,
"tracker": 27080,
"pursuant": 27081,
"##cide": 27082,
"cranes": 27083,
"soc": 27084,
"##cini": 27085,
"##typical": 27086,
"##viere": 27087,
"anhalt": 27088,
"overboard": 27089,
"workout": 27090,
"chores": 27091,
"fares": 27092,
"orphaned": 27093,
"stains": 27094,
"##logie": 27095,
"fenton": 27096,
"surpassing": 27097,
"joyah": 27098,
"triggers": 27099,
"##itte": 27100,
"grandmaster": 27101,
"##lass": 27102,
"##lists": 27103,
"clapping": 27104,
"fraudulent": 27105,
"ledger": 27106,
"nagasaki": 27107,
"##cor": 27108,
"##nosis": 27109,
"##tsa": 27110,
"eucalyptus": 27111,
"tun": 27112,
"##icio": 27113,
"##rney": 27114,
"##tara": 27115,
"dax": 27116,
"heroism": 27117,
"ina": 27118,
"wrexham": 27119,
"onboard": 27120,
"unsigned": 27121,
"##dates": 27122,
"moshe": 27123,
"galley": 27124,
"winnie": 27125,
"droplets": 27126,
"exiles": 27127,
"praises": 27128,
"watered": 27129,
"noodles": 27130,
"##aia": 27131,
"fein": 27132,
"adi": 27133,
"leland": 27134,
"multicultural": 27135,
"stink": 27136,
"bingo": 27137,
"comets": 27138,
"erskine": 27139,
"modernized": 27140,
"canned": 27141,
"constraint": 27142,
"domestically": 27143,
"chemotherapy": 27144,
"featherweight": 27145,
"stifled": 27146,
"##mum": 27147,
"darkly": 27148,
"irresistible": 27149,
"refreshing": 27150,
"hasty": 27151,
"isolate": 27152,
"##oys": 27153,
"kitchener": 27154,
"planners": 27155,
"##wehr": 27156,
"cages": 27157,
"yarn": 27158,
"implant": 27159,
"toulon": 27160,
"elects": 27161,
"childbirth": 27162,
"yue": 27163,
"##lind": 27164,
"##lone": 27165,
"cn": 27166,
"rightful": 27167,
"sportsman": 27168,
"junctions": 27169,
"remodeled": 27170,
"specifies": 27171,
"##rgh": 27172,
"291": 27173,
"##oons": 27174,
"complimented": 27175,
"##urgent": 27176,
"lister": 27177,
"ot": 27178,
"##logic": 27179,
"bequeathed": 27180,
"cheekbones": 27181,
"fontana": 27182,
"gabby": 27183,
"##dial": 27184,
"amadeus": 27185,
"corrugated": 27186,
"maverick": 27187,
"resented": 27188,
"triangles": 27189,
"##hered": 27190,
"##usly": 27191,
"nazareth": 27192,
"tyrol": 27193,
"1675": 27194,
"assent": 27195,
"poorer": 27196,
"sectional": 27197,
"aegean": 27198,
"##cous": 27199,
"296": 27200,
"nylon": 27201,
"ghanaian": 27202,
"##egorical": 27203,
"##weig": 27204,
"cushions": 27205,
"forbid": 27206,
"fusiliers": 27207,
"obstruction": 27208,
"somerville": 27209,
"##scia": 27210,
"dime": 27211,
"earrings": 27212,
"elliptical": 27213,
"leyte": 27214,
"oder": 27215,
"polymers": 27216,
"timmy": 27217,
"atm": 27218,
"midtown": 27219,
"piloted": 27220,
"settles": 27221,
"continual": 27222,
"externally": 27223,
"mayfield": 27224,
"##uh": 27225,
"enrichment": 27226,
"henson": 27227,
"keane": 27228,
"persians": 27229,
"1733": 27230,
"benji": 27231,
"braden": 27232,
"pep": 27233,
"324": 27234,
"##efe": 27235,
"contenders": 27236,
"pepsi": 27237,
"valet": 27238,
"##isches": 27239,
"298": 27240,
"##asse": 27241,
"##earing": 27242,
"goofy": 27243,
"stroll": 27244,
"##amen": 27245,
"authoritarian": 27246,
"occurrences": 27247,
"adversary": 27248,
"ahmedabad": 27249,
"tangent": 27250,
"toppled": 27251,
"dorchester": 27252,
"1672": 27253,
"modernism": 27254,
"marxism": 27255,
"islamist": 27256,
"charlemagne": 27257,
"exponential": 27258,
"racks": 27259,
"unicode": 27260,
"brunette": 27261,
"mbc": 27262,
"pic": 27263,
"skirmish": 27264,
"##bund": 27265,
"##lad": 27266,
"##powered": 27267,
"##yst": 27268,
"hoisted": 27269,
"messina": 27270,
"shatter": 27271,
"##ctum": 27272,
"jedi": 27273,
"vantage": 27274,
"##music": 27275,
"##neil": 27276,
"clemens": 27277,
"mahmoud": 27278,
"corrupted": 27279,
"authentication": 27280,
"lowry": 27281,
"nils": 27282,
"##washed": 27283,
"omnibus": 27284,
"wounding": 27285,
"jillian": 27286,
"##itors": 27287,
"##opped": 27288,
"serialized": 27289,
"narcotics": 27290,
"handheld": 27291,
"##arm": 27292,
"##plicity": 27293,
"intersecting": 27294,
"stimulating": 27295,
"##onis": 27296,
"crate": 27297,
"fellowships": 27298,
"hemingway": 27299,
"casinos": 27300,
"climatic": 27301,
"fordham": 27302,
"copeland": 27303,
"drip": 27304,
"beatty": 27305,
"leaflets": 27306,
"robber": 27307,
"brothel": 27308,
"madeira": 27309,
"##hedral": 27310,
"sphinx": 27311,
"ultrasound": 27312,
"##vana": 27313,
"valor": 27314,
"forbade": 27315,
"leonid": 27316,
"villas": 27317,
"##aldo": 27318,
"duane": 27319,
"marquez": 27320,
"##cytes": 27321,
"disadvantaged": 27322,
"forearms": 27323,
"kawasaki": 27324,
"reacts": 27325,
"consular": 27326,
"lax": 27327,
"uncles": 27328,
"uphold": 27329,
"##hopper": 27330,
"concepcion": 27331,
"dorsey": 27332,
"lass": 27333,
"##izan": 27334,
"arching": 27335,
"passageway": 27336,
"1708": 27337,
"researches": 27338,
"tia": 27339,
"internationals": 27340,
"##graphs": 27341,
"##opers": 27342,
"distinguishes": 27343,
"javanese": 27344,
"divert": 27345,
"##uven": 27346,
"plotted": 27347,
"##listic": 27348,
"##rwin": 27349,
"##erik": 27350,
"##tify": 27351,
"affirmative": 27352,
"signifies": 27353,
"validation": 27354,
"##bson": 27355,
"kari": 27356,
"felicity": 27357,
"georgina": 27358,
"zulu": 27359,
"##eros": 27360,
"##rained": 27361,
"##rath": 27362,
"overcoming": 27363,
"##dot": 27364,
"argyll": 27365,
"##rbin": 27366,
"1734": 27367,
"chiba": 27368,
"ratification": 27369,
"windy": 27370,
"earls": 27371,
"parapet": 27372,
"##marks": 27373,
"hunan": 27374,
"pristine": 27375,
"astrid": 27376,
"punta": 27377,
"##gart": 27378,
"brodie": 27379,
"##kota": 27380,
"##oder": 27381,
"malaga": 27382,
"minerva": 27383,
"rouse": 27384,
"##phonic": 27385,
"bellowed": 27386,
"pagoda": 27387,
"portals": 27388,
"reclamation": 27389,
"##gur": 27390,
"##odies": 27391,
"##⁄₄": 27392,
"parentheses": 27393,
"quoting": 27394,
"allergic": 27395,
"palette": 27396,
"showcases": 27397,
"benefactor": 27398,
"heartland": 27399,
"nonlinear": 27400,
"##tness": 27401,
"bladed": 27402,
"cheerfully": 27403,
"scans": 27404,
"##ety": 27405,
"##hone": 27406,
"1666": 27407,
"girlfriends": 27408,
"pedersen": 27409,
"hiram": 27410,
"sous": 27411,
"##liche": 27412,
"##nator": 27413,
"1683": 27414,
"##nery": 27415,
"##orio": 27416,
"##umen": 27417,
"bobo": 27418,
"primaries": 27419,
"smiley": 27420,
"##cb": 27421,
"unearthed": 27422,
"uniformly": 27423,
"fis": 27424,
"metadata": 27425,
"1635": 27426,
"ind": 27427,
"##oted": 27428,
"recoil": 27429,
"##titles": 27430,
"##tura": 27431,
"##ια": 27432,
"406": 27433,
"hilbert": 27434,
"jamestown": 27435,
"mcmillan": 27436,
"tulane": 27437,
"seychelles": 27438,
"##frid": 27439,
"antics": 27440,
"coli": 27441,
"fated": 27442,
"stucco": 27443,
"##grants": 27444,
"1654": 27445,
"bulky": 27446,
"accolades": 27447,
"arrays": 27448,
"caledonian": 27449,
"carnage": 27450,
"optimism": 27451,
"puebla": 27452,
"##tative": 27453,
"##cave": 27454,
"enforcing": 27455,
"rotherham": 27456,
"seo": 27457,
"dunlop": 27458,
"aeronautics": 27459,
"chimed": 27460,
"incline": 27461,
"zoning": 27462,
"archduke": 27463,
"hellenistic": 27464,
"##oses": 27465,
"##sions": 27466,
"candi": 27467,
"thong": 27468,
"##ople": 27469,
"magnate": 27470,
"rustic": 27471,
"##rsk": 27472,
"projective": 27473,
"slant": 27474,
"##offs": 27475,
"danes": 27476,
"hollis": 27477,
"vocalists": 27478,
"##ammed": 27479,
"congenital": 27480,
"contend": 27481,
"gesellschaft": 27482,
"##ocating": 27483,
"##pressive": 27484,
"douglass": 27485,
"quieter": 27486,
"##cm": 27487,
"##kshi": 27488,
"howled": 27489,
"salim": 27490,
"spontaneously": 27491,
"townsville": 27492,
"buena": 27493,
"southport": 27494,
"##bold": 27495,
"kato": 27496,
"1638": 27497,
"faerie": 27498,
"stiffly": 27499,
"##vus": 27500,
"##rled": 27501,
"297": 27502,
"flawless": 27503,
"realising": 27504,
"taboo": 27505,
"##7th": 27506,
"bytes": 27507,
"straightening": 27508,
"356": 27509,
"jena": 27510,
"##hid": 27511,
"##rmin": 27512,
"cartwright": 27513,
"berber": 27514,
"bertram": 27515,
"soloists": 27516,
"411": 27517,
"noses": 27518,
"417": 27519,
"coping": 27520,
"fission": 27521,
"hardin": 27522,
"inca": 27523,
"##cen": 27524,
"1717": 27525,
"mobilized": 27526,
"vhf": 27527,
"##raf": 27528,
"biscuits": 27529,
"curate": 27530,
"##85": 27531,
"##anial": 27532,
"331": 27533,
"gaunt": 27534,
"neighbourhoods": 27535,
"1540": 27536,
"##abas": 27537,
"blanca": 27538,
"bypassed": 27539,
"sockets": 27540,
"behold": 27541,
"coincidentally": 27542,
"##bane": 27543,
"nara": 27544,
"shave": 27545,
"splinter": 27546,
"terrific": 27547,
"##arion": 27548,
"##erian": 27549,
"commonplace": 27550,
"juris": 27551,
"redwood": 27552,
"waistband": 27553,
"boxed": 27554,
"caitlin": 27555,
"fingerprints": 27556,
"jennie": 27557,
"naturalized": 27558,
"##ired": 27559,
"balfour": 27560,
"craters": 27561,
"jody": 27562,
"bungalow": 27563,
"hugely": 27564,
"quilt": 27565,
"glitter": 27566,
"pigeons": 27567,
"undertaker": 27568,
"bulging": 27569,
"constrained": 27570,
"goo": 27571,
"##sil": 27572,
"##akh": 27573,
"assimilation": 27574,
"reworked": 27575,
"##person": 27576,
"persuasion": 27577,
"##pants": 27578,
"felicia": 27579,
"##cliff": 27580,
"##ulent": 27581,
"1732": 27582,
"explodes": 27583,
"##dun": 27584,
"##inium": 27585,
"##zic": 27586,
"lyman": 27587,
"vulture": 27588,
"hog": 27589,
"overlook": 27590,
"begs": 27591,
"northwards": 27592,
"ow": 27593,
"spoil": 27594,
"##urer": 27595,
"fatima": 27596,
"favorably": 27597,
"accumulate": 27598,
"sargent": 27599,
"sorority": 27600,
"corresponded": 27601,
"dispersal": 27602,
"kochi": 27603,
"toned": 27604,
"##imi": 27605,
"##lita": 27606,
"internacional": 27607,
"newfound": 27608,
"##agger": 27609,
"##lynn": 27610,
"##rigue": 27611,
"booths": 27612,
"peanuts": 27613,
"##eborg": 27614,
"medicare": 27615,
"muriel": 27616,
"nur": 27617,
"##uram": 27618,
"crates": 27619,
"millennia": 27620,
"pajamas": 27621,
"worsened": 27622,
"##breakers": 27623,
"jimi": 27624,
"vanuatu": 27625,
"yawned": 27626,
"##udeau": 27627,
"carousel": 27628,
"##hony": 27629,
"hurdle": 27630,
"##ccus": 27631,
"##mounted": 27632,
"##pod": 27633,
"rv": 27634,
"##eche": 27635,
"airship": 27636,
"ambiguity": 27637,
"compulsion": 27638,
"recapture": 27639,
"##claiming": 27640,
"arthritis": 27641,
"##osomal": 27642,
"1667": 27643,
"asserting": 27644,
"ngc": 27645,
"sniffing": 27646,
"dade": 27647,
"discontent": 27648,
"glendale": 27649,
"ported": 27650,
"##amina": 27651,
"defamation": 27652,
"rammed": 27653,
"##scent": 27654,
"fling": 27655,
"livingstone": 27656,
"##fleet": 27657,
"875": 27658,
"##ppy": 27659,
"apocalyptic": 27660,
"comrade": 27661,
"lcd": 27662,
"##lowe": 27663,
"cessna": 27664,
"eine": 27665,
"persecuted": 27666,
"subsistence": 27667,
"demi": 27668,
"hoop": 27669,
"reliefs": 27670,
"710": 27671,
"coptic": 27672,
"progressing": 27673,
"stemmed": 27674,
"perpetrators": 27675,
"1665": 27676,
"priestess": 27677,
"##nio": 27678,
"dobson": 27679,
"ebony": 27680,
"rooster": 27681,
"itf": 27682,
"tortricidae": 27683,
"##bbon": 27684,
"##jian": 27685,
"cleanup": 27686,
"##jean": 27687,
"##øy": 27688,
"1721": 27689,
"eighties": 27690,
"taxonomic": 27691,
"holiness": 27692,
"##hearted": 27693,
"##spar": 27694,
"antilles": 27695,
"showcasing": 27696,
"stabilized": 27697,
"##nb": 27698,
"gia": 27699,
"mascara": 27700,
"michelangelo": 27701,
"dawned": 27702,
"##uria": 27703,
"##vinsky": 27704,
"extinguished": 27705,
"fitz": 27706,
"grotesque": 27707,
"£100": 27708,
"##fera": 27709,
"##loid": 27710,
"##mous": 27711,
"barges": 27712,
"neue": 27713,
"throbbed": 27714,
"cipher": 27715,
"johnnie": 27716,
"##a1": 27717,
"##mpt": 27718,
"outburst": 27719,
"##swick": 27720,
"spearheaded": 27721,
"administrations": 27722,
"c1": 27723,
"heartbreak": 27724,
"pixels": 27725,
"pleasantly": 27726,
"##enay": 27727,
"lombardy": 27728,
"plush": 27729,
"##nsed": 27730,
"bobbie": 27731,
"##hly": 27732,
"reapers": 27733,
"tremor": 27734,
"xiang": 27735,
"minogue": 27736,
"substantive": 27737,
"hitch": 27738,
"barak": 27739,
"##wyl": 27740,
"kwan": 27741,
"##encia": 27742,
"910": 27743,
"obscene": 27744,
"elegance": 27745,
"indus": 27746,
"surfer": 27747,
"bribery": 27748,
"conserve": 27749,
"##hyllum": 27750,
"##masters": 27751,
"horatio": 27752,
"##fat": 27753,
"apes": 27754,
"rebound": 27755,
"psychotic": 27756,
"##pour": 27757,
"iteration": 27758,
"##mium": 27759,
"##vani": 27760,
"botanic": 27761,
"horribly": 27762,
"antiques": 27763,
"dispose": 27764,
"paxton": 27765,
"##hli": 27766,
"##wg": 27767,
"timeless": 27768,
"1704": 27769,
"disregard": 27770,
"engraver": 27771,
"hounds": 27772,
"##bau": 27773,
"##version": 27774,
"looted": 27775,
"uno": 27776,
"facilitates": 27777,
"groans": 27778,
"masjid": 27779,
"rutland": 27780,
"antibody": 27781,
"disqualification": 27782,
"decatur": 27783,
"footballers": 27784,
"quake": 27785,
"slacks": 27786,
"48th": 27787,
"rein": 27788,
"scribe": 27789,
"stabilize": 27790,
"commits": 27791,
"exemplary": 27792,
"tho": 27793,
"##hort": 27794,
"##chison": 27795,
"pantry": 27796,
"traversed": 27797,
"##hiti": 27798,
"disrepair": 27799,
"identifiable": 27800,
"vibrated": 27801,
"baccalaureate": 27802,
"##nnis": 27803,
"csa": 27804,
"interviewing": 27805,
"##iensis": 27806,
"##raße": 27807,
"greaves": 27808,
"wealthiest": 27809,
"343": 27810,
"classed": 27811,
"jogged": 27812,
"£5": 27813,
"##58": 27814,
"##atal": 27815,
"illuminating": 27816,
"knicks": 27817,
"respecting": 27818,
"##uno": 27819,
"scrubbed": 27820,
"##iji": 27821,
"##dles": 27822,
"kruger": 27823,
"moods": 27824,
"growls": 27825,
"raider": 27826,
"silvia": 27827,
"chefs": 27828,
"kam": 27829,
"vr": 27830,
"cree": 27831,
"percival": 27832,
"##terol": 27833,
"gunter": 27834,
"counterattack": 27835,
"defiant": 27836,
"henan": 27837,
"ze": 27838,
"##rasia": 27839,
"##riety": 27840,
"equivalence": 27841,
"submissions": 27842,
"##fra": 27843,
"##thor": 27844,
"bautista": 27845,
"mechanically": 27846,
"##heater": 27847,
"cornice": 27848,
"herbal": 27849,
"templar": 27850,
"##mering": 27851,
"outputs": 27852,
"ruining": 27853,
"ligand": 27854,
"renumbered": 27855,
"extravagant": 27856,
"mika": 27857,
"blockbuster": 27858,
"eta": 27859,
"insurrection": 27860,
"##ilia": 27861,
"darkening": 27862,
"ferocious": 27863,
"pianos": 27864,
"strife": 27865,
"kinship": 27866,
"##aer": 27867,
"melee": 27868,
"##anor": 27869,
"##iste": 27870,
"##may": 27871,
"##oue": 27872,
"decidedly": 27873,
"weep": 27874,
"##jad": 27875,
"##missive": 27876,
"##ppel": 27877,
"354": 27878,
"puget": 27879,
"unease": 27880,
"##gnant": 27881,
"1629": 27882,
"hammering": 27883,
"kassel": 27884,
"ob": 27885,
"wessex": 27886,
"##lga": 27887,
"bromwich": 27888,
"egan": 27889,
"paranoia": 27890,
"utilization": 27891,
"##atable": 27892,
"##idad": 27893,
"contradictory": 27894,
"provoke": 27895,
"##ols": 27896,
"##ouring": 27897,
"##tangled": 27898,
"knesset": 27899,
"##very": 27900,
"##lette": 27901,
"plumbing": 27902,
"##sden": 27903,
"##¹": 27904,
"greensboro": 27905,
"occult": 27906,
"sniff": 27907,
"338": 27908,
"zev": 27909,
"beaming": 27910,
"gamer": 27911,
"haggard": 27912,
"mahal": 27913,
"##olt": 27914,
"##pins": 27915,
"mendes": 27916,
"utmost": 27917,
"briefing": 27918,
"gunnery": 27919,
"##gut": 27920,
"##pher": 27921,
"##zh": 27922,
"##rok": 27923,
"1679": 27924,
"khalifa": 27925,
"sonya": 27926,
"##boot": 27927,
"principals": 27928,
"urbana": 27929,
"wiring": 27930,
"##liffe": 27931,
"##minating": 27932,
"##rrado": 27933,
"dahl": 27934,
"nyu": 27935,
"skepticism": 27936,
"np": 27937,
"townspeople": 27938,
"ithaca": 27939,
"lobster": 27940,
"somethin": 27941,
"##fur": 27942,
"##arina": 27943,
"##−1": 27944,
"freighter": 27945,
"zimmerman": 27946,
"biceps": 27947,
"contractual": 27948,
"##herton": 27949,
"amend": 27950,
"hurrying": 27951,
"subconscious": 27952,
"##anal": 27953,
"336": 27954,
"meng": 27955,
"clermont": 27956,
"spawning": 27957,
"##eia": 27958,
"##lub": 27959,
"dignitaries": 27960,
"impetus": 27961,
"snacks": 27962,
"spotting": 27963,
"twigs": 27964,
"##bilis": 27965,
"##cz": 27966,
"##ouk": 27967,
"libertadores": 27968,
"nic": 27969,
"skylar": 27970,
"##aina": 27971,
"##firm": 27972,
"gustave": 27973,
"asean": 27974,
"##anum": 27975,
"dieter": 27976,
"legislatures": 27977,
"flirt": 27978,
"bromley": 27979,
"trolls": 27980,
"umar": 27981,
"##bbies": 27982,
"##tyle": 27983,
"blah": 27984,
"parc": 27985,
"bridgeport": 27986,
"crank": 27987,
"negligence": 27988,
"##nction": 27989,
"46th": 27990,
"constantin": 27991,
"molded": 27992,
"bandages": 27993,
"seriousness": 27994,
"00pm": 27995,
"siegel": 27996,
"carpets": 27997,
"compartments": 27998,
"upbeat": 27999,
"statehood": 28000,
"##dner": 28001,
"##edging": 28002,
"marko": 28003,
"730": 28004,
"platt": 28005,
"##hane": 28006,
"paving": 28007,
"##iy": 28008,
"1738": 28009,
"abbess": 28010,
"impatience": 28011,
"limousine": 28012,
"nbl": 28013,
"##talk": 28014,
"441": 28015,
"lucille": 28016,
"mojo": 28017,
"nightfall": 28018,
"robbers": 28019,
"##nais": 28020,
"karel": 28021,
"brisk": 28022,
"calves": 28023,
"replicate": 28024,
"ascribed": 28025,
"telescopes": 28026,
"##olf": 28027,
"intimidated": 28028,
"##reen": 28029,
"ballast": 28030,
"specialization": 28031,
"##sit": 28032,
"aerodynamic": 28033,
"caliphate": 28034,
"rainer": 28035,
"visionary": 28036,
"##arded": 28037,
"epsilon": 28038,
"##aday": 28039,
"##onte": 28040,
"aggregation": 28041,
"auditory": 28042,
"boosted": 28043,
"reunification": 28044,
"kathmandu": 28045,
"loco": 28046,
"robyn": 28047,
"402": 28048,
"acknowledges": 28049,
"appointing": 28050,
"humanoid": 28051,
"newell": 28052,
"redeveloped": 28053,
"restraints": 28054,
"##tained": 28055,
"barbarians": 28056,
"chopper": 28057,
"1609": 28058,
"italiana": 28059,
"##lez": 28060,
"##lho": 28061,
"investigates": 28062,
"wrestlemania": 28063,
"##anies": 28064,
"##bib": 28065,
"690": 28066,
"##falls": 28067,
"creaked": 28068,
"dragoons": 28069,
"gravely": 28070,
"minions": 28071,
"stupidity": 28072,
"volley": 28073,
"##harat": 28074,
"##week": 28075,
"musik": 28076,
"##eries": 28077,
"##uously": 28078,
"fungal": 28079,
"massimo": 28080,
"semantics": 28081,
"malvern": 28082,
"##ahl": 28083,
"##pee": 28084,
"discourage": 28085,
"embryo": 28086,
"imperialism": 28087,
"1910s": 28088,
"profoundly": 28089,
"##ddled": 28090,
"jiangsu": 28091,
"sparkled": 28092,
"stat": 28093,
"##holz": 28094,
"sweatshirt": 28095,
"tobin": 28096,
"##iction": 28097,
"sneered": 28098,
"##cheon": 28099,
"##oit": 28100,
"brit": 28101,
"causal": 28102,
"smyth": 28103,
"##neuve": 28104,
"diffuse": 28105,
"perrin": 28106,
"silvio": 28107,
"##ipes": 28108,
"##recht": 28109,
"detonated": 28110,
"iqbal": 28111,
"selma": 28112,
"##nism": 28113,
"##zumi": 28114,
"roasted": 28115,
"##riders": 28116,
"tay": 28117,
"##ados": 28118,
"##mament": 28119,
"##mut": 28120,
"##rud": 28121,
"840": 28122,
"completes": 28123,
"nipples": 28124,
"cfa": 28125,
"flavour": 28126,
"hirsch": 28127,
"##laus": 28128,
"calderon": 28129,
"sneakers": 28130,
"moravian": 28131,
"##ksha": 28132,
"1622": 28133,
"rq": 28134,
"294": 28135,
"##imeters": 28136,
"bodo": 28137,
"##isance": 28138,
"##pre": 28139,
"##ronia": 28140,
"anatomical": 28141,
"excerpt": 28142,
"##lke": 28143,
"dh": 28144,
"kunst": 28145,
"##tablished": 28146,
"##scoe": 28147,
"biomass": 28148,
"panted": 28149,
"unharmed": 28150,
"gael": 28151,
"housemates": 28152,
"montpellier": 28153,
"##59": 28154,
"coa": 28155,
"rodents": 28156,
"tonic": 28157,
"hickory": 28158,
"singleton": 28159,
"##taro": 28160,
"451": 28161,
"1719": 28162,
"aldo": 28163,
"breaststroke": 28164,
"dempsey": 28165,
"och": 28166,
"rocco": 28167,
"##cuit": 28168,
"merton": 28169,
"dissemination": 28170,
"midsummer": 28171,
"serials": 28172,
"##idi": 28173,
"haji": 28174,
"polynomials": 28175,
"##rdon": 28176,
"gs": 28177,
"enoch": 28178,
"prematurely": 28179,
"shutter": 28180,
"taunton": 28181,
"£3": 28182,
"##grating": 28183,
"##inates": 28184,
"archangel": 28185,
"harassed": 28186,
"##asco": 28187,
"326": 28188,
"archway": 28189,
"dazzling": 28190,
"##ecin": 28191,
"1736": 28192,
"sumo": 28193,
"wat": 28194,
"##kovich": 28195,
"1086": 28196,
"honneur": 28197,
"##ently": 28198,
"##nostic": 28199,
"##ttal": 28200,
"##idon": 28201,
"1605": 28202,
"403": 28203,
"1716": 28204,
"blogger": 28205,
"rents": 28206,
"##gnan": 28207,
"hires": 28208,
"##ikh": 28209,
"##dant": 28210,
"howie": 28211,
"##rons": 28212,
"handler": 28213,
"retracted": 28214,
"shocks": 28215,
"1632": 28216,
"arun": 28217,
"duluth": 28218,
"kepler": 28219,
"trumpeter": 28220,
"##lary": 28221,
"peeking": 28222,
"seasoned": 28223,
"trooper": 28224,
"##mara": 28225,
"laszlo": 28226,
"##iciencies": 28227,
"##rti": 28228,
"heterosexual": 28229,
"##inatory": 28230,
"##ssion": 28231,
"indira": 28232,
"jogging": 28233,
"##inga": 28234,
"##lism": 28235,
"beit": 28236,
"dissatisfaction": 28237,
"malice": 28238,
"##ately": 28239,
"nedra": 28240,
"peeling": 28241,
"##rgeon": 28242,
"47th": 28243,
"stadiums": 28244,
"475": 28245,
"vertigo": 28246,
"##ains": 28247,
"iced": 28248,
"restroom": 28249,
"##plify": 28250,
"##tub": 28251,
"illustrating": 28252,
"pear": 28253,
"##chner": 28254,
"##sibility": 28255,
"inorganic": 28256,
"rappers": 28257,
"receipts": 28258,
"watery": 28259,
"##kura": 28260,
"lucinda": 28261,
"##oulos": 28262,
"reintroduced": 28263,
"##8th": 28264,
"##tched": 28265,
"gracefully": 28266,
"saxons": 28267,
"nutritional": 28268,
"wastewater": 28269,
"rained": 28270,
"favourites": 28271,
"bedrock": 28272,
"fisted": 28273,
"hallways": 28274,
"likeness": 28275,
"upscale": 28276,
"##lateral": 28277,
"1580": 28278,
"blinds": 28279,
"prequel": 28280,
"##pps": 28281,
"##tama": 28282,
"deter": 28283,
"humiliating": 28284,
"restraining": 28285,
"tn": 28286,
"vents": 28287,
"1659": 28288,
"laundering": 28289,
"recess": 28290,
"rosary": 28291,
"tractors": 28292,
"coulter": 28293,
"federer": 28294,
"##ifiers": 28295,
"##plin": 28296,
"persistence": 28297,
"##quitable": 28298,
"geschichte": 28299,
"pendulum": 28300,
"quakers": 28301,
"##beam": 28302,
"bassett": 28303,
"pictorial": 28304,
"buffet": 28305,
"koln": 28306,
"##sitor": 28307,
"drills": 28308,
"reciprocal": 28309,
"shooters": 28310,
"##57": 28311,
"##cton": 28312,
"##tees": 28313,
"converge": 28314,
"pip": 28315,
"dmitri": 28316,
"donnelly": 28317,
"yamamoto": 28318,
"aqua": 28319,
"azores": 28320,
"demographics": 28321,
"hypnotic": 28322,
"spitfire": 28323,
"suspend": 28324,
"wryly": 28325,
"roderick": 28326,
"##rran": 28327,
"sebastien": 28328,
"##asurable": 28329,
"mavericks": 28330,
"##fles": 28331,
"##200": 28332,
"himalayan": 28333,
"prodigy": 28334,
"##iance": 28335,
"transvaal": 28336,
"demonstrators": 28337,
"handcuffs": 28338,
"dodged": 28339,
"mcnamara": 28340,
"sublime": 28341,
"1726": 28342,
"crazed": 28343,
"##efined": 28344,
"##till": 28345,
"ivo": 28346,
"pondered": 28347,
"reconciled": 28348,
"shrill": 28349,
"sava": 28350,
"##duk": 28351,
"bal": 28352,
"cad": 28353,
"heresy": 28354,
"jaipur": 28355,
"goran": 28356,
"##nished": 28357,
"341": 28358,
"lux": 28359,
"shelly": 28360,
"whitehall": 28361,
"##hre": 28362,
"israelis": 28363,
"peacekeeping": 28364,
"##wled": 28365,
"1703": 28366,
"demetrius": 28367,
"ousted": 28368,
"##arians": 28369,
"##zos": 28370,
"beale": 28371,
"anwar": 28372,
"backstroke": 28373,
"raged": 28374,
"shrinking": 28375,
"cremated": 28376,
"##yck": 28377,
"benign": 28378,
"towing": 28379,
"wadi": 28380,
"darmstadt": 28381,
"landfill": 28382,
"parana": 28383,
"soothe": 28384,
"colleen": 28385,
"sidewalks": 28386,
"mayfair": 28387,
"tumble": 28388,
"hepatitis": 28389,
"ferrer": 28390,
"superstructure": 28391,
"##gingly": 28392,
"##urse": 28393,
"##wee": 28394,
"anthropological": 28395,
"translators": 28396,
"##mies": 28397,
"closeness": 28398,
"hooves": 28399,
"##pw": 28400,
"mondays": 28401,
"##roll": 28402,
"##vita": 28403,
"landscaping": 28404,
"##urized": 28405,
"purification": 28406,
"sock": 28407,
"thorns": 28408,
"thwarted": 28409,
"jalan": 28410,
"tiberius": 28411,
"##taka": 28412,
"saline": 28413,
"##rito": 28414,
"confidently": 28415,
"khyber": 28416,
"sculptors": 28417,
"##ij": 28418,
"brahms": 28419,
"hammersmith": 28420,
"inspectors": 28421,
"battista": 28422,
"fivb": 28423,
"fragmentation": 28424,
"hackney": 28425,
"##uls": 28426,
"arresting": 28427,
"exercising": 28428,
"antoinette": 28429,
"bedfordshire": 28430,
"##zily": 28431,
"dyed": 28432,
"##hema": 28433,
"1656": 28434,
"racetrack": 28435,
"variability": 28436,
"##tique": 28437,
"1655": 28438,
"austrians": 28439,
"deteriorating": 28440,
"madman": 28441,
"theorists": 28442,
"aix": 28443,
"lehman": 28444,
"weathered": 28445,
"1731": 28446,
"decreed": 28447,
"eruptions": 28448,
"1729": 28449,
"flaw": 28450,
"quinlan": 28451,
"sorbonne": 28452,
"flutes": 28453,
"nunez": 28454,
"1711": 28455,
"adored": 28456,
"downwards": 28457,
"fable": 28458,
"rasped": 28459,
"1712": 28460,
"moritz": 28461,
"mouthful": 28462,
"renegade": 28463,
"shivers": 28464,
"stunts": 28465,
"dysfunction": 28466,
"restrain": 28467,
"translit": 28468,
"327": 28469,
"pancakes": 28470,
"##avio": 28471,
"##cision": 28472,
"##tray": 28473,
"351": 28474,
"vial": 28475,
"##lden": 28476,
"bain": 28477,
"##maid": 28478,
"##oxide": 28479,
"chihuahua": 28480,
"malacca": 28481,
"vimes": 28482,
"##rba": 28483,
"##rnier": 28484,
"1664": 28485,
"donnie": 28486,
"plaques": 28487,
"##ually": 28488,
"337": 28489,
"bangs": 28490,
"floppy": 28491,
"huntsville": 28492,
"loretta": 28493,
"nikolay": 28494,
"##otte": 28495,
"eater": 28496,
"handgun": 28497,
"ubiquitous": 28498,
"##hett": 28499,
"eras": 28500,
"zodiac": 28501,
"1634": 28502,
"##omorphic": 28503,
"1820s": 28504,
"##zog": 28505,
"cochran": 28506,
"##bula": 28507,
"##lithic": 28508,
"warring": 28509,
"##rada": 28510,
"dalai": 28511,
"excused": 28512,
"blazers": 28513,
"mcconnell": 28514,
"reeling": 28515,
"bot": 28516,
"este": 28517,
"##abi": 28518,
"geese": 28519,
"hoax": 28520,
"taxon": 28521,
"##bla": 28522,
"guitarists": 28523,
"##icon": 28524,
"condemning": 28525,
"hunts": 28526,
"inversion": 28527,
"moffat": 28528,
"taekwondo": 28529,
"##lvis": 28530,
"1624": 28531,
"stammered": 28532,
"##rest": 28533,
"##rzy": 28534,
"sousa": 28535,
"fundraiser": 28536,
"marylebone": 28537,
"navigable": 28538,
"uptown": 28539,
"cabbage": 28540,
"daniela": 28541,
"salman": 28542,
"shitty": 28543,
"whimper": 28544,
"##kian": 28545,
"##utive": 28546,
"programmers": 28547,
"protections": 28548,
"rm": 28549,
"##rmi": 28550,
"##rued": 28551,
"forceful": 28552,
"##enes": 28553,
"fuss": 28554,
"##tao": 28555,
"##wash": 28556,
"brat": 28557,
"oppressive": 28558,
"reykjavik": 28559,
"spartak": 28560,
"ticking": 28561,
"##inkles": 28562,
"##kiewicz": 28563,
"adolph": 28564,
"horst": 28565,
"maui": 28566,
"protege": 28567,
"straighten": 28568,
"cpc": 28569,
"landau": 28570,
"concourse": 28571,
"clements": 28572,
"resultant": 28573,
"##ando": 28574,
"imaginative": 28575,
"joo": 28576,
"reactivated": 28577,
"##rem": 28578,
"##ffled": 28579,
"##uising": 28580,
"consultative": 28581,
"##guide": 28582,
"flop": 28583,
"kaitlyn": 28584,
"mergers": 28585,
"parenting": 28586,
"somber": 28587,
"##vron": 28588,
"supervise": 28589,
"vidhan": 28590,
"##imum": 28591,
"courtship": 28592,
"exemplified": 28593,
"harmonies": 28594,
"medallist": 28595,
"refining": 28596,
"##rrow": 28597,
"##ка": 28598,
"amara": 28599,
"##hum": 28600,
"780": 28601,
"goalscorer": 28602,
"sited": 28603,
"overshadowed": 28604,
"rohan": 28605,
"displeasure": 28606,
"secretive": 28607,
"multiplied": 28608,
"osman": 28609,
"##orth": 28610,
"engravings": 28611,
"padre": 28612,
"##kali": 28613,
"##veda": 28614,
"miniatures": 28615,
"mis": 28616,
"##yala": 28617,
"clap": 28618,
"pali": 28619,
"rook": 28620,
"##cana": 28621,
"1692": 28622,
"57th": 28623,
"antennae": 28624,
"astro": 28625,
"oskar": 28626,
"1628": 28627,
"bulldog": 28628,
"crotch": 28629,
"hackett": 28630,
"yucatan": 28631,
"##sure": 28632,
"amplifiers": 28633,
"brno": 28634,
"ferrara": 28635,
"migrating": 28636,
"##gree": 28637,
"thanking": 28638,
"turing": 28639,
"##eza": 28640,
"mccann": 28641,
"ting": 28642,
"andersson": 28643,
"onslaught": 28644,
"gaines": 28645,
"ganga": 28646,
"incense": 28647,
"standardization": 28648,
"##mation": 28649,
"sentai": 28650,
"scuba": 28651,
"stuffing": 28652,
"turquoise": 28653,
"waivers": 28654,
"alloys": 28655,
"##vitt": 28656,
"regaining": 28657,
"vaults": 28658,
"##clops": 28659,
"##gizing": 28660,
"digger": 28661,
"furry": 28662,
"memorabilia": 28663,
"probing": 28664,
"##iad": 28665,
"payton": 28666,
"rec": 28667,
"deutschland": 28668,
"filippo": 28669,
"opaque": 28670,
"seamen": 28671,
"zenith": 28672,
"afrikaans": 28673,
"##filtration": 28674,
"disciplined": 28675,
"inspirational": 28676,
"##merie": 28677,
"banco": 28678,
"confuse": 28679,
"grafton": 28680,
"tod": 28681,
"##dgets": 28682,
"championed": 28683,
"simi": 28684,
"anomaly": 28685,
"biplane": 28686,
"##ceptive": 28687,
"electrode": 28688,
"##para": 28689,
"1697": 28690,
"cleavage": 28691,
"crossbow": 28692,
"swirl": 28693,
"informant": 28694,
"##lars": 28695,
"##osta": 28696,
"afi": 28697,
"bonfire": 28698,
"spec": 28699,
"##oux": 28700,
"lakeside": 28701,
"slump": 28702,
"##culus": 28703,
"##lais": 28704,
"##qvist": 28705,
"##rrigan": 28706,
"1016": 28707,
"facades": 28708,
"borg": 28709,
"inwardly": 28710,
"cervical": 28711,
"xl": 28712,
"pointedly": 28713,
"050": 28714,
"stabilization": 28715,
"##odon": 28716,
"chests": 28717,
"1699": 28718,
"hacked": 28719,
"ctv": 28720,
"orthogonal": 28721,
"suzy": 28722,
"##lastic": 28723,
"gaulle": 28724,
"jacobite": 28725,
"rearview": 28726,
"##cam": 28727,
"##erted": 28728,
"ashby": 28729,
"##drik": 28730,
"##igate": 28731,
"##mise": 28732,
"##zbek": 28733,
"affectionately": 28734,
"canine": 28735,
"disperse": 28736,
"latham": 28737,
"##istles": 28738,
"##ivar": 28739,
"spielberg": 28740,
"##orin": 28741,
"##idium": 28742,
"ezekiel": 28743,
"cid": 28744,
"##sg": 28745,
"durga": 28746,
"middletown": 28747,
"##cina": 28748,
"customized": 28749,
"frontiers": 28750,
"harden": 28751,
"##etano": 28752,
"##zzy": 28753,
"1604": 28754,
"bolsheviks": 28755,
"##66": 28756,
"coloration": 28757,
"yoko": 28758,
"##bedo": 28759,
"briefs": 28760,
"slabs": 28761,
"debra": 28762,
"liquidation": 28763,
"plumage": 28764,
"##oin": 28765,
"blossoms": 28766,
"dementia": 28767,
"subsidy": 28768,
"1611": 28769,
"proctor": 28770,
"relational": 28771,
"jerseys": 28772,
"parochial": 28773,
"ter": 28774,
"##ici": 28775,
"esa": 28776,
"peshawar": 28777,
"cavalier": 28778,
"loren": 28779,
"cpi": 28780,
"idiots": 28781,
"shamrock": 28782,
"1646": 28783,
"dutton": 28784,
"malabar": 28785,
"mustache": 28786,
"##endez": 28787,
"##ocytes": 28788,
"referencing": 28789,
"terminates": 28790,
"marche": 28791,
"yarmouth": 28792,
"##sop": 28793,
"acton": 28794,
"mated": 28795,
"seton": 28796,
"subtly": 28797,
"baptised": 28798,
"beige": 28799,
"extremes": 28800,
"jolted": 28801,
"kristina": 28802,
"telecast": 28803,
"##actic": 28804,
"safeguard": 28805,
"waldo": 28806,
"##baldi": 28807,
"##bular": 28808,
"endeavors": 28809,
"sloppy": 28810,
"subterranean": 28811,
"##ensburg": 28812,
"##itung": 28813,
"delicately": 28814,
"pigment": 28815,
"tq": 28816,
"##scu": 28817,
"1626": 28818,
"##ound": 28819,
"collisions": 28820,
"coveted": 28821,
"herds": 28822,
"##personal": 28823,
"##meister": 28824,
"##nberger": 28825,
"chopra": 28826,
"##ricting": 28827,
"abnormalities": 28828,
"defective": 28829,
"galician": 28830,
"lucie": 28831,
"##dilly": 28832,
"alligator": 28833,
"likened": 28834,
"##genase": 28835,
"burundi": 28836,
"clears": 28837,
"complexion": 28838,
"derelict": 28839,
"deafening": 28840,
"diablo": 28841,
"fingered": 28842,
"champaign": 28843,
"dogg": 28844,
"enlist": 28845,
"isotope": 28846,
"labeling": 28847,
"mrna": 28848,
"##erre": 28849,
"brilliance": 28850,
"marvelous": 28851,
"##ayo": 28852,
"1652": 28853,
"crawley": 28854,
"ether": 28855,
"footed": 28856,
"dwellers": 28857,
"deserts": 28858,
"hamish": 28859,
"rubs": 28860,
"warlock": 28861,
"skimmed": 28862,
"##lizer": 28863,
"870": 28864,
"buick": 28865,
"embark": 28866,
"heraldic": 28867,
"irregularities": 28868,
"##ajan": 28869,
"kiara": 28870,
"##kulam": 28871,
"##ieg": 28872,
"antigen": 28873,
"kowalski": 28874,
"##lge": 28875,
"oakley": 28876,
"visitation": 28877,
"##mbit": 28878,
"vt": 28879,
"##suit": 28880,
"1570": 28881,
"murderers": 28882,
"##miento": 28883,
"##rites": 28884,
"chimneys": 28885,
"##sling": 28886,
"condemn": 28887,
"custer": 28888,
"exchequer": 28889,
"havre": 28890,
"##ghi": 28891,
"fluctuations": 28892,
"##rations": 28893,
"dfb": 28894,
"hendricks": 28895,
"vaccines": 28896,
"##tarian": 28897,
"nietzsche": 28898,
"biking": 28899,
"juicy": 28900,
"##duced": 28901,
"brooding": 28902,
"scrolling": 28903,
"selangor": 28904,
"##ragan": 28905,
"352": 28906,
"annum": 28907,
"boomed": 28908,
"seminole": 28909,
"sugarcane": 28910,
"##dna": 28911,
"departmental": 28912,
"dismissing": 28913,
"innsbruck": 28914,
"arteries": 28915,
"ashok": 28916,
"batavia": 28917,
"daze": 28918,
"kun": 28919,
"overtook": 28920,
"##rga": 28921,
"##tlan": 28922,
"beheaded": 28923,
"gaddafi": 28924,
"holm": 28925,
"electronically": 28926,
"faulty": 28927,
"galilee": 28928,
"fractures": 28929,
"kobayashi": 28930,
"##lized": 28931,
"gunmen": 28932,
"magma": 28933,
"aramaic": 28934,
"mala": 28935,
"eastenders": 28936,
"inference": 28937,
"messengers": 28938,
"bf": 28939,
"##qu": 28940,
"407": 28941,
"bathrooms": 28942,
"##vere": 28943,
"1658": 28944,
"flashbacks": 28945,
"ideally": 28946,
"misunderstood": 28947,
"##jali": 28948,
"##weather": 28949,
"mendez": 28950,
"##grounds": 28951,
"505": 28952,
"uncanny": 28953,
"##iii": 28954,
"1709": 28955,
"friendships": 28956,
"##nbc": 28957,
"sacrament": 28958,
"accommodated": 28959,
"reiterated": 28960,
"logistical": 28961,
"pebbles": 28962,
"thumped": 28963,
"##escence": 28964,
"administering": 28965,
"decrees": 28966,
"drafts": 28967,
"##flight": 28968,
"##cased": 28969,
"##tula": 28970,
"futuristic": 28971,
"picket": 28972,
"intimidation": 28973,
"winthrop": 28974,
"##fahan": 28975,
"interfered": 28976,
"339": 28977,
"afar": 28978,
"francoise": 28979,
"morally": 28980,
"uta": 28981,
"cochin": 28982,
"croft": 28983,
"dwarfs": 28984,
"##bruck": 28985,
"##dents": 28986,
"##nami": 28987,
"biker": 28988,
"##hner": 28989,
"##meral": 28990,
"nano": 28991,
"##isen": 28992,
"##ometric": 28993,
"##pres": 28994,
"##ан": 28995,
"brightened": 28996,
"meek": 28997,
"parcels": 28998,
"securely": 28999,
"gunners": 29000,
"##jhl": 29001,
"##zko": 29002,
"agile": 29003,
"hysteria": 29004,
"##lten": 29005,
"##rcus": 29006,
"bukit": 29007,
"champs": 29008,
"chevy": 29009,
"cuckoo": 29010,
"leith": 29011,
"sadler": 29012,
"theologians": 29013,
"welded": 29014,
"##section": 29015,
"1663": 29016,
"jj": 29017,
"plurality": 29018,
"xander": 29019,
"##rooms": 29020,
"##formed": 29021,
"shredded": 29022,
"temps": 29023,
"intimately": 29024,
"pau": 29025,
"tormented": 29026,
"##lok": 29027,
"##stellar": 29028,
"1618": 29029,
"charred": 29030,
"ems": 29031,
"essen": 29032,
"##mmel": 29033,
"alarms": 29034,
"spraying": 29035,
"ascot": 29036,
"blooms": 29037,
"twinkle": 29038,
"##abia": 29039,
"##apes": 29040,
"internment": 29041,
"obsidian": 29042,
"##chaft": 29043,
"snoop": 29044,
"##dav": 29045,
"##ooping": 29046,
"malibu": 29047,
"##tension": 29048,
"quiver": 29049,
"##itia": 29050,
"hays": 29051,
"mcintosh": 29052,
"travers": 29053,
"walsall": 29054,
"##ffie": 29055,
"1623": 29056,
"beverley": 29057,
"schwarz": 29058,
"plunging": 29059,
"structurally": 29060,
"m3": 29061,
"rosenthal": 29062,
"vikram": 29063,
"##tsk": 29064,
"770": 29065,
"ghz": 29066,
"##onda": 29067,
"##tiv": 29068,
"chalmers": 29069,
"groningen": 29070,
"pew": 29071,
"reckon": 29072,
"unicef": 29073,
"##rvis": 29074,
"55th": 29075,
"##gni": 29076,
"1651": 29077,
"sulawesi": 29078,
"avila": 29079,
"cai": 29080,
"metaphysical": 29081,
"screwing": 29082,
"turbulence": 29083,
"##mberg": 29084,
"augusto": 29085,
"samba": 29086,
"56th": 29087,
"baffled": 29088,
"momentary": 29089,
"toxin": 29090,
"##urian": 29091,
"##wani": 29092,
"aachen": 29093,
"condoms": 29094,
"dali": 29095,
"steppe": 29096,
"##3d": 29097,
"##app": 29098,
"##oed": 29099,
"##year": 29100,
"adolescence": 29101,
"dauphin": 29102,
"electrically": 29103,
"inaccessible": 29104,
"microscopy": 29105,
"nikita": 29106,
"##ega": 29107,
"atv": 29108,
"##cel": 29109,
"##enter": 29110,
"##oles": 29111,
"##oteric": 29112,
"##ы": 29113,
"accountants": 29114,
"punishments": 29115,
"wrongly": 29116,
"bribes": 29117,
"adventurous": 29118,
"clinch": 29119,
"flinders": 29120,
"southland": 29121,
"##hem": 29122,
"##kata": 29123,
"gough": 29124,
"##ciency": 29125,
"lads": 29126,
"soared": 29127,
"##ה": 29128,
"undergoes": 29129,
"deformation": 29130,
"outlawed": 29131,
"rubbish": 29132,
"##arus": 29133,
"##mussen": 29134,
"##nidae": 29135,
"##rzburg": 29136,
"arcs": 29137,
"##ingdon": 29138,
"##tituted": 29139,
"1695": 29140,
"wheelbase": 29141,
"wheeling": 29142,
"bombardier": 29143,
"campground": 29144,
"zebra": 29145,
"##lices": 29146,
"##oj": 29147,
"##bain": 29148,
"lullaby": 29149,
"##ecure": 29150,
"donetsk": 29151,
"wylie": 29152,
"grenada": 29153,
"##arding": 29154,
"##ης": 29155,
"squinting": 29156,
"eireann": 29157,
"opposes": 29158,
"##andra": 29159,
"maximal": 29160,
"runes": 29161,
"##broken": 29162,
"##cuting": 29163,
"##iface": 29164,
"##ror": 29165,
"##rosis": 29166,
"additive": 29167,
"britney": 29168,
"adultery": 29169,
"triggering": 29170,
"##drome": 29171,
"detrimental": 29172,
"aarhus": 29173,
"containment": 29174,
"jc": 29175,
"swapped": 29176,
"vichy": 29177,
"##ioms": 29178,
"madly": 29179,
"##oric": 29180,
"##rag": 29181,
"brant": 29182,
"##ckey": 29183,
"##trix": 29184,
"1560": 29185,
"1612": 29186,
"broughton": 29187,
"rustling": 29188,
"##stems": 29189,
"##uder": 29190,
"asbestos": 29191,
"mentoring": 29192,
"##nivorous": 29193,
"finley": 29194,
"leaps": 29195,
"##isan": 29196,
"apical": 29197,
"pry": 29198,
"slits": 29199,
"substitutes": 29200,
"##dict": 29201,
"intuitive": 29202,
"fantasia": 29203,
"insistent": 29204,
"unreasonable": 29205,
"##igen": 29206,
"##vna": 29207,
"domed": 29208,
"hannover": 29209,
"margot": 29210,
"ponder": 29211,
"##zziness": 29212,
"impromptu": 29213,
"jian": 29214,
"lc": 29215,
"rampage": 29216,
"stemming": 29217,
"##eft": 29218,
"andrey": 29219,
"gerais": 29220,
"whichever": 29221,
"amnesia": 29222,
"appropriated": 29223,
"anzac": 29224,
"clicks": 29225,
"modifying": 29226,
"ultimatum": 29227,
"cambrian": 29228,
"maids": 29229,
"verve": 29230,
"yellowstone": 29231,
"##mbs": 29232,
"conservatoire": 29233,
"##scribe": 29234,
"adherence": 29235,
"dinners": 29236,
"spectra": 29237,
"imperfect": 29238,
"mysteriously": 29239,
"sidekick": 29240,
"tatar": 29241,
"tuba": 29242,
"##aks": 29243,
"##ifolia": 29244,
"distrust": 29245,
"##athan": 29246,
"##zle": 29247,
"c2": 29248,
"ronin": 29249,
"zac": 29250,
"##pse": 29251,
"celaena": 29252,
"instrumentalist": 29253,
"scents": 29254,
"skopje": 29255,
"##mbling": 29256,
"comical": 29257,
"compensated": 29258,
"vidal": 29259,
"condor": 29260,
"intersect": 29261,
"jingle": 29262,
"wavelengths": 29263,
"##urrent": 29264,
"mcqueen": 29265,
"##izzly": 29266,
"carp": 29267,
"weasel": 29268,
"422": 29269,
"kanye": 29270,
"militias": 29271,
"postdoctoral": 29272,
"eugen": 29273,
"gunslinger": 29274,
"##ɛ": 29275,
"faux": 29276,
"hospice": 29277,
"##for": 29278,
"appalled": 29279,
"derivation": 29280,
"dwarves": 29281,
"##elis": 29282,
"dilapidated": 29283,
"##folk": 29284,
"astoria": 29285,
"philology": 29286,
"##lwyn": 29287,
"##otho": 29288,
"##saka": 29289,
"inducing": 29290,
"philanthropy": 29291,
"##bf": 29292,
"##itative": 29293,
"geek": 29294,
"markedly": 29295,
"sql": 29296,
"##yce": 29297,
"bessie": 29298,
"indices": 29299,
"rn": 29300,
"##flict": 29301,
"495": 29302,
"frowns": 29303,
"resolving": 29304,
"weightlifting": 29305,
"tugs": 29306,
"cleric": 29307,
"contentious": 29308,
"1653": 29309,
"mania": 29310,
"rms": 29311,
"##miya": 29312,
"##reate": 29313,
"##ruck": 29314,
"##tucket": 29315,
"bien": 29316,
"eels": 29317,
"marek": 29318,
"##ayton": 29319,
"##cence": 29320,
"discreet": 29321,
"unofficially": 29322,
"##ife": 29323,
"leaks": 29324,
"##bber": 29325,
"1705": 29326,
"332": 29327,
"dung": 29328,
"compressor": 29329,
"hillsborough": 29330,
"pandit": 29331,
"shillings": 29332,
"distal": 29333,
"##skin": 29334,
"381": 29335,
"##tat": 29336,
"##you": 29337,
"nosed": 29338,
"##nir": 29339,
"mangrove": 29340,
"undeveloped": 29341,
"##idia": 29342,
"textures": 29343,
"##inho": 29344,
"##500": 29345,
"##rise": 29346,
"ae": 29347,
"irritating": 29348,
"nay": 29349,
"amazingly": 29350,
"bancroft": 29351,
"apologetic": 29352,
"compassionate": 29353,
"kata": 29354,
"symphonies": 29355,
"##lovic": 29356,
"airspace": 29357,
"##lch": 29358,
"930": 29359,
"gifford": 29360,
"precautions": 29361,
"fulfillment": 29362,
"sevilla": 29363,
"vulgar": 29364,
"martinique": 29365,
"##urities": 29366,
"looting": 29367,
"piccolo": 29368,
"tidy": 29369,
"##dermott": 29370,
"quadrant": 29371,
"armchair": 29372,
"incomes": 29373,
"mathematicians": 29374,
"stampede": 29375,
"nilsson": 29376,
"##inking": 29377,
"##scan": 29378,
"foo": 29379,
"quarterfinal": 29380,
"##ostal": 29381,
"shang": 29382,
"shouldered": 29383,
"squirrels": 29384,
"##owe": 29385,
"344": 29386,
"vinegar": 29387,
"##bner": 29388,
"##rchy": 29389,
"##systems": 29390,
"delaying": 29391,
"##trics": 29392,
"ars": 29393,
"dwyer": 29394,
"rhapsody": 29395,
"sponsoring": 29396,
"##gration": 29397,
"bipolar": 29398,
"cinder": 29399,
"starters": 29400,
"##olio": 29401,
"##urst": 29402,
"421": 29403,
"signage": 29404,
"##nty": 29405,
"aground": 29406,
"figurative": 29407,
"mons": 29408,
"acquaintances": 29409,
"duets": 29410,
"erroneously": 29411,
"soyuz": 29412,
"elliptic": 29413,
"recreated": 29414,
"##cultural": 29415,
"##quette": 29416,
"##ssed": 29417,
"##tma": 29418,
"##zcz": 29419,
"moderator": 29420,
"scares": 29421,
"##itaire": 29422,
"##stones": 29423,
"##udence": 29424,
"juniper": 29425,
"sighting": 29426,
"##just": 29427,
"##nsen": 29428,
"britten": 29429,
"calabria": 29430,
"ry": 29431,
"bop": 29432,
"cramer": 29433,
"forsyth": 29434,
"stillness": 29435,
"##л": 29436,
"airmen": 29437,
"gathers": 29438,
"unfit": 29439,
"##umber": 29440,
"##upt": 29441,
"taunting": 29442,
"##rip": 29443,
"seeker": 29444,
"streamlined": 29445,
"##bution": 29446,
"holster": 29447,
"schumann": 29448,
"tread": 29449,
"vox": 29450,
"##gano": 29451,
"##onzo": 29452,
"strive": 29453,
"dil": 29454,
"reforming": 29455,
"covent": 29456,
"newbury": 29457,
"predicting": 29458,
"##orro": 29459,
"decorate": 29460,
"tre": 29461,
"##puted": 29462,
"andover": 29463,
"ie": 29464,
"asahi": 29465,
"dept": 29466,
"dunkirk": 29467,
"gills": 29468,
"##tori": 29469,
"buren": 29470,
"huskies": 29471,
"##stis": 29472,
"##stov": 29473,
"abstracts": 29474,
"bets": 29475,
"loosen": 29476,
"##opa": 29477,
"1682": 29478,
"yearning": 29479,
"##glio": 29480,
"##sir": 29481,
"berman": 29482,
"effortlessly": 29483,
"enamel": 29484,
"napoli": 29485,
"persist": 29486,
"##peration": 29487,
"##uez": 29488,
"attache": 29489,
"elisa": 29490,
"b1": 29491,
"invitations": 29492,
"##kic": 29493,
"accelerating": 29494,
"reindeer": 29495,
"boardwalk": 29496,
"clutches": 29497,
"nelly": 29498,
"polka": 29499,
"starbucks": 29500,
"##kei": 29501,
"adamant": 29502,
"huey": 29503,
"lough": 29504,
"unbroken": 29505,
"adventurer": 29506,
"embroidery": 29507,
"inspecting": 29508,
"stanza": 29509,
"##ducted": 29510,
"naia": 29511,
"taluka": 29512,
"##pone": 29513,
"##roids": 29514,
"chases": 29515,
"deprivation": 29516,
"florian": 29517,
"##jing": 29518,
"##ppet": 29519,
"earthly": 29520,
"##lib": 29521,
"##ssee": 29522,
"colossal": 29523,
"foreigner": 29524,
"vet": 29525,
"freaks": 29526,
"patrice": 29527,
"rosewood": 29528,
"triassic": 29529,
"upstate": 29530,
"##pkins": 29531,
"dominates": 29532,
"ata": 29533,
"chants": 29534,
"ks": 29535,
"vo": 29536,
"##400": 29537,
"##bley": 29538,
"##raya": 29539,
"##rmed": 29540,
"555": 29541,
"agra": 29542,
"infiltrate": 29543,
"##ailing": 29544,
"##ilation": 29545,
"##tzer": 29546,
"##uppe": 29547,
"##werk": 29548,
"binoculars": 29549,
"enthusiast": 29550,
"fujian": 29551,
"squeak": 29552,
"##avs": 29553,
"abolitionist": 29554,
"almeida": 29555,
"boredom": 29556,
"hampstead": 29557,
"marsden": 29558,
"rations": 29559,
"##ands": 29560,
"inflated": 29561,
"334": 29562,
"bonuses": 29563,
"rosalie": 29564,
"patna": 29565,
"##rco": 29566,
"329": 29567,
"detachments": 29568,
"penitentiary": 29569,
"54th": 29570,
"flourishing": 29571,
"woolf": 29572,
"##dion": 29573,
"##etched": 29574,
"papyrus": 29575,
"##lster": 29576,
"##nsor": 29577,
"##toy": 29578,
"bobbed": 29579,
"dismounted": 29580,
"endelle": 29581,
"inhuman": 29582,
"motorola": 29583,
"tbs": 29584,
"wince": 29585,
"wreath": 29586,
"##ticus": 29587,
"hideout": 29588,
"inspections": 29589,
"sanjay": 29590,
"disgrace": 29591,
"infused": 29592,
"pudding": 29593,
"stalks": 29594,
"##urbed": 29595,
"arsenic": 29596,
"leases": 29597,
"##hyl": 29598,
"##rrard": 29599,
"collarbone": 29600,
"##waite": 29601,
"##wil": 29602,
"dowry": 29603,
"##bant": 29604,
"##edance": 29605,
"genealogical": 29606,
"nitrate": 29607,
"salamanca": 29608,
"scandals": 29609,
"thyroid": 29610,
"necessitated": 29611,
"##!": 29612,
"##\"": 29613,
"###": 29614,
"##$": 29615,
"##%": 29616,
"##&": 29617,
"##'": 29618,
"##(": 29619,
"##)": 29620,
"##*": 29621,
"##+": 29622,
"##,": 29623,
"##-": 29624,
"##.": 29625,
"##/": 29626,
"##:": 29627,
"##;": 29628,
"##<": 29629,
"##=": 29630,
"##>": 29631,
"##?": 29632,
"##@": 29633,
"##[": 29634,
"##\\": 29635,
"##]": 29636,
"##^": 29637,
"##_": 29638,
"##
"##{": 29640,
"##|": 29641,
"##}": 29642,
"##~": 29643,
"##¡": 29644,
"##¢": 29645,
"##£": 29646,
"##¤": 29647,
"##¥": 29648,
"##¦": 29649,
"##§": 29650,
"##¨": 29651,
"##©": 29652,
"##ª": 29653,
"##«": 29654,
"##¬": 29655,
"##®": 29656,
"##±": 29657,
"##´": 29658,
"##µ": 29659,
"##¶": 29660,
"##·": 29661,
"##º": 29662,
"##»": 29663,
"##¼": 29664,
"##¾": 29665,
"##¿": 29666,
"##æ": 29667,
"##ð": 29668,
"##÷": 29669,
"##þ": 29670,
"##đ": 29671,
"##ħ": 29672,
"##ŋ": 29673,
"##œ": 29674,
"##ƒ": 29675,
"##ɐ": 29676,
"##ɑ": 29677,
"##ɒ": 29678,
"##ɔ": 29679,
"##ɕ": 29680,
"##ə": 29681,
"##ɡ": 29682,
"##ɣ": 29683,
"##ɨ": 29684,
"##ɪ": 29685,
"##ɫ": 29686,
"##ɬ": 29687,
"##ɯ": 29688,
"##ɲ": 29689,
"##ɴ": 29690,
"##ɹ": 29691,
"##ɾ": 29692,
"##ʀ": 29693,
"##ʁ": 29694,
"##ʂ": 29695,
"##ʃ": 29696,
"##ʉ": 29697,
"##ʊ": 29698,
"##ʋ": 29699,
"##ʌ": 29700,
"##ʎ": 29701,
"##ʐ": 29702,
"##ʑ": 29703,
"##ʒ": 29704,
"##ʔ": 29705,
"##ʰ": 29706,
"##ʲ": 29707,
"##ʳ": 29708,
"##ʷ": 29709,
"##ʸ": 29710,
"##ʻ": 29711,
"##ʼ": 29712,
"##ʾ": 29713,
"##ʿ": 29714,
"##ˈ": 29715,
"##ˡ": 29716,
"##ˢ": 29717,
"##ˣ": 29718,
"##ˤ": 29719,
"##β": 29720,
"##γ": 29721,
"##δ": 29722,
"##ε": 29723,
"##ζ": 29724,
"##θ": 29725,
"##κ": 29726,
"##λ": 29727,
"##μ": 29728,
"##ξ": 29729,
"##ο": 29730,
"##π": 29731,
"##ρ": 29732,
"##σ": 29733,
"##τ": 29734,
"##υ": 29735,
"##φ": 29736,
"##χ": 29737,
"##ψ": 29738,
"##ω": 29739,
"##б": 29740,
"##г": 29741,
"##д": 29742,
"##ж": 29743,
"##з": 29744,
"##м": 29745,
"##п": 29746,
"##с": 29747,
"##у": 29748,
"##ф": 29749,
"##х": 29750,
"##ц": 29751,
"##ч": 29752,
"##ш": 29753,
"##щ": 29754,
"##ъ": 29755,
"##э": 29756,
"##ю": 29757,
"##ђ": 29758,
"##є": 29759,
"##і": 29760,
"##ј": 29761,
"##љ": 29762,
"##њ": 29763,
"##ћ": 29764,
"##ӏ": 29765,
"##ա": 29766,
"##բ": 29767,
"##գ": 29768,
"##դ": 29769,
"##ե": 29770,
"##թ": 29771,
"##ի": 29772,
"##լ": 29773,
"##կ": 29774,
"##հ": 29775,
"##մ": 29776,
"##յ": 29777,
"##ն": 29778,
"##ո": 29779,
"##պ": 29780,
"##ս": 29781,
"##վ": 29782,
"##տ": 29783,
"##ր": 29784,
"##ւ": 29785,
"##ք": 29786,
"##־": 29787,
"##א": 29788,
"##ב": 29789,
"##ג": 29790,
"##ד": 29791,
"##ו": 29792,
"##ז": 29793,
"##ח": 29794,
"##ט": 29795,
"##י": 29796,
"##ך": 29797,
"##כ": 29798,
"##ל": 29799,
"##ם": 29800,
"##מ": 29801,
"##ן": 29802,
"##נ": 29803,
"##ס": 29804,
"##ע": 29805,
"##ף": 29806,
"##פ": 29807,
"##ץ": 29808,
"##צ": 29809,
"##ק": 29810,
"##ר": 29811,
"##ש": 29812,
"##ת": 29813,
"##،": 29814,
"##ء": 29815,
"##ب": 29816,
"##ت": 29817,
"##ث": 29818,
"##ج": 29819,
"##ح": 29820,
"##خ": 29821,
"##ذ": 29822,
"##ز": 29823,
"##س": 29824,
"##ش": 29825,
"##ص": 29826,
"##ض": 29827,
"##ط": 29828,
"##ظ": 29829,
"##ع": 29830,
"##غ": 29831,
"##ـ": 29832,
"##ف": 29833,
"##ق": 29834,
"##ك": 29835,
"##و": 29836,
"##ى": 29837,
"##ٹ": 29838,
"##پ": 29839,
"##چ": 29840,
"##ک": 29841,
"##گ": 29842,
"##ں": 29843,
"##ھ": 29844,
"##ہ": 29845,
"##ے": 29846,
"##अ": 29847,
"##आ": 29848,
"##उ": 29849,
"##ए": 29850,
"##क": 29851,
"##ख": 29852,
"##ग": 29853,
"##च": 29854,
"##ज": 29855,
"##ट": 29856,
"##ड": 29857,
"##ण": 29858,
"##त": 29859,
"##थ": 29860,
"##द": 29861,
"##ध": 29862,
"##न": 29863,
"##प": 29864,
"##ब": 29865,
"##भ": 29866,
"##म": 29867,
"##य": 29868,
"##र": 29869,
"##ल": 29870,
"##व": 29871,
"##श": 29872,
"##ष": 29873,
"##स": 29874,
"##ह": 29875,
"##ा": 29876,
"##ि": 29877,
"##ी": 29878,
"##ो": 29879,
"##।": 29880,
"##॥": 29881,
"##ং": 29882,
"##অ": 29883,
"##আ": 29884,
"##ই": 29885,
"##উ": 29886,
"##এ": 29887,
"##ও": 29888,
"##ক": 29889,
"##খ": 29890,
"##গ": 29891,
"##চ": 29892,
"##ছ": 29893,
"##জ": 29894,
"##ট": 29895,
"##ড": 29896,
"##ণ": 29897,
"##ত": 29898,
"##থ": 29899,
"##দ": 29900,
"##ধ": 29901,
"##ন": 29902,
"##প": 29903,
"##ব": 29904,
"##ভ": 29905,
"##ম": 29906,
"##য": 29907,
"##র": 29908,
"##ল": 29909,
"##শ": 29910,
"##ষ": 29911,
"##স": 29912,
"##হ": 29913,
"##া": 29914,
"##ি": 29915,
"##ী": 29916,
"##ে": 29917,
"##க": 29918,
"##ச": 29919,
"##ட": 29920,
"##த": 29921,
"##ந": 29922,
"##ன": 29923,
"##ப": 29924,
"##ம": 29925,
"##ய": 29926,
"##ர": 29927,
"##ல": 29928,
"##ள": 29929,
"##வ": 29930,
"##ா": 29931,
"##ி": 29932,
"##ு": 29933,
"##ே": 29934,
"##ை": 29935,
"##ನ": 29936,
"##ರ": 29937,
"##ಾ": 29938,
"##ක": 29939,
"##ය": 29940,
"##ර": 29941,
"##ල": 29942,
"##ව": 29943,
"##ා": 29944,
"##ก": 29945,
"##ง": 29946,
"##ต": 29947,
"##ท": 29948,
"##น": 29949,
"##พ": 29950,
"##ม": 29951,
"##ย": 29952,
"##ร": 29953,
"##ล": 29954,
"##ว": 29955,
"##ส": 29956,
"##อ": 29957,
"##า": 29958,
"##เ": 29959,
"##་": 29960,
"##།": 29961,
"##ག": 29962,
"##ང": 29963,
"##ད": 29964,
"##ན": 29965,
"##པ": 29966,
"##བ": 29967,
"##མ": 29968,
"##འ": 29969,
"##ར": 29970,
"##ལ": 29971,
"##ས": 29972,
"##မ": 29973,
"##ა": 29974,
"##ბ": 29975,
"##გ": 29976,
"##დ": 29977,
"##ე": 29978,
"##ვ": 29979,
"##თ": 29980,
"##ი": 29981,
"##კ": 29982,
"##ლ": 29983,
"##მ": 29984,
"##ნ": 29985,
"##ო": 29986,
"##რ": 29987,
"##ს": 29988,
"##ტ": 29989,
"##უ": 29990,
"##ᄀ": 29991,
"##ᄂ": 29992,
"##ᄃ": 29993,
"##ᄅ": 29994,
"##ᄆ": 29995,
"##ᄇ": 29996,
"##ᄉ": 29997,
"##ᄊ": 29998,
"##ᄋ": 29999,
"##ᄌ": 30000,
"##ᄎ": 30001,
"##ᄏ": 30002,
"##ᄐ": 30003,
"##ᄑ": 30004,
"##ᄒ": 30005,
"##ᅡ": 30006,
"##ᅢ": 30007,
"##ᅥ": 30008,
"##ᅦ": 30009,
"##ᅧ": 30010,
"##ᅩ": 30011,
"##ᅪ": 30012,
"##ᅭ": 30013,
"##ᅮ": 30014,
"##ᅯ": 30015,
"##ᅲ": 30016,
"##ᅳ": 30017,
"##ᅴ": 30018,
"##ᅵ": 30019,
"##ᆨ": 30020,
"##ᆫ": 30021,
"##ᆯ": 30022,
"##ᆷ": 30023,
"##ᆸ": 30024,
"##ᆼ": 30025,
"##ᴬ": 30026,
"##ᴮ": 30027,
"##ᴰ": 30028,
"##ᴵ": 30029,
"##ᴺ": 30030,
"##ᵀ": 30031,
"##ᵃ": 30032,
"##ᵇ": 30033,
"##ᵈ": 30034,
"##ᵉ": 30035,
"##ᵍ": 30036,
"##ᵏ": 30037,
"##ᵐ": 30038,
"##ᵒ": 30039,
"##ᵖ": 30040,
"##ᵗ": 30041,
"##ᵘ": 30042,
"##ᵣ": 30043,
"##ᵤ": 30044,
"##ᵥ": 30045,
"##ᶜ": 30046,
"##ᶠ": 30047,
"##‐": 30048,
"##‑": 30049,
"##‒": 30050,
"##–": 30051,
"##—": 30052,
"##―": 30053,
"##‖": 30054,
"##‘": 30055,
"##’": 30056,
"##‚": 30057,
"##“": 30058,
"##”": 30059,
"##„": 30060,
"##†": 30061,
"##‡": 30062,
"##•": 30063,
"##…": 30064,
"##‰": 30065,
"##′": 30066,
"##″": 30067,
"##›": 30068,
"##‿": 30069,
"##⁄": 30070,
"##⁰": 30071,
"##ⁱ": 30072,
"##⁴": 30073,
"##⁵": 30074,
"##⁶": 30075,
"##⁷": 30076,
"##⁸": 30077,
"##⁹": 30078,
"##⁻": 30079,
"##ⁿ": 30080,
"##₅": 30081,
"##₆": 30082,
"##₇": 30083,
"##₈": 30084,
"##₉": 30085,
"##₊": 30086,
"##₍": 30087,
"##₎": 30088,
"##ₐ": 30089,
"##ₑ": 30090,
"##ₒ": 30091,
"##ₓ": 30092,
"##ₕ": 30093,
"##ₖ": 30094,
"##ₗ": 30095,
"##ₘ": 30096,
"##ₚ": 30097,
"##ₛ": 30098,
"##ₜ": 30099,
"##₤": 30100,
"##₩": 30101,
"##€": 30102,
"##₱": 30103,
"##₹": 30104,
"##ℓ": 30105,
"##№": 30106,
"##ℝ": 30107,
"##™": 30108,
"##⅓": 30109,
"##⅔": 30110,
"##←": 30111,
"##↑": 30112,
"##→": 30113,
"##↓": 30114,
"##↔": 30115,
"##↦": 30116,
"##⇄": 30117,
"##⇌": 30118,
"##⇒": 30119,
"##∂": 30120,
"##∅": 30121,
"##∆": 30122,
"##∇": 30123,
"##∈": 30124,
"##∗": 30125,
"##∘": 30126,
"##√": 30127,
"##∞": 30128,
"##∧": 30129,
"##∨": 30130,
"##∩": 30131,
"##∪": 30132,
"##≈": 30133,
"##≡": 30134,
"##≤": 30135,
"##≥": 30136,
"##⊂": 30137,
"##⊆": 30138,
"##⊕": 30139,
"##⊗": 30140,
"##⋅": 30141,
"##─": 30142,
"##│": 30143,
"##■": 30144,
"##▪": 30145,
"##●": 30146,
"##★": 30147,
"##☆": 30148,
"##☉": 30149,
"##♠": 30150,
"##♣": 30151,
"##♥": 30152,
"##♦": 30153,
"##♯": 30154,
"##⟨": 30155,
"##⟩": 30156,
"##ⱼ": 30157,
"##⺩": 30158,
"##⺼": 30159,
"##⽥": 30160,
"##、": 30161,
"##。": 30162,
"##〈": 30163,
"##〉": 30164,
"##《": 30165,
"##》": 30166,
"##「": 30167,
"##」": 30168,
"##『": 30169,
"##』": 30170,
"##〜": 30171,
"##あ": 30172,
"##い": 30173,
"##う": 30174,
"##え": 30175,
"##お": 30176,
"##か": 30177,
"##き": 30178,
"##く": 30179,
"##け": 30180,
"##こ": 30181,
"##さ": 30182,
"##し": 30183,
"##す": 30184,
"##せ": 30185,
"##そ": 30186,
"##た": 30187,
"##ち": 30188,
"##っ": 30189,
"##つ": 30190,
"##て": 30191,
"##と": 30192,
"##な": 30193,
"##に": 30194,
"##ぬ": 30195,
"##ね": 30196,
"##の": 30197,
"##は": 30198,
"##ひ": 30199,
"##ふ": 30200,
"##へ": 30201,
"##ほ": 30202,
"##ま": 30203,
"##み": 30204,
"##む": 30205,
"##め": 30206,
"##も": 30207,
"##や": 30208,
"##ゆ": 30209,
"##よ": 30210,
"##ら": 30211,
"##り": 30212,
"##る": 30213,
"##れ": 30214,
"##ろ": 30215,
"##を": 30216,
"##ん": 30217,
"##ァ": 30218,
"##ア": 30219,
"##ィ": 30220,
"##イ": 30221,
"##ウ": 30222,
"##ェ": 30223,
"##エ": 30224,
"##オ": 30225,
"##カ": 30226,
"##キ": 30227,
"##ク": 30228,
"##ケ": 30229,
"##コ": 30230,
"##サ": 30231,
"##シ": 30232,
"##ス": 30233,
"##セ": 30234,
"##タ": 30235,
"##チ": 30236,
"##ッ": 30237,
"##ツ": 30238,
"##テ": 30239,
"##ト": 30240,
"##ナ": 30241,
"##ニ": 30242,
"##ノ": 30243,
"##ハ": 30244,
"##ヒ": 30245,
"##フ": 30246,
"##ヘ": 30247,
"##ホ": 30248,
"##マ": 30249,
"##ミ": 30250,
"##ム": 30251,
"##メ": 30252,
"##モ": 30253,
"##ャ": 30254,
"##ュ": 30255,
"##ョ": 30256,
"##ラ": 30257,
"##リ": 30258,
"##ル": 30259,
"##レ": 30260,
"##ロ": 30261,
"##ワ": 30262,
"##ン": 30263,
"##・": 30264,
"##ー": 30265,
"##一": 30266,
"##三": 30267,
"##上": 30268,
"##下": 30269,
"##不": 30270,
"##世": 30271,
"##中": 30272,
"##主": 30273,
"##久": 30274,
"##之": 30275,
"##也": 30276,
"##事": 30277,
"##二": 30278,
"##五": 30279,
"##井": 30280,
"##京": 30281,
"##人": 30282,
"##亻": 30283,
"##仁": 30284,
"##介": 30285,
"##代": 30286,
"##仮": 30287,
"##伊": 30288,
"##会": 30289,
"##佐": 30290,
"##侍": 30291,
"##保": 30292,
"##信": 30293,
"##健": 30294,
"##元": 30295,
"##光": 30296,
"##八": 30297,
"##公": 30298,
"##内": 30299,
"##出": 30300,
"##分": 30301,
"##前": 30302,
"##劉": 30303,
"##力": 30304,
"##加": 30305,
"##勝": 30306,
"##北": 30307,
"##区": 30308,
"##十": 30309,
"##千": 30310,
"##南": 30311,
"##博": 30312,
"##原": 30313,
"##口": 30314,
"##古": 30315,
"##史": 30316,
"##司": 30317,
"##合": 30318,
"##吉": 30319,
"##同": 30320,
"##名": 30321,
"##和": 30322,
"##囗": 30323,
"##四": 30324,
"##国": 30325,
"##國": 30326,
"##土": 30327,
"##地": 30328,
"##坂": 30329,
"##城": 30330,
"##堂": 30331,
"##場": 30332,
"##士": 30333,
"##夏": 30334,
"##外": 30335,
"##大": 30336,
"##天": 30337,
"##太": 30338,
"##夫": 30339,
"##奈": 30340,
"##女": 30341,
"##子": 30342,
"##学": 30343,
"##宀": 30344,
"##宇": 30345,
"##安": 30346,
"##宗": 30347,
"##定": 30348,
"##宣": 30349,
"##宮": 30350,
"##家": 30351,
"##宿": 30352,
"##寺": 30353,
"##將": 30354,
"##小": 30355,
"##尚": 30356,
"##山": 30357,
"##岡": 30358,
"##島": 30359,
"##崎": 30360,
"##川": 30361,
"##州": 30362,
"##巿": 30363,
"##帝": 30364,
"##平": 30365,
"##年": 30366,
"##幸": 30367,
"##广": 30368,
"##弘": 30369,
"##張": 30370,
"##彳": 30371,
"##後": 30372,
"##御": 30373,
"##德": 30374,
"##心": 30375,
"##忄": 30376,
"##志": 30377,
"##忠": 30378,
"##愛": 30379,
"##成": 30380,
"##我": 30381,
"##戦": 30382,
"##戸": 30383,
"##手": 30384,
"##扌": 30385,
"##政": 30386,
"##文": 30387,
"##新": 30388,
"##方": 30389,
"##日": 30390,
"##明": 30391,
"##星": 30392,
"##春": 30393,
"##昭": 30394,
"##智": 30395,
"##曲": 30396,
"##書": 30397,
"##月": 30398,
"##有": 30399,
"##朝": 30400,
"##木": 30401,
"##本": 30402,
"##李": 30403,
"##村": 30404,
"##東": 30405,
"##松": 30406,
"##林": 30407,
"##森": 30408,
"##楊": 30409,
"##樹": 30410,
"##橋": 30411,
"##歌": 30412,
"##止": 30413,
"##正": 30414,
"##武": 30415,
"##比": 30416,
"##氏": 30417,
"##民": 30418,
"##水": 30419,
"##氵": 30420,
"##氷": 30421,
"##永": 30422,
"##江": 30423,
"##沢": 30424,
"##河": 30425,
"##治": 30426,
"##法": 30427,
"##海": 30428,
"##清": 30429,
"##漢": 30430,
"##瀬": 30431,
"##火": 30432,
"##版": 30433,
"##犬": 30434,
"##王": 30435,
"##生": 30436,
"##田": 30437,
"##男": 30438,
"##疒": 30439,
"##発": 30440,
"##白": 30441,
"##的": 30442,
"##皇": 30443,
"##目": 30444,
"##相": 30445,
"##省": 30446,
"##真": 30447,
"##石": 30448,
"##示": 30449,
"##社": 30450,
"##神": 30451,
"##福": 30452,
"##禾": 30453,
"##秀": 30454,
"##秋": 30455,
"##空": 30456,
"##立": 30457,
"##章": 30458,
"##竹": 30459,
"##糹": 30460,
"##美": 30461,
"##義": 30462,
"##耳": 30463,
"##良": 30464,
"##艹": 30465,
"##花": 30466,
"##英": 30467,
"##華": 30468,
"##葉": 30469,
"##藤": 30470,
"##行": 30471,
"##街": 30472,
"##西": 30473,
"##見": 30474,
"##訁": 30475,
"##語": 30476,
"##谷": 30477,
"##貝": 30478,
"##貴": 30479,
"##車": 30480,
"##軍": 30481,
"##辶": 30482,
"##道": 30483,
"##郎": 30484,
"##郡": 30485,
"##部": 30486,
"##都": 30487,
"##里": 30488,
"##野": 30489,
"##金": 30490,
"##鈴": 30491,
"##镇": 30492,
"##長": 30493,
"##門": 30494,
"##間": 30495,
"##阝": 30496,
"##阿": 30497,
"##陳": 30498,
"##陽": 30499,
"##雄": 30500,
"##青": 30501,
"##面": 30502,
"##風": 30503,
"##食": 30504,
"##香": 30505,
"##馬": 30506,
"##高": 30507,
"##龍": 30508,
"##龸": 30509,
"##fi": 30510,
"##fl": 30511,
"##!": 30512,
"##(": 30513,
"##)": 30514,
"##,": 30515,
"##-": 30516,
"##.": 30517,
"##/": 30518,
"##:": 30519,
"##?": 30520,
"##~": 30521
}
}
}
Spring Ai Client Chat/Src/Test/Resources/Bikes.Json (spring-ai-client-chat/src/test/resources/bikes.json)
[
{
"name": "E-Adrenaline 8.0 EX1",
"shortDescription": "a versatile and comfortable e-MTB designed for adrenaline enthusiasts who want to explore all types of terrain. It features a powerful motor and advanced suspension to provide a smooth and responsive ride, with a variety of customizable settings to fit any rider's needs.",
"description": "## Overview\r\nIt's right for you if...\r\nYou want to push your limits on challenging trails and terrain, with the added benefit of an electric assist to help you conquer steep climbs and rough terrain. You also want a bike with a comfortable and customizable fit, loaded with high-quality components and technology.\r\n\r\nThe tech you get\r\nA lightweight, full ADV Mountain Carbon frame with a customizable geometry, including an adjustable head tube and chainstay length. A powerful and efficient motor with a 375Wh battery that can assist up to 28 mph when it's on, and provides a smooth and seamless transition when it's off. A SRAM EX1 8-speed drivetrain, a RockShox Lyrik Ultimate fork, and a RockShox Super Deluxe Ultimate rear shock.\r\n\r\nThe final word\r\nOur E-Adrenaline 8.0 EX1 is the perfect bike for adrenaline enthusiasts who want to explore all types of terrain. It's versatile, comfortable, and loaded with advanced technology to provide a smooth and responsive ride, no matter where your adventures take you.\r\n\r\n\r\n## Features\r\nVersatile and customizable\r\nThe E-Adrenaline 8.0 EX1 features a customizable geometry, including an adjustable head tube and chainstay length, so you can fine-tune your ride to fit your needs and preferences. It also features a variety of customizable settings, including suspension tuning, motor assistance levels, and more.\r\n\r\nPowerful and efficient\r\nThe bike is equipped with a powerful and efficient motor that provides a smooth and seamless transition between human power and electric assist. It can assist up to 28 mph when it's on, and provides zero drag when it's off.\r\n\r\nAdvanced suspension\r\nThe E-Adrenaline 8.0 EX1 features a RockShox Lyrik Ultimate fork and a RockShox Super Deluxe Ultimate rear shock, providing advanced suspension technology to absorb shocks and bumps on any terrain. The suspension is also customizable to fit your riding style and preferences.\r\n\r\n\r\n## Specs\r\nFrameset\r\nFrame ADV Mountain Carbon main frame & stays, adjustable head tube and chainstay length, tapered head tube, Knock Block, Control Freak internal routing, Boost148, 150mm travel\r\nFork RockShox Lyrik Ultimate, DebonAir spring, Charger 2.1 RC2 damper, remote lockout, tapered steerer, 42mm offset, Boost110, 15mm Maxle Stealth, 160mm travel\r\nShock RockShox Super Deluxe Ultimate, DebonAir spring, Thru Shaft 3-position damper, 230x57.5mm\r\n\r\nWheels\r\nWheel front Bontrager Line Elite 30, ADV Mountain Carbon, Tubeless Ready, 6-bolt, Boost110, 15mm thru axle\r\nWheel rear Bontrager Line Elite 30, ADV Mountain Carbon, Tubeless Ready, 54T Rapid Drive, 6-bolt, Shimano MicroSpline freehub, Boost148, 12mm thru axle\r\nSkewer rear Bontrager Switch thru axle, removable lever\r\nTire Bontrager XR5 Team Issue, Tubeless Ready, Inner Strength sidewall, aramid bead, 120tpi, 29x2.50''\r\nTire part Bontrager TLR sealant, 6oz\r\n\r\nDrivetrain\r\nShifter SRAM EX1, 8 speed\r\nRear derailleur SRAM EX1, 8 speed\r\nCrank Bosch Performance CX, magnesium motor body, 250 watt, 75 Nm torque\r\nChainring SRAM EX1, 18T, steel\r\nCassette SRAM EX1, 11-48, 8 speed\r\nChain SRAM EX1, 8 speed\r\n\r\nComponents\r\nSaddle Bontrager Arvada, hollow chromoly rails, 138mm width\r\nSeatpost Bontrager Line Elite Dropper, internal routing, 31.6mm\r\nHandlebar Bontrager Line Pro, ADV Carbon, 35mm, 27.5mm rise, 780mm width\r\nGrips Bontrager XR Trail Elite, alloy lock-on\r\nStem Bontrager Line Pro, 35mm, Knock Block, Blendr compatible, 0 degree, 50mm length\r\nHeadset Knock Block Integrated, 62-degree radius, cartridge bearing, 1-1\/8'' top, 1.5'' bottom\r\nBrake SRAM G2 RSC hydraulic disc, carbon levers\r\nBrake rotor SRAM Centerline, centerlock, round edge, 200mm\r\n\r\nAccessories\r\nE-bike system Bosch Performance CX, magnesium motor body, 250 watt, 75 Nm torque\r\nBattery Bosch PowerTube 625, 625Wh\r\nCharger Bosch 4A standard charger\r\nController Bosch Kiox with Anti-theft solution, Bluetooth connectivity, 1.9'' display\r\nTool Bontrager Switch thru axle, removable lever\r\n\r\nWeight\r\nWeight M - 20.25 kg \/ 44.6 lbs (with TLR sealant, no tubes)\r\nWeight limit This bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\r\n\r\n## Sizing & fit\r\n\r\n| Size | Rider Height | Inseam |\r\n|:----:|:------------------------:|:--------------------:|\r\n| S | 155 - 170 cm 5'1\" - 5'7\" | 73 - 80 cm 29\" - 31.5\" |\r\n| M | 163 - 178 cm 5'4\" - 5'10\" | 77 - 83 cm 30.5\" - 32.5\" |\r\n| L | 176 - 191 cm 5'9\" - 6'3\" | 83 - 89 cm 32.5\" - 35\" |\r\n| XL | 188 - 198 cm 6'2\" - 6'6\" | 88 - 93 cm 34.5\" - 36.5\" |\r\n\r\n\r\n## Geometry\r\n\r\nAll measurements provided in cm unless otherwise noted.\r\nSizing table\r\n| Frame size letter | S | M | L | XL |\r\n|---------------------------|-------|-------|-------|-------|\r\n| Actual frame size | 15.8 | 17.8 | 19.8 | 21.8 |\r\n| Wheel size | 29\" | 29\" | 29\" | 29\" |\r\n| A \u2014 Seat tube | 40.0 | 42.5 | 47.5 | 51.0 |\r\n| B \u2014 Seat tube angle | 72.5\u00B0 | 72.8\u00B0 | 73.0\u00B0 | 73.0\u00B0 |\r\n| C \u2014 Head tube length | 9.5 | 10.5 | 11.0 | 11.5 |\r\n| D \u2014 Head angle | 67.8\u00B0 | 67.8\u00B0 | 67.8\u00B0 | 67.8\u00B0 |\r\n| E \u2014 Effective top tube | 59.0 | 62.0 | 65.0 | 68.0 |\r\n| F \u2014 Bottom bracket height | 32.5 | 32.5 | 32.5 | 32.5 |\r\n| G \u2014 Bottom bracket drop | 5.5 | 5.5 | 5.5 | 5.5 |\r\n| H \u2014 Chainstay length | 45.0 | 45.0 | 45.0 | 45.0 |\r\n| I \u2014 Offset | 4.5 | 4.5 | 4.5 | 4.5 |\r\n| J \u2014 Trail | 11.0 | 11.0 | 11.0 | 11.0 |\r\n| K \u2014 Wheelbase | 113.0 | 117.0 | 120.0 | 123.0 |\r\n| L \u2014 Standover | 77.0 | 77.0 | 77.0 | 77.0 |\r\n| M \u2014 Frame reach | 41.0 | 44.5 | 47.5 | 50.0 |\r\n| N \u2014 Frame stack | 61.0 | 62.0 | 62.5 | 63.0 |",
"price": 1499.99,
"tags": [
"bicycle"
]
},
{
"name": "Enduro X Pro",
"shortDescription": "The Enduro X Pro is the ultimate mountain bike for riders who demand the best. With its full carbon frame and top-of-the-line components, this bike is ready to tackle any trail, from technical downhill descents to grueling uphill climbs.",
"text": "## Overview\nIt's right for you if...\nYou're an experienced mountain biker who wants a high-performance bike that can handle any terrain. You want a bike with the best components available, including a full carbon frame, suspension system, and hydraulic disc brakes.\n\nThe tech you get\nOur top-of-the-line full carbon frame with aggressive geometry and a slack head angle for maximum control. It's equipped with a Fox Factory suspension system with 170mm of travel in the front and 160mm in the rear, a Shimano XTR 12-speed drivetrain, and hydraulic disc brakes for maximum stopping power. The bike also features a dropper seatpost for easy adjustments on the fly.\n\nThe final word\nThe Enduro X Pro is the ultimate mountain bike for riders who demand the best. With its full carbon frame, top-of-the-line components, and aggressive geometry, this bike is ready to take on any trail. Whether you're a seasoned pro or just starting out, the Enduro X Pro will help you take your riding to the next level.\n\n## Features\nFull carbon frame\nAggressive geometry with a slack head angle\nFox Factory suspension system with 170mm of travel in the front and 160mm in the rear\nShimano XTR 12-speed drivetrain\nHydraulic disc brakes for maximum stopping power\nDropper seatpost for easy adjustments on the fly\n\n## Specifications\nFrameset\nFrame\tFull carbon frame\nFork\tFox Factory suspension system with 170mm of travel\nRear suspension\tFox Factory suspension system with 160mm of travel\n\nWheels\nWheel size\t27.5\" or 29\"\nTires\tTubeless-ready Maxxis tires\n\nDrivetrain\nShifters\tShimano XTR 12-speed\nFront derailleur\tN/A\nRear derailleur\tShimano XTR\nCrankset\tShimano XTR\nCassette\tShimano XTR 12-speed\nChain\tShimano XTR\n\nComponents\nBrakes\tHydraulic disc brakes\nHandlebar\tAlloy handlebar\nStem\tAlloy stem\nSeatpost\tDropper seatpost\n\nAccessories\nPedals\tNot included\n\nWeight\nWeight\tApproximately 27-29 lbs\n\n## Sizing\n| Size | Rider Height |\n|:----:|:-------------------------:|\n| S | 5'4\" - 5'8\" (162-172cm) |\n| M | 5'8\" - 5'11\" (172-180cm) |\n| L | 5'11\" - 6'3\" (180-191cm) |\n| XL | 6'3\" - 6'6\" (191-198cm) |\n\n## Geometry\n| Size | S | M | L | XL |\n|:----:|:---------------:|:---------------:|:-----------------:|:---------------:|\n| A - Seat tube length | 390mm | 425mm | 460mm | 495mm |\n| B - Effective top tube length | 585mm | 610mm | 635mm | 660mm |\n| C - Head tube angle | 65.5° | 65.5° | 65.5° | 65.5° |\n| D - Seat tube angle | 76° | 76° | 76° | 76° |\n| E - Chainstay length | 435mm | 435mm | 435mm | 435mm |\n| F - Head tube length | 100mm | 110mm | 120mm | 130mm |\n| G - BB drop | 20mm | 20mm | 20mm | 20mm |\n| H - Wheelbase | 1155mm | 1180mm | 1205mm | 1230mm |\n| I - Standover height | 780mm | 800mm | 820mm | 840mm |\n| J - Reach | 425mm | 450mm | 475mm | 500mm |\n| K - Stack | 610mm | 620mm | 630mm | 640mm |",
"price": 599.99,
"tags": [
"bicycle"
]
},
{
"name": "Blaze X1",
"shortDescription": "Blaze X1 is a high-performance road bike that offers superior speed and agility, making it perfect for competitive racing or fast-paced group rides. The bike features a lightweight carbon frame, aerodynamic tube shapes, a 12-speed Shimano Ultegra drivetrain, and hydraulic disc brakes for precise stopping power. With its sleek design and cutting-edge technology, Blaze X1 is a bike that is built to perform and dominate on any road.",
"description": "## Overview\nIt's right for you if...\nYou're a competitive road cyclist or an enthusiast who enjoys fast-paced group rides. You want a bike that is lightweight, agile, and delivers exceptional speed.\n\nThe tech you get\nBlaze X1 features a lightweight carbon frame with a tapered head tube and aerodynamic tube shapes for maximum speed and efficiency. The bike is equipped with a 12-speed Shimano Ultegra drivetrain for smooth and precise shifting, Shimano hydraulic disc brakes for powerful and reliable stopping power, and Bontrager Aeolus Elite 35 carbon wheels for increased speed and agility.\n\nThe final word\nBlaze X1 is a high-performance road bike that is designed to deliver exceptional speed and agility. With its cutting-edge technology and top-of-the-line components, it's a bike that is built to perform and dominate on any road.\n\n## Features\nSpeed and efficiency\nBlaze X1's lightweight carbon frame and aerodynamic tube shapes offer maximum speed and efficiency, allowing you to ride faster and farther with ease.\n\nPrecision stopping power\nShimano hydraulic disc brakes provide precise and reliable stopping power, even in wet or muddy conditions.\n\nAgility and control\nBontrager Aeolus Elite 35 carbon wheels make Blaze X1 incredibly agile and responsive, allowing you to navigate tight turns and corners with ease.\n\nSmooth and precise shifting\nThe 12-speed Shimano Ultegra drivetrain offers smooth and precise shifting, so you can easily find the right gear for any terrain.\n\n## Specifications\nFrameset\nFrame\tADV Carbon, tapered head tube, BB90, direct mount rim brakes, internal cable routing, DuoTrap S compatible, 130x9mm QR\nFork\tADV Carbon, tapered steerer, direct mount rim brakes, internal brake routing, 100x9mm QR\n\nWheels\nWheel front\tBontrager Aeolus Elite 35, ADV Carbon, Tubeless Ready, 35mm rim depth, 100x9mm QR\nWheel rear\tBontrager Aeolus Elite 35, ADV Carbon, Tubeless Ready, 35mm rim depth, Shimano 11-speed freehub, 130x9mm QR\nTire front\tBontrager R3 Hard-Case Lite, aramid bead, 120 tpi, 700x25c\nTire rear\tBontrager R3 Hard-Case Lite, aramid bead, 120 tpi, 700x25c\nMax tire size\t25c Bontrager tires (with at least 4mm of clearance to frame)\n\nDrivetrain\nShifter\tShimano Ultegra R8020, 12 speed\nFront derailleur\tShimano Ultegra R8000, braze-on\nRear derailleur\tShimano Ultegra R8000, short cage, 30T max cog\nCrank\tSize: 50, 52, 54\nShimano Ultegra R8000, 50/34 (compact), 170mm length\nSize: 56, 58, 60, 62\nShimano Ultegra R8000, 50/34 (compact), 172.5mm length\nBottom bracket\tBB90, Shimano press-fit\nCassette\tShimano Ultegra R8000, 11-30, 12 speed\nChain\tShimano Ultegra HG701, 12 speed\n\nComponents\nSaddle\tBontrager Montrose Elite, titanium rails, 138mm width\nSeatpost\tBontrager carbon seatmast cap, 20mm offset\nHandlebar\tBontrager Elite Aero VR-CF, alloy, 31.8mm, internal cable routing, 40cm width\nGrips\tBontrager Supertack Perf tape\nStem\tBontrager Elite, 31.8mm, Blendr-compatible, 7 degree, 80mm length\nBrake Shimano Ultegra hydraulic disc brake\n\nWeight\nWeight\t56 - 8.91 kg / 19.63 lbs (with tubes)\nWeight limit\tThis bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 275 pounds (125 kg).\n\n## Sizing\n| Size | Rider height |\n|------|-------------|\n| 50 | 162-166cm |\n| 52 | 165-170cm |\n| 54 | 168-174cm |\n| 56 | 174-180cm |\n| 58 | 179-184cm |\n| 60 | 184-189cm |\n| 62 | 189-196cm |\n\n## Geometry\n| Frame size | 50cm | 52cm | 54cm | 56cm | 58cm | 60cm | 62cm |\n|------------|-------|-------|-------|-------|-------|-------|-------|\n| Wheel size | 700c | 700c | 700c | 700c | 700c | 700c | 700c |\n| A - Seat tube | 443mm | 460mm | 478mm | 500mm | 520mm | 540mm | 560mm |\n| B - Seat tube angle | 74.1° | 73.9° | 73.7° | 73.4° | 73.2° | 73.0° | 72.8° |\n| C - Head tube length | 100mm | 110mm | 130mm | 150mm | 170mm | 190mm | 210mm |\n| D - Head angle | 71.4° | 72.0° | 72.5° | 73.0° | 73.3° | 73.6° | 73.8° |\n| E - Effective top tube | 522mm | 535mm | 547mm | 562mm | 577mm | 593mm | 610mm |\n| F - Bottom bracket height | 268mm | 268mm | 268mm | 268mm | 268mm | 268mm | 268mm |\n| G - Bottom bracket drop | 69mm | 69mm | 69mm | 69mm | 69mm | 69mm | 69mm |\n| H - Chainstay length | 410mm | 410mm | 410mm | 410mm | 410mm | 410mm | 410mm |\n| I - Offset | 50mm | 50mm | 50mm | 50mm | 50mm | 50mm | 50mm |\n| J - Trail | 65mm | 62mm | 59mm | 56mm | 55mm | 53mm | 52mm |\n| K - Wheelbase | 983mm | 983mm | 990mm | 1005mm | 1019mm | 1036mm | 1055mm |\n| L - Standover | 741mm | 765mm | 787mm | 806mm | 825mm | 847mm | 869mm |",
"price": 799.99,
"tags": [
"bicycle",
"mountain bike"
]
},
{
"name": "Celerity X5",
"shortDescription": "Celerity X5 is a versatile and reliable road bike that is designed for experienced and amateur riders alike. It's designed to provide smooth and comfortable rides over long distances. With an ultra-lightweight and responsive carbon fiber frame, Shimano 105 groupset, hydraulic disc brakes, and 28mm wide tires, this bike ensures efficient power transfer, precise handling, and superior stopping power.",
"description": "## Overview\n\nIt's right for you if... \nYou are looking for a high-performance road bike that offers a perfect balance of speed, comfort, and control. You enjoy long-distance rides and need a bike that is designed to handle various road conditions with ease. You also appreciate the latest technology and reliable components that make your riding experience more enjoyable.\n\nThe tech you get \nCelerity X5 is equipped with a full carbon fiber frame that ensures maximum strength and durability while keeping the weight down. It features a Shimano 105 groupset with 11-speed gearing for precise and efficient shifting. Hydraulic disc brakes offer superior stopping power, and 28mm wide tires provide comfort and stability on various road surfaces. Internal cable routing enhances the bike's sleek appearance.\n\nThe final word \nIf you are looking for a high-performance road bike that offers comfort, speed, and control, Celerity X5 is the perfect choice. With its lightweight carbon fiber frame, reliable components, and advanced technology, this bike is designed to help you enjoy long-distance rides with ease.\n\n## Features \n\nLightweight and responsive \nCelerity X5 comes with a full carbon fiber frame that is not only lightweight but also responsive, providing excellent handling and control.\n\nHydraulic disc brakes \nThis bike is equipped with hydraulic disc brakes that provide superior stopping power in all weather conditions, ensuring your safety and confidence on the road.\n\nComfortable rides \nThe 28mm wide tires and carbon seat post provide ample cushioning, ensuring a smooth and comfortable ride over long distances.\n\nSleek appearance \nThe bike's internal cable routing enhances its sleek appearance while also protecting the cables from the elements, ensuring smooth shifting for longer periods.\n\n## Specifications \n\nFrameset \nFrame\tCelerity X5 Full Carbon Fiber Frame, Internal Cable Routing, Tapered Headtube, Press Fit Bottom Bracket, 12x142mm Thru-Axle \nFork\tCelerity X5 Full Carbon Fiber Fork, Internal Brake Routing, 12x100mm Thru-Axle \n\nWheels \nWheelset\tAlexRims CXD7 Wheelset \nTire\tSchwalbe Durano Plus 700x28mm \nInner Tubes\tSchwalbe SV15 700x18-28mm \nSkewers\tCelerity X5 Thru-Axle Skewers \n\nDrivetrain \nShifter\tShimano 105 R7025 Hydraulic Disc Shifters \nFront Derailleur\tShimano 105 R7000 \nRear Derailleur\tShimano 105 R7000 \nCrankset\tShimano 105 R7000 50-34T \nBottom Bracket\tShimano BB72-41B \nCassette\tShimano 105 R7000 11-30T \nChain\tShimano HG601 11-Speed Chain \n\nComponents \nSaddle\tSelle Royal Asphalt Saddle \nSeatpost\tCelerity X5 Carbon Seatpost \nHandlebar\tCelerity X5 Compact Handlebar \nStem\tCelerity X5 Aluminum Stem \nHeadset\tFSA Orbit IS-2 \n\nBrakes \nBrakes\tShimano 105 R7025 Hydraulic Disc Brakes \nRotors\tShimano SM-RT70 160mm Rotors \n\nAccessories \nPedals\tCelerity X5 Road Pedals \n\nWeight \nWeight\t8.2 kg / 18.1 lbs \nWeight Limit\tThis bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 120 kg (265 lbs).\n\n## Sizing \n| Size | Rider Height | Inseam |\n|:----:|:-------------------------:|:--------------------:|\n| 49 | 155 - 162 cm 5'1\" - 5'4\" | 71 - 76 cm 28\" - 30\" |\n| 52 | 162 - 170 cm 5'4\" - 5'7\" | 74 - 79 cm 29\" - 31\" |\n| 54 | 170 - 178 cm 5'7\" - 5'10\" | 77 - 83 cm 30\" - 32\" |\n| 56 | 178 - 185 cm 5'10\" - 6'1\" | 82 - 88 cm 32\" - 34\" |\n| 58 | 185 - 193 cm 6'1\" - 6'4\" | 86 - 92 cm 34\" - 36\" |\n| 61 | 193 - 200 cm 6'4\" - 6'7\" | 90 - 95 cm 35\" - 37\" |\n\n## Geometry \n| Frame size number | 49 cm | 52 cm | 54 cm | 56 cm | 58 cm | 61 cm |\n|---------------------------------------|-------|-------|-------|-------|-------|-------|\n| Wheel size | 700c | 700c | 700c | 700c | 700c | 700c |\n| A — Seat tube | 47.5 | 50.0 | 52.0 | 54.0 | 56.0 | 58.5 |\n| B — Seat tube angle | 75.0° | 74.5° | 74.0° | 73.5° | 73.0° | 72.5° |\n| C — Head tube length | 12.0 | 14.5 | 16.5 | 18.5 | 20.5 | 23.5 |\n| D — Head angle | 70.0° | 71.0° | 71.5° | 72.0° | 72.5° | 72.5° |\n| E — Effective top tube | 52.5 | 53.5 | 54.5 | 56.0 | 57.5 | 59.5 |\n| G — Bottom bracket drop | 7.0 | 7.0 | 7.0 | 7.0 | 7.0 | 7.0 |\n| H — Chainstay length | 41.5 | 41.5 | 41.5 | 41.5 | 41.5 | 41.5 |\n| K — Wheelbase | 98.4 | 98.9 | 99.8 | 100.8 | 101.7 | 103.6 |\n| L — Standover | 72.0 | 74.0 | 76.0 | 78.0 | 80.0 | 82.0 |\n| M — Frame reach | 36.2 | 36.8 | 37.3 | 38.1 | 38.6 | 39.4 |\n| N — Frame stack | 52.0 | 54.3 | 56.2 | 58.1 | 59.8 | 62.4 |\n| Saddle rail height min | 67.0 | 69.5 | 71.5 | 74.0 | 76.0 | 78.0 |\n| Saddle rail height max | 75.0 | 77.5 | 79.5 | 82.0 | 84.0 | 86.0 |",
"price": 399.99,
"tags": [
"bicycle",
"city bike"
]
},
{
"name": "Velocity V8",
"shortDescription": "Velocity V8 is a high-performance road bike that is designed to deliver speed, agility, and control on the road. With its lightweight aluminum frame, carbon fiber fork, Shimano Tiagra groupset, and hydraulic disc brakes, this bike is perfect for experienced riders who are looking for a fast and responsive bike that can handle various road conditions.",
"description": "## Overview\n\nIt's right for you if... \nYou are an experienced rider who is looking for a high-performance road bike that is lightweight, agile, and responsive. You want a bike that can handle long-distance rides, steep climbs, and fast descents with ease. You also appreciate the latest technology and reliable components that make your riding experience more enjoyable.\n\nThe tech you get \nVelocity V8 features a lightweight aluminum frame with a carbon fiber fork that ensures a comfortable ride without sacrificing stiffness and power transfer. It comes with a Shimano Tiagra groupset with 10-speed gearing for precise and efficient shifting. Hydraulic disc brakes offer superior stopping power in all weather conditions, while 28mm wide tires provide comfort and stability on various road surfaces. Internal cable routing enhances the bike's sleek appearance.\n\nThe final word \nIf you are looking for a high-performance road bike that is lightweight, fast, and responsive, Velocity V8 is the perfect choice. With its lightweight aluminum frame, reliable components, and advanced technology, this bike is designed to help you enjoy fast and comfortable rides on the road.\n\n## Features \n\nLightweight and responsive \nVelocity V8 comes with a lightweight aluminum frame that is not only lightweight but also responsive, providing excellent handling and control.\n\nHydraulic disc brakes \nThis bike is equipped with hydraulic disc brakes that provide superior stopping power in all weather conditions, ensuring your safety and confidence on the road.\n\nComfortable rides \nThe 28mm wide tires and carbon fork provide ample cushioning, ensuring a smooth and comfortable ride over long distances.\n\nSleek appearance \nThe bike's internal cable routing enhances its sleek appearance while also protecting the cables from the elements, ensuring smooth shifting for longer periods.\n\n## Specifications \n\nFrameset \nFrame\tVelocity V8 Aluminum Frame, Internal Cable Routing, Tapered Headtube, Press Fit Bottom Bracket, 12x142mm Thru-Axle \nFork\tVelocity V8 Carbon Fiber Fork, Internal Brake Routing, 12x100mm Thru-Axle \n\nWheels \nWheelset\tAlexRims CXD7 Wheelset \nTire\tSchwalbe Durano Plus 700x28mm \nInner Tubes\tSchwalbe SV15 700x18-28mm \nSkewers\tVelocity V8 Thru-Axle Skewers \n\nDrivetrain \nShifter\tShimano Tiagra Hydraulic Disc Shifters \nFront Derailleur\tShimano Tiagra \nRear Derailleur\tShimano Tiagra \nCrankset\tShimano Tiagra 50-34T \nBottom Bracket\tShimano BB-RS500-PB \nCassette\tShimano Tiagra 11-32T \nChain\tShimano HG54 10-Speed Chain \n\nComponents \nSaddle\tVelocity V8 Saddle \nSeatpost\tVelocity V8 Aluminum Seatpost \nHandlebar\tVelocity V8 Compact Handlebar \nStem\tVelocity V8 Aluminum Stem \nHeadset\tFSA Orbit IS-2 \n\nBrakes \nBrakes\tShimano Tiagra Hydraulic Disc Brakes \nRotors\tShimano SM-RT64 160mm Rotors \n\nAccessories \nPedals\tVelocity V8 Road Pedals \n\nWeight \nWeight\t9.4 kg / 20.7 lbs \nWeight Limit\tThis bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 120 kg (265 lbs).\n\n## Sizing \n| Size | Rider Height | Inseam |\n|:----:|:-------------------------:|:--------------------:|\n| 49 | 155 - 162 cm 5'1\" - 5'4\" | 71 - 76 cm 28\" - 30\" |\n| 52 | 162 - 170 cm 5'4\" - 5'7\" | 74 - 79 cm 29\" - 31\" |\n| 54 | 170 - 178 cm 5'7\" - 5'10\" | 77 - 83 cm 30\" - 32\" |\n| 56 | 178 - 185 cm 5'10\" - 6'1\" | 82 - 88 cm 32\" - 34\" |\n| 58 | 185 - 193 cm 6'1\" - 6'4\" | 86 - 92 cm 34\" - 36\" |\n| 61 | 193 - 200 cm 6'4\" - 6'7\" | 90 - 95 cm 35\" - 37\" |\n\n## Geometry \n| Frame size number | 49 cm | 52 cm | 54 cm | 56 cm | 58 cm | 61 cm |\n|---------------------------------------|-------|-------|-------|-------|-------|-------|\n| Wheel size | 700c | 700c | 700c | 700c | 700c | 700c |\n| A — Seat tube | 47.5 | 50.0 | 52.0 | 54.0 | 56.0 | 58.5 |\n| B — Seat tube angle | 75.0° | 74.5° | 74.0° | 73.5° | 73.0° | 72.5° |\n| C — Head tube length | 12.0 | 14.5 | 16.5 | 18.5 | 20.5 | 23.5 |\n| D — Head angle | 70.0° | 71.0° | 71.5° | 72.0° | 72.5° | 72.5° |\n| E — Effective top tube | 52.5 | 53.5 | 54.5 | 56.0 | 57.5 | 59.5 |\n| G — Bottom bracket drop | 7.0 | 7.0 | 7.0 | 7.0 | 7.0 | 7.0 |\n| H — Chainstay length | 41.5 | 41.5 | 41.5 | 41.5 | 41.5 | 41.5 |\n| K — Wheelbase | 98.4 | 98.9 | 99.8 | 100.8 | 101.7 | 103.6 |\n| L — Standover | 72.0 | 74.0 | 76.0 | 78.0 | 80.0 | 82.0 |\n| M — Frame reach | 36.2 | 36.8 | 37.3 | 38.1 | 38.6 | 39.4 |\n| N — Frame stack | 52.0 | 54.3 | 56.2 | 58.1 | 59.8 | 62.4 |\n| Saddle rail height min | 67.0 | 69.5 | 71.5 | 74.0 | 76.0 | 78.0 |\n| Saddle rail height max | 75.0 | 77.5 | 79.5 | 82.0 | 84.0 | 86.0 |",
"price": 1899.99,
"tags": [
"bicycle",
"electric bike"
]
},
{
"name": "VeloCore X9 eMTB",
"shortDescription": "The VeloCore X9 eMTB is a light, agile and versatile electric mountain bike designed for adventure and performance. Its purpose-built frame and premium components offer an exhilarating ride experience on both technical terrain and smooth singletrack.",
"description": "## Overview\nIt's right for you if...\nYou love exploring new trails and testing your limits on challenging terrain. You want an electric mountain bike that offers power when you need it, without sacrificing performance or agility. You're looking for a high-quality bike with top-notch components and a sleek design.\n\nThe tech you get\nA lightweight, full carbon frame with custom geometry, a 140mm RockShox Pike Ultimate fork with Charger 2.1 damper, and a Fox Float DPS Performance shock. A Shimano STEPS E8000 motor and 504Wh battery that provide up to 62 miles of range and 20 mph assistance. A Shimano XT 12-speed drivetrain, Shimano SLX brakes, and DT Swiss wheels.\n\nThe final word\nThe VeloCore X9 eMTB delivers power and agility in equal measure. It's a versatile and capable electric mountain bike that can handle any trail with ease. With premium components, a custom carbon frame, and a sleek design, this bike is built for adventure.\n\n## Features\nAgile and responsive\n\nThe VeloCore X9 eMTB is designed to be nimble and responsive on the trail. Its custom carbon frame offers a perfect balance of stiffness and compliance, while the suspension system provides smooth and stable performance on technical terrain.\n\nPowerful and efficient\n\nThe Shimano STEPS E8000 motor and 504Wh battery provide up to 62 miles of range and 20 mph assistance. The motor delivers smooth and powerful performance, while the battery offers reliable and consistent power for long rides.\n\nCustomizable ride experience\n\nThe VeloCore X9 eMTB comes with an intuitive and customizable Shimano STEPS display that allows you to adjust the level of assistance, monitor your speed and battery life, and customize your ride experience to suit your needs.\n\nPremium components\n\nThe VeloCore X9 eMTB is equipped with high-end components, including a Shimano XT 12-speed drivetrain, Shimano SLX brakes, and DT Swiss wheels. These components offer reliable and precise performance, allowing you to push your limits with confidence.\n\n## Specs\nFrameset\nFrame\tVeloCore carbon fiber frame, Boost, tapered head tube, internal cable routing, 140mm travel\nFork\tRockShox Pike Ultimate, Charger 2.1 damper, DebonAir spring, 15x110mm Boost Maxle Ultimate, 46mm offset, 140mm travel\nShock\tFox Float DPS Performance, EVOL, 3-position adjust, Kashima Coat, 210x50mm\n\nWheels\nWheel front\tDT Swiss XM1700 Spline, 30mm internal width, 15x110mm Boost axle\nWheel rear\tDT Swiss XM1700 Spline, 30mm internal width, Shimano Microspline driver, 12x148mm Boost axle\nTire front\tMaxxis Minion DHF, 29x2.5\", EXO+ casing, tubeless ready\nTire rear\tMaxxis Minion DHR II, 29x2.4\", EXO+ casing, tubeless ready\n\nDrivetrain\nShifter\tShimano XT M8100, 12-speed\nRear derailleur\tShimano XT M8100, Shadow Plus, long cage, 51T max cog\nCrankset\tShimano STEPS E8000, 165mm length, 34T chainring\nCassette\tShimano XT M8100, 10-51T, 12-speed\nChain\tShimano CN-M8100, 12-speed\nPedals\tNot included\n\nComponents\nSaddle\tBontrager Arvada, hollow chromoly rails\nSeatpost\tDrop Line, internal routing, 31.6mm (15.5: 100mm, 17.5 & 18.5: 125mm, 19.5 & 21.5: 150mm)\nHandlebar\tBontrager Line Pro, ADV Carbon, 35mm, 27.5mm rise, 780mm width\nStem\tBontrager Line Pro, 35mm, Knock Block, 0 degree, 50mm length\nGrips\tBontrager XR Trail Elite, alloy lock-on\nHeadset\tIntegrated, sealed cartridge bearing, 1-1/8\" top, 1.5\" bottom\nBrakeset\tShimano SLX M7120, 4-piston hydraulic disc\n\nAccessories\nBattery\tShimano STEPS BT-E8010, 504Wh\nCharger\tShimano STEPS EC-E8004, 4A\nController\tShimano STEPS E8000 display\nBike weight\tM - 22.5 kg / 49.6 lbs (with tubes)\n\n## Sizing & fit\n\n| Size | Rider Height |\n|:----:|:------------------------:|\n| S | 162 - 170 cm 5'4\" - 5'7\" |\n| M | 170 - 178 cm 5'7\" - 5'10\"|\n| L | 178 - 186 cm 5'10\" - 6'1\"|\n| XL | 186 - 196 cm 6'1\" - 6'5\" |\n\n## Geometry\n\nAll measurements provided in cm unless otherwise noted.\n\n| Frame size | S | M | L | XL |\n|---------------------------|-------|-------|-------|-------|\n| A — Seat tube | 40.6 | 43.2 | 47.0 | 51.0 |\n| B — Seat tube angle | 75.0° | 75.0° | 75.0° | 75.0° |\n| C — Head tube length | 9.6 | 10.6 | 11.6 | 12.6 |\n| D — Head angle | 66.5° | 66.5° | 66.5° | 66.5° |\n| E — Effective top tube | 60.4 | 62.6 | 64.8 | 66.9 |\n| F — Bottom bracket height | 33.2 | 33.2 | 33.2 | 33.2 |\n| G — Bottom bracket drop | 3.0 | 3.0 | 3.0 | 3.0 |\n| H — Chainstay length | 45.5 | 45.5 | 45.5 | 45.5 |\n| I — Offset | 4.6 | 4.6 | 4.6 | 4.6 |\n| J — Trail | 11.9 | 11.9 | 11.9 | 11.9 |\n| K — Wheelbase | 117.0 | 119.3 | 121.6 | 123.9 |\n| L — Standover | 75.9 | 75.9 | 78.6 | 78.6 |\n| M — Frame reach | 43.6 | 45.6 | 47.6 | 49.6 |\n| N — Frame stack | 60.5 | 61.5 | 62.4 | 63.4 |",
"price": 1299.99,
"tags": [
"bicycle",
"touring bike"
]
},
{
"name": "Zephyr 8.8 GX Eagle AXS Gen 3",
"shortDescription": "Zephyr 8.8 GX Eagle AXS is a light and nimble full-suspension mountain bike. It's designed to handle technical terrain with ease and has a smooth and efficient ride feel. The sleek and powerful Bosch Performance Line CX motor and removable Powertube battery provide a boost to your pedaling and give you long-lasting riding time. The bike also features high-end components and advanced technology for an ultimate mountain biking experience.",
"description": "## Overview\nIt's right for you if...\nYou're an avid mountain biker looking for a high-performance e-MTB that can tackle challenging trails. You want a bike with a powerful motor, efficient suspension, and advanced technology to enhance your riding experience. You also need a bike that's reliable and durable for long-lasting use.\n\nThe tech you get\nA lightweight, full carbon frame with 150mm of rear travel and a 160mm RockShox Pike Ultimate fork with Charger 2.1 RCT3 damper, remote lockout, and DebonAir spring. A Bosch Performance Line CX motor and removable Powertube 625Wh battery that can assist up to 20mph when it's on and gives zero drag when it's off, plus an easy-to-use handlebar-mounted Bosch Purion controller. A SRAM GX Eagle AXS wireless electronic drivetrain, a RockShox Reverb Stealth dropper, and DT Swiss HX1501 Spline One wheels.\n\nThe final word\nZephyr 8.8 GX Eagle AXS is a high-performance e-MTB that's designed to handle technical terrain with ease. With a powerful Bosch motor and long-lasting battery, you can conquer challenging climbs and enjoy long rides. The bike also features high-end components and advanced technology for an ultimate mountain biking experience.\n\n## Features\nPowerful motor\n\nThe Bosch Performance Line CX motor provides a boost to your pedaling and can assist up to 20mph. It has four power modes and a walk-assist function for easy navigation on steep climbs. The motor is also reliable and durable for long-lasting use.\n\nEfficient suspension\n\nZephyr 8.8 has a 150mm of rear travel and a 160mm RockShox Pike Ultimate fork with Charger 2.1 RCT3 damper, remote lockout, and DebonAir spring. The suspension is efficient and responsive, allowing you to handle technical terrain with ease.\n\nRemovable battery\n\nThe Powertube 625Wh battery is removable for easy charging and storage. It provides long-lasting riding time and can be replaced with a spare battery for even longer rides. The battery is also durable and weather-resistant for all-season riding.\n\nAdvanced technology\n\nZephyr 8.8 is equipped with advanced technology, including a Bosch Purion controller for easy motor control, a SRAM GX Eagle AXS wireless electronic drivetrain for precise shifting, and a RockShox Reverb Stealth dropper for adjustable saddle height. The bike also has DT Swiss HX1501 Spline One wheels for reliable performance on any terrain.\n\nCarbon frame\n\nThe full carbon frame is lightweight and durable, providing a smooth and efficient ride. It's also designed with a tapered head tube, internal cable routing, and Boost148 spacing for enhanced stiffness and responsiveness.\n\n## Specs\nFrameset\nFrame\tCarbon main frame & stays, tapered head tube, internal routing, Boost148, 150mm travel\nFork\tRockShox Pike Ultimate, Charger 2.1 RCT3 damper, DebonAir spring, remote lockout, tapered steerer, Boost110, 15mm Maxle Stealth, 160mm travel\nShock\tRockShox Deluxe RT3, DebonAir spring, 205mm x 57.5mm\nMax compatible fork travel\t170mm\n\nWheels\nWheel front\tDT Swiss HX1501 Spline One, Centerlock, 30mm inner width, 110x15mm Boost\nWheel rear\tDT Swiss HX1501 Spline One, Centerlock, 30mm inner width, SRAM XD driver, 148x12mm Boost\nTire\tBontrager XR4 Team Issue, Tubeless Ready, Inner Strength sidewall, aramid bead, 120tpi, 29x2.40''\nMax tire size\t29x2.60\"\n\nDrivetrain\nShifter\tSRAM GX Eagle AXS, wireless, 12 speed\nRear derailleur\tSRAM GX Eagle AXS\nCrank\tBosch Gen 4, 32T\nChainring\tSRAM X-Sync 2, 32T, direct-mount\nCassette\tSRAM PG-1275 Eagle, 10-52, 12 speed\nChain\tSRAM GX Eagle, 12 speed\n\nComponents\nSaddle\tBontrager Arvada, hollow titanium rails, 138mm width\nSeatpost\tRockShox Reverb Stealth, 31.6mm, internal routing, 150mm (S), 170mm (M/L), 200mm (XL)\nHandlebar\tBontrager Line Pro, ADV Carbon, 35mm, 27.5mm rise, 780mm width\nGrips\tBontrager XR Trail Elite, alloy lock-on\nStem\tBontrager Line Pro, Knock Block, 35mm, 0 degree, 50mm length\nHeadset\tIntegrated, sealed cartridge bearing, 1-1/8'' top, 1.5'' bottom\nBrake\tSRAM Code RSC hydraulic disc, 200mm (front), 180mm (rear)\nBrake rotor\tSRAM CenterLine, centerlock, round edge, 200mm (front), 180mm (rear)\n\nAccessories\nE-bike system\tBosch Performance Line CX\nBattery\tBosch Powertube 625Wh\nCharger\tBosch 4A compact charger\nController\tBosch Purion\nTool\tBontrager multi-tool, integrated storage bag\n\nWeight\nWeight\tM - 24.08 kg / 53.07 lbs (with TLR sealant, no tubes)\nWeight limit\tThis bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\n\n\n## Sizing & fit\n\n| Size | Rider Height | Inseam |\n|:----:|:------------------------:|:--------------------:|\n| S | 153 - 162 cm 5'0\" - 5'4\" | 67 - 74 cm 26\" - 29\" |\n| M | 161 - 172 cm 5'3\" - 5'8\" | 74 - 79 cm 29\" - 31\" |\n| L | 171 - 180 cm 5'7\" - 5'11\" | 79 - 84 cm 31\" - 33\" |\n| XL | 179 - 188 cm 5'10\" - 6'2\" | 84 - 89 cm 33\" - 35\" |\n\n\n## Geometry\n\nAll measurements provided in cm unless otherwise noted.\nSizing table\n| Frame size letter | S | M | L | XL |\n|---------------------------|-------|-------|-------|-------|\n| Actual frame size | 15.5 | 17.5 | 19.5 | 21.5 |\n| Wheel size | 29\" | 29\" | 29\" | 29\" |\n| A — Seat tube | 39.4 | 41.9 | 44.5 | 47.6 |\n| B — Seat tube angle | 76.1° | 76.1° | 76.1° | 76.1° |\n| C — Head tube length | 9.6 | 10.5 | 11.5 | 12.5 |\n| D — Head angle | 65.5° | 65.5° | 65.5° | 65.5° |\n| E — Effective top tube | 58.6 | 61.3 | 64.0 | 66.7 |\n| F — Bottom bracket height | 34.0 | 34.0 | 34.0 | 34.0 |\n| G — Bottom bracket drop | 1.0 | 1.0 | 1.0 | 1.0 |\n| H — Chainstay length | 45.0 | 45.0 | 45.0 | 45.0 |\n| I — Offset | 4.6 | 4.6 | 4.6 | 4.6 |\n| J — Trail | 10.5 | 10.5 | 10.5 | 10.5 |\n| K — Wheelbase | 119.5 | 122.3 | 125.0 | 127.8 |\n| L — Standover | 72.7 | 74.7 | 77.6 | 81.0 |\n|",
"price": 1499.99,
"tags": [
"bicycle",
"electric bike",
"city bike"
]
},
{
"name": "Velo 99 XR1 AXS",
"shortDescription": "Velo 99 XR1 AXS is a next-generation bike designed for fast-paced adventure seekers and speed enthusiasts. Built for high-performance racing, the bike boasts state-of-the-art technology and premium components. It is the ultimate bike for riders who want to push their limits and get their adrenaline pumping.",
"description": "## Overview\nIt's right for you if...\nYou are a passionate cyclist looking for a bike that can keep up with your speed, agility, and endurance. You are an adventurer who loves to explore new terrains and challenge yourself on the toughest courses. You want a bike that is lightweight, durable, and packed with the latest technology.\n\nThe tech you get\nA lightweight, full carbon frame with advanced aerodynamics and integrated cable routing for a clean look. A high-performance SRAM XX1 Eagle AXS wireless electronic drivetrain, featuring a 12-speed cassette and a 32T chainring. A RockShox SID Ultimate fork with a remote lockout, 120mm travel, and Charger Race Day damper. A high-end SRAM G2 Ultimate hydraulic disc brake with carbon levers. A FOX Transfer SL dropper post for quick and easy height adjustments. DT Swiss XRC 1501 carbon wheels for superior speed and handling.\n\nThe final word\nVelo 99 XR1 AXS is a premium racing bike that can help you achieve your goals and reach new heights. It is designed for speed, agility, and performance, and it is packed with the latest technology and premium components. If you are a serious cyclist who wants the best, this is the bike for you.\n\n## Features\nAerodynamic design\n\nThe Velo 99 XR1 AXS features a state-of-the-art frame design that reduces drag and improves speed. It has an aerodynamic seatpost, integrated cable routing, and a sleek, streamlined look that sets it apart from other bikes.\n\nWireless electronic drivetrain\n\nThe SRAM XX1 Eagle AXS drivetrain features a wireless electronic system that provides precise, instant shifting and unmatched efficiency. It eliminates the need for cables and makes the bike lighter and faster.\n\nHigh-performance suspension\n\nThe RockShox SID Ultimate fork and Charger Race Day damper provide 120mm of smooth, responsive suspension that can handle any terrain. The fork also has a remote lockout for quick adjustments on the fly.\n\nSuperior braking power\n\nThe SRAM G2 Ultimate hydraulic disc brake system delivers unmatched stopping power and control. It has carbon levers for a lightweight, ergonomic design and precision control.\n\nCarbon wheels\n\nThe DT Swiss XRC 1501 carbon wheels are ultra-lightweight, yet incredibly strong and durable. They provide superior speed and handling, making the bike more agile and responsive.\n\n## Specs\nFrameset\nFrame\tFull carbon frame, integrated cable routing, aerodynamic design, Boost148\nFork\tRockShox SID Ultimate, Charger Race Day damper, remote lockout, tapered steerer, Boost110, 15mm Maxle Stealth, 120mm travel\n\nWheels\nWheel front\tDT Swiss XRC 1501 carbon wheel, Boost110, 15mm thru axle\nWheel rear\tDT Swiss XRC 1501 carbon wheel, SRAM XD driver, Boost148, 12mm thru axle\nTire\tSchwalbe Racing Ray, Performance Line, Addix, 29x2.25\"\nTire part\tSchwalbe Doc Blue Professional, 500ml\nMax tire size\t29x2.3\"\n\nDrivetrain\nShifter\tSRAM Eagle AXS, wireless, 12-speed\nRear derailleur\tSRAM XX1 Eagle AXS\nCrank\tSRAM XX1 Eagle, 32T, carbon\nChainring\tSRAM X-SYNC, 32T, alloy\nCassette\tSRAM Eagle XG-1299, 10-52, 12-speed\nChain\tSRAM XX1 Eagle, 12-speed\nMax chainring size\t1x: 32T\n\nComponents\nSaddle\tBontrager Montrose Elite, carbon rails, 138mm width\nSeatpost\tFOX Transfer SL, 125mm travel, internal routing, 31.6mm\nHandlebar\tBontrager Kovee Pro, ADV Carbon, 35mm, 5mm rise, 720mm width\nGrips\tBontrager XR Endurance Elite\nStem\tBontrager Kovee Pro, 35mm, Blendr compatible, 7 degree, 60mm length\nHeadset\tIntegrated, cartridge bearing, 1-1/8\" top, 1.5\" bottom\nBrake\tSRAM G2 Ultimate hydraulic disc, carbon levers, 180mm rotors\n\nAccessories\nBike computer\tBontrager Trip 300\nTool\tBontrager Flatline Pro pedal wrench, T25 Torx\n\n\n## Sizing & fit\n\n| Size | Rider Height | Inseam |\n|:----:|:------------------------:|:--------------------:|\n| S | 158 - 168 cm 5'2\" - 5'6\" | 74 - 78 cm 29\" - 31\" |\n| M | 165 - 175 cm 5'5\" - 5'9\" | 78 - 82 cm 31\" - 32\" |\n| L | 173 - 183 cm 5'8\" - 6'0\" | 82 - 86 cm 32\" - 34\" |\n| XL | 180 - 193 cm 5'11\" - 6'4\" | 86 - 90 cm 34\" - 35\" |\n\n\n## Geometry\n\nAll measurements provided in cm unless otherwise noted.\nSizing table\n| Frame size letter | S | M | L | XL |\n|---------------------------|-------|-------|-------|-------|\n| Actual frame size | 15.5 | 17.5 | 19.5 | 21.5 |\n| Wheel size | 29\" | 29\" | 29\" | 29\" |\n| A — Seat tube | 39.9 | 43.0 | 47.0 | 51.0 |\n| B — Seat tube angle | 74.5° | 74.5° | 74.5° | 74.5° |\n| C — Head tube length | 9.0 | 10.0 | 11.0 | 12.0 |\n| D — Head angle | 68.0° | 68.0° | 68.0° | 68.0° |\n| E — Effective top tube | 57.8 | 59.7 | 61.6 | 63.6 |\n| F — Bottom bracket height | 33.0 | 33.0 | 33.0 | 33.0 |\n| G — Bottom bracket drop | 5.0 | 5.0 | 5.0 | 5.0 |\n| H — Chainstay length | 43.0 | 43.0 | 43.0 | 43.0 |\n| I — Offset | 4.2 | 4.2 | 4.2 | 4.2 |\n| J — Trail | 9.7 | 9.7 | 9.7 | 9.7 |\n| K — Wheelbase | 112.5 | 114.5 | 116.5 | 118.6 |\n| L — Standover | 75.9 | 77.8 | 81.5 | 84.2 |\n| M — Frame reach | 41.6 | 43.4 | 45.2 | 47.1 |\n| N — Frame stack | 58.2 | 58.9 | 59.3 | 59.9 |",
"price": 1099.99,
"tags": [
"bicycle",
"mountain bike"
]
},
{
"name": "AURORA 11S E-MTB",
"shortDescription": "The AURORA 11S is a powerful and stylish electric mountain bike designed to take you on thrilling off-road adventures. With its sturdy frame and premium components, this bike is built to handle any terrain. It features a high-performance motor, long-lasting battery, and advanced suspension system that guarantee a smooth and comfortable ride.",
"description": "## Overview\nIt's right for you if...\nYou want a top-of-the-line e-MTB that is both powerful and stylish. You also want a bike that can handle any terrain, from steep climbs to rocky descents. With its advanced features and premium components, the AURORA 11S is designed for serious off-road riders who demand the best.\n\nThe tech you get\nA sturdy aluminum frame with advanced suspension system that provides 120mm of travel. A 750W brushless motor that delivers up to 28mph, and a 48V/14Ah lithium-ion battery that provides up to 60 miles of range on a single charge. An advanced 11-speed Shimano drivetrain with hydraulic disc brakes for precise shifting and reliable stopping power. \n\nThe final word\nThe AURORA 11S is a top-of-the-line e-MTB that delivers exceptional performance and style. Whether you're tackling steep climbs or hitting rocky descents, this bike is built to handle any terrain with ease. With its advanced features and premium components, the AURORA 11S is the perfect choice for serious off-road riders who demand the best.\n\n## Features\nPowerful and efficient\n\nThe AURORA 11S is equipped with a high-performance 750W brushless motor that delivers up to 28mph. The motor is powered by a long-lasting 48V/14Ah lithium-ion battery that provides up to 60 miles of range on a single charge.\n\nAdvanced suspension system\n\nThe bike's advanced suspension system provides 120mm of travel, ensuring a smooth and comfortable ride on any terrain. The front suspension is a Suntour XCR32 Air fork, while the rear suspension is a KS-281 hydraulic shock absorber.\n\nPremium components\n\nThe AURORA 11S features an advanced 11-speed Shimano drivetrain with hydraulic disc brakes. The bike is also equipped with a Tektro HD-E725 hydraulic disc brake system that provides reliable stopping power.\n\nSleek and stylish design\n\nWith its sleek and stylish design, the AURORA 11S is sure to turn heads on the trail. The bike's sturdy aluminum frame is available in a range of colors, including black, blue, and red.\n\n## Specs\nFrameset\nFrame Material: Aluminum\nFrame Size: S, M, L\nFork: Suntour XCR32 Air, 120mm Travel\nShock Absorber: KS-281 Hydraulic Shock Absorber\n\nWheels\nWheel Size: 27.5 inches\nTires: Kenda K1151 Nevegal, 27.5x2.35\nRims: Alloy Double Wall\nSpokes: 32H, Stainless Steel\n\nDrivetrain\nShifters: Shimano SL-M7000\nRear Derailleur: Shimano RD-M8000\nCrankset: Prowheel 42T, Alloy Crank Arm\nCassette: Shimano CS-M7000, 11-42T\nChain: KMC X11EPT\n\nBrakes\nBrake System: Tektro HD-E725 Hydraulic Disc Brake\nBrake Rotors: 180mm Front, 160mm Rear\n\nE-bike system\nMotor: 750W Brushless\nBattery: 48V/14Ah Lithium-Ion\nCharger: 48V/3A Smart Charger\nController: Intelligent Sinusoidal Wave\n\nWeight\nWeight: 59.5 lbs\n\n## Sizing & fit\n| Size | Rider Height | Standover Height |\n|------|-------------|-----------------|\n| S | 5'2\"-5'6\" | 28.5\" |\n| M | 5'7\"-6'0\" | 29.5\" |\n| L | 6'0\"-6'4\" | 30.5\" |\n\n## Geometry\nAll measurements provided in cm.\nSizing table\n| Frame size letter | S | M | L |\n|-------------------|-----|-----|-----|\n| Wheel Size | 27.5\"| 27.5\"| 27.5\"|\n| Seat tube length | 44.5| 48.5| 52.5|\n| Head tube angle | 68° | 68° | 68° |\n| Seat tube angle | 74.5°| 74.5°| 74.5°|\n| Effective top tube | 57.5| 59.5| 61.5|\n| Head tube length | 12.0| 12.0| 13.0|\n| Chainstay length | 45.5| 45.5| 45.5|\n| Bottom bracket height | 30.0| 30.0| 30.0|\n| Wheelbase | 115.0|116.5|118.5|",
"price": 1999.99,
"tags": [
"bicycle",
"road bike"
]
},
{
"name": "VeloTech V9.5 AXS Gen 3",
"shortDescription": "VeloTech V9.5 AXS is a sleek and fast carbon bike that combines high-end tech with a comfortable ride. It's designed to provide the ultimate experience for the most serious riders. The bike comes with a lightweight and powerful motor that can be activated when needed, and you get a spec filled with premium parts.",
"description": "## Overview\nIt's right for you if...\nYou want a bike that is fast, efficient, and delivers an adrenaline-filled experience. You are looking for a bike that is built with cutting-edge technology, and you want a ride that is both comfortable and exciting.\n\nThe tech you get\nA lightweight and durable full carbon frame with a fork that has 100mm of travel. The bike comes with a powerful motor that can deliver up to 20 mph of assistance. The drivetrain is a wireless electronic system that is precise and reliable. The bike is also equipped with hydraulic disc brakes, tubeless-ready wheels, and comfortable grips.\n\nThe final word\nThe VeloTech V9.5 AXS is a high-end bike that delivers an incredible experience for serious riders. It combines the latest technology with a comfortable ride, making it perfect for long rides, tough climbs, and fast descents.\n\n## Features\nFast and efficient\nThe VeloTech V9.5 AXS comes with a powerful motor that can provide up to 20 mph of assistance. The motor is lightweight and efficient, providing a boost when you need it without adding bulk. The bike's battery is removable, allowing you to ride without assistance when you don't need it.\n\nSmart software for the trail\nThe VeloTech V9.5 AXS is equipped with intelligent software that delivers a smooth and responsive ride. The software allows the motor to respond immediately as you start to pedal, delivering more power over a wider cadence range. You can also customize your user settings to suit your preferences.\n\nComfortable ride\nThe VeloTech V9.5 AXS is designed to provide a comfortable ride, even on long rides. The bike's fork has 100mm of travel, providing ample cushioning for rough terrain. The bike's grips are also designed to provide a comfortable and secure grip, even on the most challenging rides.\n\n## Specs\nFrameset\nFrame\tCarbon fiber frame with internal cable routing and Boost148\nFork\t100mm of travel with remote lockout\nShock\tN/A\n\nWheels\nWheel front\tCarbon fiber tubeless-ready wheel\nWheel rear\tCarbon fiber tubeless-ready wheel\nSkewer rear\t12mm thru-axle\nTire\tTubeless-ready tire\nTire part\tTubeless sealant\n\nDrivetrain\nShifter\tWireless electronic shifter\nRear derailleur\tWireless electronic derailleur\nCrank\tCarbon fiber crankset with chainring\nCrank arm\tCarbon fiber crank arm\nChainring\tAlloy chainring\nCassette\t12-speed cassette\nChain\t12-speed chain\n\nComponents\nSaddle\tCarbon fiber saddle\nSeatpost\tCarbon fiber seatpost\nHandlebar\tCarbon fiber handlebar\nGrips\tComfortable and secure grips\nStem\tCarbon fiber stem\nHeadset\tCarbon fiber headset\nBrake\tHydraulic disc brakes\nBrake rotor\tDisc brake rotor\n\nAccessories\nE-bike system\tPowerful motor with removable battery\nBattery\tLithium-ion battery\nCharger\tFast charging adapter\nController\tHandlebar-mounted controller\nTool\tBasic toolkit\n\nWeight\nWeight\tM - 17.5 kg / 38.5 lbs (with tubeless sealant)\n\nWeight limit\nThis bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\n\n## Sizing & fit\n| Size | Rider Height | Inseam |\n|:----:|:------------------------:|:--------------------:|\n| S | 160 - 170 cm 5'3\" - 5'7\" | 74 - 79 cm 29\" - 31\" |\n| M | 170 - 180 cm 5'7\" - 5'11\" | 79 - 84 cm 31\" - 33\" |\n| L | 180 - 190 cm 5'11\" - 6'3\" | 84 - 89 cm 33\" - 35\" |\n| XL | 190 - 200 cm 6'3\" - 6'7\" | 89 - 94 cm 35\" - 37\" |\n\n## Geometry\nAll measurements provided in cm unless otherwise noted.\nSizing table\n| Frame size letter | S | M | L | XL |\n|---------------------------|-------|-------|-------|-------|\n| Actual frame size | 50.0 | 53.3 | 55.6 | 58.8 |\n| Wheel size | 29\" | 29\" | 29\" | 29\" |\n| A — Seat tube | 39.4 | 43.2 | 48.3 | 53.3 |\n| B — Seat tube angle | 72.3° | 72.6° | 72.8° | 72.8° |\n| C — Head tube length | 9.0 | 10.0 | 10.5 | 11.0 |\n| D — Head angle | 67.5° | 67.5° | 67.5° | 67.5° |\n| E — Effective top tube | 58.0 | 61.7 | 64.8 | 67.0 |\n| F — Bottom bracket height | 32.3 | 32.3 | 32.3 | 32.3 |\n| G — Bottom bracket drop | 5.0 | 5.0 | 5.0 | 5.0 |\n| H — Chainstay length | 44.7 | 44.7 | 44.7 | 44.7 |\n| I — Offset | 4.2 | 4.2 | 4.2 | 4.2 |\n| J — Trail | 10.9 | 10.9 | 10.9 | 10.9 |\n| K — Wheelbase | 112.6 | 116.5 | 119.7 | 121.9 |\n| L — Standover | 76.8 | 76.8 | 76.8 | 76.8 |\n| M — Frame reach | 40.5 | 44.0 | 47.0 | 49.0 |\n| N — Frame stack | 60.9 | 61.8 | 62.2 | 62.7 |",
"price": 1699.99,
"tags": [
"bicycle",
"electric bike",
"city bike"
]
},
{
"name": "Axiom D8 E-Mountain Bike",
"shortDescription": "The Axiom D8 is an electrifying mountain bike that is built for adventure. It boasts a light aluminum frame, a powerful motor and the latest tech to tackle the toughest of terrains. The D8 provides assistance without adding bulk to the bike, giving you the flexibility to ride like a traditional mountain bike or have an extra push when you need it.",
"description": "## Overview \nIt's right for you if... \nYou're looking for an electric mountain bike that can handle a wide variety of terrain, from flowing singletrack to technical descents. You also want a bike that offers a powerful motor that provides assistance without adding bulk to the bike. The D8 is designed to take you anywhere, quickly and comfortably.\n\nThe tech you get \nA lightweight aluminum frame with 140mm of travel, a Suntour fork with hydraulic lockout, and a reliable and powerful Bafang M400 mid-motor that provides a boost up to 20 mph. The bike features a Shimano Deore drivetrain, hydraulic disc brakes, and a dropper seat post. With the latest tech on-board, the D8 is designed to take you to new heights.\n\nThe final word \nThe Axiom D8 is an outstanding electric mountain bike that is designed for adventure. It's built with the latest tech and provides the flexibility to ride like a traditional mountain bike or have an extra push when you need it. Whether you're a beginner or an experienced rider, the D8 is the perfect companion for your next adventure.\n\n## Features \nBuilt for Adventure \n\nThe D8 features a lightweight aluminum frame that is built to withstand rugged terrain. It comes equipped with 140mm of travel and a Suntour fork that can handle even the toughest of trails. With this bike, you're ready to take on anything the mountain can throw at you.\n\nPowerful Motor \n\nThe Bafang M400 mid-motor provides reliable and powerful assistance without adding bulk to the bike. You can quickly and easily switch between the different assistance levels to find the perfect balance between range and power.\n\nShimano Deore Drivetrain \n\nThe Shimano Deore drivetrain is reliable and offers smooth shifting on any terrain. You can easily adjust the gears to match your riding style and maximize your performance on the mountain.\n\nDropper Seat Post \n\nThe dropper seat post allows you to easily adjust your seat height on the fly, so you can maintain the perfect position for any terrain. With the flick of a switch, you can quickly and easily lower or raise your seat to match the terrain.\n\nHydraulic Disc Brakes \n\nThe D8 features powerful hydraulic disc brakes that offer reliable stopping power in any weather condition. You can ride with confidence knowing that you have the brakes to stop on a dime.\n\n## Specs \nFrameset \nFrame\tAluminum frame with 140mm of travel \nFork\tSuntour fork with hydraulic lockout, 140mm of travel \nShock\tN/A \nMax compatible fork travel\t140mm \n \nWheels \nWheel front\tAlloy wheel \nWheel rear\tAlloy wheel \nSkewer rear\tThru axle \nTire\t29\" x 2.35\" \nTire part\tN/A \nMax tire size\t29\" x 2.6\" \n \nDrivetrain \nShifter\tShimano Deore \nRear derailleur\tShimano Deore \nCrank\tBafang M400 \nCrank arm\tN/A \nChainring\tN/A \nCassette\tShimano Deore \nChain\tShimano Deore \nMax chainring size\tN/A \n \nComponents \nSaddle\tAxiom D8 saddle \nSeatpost\tDropper seat post \nHandlebar\tAxiom D8 handlebar \nGrips\tAxiom D8 grips \nStem\tAxiom D8 stem \nHeadset\tAxiom D8 headset \nBrake\tHydraulic disc brakes \nBrake rotor\t180mm \n\nAccessories \nE-bike system\tBafang M400 mid-motor \nBattery\tLithium-ion battery, 500Wh \nCharger\tLithium-ion charger \nController\tBafang M400 controller \nTool\tN/A \n \nWeight \nWeight\tM - 22 kg / 48.5 lbs \nWeight limit\tThis bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 136 kg (300 lbs). \n \n \n## Sizing & fit \n \n| Size | Rider Height | Inseam | \n|:----:|:------------------------:|:--------------------:| \n| S | 152 - 165 cm 5'0\" - 5'5\" | 70 - 76 cm 27\" - 30\" | \n| M | 165 - 178 cm 5'5\" - 5'10\" | 76 - 81 cm 30\" - 32\" | \n| L | 178 - 185 cm 5'10\" - 6'1\" | 81 - 86 cm 32\" - 34\" | \n| XL | 185 - 193 cm 6'1\" - 6'4\" | 86 - 91 cm 34\" - 36\" | \n \n \n## Geometry \n \nAll measurements provided in cm unless otherwise noted. \nSizing table \n| Frame size letter | S | M | L | XL | \n|---------------------------|-------|-------|-------|-------| \n| Actual frame size | 41.9 | 46.5 | 50.8 | 55.9 | \n| Wheel size | 29\" | 29\" | 29\" | 29\" | \n| A — Seat tube | 42.0 | 46.5 | 51.0 | 56.0 | \n| B — Seat tube angle | 74.0° | 74.0° | 74.0° | 74.0° | \n| C — Head tube length | 11.0 | 12.0 | 13.0 | 15.0 | \n| D — Head angle | 68.0° | 68.0° | 68.0° | 68.0° | \n| E — Effective top tube | 57.0 | 60.0 | 62.0 | 65.0 | \n| F — Bottom bracket height | 33.0 | 33.0 | 33.0 | 33.0 | \n| G — Bottom bracket drop | 3.0 | 3.0 | 3.0 | 3.0 | \n| H — Chainstay length | 46.0 | 46.0 | 46.0 | 46.0 | \n| I — Offset | 4.5 | 4.5 | 4.5 | 4.5 | \n| J — Trail | 10.9 | 10.9 | 10.9 | 10.9 | \n| K — Wheelbase | 113.0 | 116.0 | 117.5 | 120.5 | \n| L — Standover | 73.5 | 75.5 | 76.5 | 79.5 | \n| M — Frame reach | 41.0 | 43.5 | 45.0 | 47.5 | \n| N — Frame stack | 60.5 | 61.5 | 62.5 | 64.5 |",
"price": 1399.99,
"tags": [
"bicycle",
"electric bike",
"mountain bike"
]
},
{
"name": "Velocity X1",
"shortDescription": "Velocity X1 is a high-performance road bike designed for speed enthusiasts. It features a lightweight yet durable frame, aerodynamic design, and top-quality components, making it the perfect choice for those who want to take their cycling experience to the next level.",
"description": "## Overview\nIt's right for you if...\nYou're an experienced cyclist looking for a bike that can keep up with your need for speed. You want a bike that's lightweight, aerodynamic, and built to perform, whether you're training for a race or just pushing yourself to go faster.\n\nThe tech you get\nA lightweight aluminum frame with a carbon fork, Shimano Ultegra groupset with a wide range of gearing, hydraulic disc brakes, aerodynamic carbon wheels, and a vibration-absorbing handlebar with ergonomic grips.\n\nThe final word\nVelocity X1 is the ultimate road bike for speed enthusiasts. Its lightweight frame, aerodynamic design, and top-quality components make it the perfect choice for those who want to take their cycling experience to the next level.\n\n\n## Features\n\nAerodynamic design\nVelocity X1 is built with an aerodynamic design to help you go faster with less effort. It features a sleek profile, hidden cables, and a carbon fork that cuts through the wind, reducing drag and increasing speed.\n\nHydraulic disc brakes\nVelocity X1 comes equipped with hydraulic disc brakes, providing excellent stopping power in all weather conditions. They're also low maintenance, with minimal adjustments needed over time.\n\nCarbon wheels\nThe Velocity X1's aerodynamic carbon wheels provide excellent speed and responsiveness, helping you achieve your fastest times yet. They're also lightweight, reducing overall bike weight and making acceleration and handling even easier.\n\nShimano Ultegra groupset\nThe Shimano Ultegra groupset provides smooth shifting and reliable performance, ensuring you get the most out of every ride. With a wide range of gearing options, it's ideal for tackling any terrain, from steep climbs to fast descents.\n\n\n## Specifications\nFrameset\nFrame with Fork\tAluminium frame, internal cable routing, 135x9mm QR\nFork\tCarbon, hidden cable routing, 100x9mm QR\n\nWheels\nWheel front\tCarbon, 30mm deep rim, 23mm width, 100x9mm QR\nWheel rear\tCarbon, 30mm deep rim, 23mm width, 135x9mm QR\nSkewer front\t100x9mm QR\nSkewer rear\t135x9mm QR\nTire\tContinental Grand Prix 5000, 700x25mm, folding bead\nMax tire size\t700x28mm without fenders\n\nDrivetrain\nShifter\tShimano Ultegra R8020, 11 speed\nRear derailleur\tShimano Ultegra R8000, 11 speed\nCrank\tSize: S, M\nShimano Ultegra R8000, 50/34T, 170mm length\nSize: L, XL\nShimano Ultegra R8000, 50/34T, 175mm length\nBottom bracket\tShimano BB-RS500-PB, PressFit\nCassette\tShimano Ultegra R8000, 11-30T, 11 speed\nChain\tShimano Ultegra HG701, 11 speed\nPedal\tNot included\nMax chainring size\t50/34T\n\nComponents\nSaddle\tBontrager Montrose Comp, steel rails, 138mm width\nSeatpost\tBontrager Comp, 6061 alloy, 27.2mm, 8mm offset, 330mm length\nHandlebar\tSize: S, M, L\nBontrager Elite Aero VR-CF, alloy, 31.8mm, 93mm reach, 123mm drop, 400mm width\nSize: XL\nBontrager Elite Aero VR-CF, alloy, 31.8mm, 93mm reach, 123mm drop, 420mm width\nGrips\tBontrager Supertack Perf tape\n*Stem\tSize: S, M, L\nBontrager Elite Blendr, 31.8mm clamp, 7 degree, 90mm length\nSize: XL\nBontrager Elite Blendr, 31.8mm clamp, 7 degree, 100mm length\nBrake\tShimano Ultegra R8070 hydraulic disc, flat mount\nBrake rotor\tShimano RT800, centerlock, 160mm\nRotor size\tMax brake rotor sizes: 160mm front & rear\n\nWeight\nWeight\tM - 8.15 kg / 17.97 lbs\nWeight limit\tThis bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 275 pounds (125 kg).\n\n\n## Sizing\n| Size | Rider Height | Inseam |\n|:----:|:-------------------------:|:--------------------:|\n| S | 162 - 170 cm 5'4\" - 5'7\" | 74 - 78 cm 29\" - 31\" |\n| M | 170 - 178 cm 5'7\" - 5'10\" | 77 - 82 cm 30\" - 32\" |\n| L | 178 - 186 cm 5'10\" - 6'1\" | 82 - 86 cm 32\" - 34\" |\n| XL | 186 - 196 cm 6'1\" - 6'5\" | 87 - 92 cm 34\" - 36\" |\n\n\n## Geometry\n| Frame size letter | S | M | L | XL |\n|---------------------------|-------|-------|-------|-------|\n| Wheel size | 700c | 700c | 700c | 700c |\n| A — Seat tube | 50.0 | 52.0 | 54.0 | 56.0 |\n| B — Seat tube angle | 74.0° | 73.5° | 73.0° | 72.5° |\n| C — Head tube length | 13.0 | 15.0 | 17.0 | 19.0 |\n| D — Head angle | 71.0° | 72.0° | 72.0° | 72.5° |\n| E — Effective top tube | 53.7 | 55.0 | 56.5 | 58.0 |\n| F — Bottom bracket height | 27.5 | 27.5 | 27.5 | 27.5 |\n| G — Bottom bracket drop | 7.3 | 7.3 | 7.3 | 7.3 |\n| H — Chainstay length | 41.0 | 41.0 | 41.0 | 41.0 |\n| I — Offset | 4.5 | 4.5 | 4.5 | 4.5 |\n| J — Trail | 6.0 | 6.0 | 6.0 | 5.8 |\n| K — Wheelbase | 98.2 | 99.1 | 100.1 | 101.0 |\n| L — Standover | 75.2 | 78.2 | 81.1 | 84.1 |\n| M — Frame reach | 37.5 | 38.3 | 39.1 | 39.9 |\n| N — Frame stack | 53.3 | 55.4 | 57.4 | 59.5 |",
"price": 1799.99,
"tags": [
"bicycle",
"touring bike"
]
},
{
"name": "Velocity V9",
"shortDescription": "Velocity V9 is a high-performance hybrid bike that combines speed and comfort for riders who demand the best of both worlds. The lightweight aluminum frame, along with the carbon fork and seat post, provide optimal stiffness and absorption to tackle any terrain. A 2x Shimano Deore drivetrain, hydraulic disc brakes, and 700c wheels with high-quality tires make it a versatile ride for commuters, fitness riders, and weekend adventurers alike.",
"description": "## Overview\nIt's right for you if...\nYou want a fast, versatile bike that can handle anything from commuting to weekend adventures. You value comfort as much as speed and performance. You want a reliable and durable bike that will last for years to come.\n\nThe tech you get\nA lightweight aluminum frame with a carbon fork and seat post, a 2x Shimano Deore drivetrain with a wide range of gearing, hydraulic disc brakes, and 700c wheels with high-quality tires. The Velocity V9 is designed for riders who demand both performance and comfort in one package.\n\nThe final word\nThe Velocity V9 is the perfect bike for riders who want speed and performance without sacrificing comfort. The lightweight aluminum frame and carbon components provide optimal stiffness and absorption, while the 2x Shimano Deore drivetrain and hydraulic disc brakes ensure precise shifting and stopping power. Whether you're commuting, hitting the trails, or training for your next race, the Velocity V9 has everything you need to achieve your goals.\n\n## Features\n\n2x drivetrain\nA 2x drivetrain means more versatility and a wider range of gearing options. Whether you're climbing hills or sprinting on the flats, the Velocity V9 has the perfect gear for any situation.\n\nCarbon components\nThe Velocity V9 features a carbon fork and seat post to provide optimal stiffness and absorption. This means you can ride faster and more comfortably over any terrain.\n\nHydraulic disc brakes\nHydraulic disc brakes provide unparalleled stopping power and modulation in any weather condition. You'll feel confident and in control no matter where you ride.\n\n## Specifications\nFrameset\nFrame with Fork\tAluminum frame with carbon fork and seat post, internal cable routing, fender mounts, 135x5mm ThruSkew\nFork\tCarbon fork, hidden fender mounts, flat mount disc, 5x100mm thru-skew\n\nWheels\nWheel front\tDouble wall aluminum rims, 700c, quick release hub\nWheel rear\tDouble wall aluminum rims, 700c, quick release hub\nTire\tKenda Kwick Tendril, puncture resistant, reflective sidewall, 700x32c\nMax tire size\t700x35c without fenders, 700x32c with fenders\n\nDrivetrain\nShifter\tShimano Deore, 10 speed\nFront derailleur\tShimano Deore\nRear derailleur\tShimano Deore\nCrank\tShimano Deore, 46-30T, 170mm (S/M), 175mm (L/XL)\nBottom bracket\tShimano BB52, 68mm, threaded\nCassette\tShimano Deore, 11-36T, 10 speed\nChain\tShimano HG54, 10 speed\nPedal\tWellgo alloy platform\n\nComponents\nSaddle\tVelo VL-2158, steel rails\nSeatpost\tCarbon seat post, 27.2mm\nHandlebar\tAluminum, 31.8mm clamp, 15mm rise, 680mm width\nGrips\tVelo ergonomic grips\nStem\tAluminum, 31.8mm clamp, 7 degree, 90mm length\nBrake\tShimano hydraulic disc, MT200 lever, MT200 caliper\nBrake rotor\tShimano RT56, centerlock, 160mm\nRotor size\tMax brake rotor sizes: 160mm front & rear\n\nWeight\nWeight\tM - 11.5 kg / 25.35 lbs\nWeight limit\tThis bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\n\n## Sizing\n| Size | Rider Height | Inseam |\n|:----:|:-------------------------:|:--------------------:|\n| S | 155 - 165 cm 5'1\" - 5'5\" | 72 - 78 cm 28\" - 31\" |\n| M | 165 - 175 cm 5'5\" - 5'9\" | 77 - 83 cm 30\" - 33\" |\n| L | 175 - 186 cm 5'9\" - 6'1\" | 82 - 88 cm 32\" - 35\" |\n| XL | 186 - 197 cm 6'1\" - 6'6\" | 87 - 93 cm 34\" - 37\" |\n\n## Geometry\n| Frame size | S | M | L | XL |\n|--------------------|-------|-------|-------|-------|\n| Wheel size | 700c | 700c | 700c | 700c |\n| A — Seat tube | 44.0 | 48.0 | 52.0 | 56.0 |\n| B — Seat tube angle | 74.5° | 74.0° | 73.5° | 73.0° |\n| C — Head tube length | 14.5 | 16.0 | 18.0 | 20.0 |\n| D — Head angle | 71.0° | 71.0° | 71.5° | 71.5° |\n| E — Effective top tube | 56.5 | 57.5 | 58.5 | 59.5 |\n| F — Bottom bracket height | 27.0 | 27.0 | 27.0 | 27.0 |\n| G — Bottom bracket drop | 7.0 | 7.0 | 7.0 | 7.0 |\n| H — Chainstay length | 43.0 | 43.0 | 43.0 | 43.0 |\n| I — Offset | 4.5 | 4.5 | 4.5 | 4.5 |\n| J — Trail | 7.0 | 7.0 | 6.6 | 6.6 |\n| K — Wheelbase | 105.4 | 106.3 | 107.2 | 108.2 |\n| L — Standover | 73.2 | 77.1 | 81.2 | 85.1 |\n| M — Frame reach | 39.0 | 39.8 | 40.4 | 41.3 |\n| N — Frame stack | 57.0 | 58.5 | 60.0 | 61.5 |",
"price": 2199.99,
"tags": [
"bicycle",
"electric bike",
"mountain bike"
]
},
{
"name": "Aero Pro X",
"shortDescription": "Aero Pro X is a high-end racing bike designed for serious cyclists who demand speed, agility, and superior performance. The lightweight carbon frame and fork, combined with the aerodynamic design, provide optimal stiffness and efficiency to maximize your speed. The bike features a 2x Shimano Ultegra drivetrain, hydraulic disc brakes, and 700c wheels with high-quality tires. Whether you're competing in a triathlon or climbing steep hills, Aero Pro X delivers exceptional performance and precision handling.",
"description": "## Overview\nIt's right for you if...\nYou are a competitive cyclist looking for a bike that is designed for racing. You want a bike that delivers exceptional speed, agility, and precision handling. You demand superior performance and reliability from your equipment.\n\nThe tech you get\nA lightweight carbon frame with an aerodynamic design, a carbon fork with hidden fender mounts, a 2x Shimano Ultegra drivetrain with a wide range of gearing, hydraulic disc brakes, and 700c wheels with high-quality tires. Aero Pro X is designed for serious cyclists who demand nothing but the best.\n\nThe final word\nAero Pro X is the ultimate racing bike for serious cyclists. The lightweight carbon frame and aerodynamic design deliver maximum speed and efficiency, while the 2x Shimano Ultegra drivetrain and hydraulic disc brakes ensure precise shifting and stopping power. Whether you're competing in a triathlon or a criterium race, Aero Pro X delivers the performance you need to win.\n\n## Features\n\nAerodynamic design\nThe Aero Pro X features an aerodynamic design that reduces drag and maximizes efficiency. The bike is optimized for speed and agility, so you can ride faster and farther with less effort.\n\nHydraulic disc brakes\nHydraulic disc brakes provide unrivaled stopping power and modulation in any weather condition. You'll feel confident and in control no matter where you ride.\n\nCarbon components\nThe Aero Pro X features a carbon fork with hidden fender mounts to provide optimal stiffness and absorption. This means you can ride faster and more comfortably over any terrain.\n\n## Specifications\nFrameset\nFrame with Fork\tCarbon frame with an aerodynamic design, internal cable routing, 3s chain keeper, 142x12mm thru-axle\nFork\tCarbon fork with hidden fender mounts, flat mount disc, 100x12mm thru-axle\n\nWheels\nWheel front\tDouble wall carbon rims, 700c, thru-axle hub\nWheel rear\tDouble wall carbon rims, 700c, thru-axle hub\nTire\tContinental Grand Prix 5000, folding bead, 700x25c\nMax tire size\t700x28c without fenders, 700x25c with fenders\n\nDrivetrain\nShifter\tShimano Ultegra, 11 speed\nFront derailleur\tShimano Ultegra\nRear derailleur\tShimano Ultegra\nCrank\tShimano Ultegra, 52-36T, 170mm (S), 172.5mm (M), 175mm (L/XL)\nBottom bracket\tShimano BB72, 68mm, PressFit\nCassette\tShimano Ultegra, 11-30T, 11 speed\nChain\tShimano HG701, 11 speed\nPedal\tNot included\n\nComponents\nSaddle\tBontrager Montrose Elite, carbon rails, 138mm width\nSeatpost\tCarbon seat post, 27.2mm, 20mm offset\nHandlebar\tBontrager XXX Aero, carbon, 31.8mm clamp, 75mm reach, 125mm drop\nGrips\tBontrager Supertack Perf tape\nStem\tBontrager Pro, 31.8mm clamp, 7 degree, 90mm length\nBrake\tShimano hydraulic disc, Ultegra lever, Ultegra caliper\nBrake rotor\tShimano RT800, centerlock, 160mm\nRotor size\tMax brake rotor sizes: 160mm front & rear\n\nWeight\nWeight\tM - 8.36 kg / 18.42 lbs\nWeight limit\tThis bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 275 pounds (125 kg).\n\n## Sizing\n| Size | Rider Height |\n|:----:|:-------------------------:|\n| S | 155 - 165 cm 5'1\" - 5'5\" |\n| M | 165 - 175 cm 5'5\" - 5'9\" |\n| L | 175 - 186 cm 5'9\" - 6'1\" |\n| XL | 186 - 197 cm 6'1\" - 6'6\" |\n\n## Geometry\n| Frame size | S | M | L | XL |\n|--------------------|-------|-------|-------|-------|\n| Wheel size | 700c | 700c | 700c | 700c |\n| A — Seat tube | 50.6 | 52.4 | 54.3 | 56.2 |\n| B — Seat tube angle | 75.5° | 74.5° | 73.5° | 72.5° |\n| C — Head tube length | 12.0 | 14.0 | 16.0 | 18.0 |\n| D — Head angle | 72.5° | 73.0° | 73.5° | 74.0° |\n| E — Effective top tube | 53.8 | 55.4 | 57.0 | 58.6 |\n| F — Bottom bracket height | 26.5 | 26.5 | 26.5 | 26.5 |\n| G — Bottom bracket drop | 7.0 | 7.0 | 7.0 | 7.0 |\n| H — Chainstay length | 41.0 | 41.0 | 41.0 | 41.0 |\n| I — Offset | 4.5 | 4.5 | 4.5 | 4.5 |\n| J — Trail | 6.0 | 6.0 | 6.0 | 6.0 |\n| K — Wheelbase | 97.1 | 98.7 | 100.2 | 101.8 |\n| L — Standover | 73.8 | 76.2 | 78.5 | 80.8 |\n| M — Frame reach | 38.8 | 39.5 | 40.2 | 40.9 |\n| N — Frame stack | 52.8 | 54.7 | 56.6 | 58.5 |",
"price": 1599.99,
"tags": [
"bicycle",
"road bike"
]
},
{
"name": "Voltex+ Ultra Lowstep",
"shortDescription": "Voltex+ Ultra Lowstep is a high-performance electric hybrid bike designed for riders who seek speed, comfort, and reliability during their everyday rides. Equipped with a powerful and efficient Voltex Drive Pro motor and a fully-integrated 600Wh battery, this e-bike allows you to cover longer distances on a single charge. The Voltex+ Ultra Lowstep comes with premium components that prioritize comfort and safety, such as a suspension seatpost, wide and stable tires, and integrated lights.",
"description": "## Overview\n\nIt's right for you if...\nYou want an e-bike that provides a boost for faster rides and effortless usage. Durability is crucial, and you need a bike with one of the most powerful and efficient motors.\n\nThe tech you get\nA lightweight Delta Carbon Fiber frame with an ultra-lowstep design, a Voltex Drive Pro (350W, 75Nm) motor capable of maintaining speeds up to 30 mph, an extended range 600Wh battery integrated into the frame, and a Voltex Control Panel. Additionally, it features a 12-speed Shimano drivetrain, hydraulic disc brakes for optimal all-weather stopping power, a suspension seatpost, wide puncture-resistant tires for added stability, ergonomic grips, a kickstand, lights, and a cargo rack.\n\nThe final word\nThis bike offers enhanced enjoyment and ease of use on long commutes, leisure rides, and adventures. With its extended-range battery, powerful Voltex motor, user-friendly controller, and a seatpost that smooths out road vibrations, it guarantees an exceptional riding experience.\n\n## Features\n\nUltra-fast assistance\n\nExperience speeds up to 30 mph with the cutting-edge Voltex Drive Pro motor, allowing you to breeze through errands, commutes, and joyrides.\n\n## Specs\n\nFrameset\n- Frame: Delta Carbon Fiber, Removable Integrated Battery (RIB), sleek welds, rack & fender mounts, internal routing, kickstand mount, 135x5mm QR\n- Fork: Voltex Alloy, threaded steel steerer, rack mounts, post mount disc, 460mm axle-to-crown, ThruSkew 5mm QR\n- Max compatible fork travel: 50mm\n\nWheels\n- Hub front: Formula DC-20, alloy, 6-bolt, 5x100mm QR\n- Skewer front: 132x5mm QR, ThruSkew\n- Hub rear: Formula DC-22, alloy, 6-bolt, Shimano 8/9/10 freehub, 135x5mm QR\n- Skewer rear: 153x5mm bolt-on\n- Rim: Voltex Connection, double-wall, 32-hole, 20 mm width, Schrader valve\n- Tire: Voltex E6 Hard-Case Lite, reflective, wire bead, 60tpi, 700x50c\n- Max tire size: 700x50mm with or without fenders\n\nDrivetrain\n- Shifter: Shimano Deore XT M8100, 12-speed\n- Rear derailleur: Shimano Deore XT M8100, long cage\n- Crank: Voltex alloy, 170mm length\n- Chainring: FSA, 44T, aluminum with guard\n- Cassette: Shimano Deore XT M8100, 10-51, 12-speed\n- Chain: KMC E12 Turbo\n- Pedal: Voltex Urban pedals\n\nComponents\n- Saddle: Voltex Boulevard\n- Seatpost: Alloy, suspension, 31.6mm, 300mm length\n- Handlebar: Voltex alloy, 31.8mm, comfort sweep, 620mm width (XS, S, M), 660mm width (L)\n- Grips: Voltex Satellite Elite, alloy lock-on\n- Stem: Voltex alloy quill, 31.8mm clamp, adjustable rise, Blendr compatible, 85mm length (XS, S), 105mm length (M, L)\n- Headset: VP sealed cartridge, 1-1/8'', threaded\n- Brake: Shimano MT520 hydraulic disc\n- Brake rotor: Shimano RT56, 6-bolt, 180mm (XS, S, M, L), 160mm (XS, S, M, L)\n\nAccessories\n- Battery: Voltex PowerTube 600Wh\n- Charger: Voltex compact 2A, 100-240V\n- Computer: Voltex Control Panel\n- Motor: Voltex Drive Pro, 75Nm, 30mph\n- Light: Voltex Solo for e-bike, taillight (XS, S, M, L), Voltex MR8, 180 lumen, 60 lux, LED, headlight (XS, S, M, L)\n- Kickstand: Adjustable length rear mount alloy kickstand\n- Cargo rack: Voltex-compatible alloy rear rack, maximum load 25 kg / 55 lbs\n- Fender: Voltex wide (XS, S, M, L), Voltex plastic (XS, S, M, L)\n\nWeight\n- Weight: M - 20.50 kg / 45.19 lbs\n- Weight limit: This bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 330 pounds (150 kg).\n\n## Sizing\n\n| Size | Rider Height | Inseam |\n|:----:|:-------------------------:|:--------------------:|\n| XS | 147 - 155 cm 4'10\" - 5'1\" | 69 - 73 cm 27\" - 29\" |\n| S | 155 - 165 cm 5'1\" - 5'5\" | 72 - 78 cm 28\" - 31\" |\n| M | 165 - 175 cm 5'5\" - 5'9\" | 77 - 83 cm 30\" - 33\" |\n| L | 175 - 186 cm 5'9\" - 6'1\" | 82 - 88 cm 32\" - 35\" |\n\n## Geometry\n\nAll measurements provided in cm unless otherwise noted.\n\nSizing table\n\n| Frame size number | 40 cm | 45 cm | 50 cm | 55 cm |\n|---------------------------|-------|-------|-------|-------|\n| Frame size letter | XS | S | M | L |\n| Wheel size | 700c | 700c | 700c | 700c |\n| A — Seat tube | 38.0 | 43.0 | 48.0 | 53.0 |\n| B — Seat tube angle | 70.5° | 70.5° | 70.5° | 70.5° |\n| C — Head tube length | 15.0 | 15.0 | 17.0 | 19.0 |\n| D — Head angle | 69.2° | 69.2° | 69.2° | 69.2° |\n| E — Effective top tube | 57.2 | 57.7 | 58.8 | 60.0 |\n| F — Bottom bracket height | 30.3 | 30.3 | 30.3 | 30.3 |\n| G — Bottom bracket drop | 6.0 | 6.0 | 6.0 | 6.0 |\n| H — Chainstay length | 48.5 | 48.5 | 48.5 | 48.5 |\n| I — Offset | 5.0 | 5.0 | 5.0 | 5.0 |\n| J — Trail | 9.0 | 9.0 | 9.0 | 9.0 |\n| K — Wheelbase | 111.8 | 112.3 | 113.6 | 114.8 |\n| L — Standover | 42.3 | 42.3 | 42.3 | 42.3 |\n| M — Frame reach | 36.0 | 38.0 | 38.0 | 38.0 |\n| N — Frame stack | 62.0 | 62.0 | 63.9 | 65.8 |\n| Stem length | 8.0 | 8.5 | 8.5 | 10.5 |\n\nPlease note that the specifications and features listed above are subject to change and may vary based on different models and versions of the Voltex+ Ultra Lowstep bike.",
"price": 2999.99,
"tags": [
"bicycle",
"road bike",
"professional"
]
},
{
"name": "SwiftRide Hybrid",
"shortDescription": "SwiftRide Hybrid is a versatile and efficient bike designed for riders who want a smooth and enjoyable ride on various terrains. It incorporates advanced technology and high-quality components to provide a comfortable and reliable cycling experience.",
"description": "## Overview\n\nIt's right for you if...\nYou are looking for a bike that combines the benefits of an electric bike with the versatility of a hybrid. You value durability, speed, and ease of use.\n\nThe tech you get\nThe SwiftRide Hybrid features a lightweight and durable aluminum frame, making it easy to handle and maneuver. It is equipped with a powerful electric motor that offers a speedy assist, helping you reach speeds of up to 25 mph. The bike comes with a removable and fully-integrated 500Wh battery, providing a long-range capacity for extended rides. It also includes a 10-speed Shimano drivetrain, hydraulic disc brakes for precise stopping power, wide puncture-resistant tires for stability, and integrated lights for enhanced visibility.\n\nThe final word\nThe SwiftRide Hybrid is designed for riders who want a bike that can handle daily commutes, recreational rides, and adventures. With its efficient motor, intuitive controls, and comfortable features, it offers an enjoyable and hassle-free riding experience.\n\n## Features\n\nEfficient electric assist\nExperience the thrill of effortless riding with the powerful electric motor that provides a speedy assist, making your everyday rides faster and more enjoyable.\n\n## Specs\n\nFrameset\n- Frame: Lightweight Aluminum, Removable Integrated Battery (RIB), rack & fender mounts, internal routing, 135x5mm QR\n- Fork: SwiftRide Alloy, threaded steel steerer, rack mounts, post mount disc, 460mm axle-to-crown, ThruSkew 5mm QR\n- Max compatible fork travel: 50mm\n\nWheels\n- Hub front: Formula DC-20, alloy, 6-bolt, 5x100mm QR\n- Skewer front: 132x5mm QR, ThruSkew\n- Hub rear: Formula DC-22, alloy, 6-bolt, Shimano 8/9/10 freehub, 135x5mm QR\n- Skewer rear: 153x5mm bolt-on\n- Rim: SwiftRide Connection, double-wall, 32-hole, 20 mm width, Schrader valve\n- Tire: SwiftRide E6 Hard-Case Lite, reflective, wire bead, 60tpi, 700x50c\n- Max tire size: 700x50mm with or without fenders\n\nDrivetrain\n- Shifter: Shimano Deore M4100, 10 speed\n- Rear derailleur: Shimano Deore M5120, long cage\n- Crank: ProWheel alloy, 170mm length\n- Chainring: FSA, 42T, steel w/guard\n- Cassette: Shimano Deore M4100, 11-42, 10 speed\n- Chain: KMC E10\n- Pedal: SwiftRide City pedals\n\nComponents\n- Saddle: SwiftRide Boulevard\n- Seatpost: Alloy, suspension, 31.6mm, 300mm length\n- Handlebar:\n - Size: XS, S, M - SwiftRide alloy, 31.8mm, comfort sweep, 620mm width\n - Size: L - SwiftRide alloy, 31.8mm, comfort sweep, 660mm width\n- Grips: SwiftRide Satellite Elite, alloy lock-on\n- Stem:\n - Size: XS, S - SwiftRide alloy quill, 31.8mm clamp, adjustable rise, 85mm length\n - Size: M, L - SwiftRide alloy quill, 31.8mm clamp, adjustable rise, 105mm length\n- Headset: VP sealed cartridge, 1-1/8'', threaded\n- Brake: Shimano MT200 hydraulic disc\n- Brake rotor:\n - Size: XS, S, M, L - Shimano RT26, 6-bolt, 180mm\n - Size: XS, S, M, L - Shimano RT26, 6-bolt, 160mm\n\nAccessories\n- Battery: SwiftRide PowerTube 500Wh\n- Charger: SwiftRide compact 2A, 100-240V\n- Computer: SwiftRide Purion\n- Motor: SwiftRide Performance Line Sport, 65Nm, 25mph\n- Light:\n - Size: XS, S, M, L - SwiftRide SOLO for e-bike, taillight\n - Size: XS, S, M, L - SwiftRide MR8, 180 lumen, 60 lux, LED, headlight\n- Kickstand: Adjustable length rear mount alloy kickstand\n- Cargo rack: SwiftRide-compatible alloy rear rack, maximum load 25 kg / 55 lbs\n- Fender:\n - Size: XS, S, M, L - SwiftRide wide\n - Size: XS, S, M, L - SwiftRide plastic\n\nWeight\n- Weight: M - 22.30 kg / 49.17 lbs\n- Weight limit: This bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\n\n## Sizing\n\n| Size | Rider Height | Inseam |\n|:----:|:-------------------------:|:--------------------:|\n| XS | 147 - 155 cm (4'10\" - 5'1\") | 69 - 73 cm (27\" - 29\") |\n| S | 155 - 165 cm (5'1\" - 5'5\") | 72 - 78 cm (28\" - 31\") |\n| M | 165 - 175 cm (5'5\" - 5'9\") | 77 - 83 cm (30\" - 33\") |\n| L | 175 - 186 cm (5'9\" - 6'1\") | 82 - 88 cm (32\" - 35\") |\n\n## Geometry\n\nAll measurements provided in cm unless otherwise noted.\n\nSizing table\n| Frame size number | 40 cm | 45 cm | 50 cm | 55 cm |\n|---------------------------|-------|-------|-------|-------|\n| Frame size letter | XS | S | M | L |\n| Wheel size | 700c | 700c | 700c | 700c |\n| A — Seat tube | 39.0 | 44.0 | 50.0 | 55.0 |\n| B — Seat tube angle | 71.0° | 71.0° | 71.0° | 71.0° |\n| C — Head tube length | 16.0 | 16.0 | 18.0 | 20.0 |\n| D — Head angle | 68.2° | 68.2° | 68.2° | 68.2° |\n| E — Effective top tube | 58.2 | 58.7 | 59.8 | 61.0 |\n| F — Bottom bracket height | 29.4 | 29.4 | 29.4 | 29.4 |\n| G — Bottom bracket drop | 6.5 | 6.5 | 6.5 | 6.5 |\n| H — Chainstay length | 48.7 | 48.7 | 48.7 | 48.7 |\n| I — Offset | 4.5 | 4.5 | 4.5 | 4.5 |\n| J — Trail | 9.5 | 9.5 | 9.5 | 9.5 |\n| K — Wheelbase | 112.2 | 112.7 | 114.0 | 115.2 |\n| L — Standover | 43.3 | 43.3 | 43.3 | 43.3 |\n| M — Frame reach | 36.5 | 38.5 | 38.5 | 38.5 |\n| N — Frame stack | 63.0 | 63.0 | 64.9 | 66.8 |\n| Stem length | 8.5 | 9.0 | 9.0 | 11.0 |",
"price": 3999.99,
"tags": [
"bicycle",
"mountain bike",
"professional"
]
},
{
"name": "RoadRunner E-Speed Lowstep",
"shortDescription": "RoadRunner E-Speed Lowstep is a high-performance electric hybrid designed for riders seeking speed and excitement on their daily rides. It is equipped with a powerful and reliable ThunderBolt drive unit that offers exceptional acceleration. The bike features a fully-integrated 500Wh battery, allowing riders to cover longer distances on a single charge. With its comfortable and safe components, including a suspension seatpost, wide and stable tires, and integrated lights, the RoadRunner E-Speed Lowstep ensures a smooth and enjoyable ride.",
"description": "## Overview\n\nIt's right for you if...\nYou're looking for an e-bike that provides an extra boost to reach your destination quickly and effortlessly. You prioritize durability and want a bike with one of the fastest motors available.\n\nThe tech you get\nA lightweight and sturdy ThunderBolt aluminum frame with a lowstep geometry. The bike is equipped with a ThunderBolt Performance Sport (250W, 65Nm) drive unit capable of reaching speeds up to 28 mph. It features a long-range 500Wh battery fully integrated into the frame and a ThunderBolt controller. Additionally, the bike has a 10-speed Shimano drivetrain, hydraulic disc brakes for reliable stopping power in all weather conditions, a suspension seatpost, wide puncture-resistant tires for stability, ergonomic grips, a kickstand, lights, and a rack and fenders.\n\nThe final word\nThe RoadRunner E-Speed Lowstep is designed to provide enjoyment and ease of use on longer commutes, recreational rides, and adventurous journeys. Its long-range battery, fast ThunderBolt motor, intuitive controller, and road-smoothing suspension seatpost make it the perfect choice for riders seeking both comfort and speed.\n\n## Features\n\nSuper speedy assist\n\nThe ThunderBolt Performance Sport drive unit allows you to accelerate up to 28mph, making errands, commutes, and joyrides a breeze.\n\n## Specs\n\nFrameset\n- Frame: ThunderBolt Smooth Aluminum, Removable Integrated Battery (RIB), sleek welds, rack & fender mounts, internal routing, kickstand mount, 135x5mm QR\n- Fork: RoadRunner Alloy, threaded steel steerer, rack mounts, post mount disc, 460mm axle-to-crown, ThruSkew 5mm QR\n- Max compatible fork travel: 50mm\n\nWheels\n- Hub front: ThunderBolt DC-20, alloy, 6-bolt, 5x100mm QR\n- Skewer front: 132x5mm QR, ThruSkew\n- Hub rear: ThunderBolt DC-22, alloy, 6-bolt, Shimano 8/9/10 freehub, 135x5mm QR\n- Skewer rear: 153x5mm bolt-on\n- Rim: ThunderBolt Connection, double-wall, 32-hole, 20 mm width, Schrader valve\n- Tire: ThunderBolt E6 Hard-Case Lite, reflective, wire bead, 60tpi, 700x50c\n- Max tire size: 700x50mm with or without fenders\n\nDrivetrain\n- Shifter: Shimano Deore M4100, 10 speed\n- Rear derailleur: Shimano Deore M5120, long cage\n- Crank: ProWheel alloy, 170mm length\n- Chainring: FSA, 42T, steel w/guard\n- Cassette: Shimano Deore M4100, 11-42, 10 speed\n- Chain: KMC E10\n- Pedal: RoadRunner City pedals\n\nComponents\n- Saddle: RoadRunner Boulevard\n- Seatpost: Alloy, suspension, 31.6mm, 300mm length\n- Handlebar:\n - Size: XS, S, M - RoadRunner alloy, 31.8mm, comfort sweep, 620mm width\n - Size: L - RoadRunner alloy, 31.8mm, comfort sweep, 660mm width\n- Grips: RoadRunner Satellite Elite, alloy lock-on\n- Stem:\n - Size: XS, S - RoadRunner alloy quill, 31.8mm clamp, adjustable rise, Blendr compatible, 85mm length\n - Size: M, L - RoadRunner alloy quill, 31.8mm clamp, adjustable rise, Blendr compatible, 105mm length\n- Headset: VP sealed cartridge, 1-1/8'', threaded\n- Brake: Shimano MT200 hydraulic disc\n- Brake rotor:\n - Size: XS, S, M, L - Shimano RT26, 6-bolt, 180mm\n - Size: XS, S, M, L - Shimano RT26, 6-bolt, 160mm\n\nAccessories\n- Battery: ThunderBolt PowerTube 500Wh\n- Charger: ThunderBolt compact 2A, 100-240V\n- Computer: ThunderBolt Purion\n- Motor: ThunderBolt Performance Line Sport, 65Nm, 28mph\n- Light:\n - Size: XS, S, M, L - ThunderBolt SOLO for e-bike, taillight\n - Size: XS, S, M, L - ThunderBolt MR8, 180 lumen, 60 lux, LED, headlight\n- Kickstand: Adjustable length rear mount alloy kickstand\n- Cargo rack: MIK-compatible alloy rear rack, maximum load 25 kg / 55 lbs\n- Fender:\n - Size: XS, S, M, L - RoadRunner wide\n - Size: XS, S, M, L - RoadRunner plastic\n\nWeight\n- Weight: M - 22.30 kg / 49.17 lbs\n- Weight limit: This bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\n\n## Sizing\n\n| Size | Rider Height | Inseam |\n|:----:|:-------------------------:|:--------------------:|\n| XS | 147 - 155 cm 4'10\" - 5'1\" | 69 - 73 cm 27\" - 29\" |\n| S | 155 - 165 cm 5'1\" - 5'5\" | 72 - 78 cm 28\" - 31\" |\n| M | 165 - 175 cm 5'5\" - 5'9\" | 77 - 83 cm 30\" - 33\" |\n| L | 175 - 186 cm 5'9\" - 6'1\" | 82 - 88 cm 32\" - 35\" |\n\n## Geometry\n\nAll measurements provided in cm unless otherwise noted.\n\nSizing table\n| Frame size number | 40 cm | 45 cm | 50 cm | 55 cm |\n|---------------------------|-------|-------|-------|-------|\n| Frame size letter | XS | S | M | L |\n| Wheel size | 700c | 700c | 700c | 700c |\n| A — Seat tube | 39.0 | 44.0 | 50.0 | 55.0 |\n| B — Seat tube angle | 71.0° | 71.0° | 71.0° | 71.0° |\n| C — Head tube length | 16.0 | 16.0 | 18.0 | 20.0 |\n| D — Head angle | 68.2° | 68.2° | 68.2° | 68.2° |\n| E — Effective top tube | 58.2 | 58.7 | 59.8 | 61.0 |\n| F — Bottom bracket height | 29.4 | 29.4 | 29.4 | 29.4 |\n| G — Bottom bracket drop | 6.5 | 6.5 | 6.5 | 6.5 |\n| H — Chainstay length | 48.7 | 48.7 | 48.7 | 48.7 |\n| I — Offset | 4.5 | 4.5 | 4.5 | 4.5 |\n| J — Trail | 9.5 | 9.5 | 9.5 | 9.5 |\n| K — Wheelbase | 112.2 | 112.7 | 114.0 | 115.2 |\n| L — Standover | 43.3 | 43.3 | 43.3 | 43.3 |\n| M — Frame reach | 36.5 | 38.5 | 38.5 | 38.5 |\n| N — Frame stack | 63.0 | 63.0 | 64.9 | 66.8 |\n| Stem length | 8.5 | 9.0 | 9.0 | 11.0 |",
"price": 4999.99,
"tags": [
"bicycle",
"road bike",
"professional"
]
},
{
"name": "Hyperdrive Turbo X1",
"shortDescription": "Hyperdrive Turbo X1 is a high-performance electric bike designed for riders seeking an exhilarating experience on their daily rides. It features a powerful and efficient Hyperdrive Sport drive unit and a sleek, integrated 500Wh battery for extended range. This e-bike is equipped with top-of-the-line components prioritizing comfort and safety, including a suspension seatpost, wide and stable tires, and integrated lights.",
"description": "## Overview\n\nIt's right for you if...\nYou crave the thrill of an e-bike that can accelerate rapidly, reaching high speeds effortlessly. You value durability and are looking for a bike that is equipped with one of the fastest motors available.\n\nThe tech you get\nA lightweight Hyper Alloy frame with a lowstep geometry, a Hyperdrive Sport (300W, 70Nm) drive unit capable of maintaining speeds up to 30 mph, a long-range 500Wh battery seamlessly integrated into the frame, and an intuitive Hyper Control controller. Additionally, it features a 10-speed Shimano drivetrain, hydraulic disc brakes for reliable stopping power in all weather conditions, a suspension seatpost, wide puncture-resistant tires for enhanced stability, ergonomic grips, a kickstand, lights, and a rack and fenders.\n\nThe final word\nThis bike is designed for riders seeking enjoyment and convenience on longer commutes, recreational rides, and thrilling adventures. With its long-range battery, high-speed motor, user-friendly controller, and smooth-riding suspension seatpost, the Hyperdrive Turbo X1 guarantees an exceptional e-biking experience.\n\n## Features\n\nHyperboost Acceleration\nExperience adrenaline-inducing rides with the powerful Hyperdrive Sport drive unit that enables quick acceleration and effortless cruising through errands, commutes, and joyrides.\n\n## Specs\n\nFrameset\nFrame\tHyper Alloy, Removable Integrated Battery (RIB), seamless welds, rack & fender mounts, internal routing, kickstand mount, 135x5mm QR\nFork\tHyper Alloy, threaded steel steerer, rack mounts, post mount disc, 460mm axle-to-crown, ThruSkew 5mm QR\nMax compatible fork travel\t50mm\n\nWheels\nHub front\tFormula DC-20, alloy, 6-bolt, 5x100mm QR\nSkewer front\t132x5mm QR, ThruSkew\nHub rear\tFormula DC-22, alloy, 6-bolt, Shimano 8/9/10 freehub, 135x5mm QR\nSkewer rear\t153x5mm bolt-on\nRim\tHyper Connection, double-wall, 32-hole, 20 mm width, Schrader valve\nTire\tHyper E6 Hard-Case Lite, reflective, wire bead, 60tpi, 700x50c\nMax tire size\t700x50mm with or without fenders\n\nDrivetrain\nShifter\tShimano Deore M4100, 10 speed\nRear derailleur\tShimano Deore M5120, long cage\nCrank\tProWheel alloy, 170mm length\nChainring\tFSA, 42T, steel w/guard\nCassette\tShimano Deore M4100, 11-42, 10 speed\nChain\tKMC E10\nPedal\tHyper City pedals\n\nComponents\nSaddle\tHyper Boulevard\nSeatpost\tAlloy, suspension, 31.6mm, 300mm length\nHandlebar\tSize: XS, S, M\nHyper alloy, 31.8mm, comfort sweep, 620mm width\nSize: L\nHyper alloy, 31.8mm, comfort sweep, 660mm width\nGrips\tHyper Satellite Elite, alloy lock-on\nStem\tSize: XS, S\nHyper alloy quill, 31.8mm clamp, adjustable rise, Blendr compatible, 85mm length\nSize: M, L\nHyper alloy quill, 31.8mm clamp, adjustable rise, Blendr compatible, 105mm length\nHeadset\tVP sealed cartridge, 1-1/8'', threaded\nBrake\tShimano MT200 hydraulic disc\nBrake rotor\tSize: XS, S, M, L\nShimano RT26, 6-bolt,180mm\nSize: XS, S, M, L\nShimano RT26, 6-bolt,160mm\n\nAccessories\nBattery\tHyper PowerTube 500Wh\nCharger\tHyper compact 2A, 100-240V\nComputer\tHyper Control\nMotor\tHyperdrive Sport, 70Nm, 30mph\nLight\tSize: XS, S, M, L\nSpanninga SOLO for e-bike, taillight\nSize: XS, S, M, L\nHerrmans MR8, 180 lumen, 60 lux, LED, headlight\nKickstand\tAdjustable length rear mount alloy kickstand\nCargo rack\tMIK-compatible alloy rear rack, maximum load 25 kg / 55 lbs\n*Fender\tSize: XS, S, M, L\nSKS wide\nSize: XS, S, M, L\nSKS plastic\n\nWeight\nWeight\tM - 22.30 kg / 49.17 lbs\nWeight limit\tThis bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\n\n## Sizing\n\n| Size | Rider Height | Inseam |\n|:----:|:-------------------------:|:--------------------:|\n| XS | 147 - 155 cm 4'10\" - 5'1\" | 69 - 73 cm 27\" - 29\" |\n| S | 155 - 165 cm 5'1\" - 5'5\" | 72 - 78 cm 28\" - 31\" |\n| M | 165 - 175 cm 5'5\" - 5'9\" | 77 - 83 cm 30\" - 33\" |\n| L | 175 - 186 cm 5'9\" - 6'1\" | 82 - 88 cm 32\" - 35\" |\n\n## Geometry\n\nAll measurements provided in cm unless otherwise noted.\n\n| Frame size number | 40 cm | 45 cm | 50 cm | 55 cm |\n|---------------------------|-------|-------|-------|-------|\n| Frame size letter | XS | S | M | L |\n| Wheel size | 700c | 700c | 700c | 700c |\n| A — Seat tube | 39.0 | 44.0 | 50.0 | 55.0 |\n| B — Seat tube angle | 71.0° | 71.0° | 71.0° | 71.0° |\n| C — Head tube length | 16.0 | 16.0 | 18.0 | 20.0 |\n| D — Head angle | 68.2° | 68.2° | 68.2° | 68.2° |\n| E — Effective top tube | 58.2 | 58.7 | 59.8 | 61.0 |\n| F — Bottom bracket height | 29.4 | 29.4 | 29.4 | 29.4 |\n| G — Bottom bracket drop | 6.5 | 6.5 | 6.5 | 6.5 |\n| H — Chainstay length | 48.7 | 48.7 | 48.7 | 48.7 |\n| I — Offset | 4.5 | 4.5 | 4.5 | 4.5 |\n| J — Trail | 9.5 | 9.5 | 9.5 | 9.5 |\n| K — Wheelbase | 112.2 | 112.7 | 114.0 | 115.2 |\n| L — Standover | 43.3 | 43.3 | 43.3 | 43.3 |\n| M — Frame reach | 36.5 | 38.5 | 38.5 | 38.5 |\n| N — Frame stack | 63.0 | 63.0 | 64.9 | 66.8 |\n| Stem length | 8.5 | 9.0 | 9.0 | 11.0 |",
"price": 1999.99,
"tags": [
"bicycle",
"city bike",
"professional"
]
},
{
"name": "Horizon+ Evo Lowstep",
"shortDescription": "The Horizon+ Evo Lowstep is a versatile electric hybrid bike designed for riders seeking a thrilling and efficient riding experience on a variety of terrains. With its powerful Bosch Performance Line Sport drive unit and integrated 500Wh battery, this e-bike enables riders to cover long distances with ease. Equipped with features prioritizing comfort and safety, such as a suspension seatpost, stable tires, and integrated lights, the Horizon+ Evo Lowstep is a reliable companion for everyday rides.",
"description": "## Overview\n\nIt's right for you if...\nYou desire the convenience and speed of an e-bike to enhance your riding, and you want an intuitive and durable bicycle. You prioritize having one of the fastest motors developed by Bosch.\n\nThe tech you get\nA lightweight Alpha Smooth Aluminum frame with a lowstep geometry, a Bosch Performance Line Sport (250W, 65Nm) drive unit capable of sustaining speeds up to 28 mph, a fully encased 500Wh battery integrated into the frame, and a Bosch Purion controller. Additionally, it features a 10-speed Shimano drivetrain, hydraulic disc brakes for reliable stopping power in all weather conditions, a suspension seatpost, wide puncture-resistant tires for improved stability, ergonomic grips, a kickstand, lights, and a rack and fenders.\n\nThe final word\nThe Horizon+ Evo Lowstep offers an enjoyable and user-friendly riding experience for longer commutes, recreational rides, and adventures. It boasts an extended range battery, a high-performance Bosch motor, an intuitive controller, and a suspension seatpost for a smooth ride on various road surfaces.\n\n## Features\n\nSuper speedy assist\nExperience effortless cruising through errands, commutes, and joyrides with the new Bosch Performance Sport drive unit, allowing acceleration of up to 28 mph.\n\n## Specs\n\nFrameset\n- Frame: Alpha Platinum Aluminum, Removable Integrated Battery (RIB), smooth welds, rack & fender mounts, internal routing, kickstand mount, 135x5mm QR\n- Fork: Horizon Alloy, threaded steel steerer, rack mounts, post mount disc, 460mm axle-to-crown, ThruSkew 5mm QR\n- Max compatible fork travel: 50mm\n\nWheels\n- Front Hub: Formula DC-20, alloy, 6-bolt, 5x100mm QR\n- Front Skewer: 132x5mm QR, ThruSkew\n- Rear Hub: Formula DC-22, alloy, 6-bolt, Shimano 8/9/10 freehub, 135x5mm QR\n- Rear Skewer: 153x5mm bolt-on\n- Rim: Bontrager Connection, double-wall, 32-hole, 20mm width, Schrader valve\n- Tire: Bontrager E6 Hard-Case Lite, reflective, wire bead, 60tpi, 700x50c\n- Max tire size: 700x50mm with or without fenders\n\nDrivetrain\n- Shifter: Shimano Deore M4100, 10-speed\n- Rear Derailleur: Shimano Deore M5120, long cage\n- Crank: ProWheel alloy, 170mm length\n- Chainring: FSA, 42T, steel w/guard\n- Cassette: Shimano Deore M4100, 11-42, 10-speed\n- Chain: KMC E10\n- Pedal: Bontrager City pedals\n\nComponents\n- Saddle: Bontrager Boulevard\n- Seatpost: Alloy, suspension, 31.6mm, 300mm length\n- Handlebar:\n - Size: XS, S, M - Bontrager alloy, 31.8mm, comfort sweep, 620mm width\n - Size: L - Bontrager alloy, 31.8mm, comfort sweep, 660mm width\n- Grips: Bontrager Satellite Elite, alloy lock-on\n- Stem:\n - Size: XS, S - Bontrager alloy quill, 31.8mm clamp, adjustable rise, Blendr compatible, 85mm length\n - Size: M, L - Bontrager alloy quill, 31.8mm clamp, adjustable rise, Blendr compatible, 105mm length\n- Headset: VP sealed cartridge, 1-1/8\", threaded\n- Brake: Shimano MT200 hydraulic disc\n- Brake rotor:\n - Size: XS, S, M, L - Shimano RT26, 6-bolt, 180mm\n - Size: XS, S, M, L - Shimano RT26, 6-bolt, 160mm\n\nAccessories\n- Battery: Bosch PowerTube 500Wh\n- Charger: Bosch compact 2A, 100-240V\n- Computer: Bosch Purion\n- Motor: Bosch Performance Line Sport, 65Nm, 28mph\n- Light:\n - Size: XS, S, M, L - Spanninga SOLO for e-bike, taillight\n - Size: XS, S, M, L - Herrmans MR8, 180 lumen, 60 lux, LED, headlight\n- Kickstand: Adjustable length rear mount alloy kickstand\n- Cargo rack: MIK-compatible alloy rear rack, maximum load 25 kg / 55 lbs\n- Fender:\n - Size: XS, S, M, L - SKS wide\n - Size: XS, S, M, L - SKS plastic\n\nWeight\n- Weight: M - 22.30 kg / 49.17 lbs\n- Weight limit: This bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\n\n## Sizing\n\n| Size | Rider Height | Inseam |\n|:----:|:-------------------------:|:--------------------:|\n| XS | 147 - 155 cm 4'10\" - 5'1\" | 69 - 73 cm 27\" - 29\" |\n| S | 155 - 165 cm 5'1\" - 5'5\" | 72 - 78 cm 28\" - 31\" |\n| M | 165 - 175 cm 5'5\" - 5'9\" | 77 - 83 cm 30\" - 33\" |\n| L | 175 - 186 cm 5'9\" - 6'1\" | 82 - 88 cm 32\" - 35\" |\n\n## Geometry\n\nAll measurements provided in cm unless otherwise noted.\nSizing table\n| Frame size number | 40 cm | 45 cm | 50 cm | 55 cm |\n|---------------------------|-------|-------|-------|-------|\n| Frame size letter | XS | S | M | L |\n| Wheel size | 700c | 700c | 700c | 700c |\n| A — Seat tube | 39.0 | 44.0 | 50.0 | 55.0 |\n| B — Seat tube angle | 71.0° | 71.0° | 71.0° | 71.0° |\n| C — Head tube length | 16.0 | 16.0 | 18.0 | 20.0 |\n| D — Head angle | 68.2° | 68.2° | 68.2° | 68.2° |\n| E — Effective top tube | 58.2 | 58.7 | 59.8 | 61.0 |\n| F — Bottom bracket height | 29.4 | 29.4 | 29.4 | 29.4 |\n| G — Bottom bracket drop | 6.5 | 6.5 | 6.5 | 6.5 |\n| H — Chainstay length | 48.7 | 48.7 | 48.7 | 48.7 |\n| I — Offset | 4.5 | 4.5 | 4.5 | 4.5 |\n| J — Trail | 9.5 | 9.5 | 9.5 | 9.5 |\n| K — Wheelbase | 112.2 | 112.7 | 114.0 | 115.2 |\n| L — Standover | 43.3 | 43.3 | 43.3 | 43.3 |\n| M — Frame reach | 36.5 | 38.5 | 38.5 | 38.5 |\n| N — Frame stack | 63.0 | 63.0 | 64.9 | 66.8 |\n| Stem length | 8.5 | 9.0 | 9.0 | 11.0 |",
"price": 4499.99,
"tags": [
"bicycle",
"road bike",
"professional"
]
},
{
"name": "FastRider X1",
"shortDescription": "FastRider X1 is a high-performance e-bike designed for riders seeking speed and long-distance capabilities. Equipped with a powerful motor and a high-capacity battery, the FastRider X1 is perfect for daily commuters and e-bike enthusiasts. It boasts a sleek and functional design, making it a great alternative to car transportation. The bike also features a smartphone controller for easy navigation and entertainment options.",
"description": "## Overview\nIt's right for you if...\nYou're looking for an e-bike that offers both speed and endurance. The FastRider X1 comes with a high-performance motor and a long-lasting battery, making it ideal for long-distance rides.\n\nThe tech you get\nThe FastRider X1 features a state-of-the-art motor and a spacious battery, ensuring a fast and efficient ride.\n\nThe final word\nWith the powerful motor and long-range battery, the FastRider X1 allows you to cover more distance at higher speeds.\n\n## Features\nConnect Your Ride with the FastRider App\nDownload the FastRider app and transform your smartphone into an on-board computer. Easily dock and charge your phone with the smartphone controller, and use the thumb pad on your handlebar to make calls, listen to music, get turn-by-turn directions, and more. The app also allows you to connect with fitness and health apps, syncing your routes and ride data.\n\nGoodbye, Car. Hello, Extended Range!\nWith the option to add the Range Boost feature, you can attach a second long-range battery to your FastRider X1, doubling the distance and time between charges. This enhancement allows you to ride longer, commute farther, and take on more adventurous routes.\n\nWhat is the range?\nTo estimate the distance you can travel on a single charge, use our range calculator tool. It automatically fills in the variables for this specific bike model and assumes an average rider, but you can adjust the settings to get the most accurate estimate for your needs.\n\n## Specifications\nFrameset\n- Frame: High-performance hydroformed alloy, Removable Integrated Battery, Range Boost-compatible, internal cable routing, Motor Armour, post-mount disc, 135x5 mm QR\n- Fork: FastRider rigid alloy fork, 1-1/8'' steel steerer, 100x15mm thru axle, post mount disc brake\n- Max compatible fork travel: 63mm\n\nWheels\n- Front Hub: FastRider sealed bearing, 32-hole 15mm alloy thru-axle\n- Front Skewer: FastRider Switch thru axle, removable lever\n- Rear Hub: FastRider alloy, sealed bearing, 6-bolt, 135x5mm QR\n- Rear Skewer: 148x5mm bolt-on\n- Rim: FastRider MD35, tubeless compatible, 32-hole, 35mm width, Presta valve\n- Spokes: Size: M, L, XL - 14g stainless steel, black\n- Tire: FastRider E6 Hard-Case Lite, reflective strip, 27.5x2.40''\n- Max tire size: 27.5x2.40\"\n\nDrivetrain\n- Shifter: Shimano Deore M4100, 10 speed\n- Rear derailleur: Size: M, L, XL - Shimano Deore M5120, long cage\n- Crank: Size: M - FastRider alloy, 170mm length / Size: L, XL - FastRider alloy, 175mm length\n- Chainring: FastRider 46T narrow/wide alloy, w/alloy guard\n- Cassette: Size: M, L, XL - Shimano Deore M4100, 11-42, 10 speed\n- Chain: Size: M, L, XL - KMC E10 / Size: M, L, XL - KMC X10e\n- Pedal: Size: M, L, XL - FastRider City pedals / Size: M, L, XL - Wellgo C157, boron axle, plastic body / Size: M, L, XL - slip-proof aluminum pedals with reflectors\n- Max chainring size: 1x: 48T\n\nComponents\n- Saddle: FastRider Commuter Comp\n- Seatpost: FastRider Comp, 6061 alloy, 31.6mm, 8mm offset, 330mm length\n- Handlebar: Size: M - FastRider alloy, 31.8mm, 15mm rise, 600mm width / Size: L, XL - FastRider alloy, 31.8mm, 15mm rise, 660mm width\n- Grips: FastRider Satellite Elite, alloy lock-on\n- Stem: Size: M - FastRider alloy, 31.8mm, Blendr compatible, 7-degree, 70mm length / Size: L - FastRider alloy, 31.8mm, Blendr compatible, 7-degree, 90mm length / Size: XL - FastRider alloy, 31.8mm, Blendr compatible, 7-degree, 100mm length\n- Headset: Size: M, L, XL - FSA IS-2 alloy, integrated, sealed cartridge bearing, 1-1/8'' top, 1.5'' bottom / Size: M, L, XL - FSA Integrated, sealed cartridge bearing, 1-1/8'' top, 1.5'' bottom\n- Brake: Shimano MT520 4-piston hydraulic disc, post-mount, 180mm rotor\n- Brake rotor: Shimano RT56, 6-bolt, 180mm\n- Rotor size: Max brake rotor sizes: 180mm front & rear\n\nAccessories\n- Battery: FastRider PowerTube 625Wh\n- Charger: FastRider standard 4A, 100-240V\n- Motor: FastRider Performance Speed, 85 Nm, 28 mph / 45 kph\n- Light: Size: M, L, XL - FastRider taillight, 50 lumens / Size: M, L, XL - FastRider headlight, 500 lumens\n- Kickstand: Size: M, L, XL - Rear mount, alloy / Size: M, L, XL - Adjustable length alloy kickstand\n- Cargo rack: FastRider integrated rear rack, aluminum\n- Fender: FastRider custom aluminum\n\nWeight\n- Weight: M - 25.54 kg / 56.3 lbs\n\nWeight limit\n- This bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\n\n## Sizing\n| Size | Rider Height | Inseam |\n|:----:|:------------------------:|:--------------------:|\n| M | 165 - 175 cm 5'5\" - 5'9\" | 77 - 83 cm 30\" - 33\" |\n| L | 175 - 186 cm 5'9\" - 6'1\" | 82 - 88 cm 32\" - 35\" |\n| XL | 186 - 197 cm 6'1\" - 6'6\" | 87 - 93 cm 34\" - 37\" |\n\n## Geometry\n| Frame size letter | M | L | XL |\n|---------------------------|-------|-------|-------|\n| Wheel size | 27.5\" | 27.5\" | 27.5\" |\n| A — Seat tube | 44.6 | 49.1 | 53.4 |\n| B — Seat tube angle | 73.0° | 73.0° | 73.0° |\n| C — Head tube length | 16.5 | 19.5 | 23.0 |\n| D — Head angle | 69.5° | 70.0° | 70.5° |\n| E — Effective top tube | 59.5 | 60.7 | 62.2 |\n| F — Bottom bracket height | 29.5 | 29.5 | 29.5 |\n| G — Bottom bracket drop | 6.0 | 6.0 | 6.0 |\n| H — Chainstay length | 48.7 | 48.7 | 48.7 |\n| I — Offset | 4.4 | 4.4 | 4.4 |\n| J — Trail | 8.6 | 8.1 | 7.9 |\n| K — Wheelbase | 114.6 | 115.0 | 116.4 |\n| L — Standover | 79.5 | 83.7 | 87.9 |\n| M — Frame reach | 40.5 | 40.8 | 41.2 |\n| N — Frame stack | 62.3 | 65.2 | 68.8 |",
"price": 5499.99,
"tags": [
"bicycle",
"mountain bike",
"professional"
]
},
{
"name": "SonicRide 8S",
"shortDescription": "SonicRide 8S is a high-performance e-bike designed for riders who crave speed and long-distance capabilities. The advanced SonicDrive motor provides powerful assistance up to 28 mph, combined with a durable and long-lasting battery for extended rides. With its sleek design and thoughtful features, the SonicRide 8S is perfect for those who prefer the freedom of riding a bike over driving a car. Plus, it comes equipped with a smartphone controller for easy navigation, music, and more.",
"description": "## Overview\nIt's right for you if...\nYou want a fast and efficient e-bike that can take you long distances. The SonicRide 8S features a hydroformed aluminum frame with a concealed 625Wh battery, a high-powered SonicDrive motor, and a Smartphone Controller. It also includes essential accessories such as lights, fenders, and a rear rack.\n\nThe tech you get\nThe SonicRide 8S is equipped with the fastest SonicDrive motor, ensuring exhilarating rides at high speeds. The long-range battery is perfect for commuters and riders looking to explore new horizons.\n\nThe final word\nWith the SonicDrive motor and long-lasting battery, you can enjoy extended rides at higher speeds.\n\n## Features\n\nConnect Your Ride with SonicRide App\nDownload the SonicRide app and transform your phone into an onboard computer. Simply attach it to the Smartphone Controller for docking and charging. Use the thumb pad on your handlebar to control calls, music, directions, and more. The Bluetooth® wireless technology allows you to connect with fitness and health apps, syncing your routes and ride data.\n\nSay Goodbye to Limited Range with Range Boost!\nExperience the convenience of Range Boost, an additional long-range 500Wh battery that seamlessly attaches to your bike's down tube. This upgrade allows you to double your distance and time between charges, enabling longer commutes and more adventurous rides. Range Boost is compatible with select SonicRide electric bike models.\n\nWhat is the range?\nFor an accurate estimate of how far you can ride on a single charge, use SonicRide's range calculator. We have pre-filled the variables for this specific bike model and the average rider, but you can adjust them to obtain the most accurate estimate.\n\n## Specifications\nFrameset\n- Frame: High-performance hydroformed alloy, Removable Integrated Battery, Range Boost-compatible, internal cable routing, Motor Armour, post-mount disc, 135x5 mm QR\n- Fork: SonicRide rigid alloy fork, 1-1/8'' steel steerer, 100x15mm thru axle, post mount disc brake\n- Max compatible fork travel: 63mm\n\nWheels\n- Front Hub: SonicRide sealed bearing, 32-hole 15mm alloy thru-axle\n- Front Skewer: SonicRide Switch thru axle, removable lever\n- Rear Hub: SonicRide alloy, sealed bearing, 6-bolt, 135x5mm QR\n- Rear Skewer: 148x5mm bolt-on\n- Rim: SonicRide MD35, tubeless compatible, 32-hole, 35mm width, Presta valve\n- Spokes: Size: M, L, XL - 14g stainless steel, black\n- Tire: SonicRide E6 Hard-Case Lite, reflective strip, 27.5x2.40''\n- Max tire size: 27.5x2.40\"\n\nDrivetrain\n- Shifter: Shimano Deore M4100, 10 speed\n- Rear Derailleur: Size: M, L, XL - Shimano Deore M5120, long cage\n- Crank: Size: M - SonicRide alloy, 170mm length; Size: L, XL - SonicRide alloy, 175mm length\n- Chainring: SonicRide 46T narrow/wide alloy, with alloy guard\n- Cassette: Size: M, L, XL - Shimano Deore M4100, 11-42, 10 speed\n- Chain: Size: M, L, XL - KMC E10; Size: M, L, XL - KMC X10e\n- Pedal: Size: M, L, XL - SonicRide City pedals; Size: M, L, XL - Wellgo C157, boron axle, plastic body; Size: M, L, XL - slip-proof aluminum pedals with reflectors\n- Max chainring size: 1x: 48T\n\nComponents\n- Saddle: SonicRide Commuter Comp\n- Seatpost: SonicRide Comp, 6061 alloy, 31.6mm, 8mm offset, 330mm length\n- Handlebar: Size: M - SonicRide alloy, 31.8mm, 15mm rise, 600mm width; Size: L, XL - SonicRide alloy, 31.8mm, 15mm rise, 660mm width\n- Grips: SonicRide Satellite Elite, alloy lock-on\n- Stem: Size: M - SonicRide alloy, 31.8mm, Blendr compatible, 7-degree, 70mm length; Size: L - SonicRide alloy, 31.8mm, Blendr compatible, 7-degree, 90mm length; Size: XL - SonicRide alloy, 31.8mm, Blendr compatible, 7-degree, 100mm length\n- Headset: Size: M, L, XL - SonicRide IS-2 alloy, integrated, sealed cartridge bearing, 1-1/8'' top, 1.5'' bottom; Size: M, L, XL - SonicRide Integrated, sealed cartridge bearing, 1-1/8'' top, 1.5'' bottom\n- Brake: Shimano MT520 4-piston hydraulic disc, post-mount, 180mm rotor\n- Brake rotor: Shimano RT56, 6-bolt, 180mm\n- Rotor size: Max brake rotor sizes: 180mm front & rear\n\nAccessories\n- Battery: SonicRide PowerTube 625Wh\n- Charger: SonicRide standard 4A, 100-240V\n- Motor: SonicRide Performance Speed, 85 Nm, 28 mph / 45 kph\n- Light: Size: M, L, XL - SonicRide Lync taillight, 50 lumens; Size: M, L, XL - SonicRide Lync headlight, 500 lumens\n- Kickstand: Size: M, L, XL - Rear mount, alloy; Size: M, L, XL - Adjustable length alloy kickstand\n- Cargo rack: SonicRide integrated rear rack, aluminum\n- Fender: SonicRide custom aluminum\n\nWeight\n- Weight: M - 25.54 kg / 56.3 lbs\n- Weight limit: This bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\n\n## Sizing\n| Size | Rider Height | Inseam |\n|:----:|:------------------------:|:--------------------:|\n| M | 165 - 175 cm / 5'5\" - 5'9\" | 77 - 83 cm / 30\" - 33\" |\n| L | 175 - 186 cm / 5'9\" - 6'1\" | 82 - 88 cm / 32\" - 35\" |\n| XL | 186 - 197 cm / 6'1\" - 6'6\" | 87 - 93 cm / 34\" - 37\" |\n\n## Geometry\n| Frame size letter | M | L | XL |\n|---------------------------|-------|-------|-------|\n| Wheel size | 27.5\" | 27.5\" | 27.5\" |\n| A — Seat tube | 44.6 | 49.1 | 53.4 |\n| B — Seat tube angle | 73.0° | 73.0° | 73.0° |\n| C — Head tube length | 16.5 | 19.5 | 23.0 |\n| D — Head angle | 69.5° | 70.0° | 70.5° |\n| E — Effective top tube | 59.5 | 60.7 | 62.2 |\n| F — Bottom bracket height | 29.5 | 29.5 | 29.5 |\n| G — Bottom bracket drop | 6.0 | 6.0 | 6.0 |\n| H — Chainstay length | 48.7 | 48.7 | 48.7 |\n| I — Offset | 4.4 | 4.4 | 4.4 |\n| J — Trail | 8.6 | 8.1 | 7.9 |\n| K — Wheelbase | 114.6 | 115.0 | 116.4 |\n| L — Standover | 79.5 | 83.7 | 87.9 |\n| M — Frame reach | 40.5 | 40.8 | 41.2 |",
"price": 5999.99,
"tags": [
"bicycle",
"road bike",
"professional"
]
},
{
"name": "SwiftVolt Pro",
"shortDescription": "SwiftVolt Pro is a high-performance e-bike designed for riders seeking a thrilling and fast riding experience. Equipped with a powerful SwiftDrive motor that provides assistance up to 30 mph and a long-lasting battery, this bike is perfect for long-distance commuting and passionate e-bike enthusiasts. The sleek and innovative design features cater specifically to individuals who prioritize cycling over driving. Additionally, the bike is seamlessly integrated with your smartphone, allowing you to use it for navigation, music, and more.",
"description": "## Overview\nThis bike is ideal for you if:\n- You desire a sleek and modern hydroformed aluminum frame that houses a 700Wh battery.\n- You want to maintain high speeds of up to 30 mph with the assistance of the SwiftDrive motor.\n- You appreciate the convenience of using your smartphone as a controller, which can be docked and charged on the handlebar.\n\n## Features\n\nConnect with SwiftSync App\nBy downloading the SwiftSync app, your smartphone becomes an interactive on-board computer. Attach it to the handlebar-mounted controller for easy access and charging. With the thumb pad, you can make calls, listen to music, receive turn-by-turn directions, and connect with fitness and health apps to track your routes and ride data via Bluetooth® wireless technology.\n\nEnhanced Range with BoostMax\nBoostMax offers the capability to attach a second 700Wh Swift battery to the downtube of your bike, effectively doubling the distance and time between charges. This allows for extended rides, longer commutes, and more significant adventures. BoostMax is compatible with select Swift electric bike models.\n\nRange Estimation\nFor an estimate of how far you can ride on a single charge, consult the Swift range calculator. The variables are automatically populated based on this bike model and the average rider, but you can modify them to obtain the most accurate estimate.\n\n## Specifications\nFrameset\n- Frame: Lightweight hydroformed alloy, Removable Integrated Battery, BoostMax-compatible, internal cable routing, post-mount disc, 135x5 mm QR\n- Fork: SwiftVolt rigid alloy fork, 1-1/8'' steel steerer, 100x15mm thru-axle, post-mount disc brake\n- Max compatible fork travel: 63mm\n\nWheels\n- Front Hub: Swift sealed bearing, 32-hole 15mm alloy thru-axle\n- Front Skewer: Swift Switch thru-axle, removable lever\n- Rear Hub: Swift alloy, sealed bearing, 6-bolt, 135x5mm QR\n- Rear Skewer: 148x5mm bolt-on\n- Rim: SwiftRim, tubeless compatible, 32-hole, 35mm width, Presta valve\n- Spokes: 14g stainless steel, black\n- Tire: Swift E6 Hard-Case Lite, reflective strip, 27.5x2.40''\n- Max tire size: 27.5x2.40\"\n\nDrivetrain\n- Shifter: Shimano Deore M4100, 10 speed\n- Rear Derailleur: Shimano Deore M5120, long cage\n- Crank: Swift alloy, 170mm length\n- Chainring: Swift 46T narrow/wide alloy, w/alloy guard\n- Cassette: Shimano Deore M4100, 11-42, 10 speed\n- Chain: KMC E10\n- Pedal: Swift City pedals\n- Max chainring size: 1x: 48T\n\nComponents\n- Saddle: Swift Commuter Comp\n- Seatpost: Swift Comp, 6061 alloy, 31.6mm, 8mm offset, 330mm length\n- Handlebar: Swift alloy, 31.8mm, 15mm rise, 600mm width (M), 660mm width (L, XL)\n- Grips: Swift Satellite Elite, alloy lock-on\n- Stem: Swift alloy, 31.8mm, Blendr compatible, 7 degree, 70mm length (M), 90mm length (L), 100mm length (XL)\n- Headset: FSA IS-2 alloy, integrated, sealed cartridge bearing, 1-1/8'' top, 1.5'' bottom\n- Brakes: Shimano MT520 4-piston hydraulic disc, post-mount, 180mm rotor\n- Brake Rotor: Shimano RT56, 6-bolt, 180mm\n- Rotor size: Max 180mm front & rear\n\nAccessories\n- Battery: Swift PowerTube 700Wh\n- Charger: Swift standard 4A, 100-240V\n- Motor: SwiftDrive, 90 Nm, 30 mph / 48 kph\n- Light: Swift Lync taillight, 50 lumens (M, L, XL), Swift Lync headlight, 500 lumens (M, L, XL)\n- Kickstand: Rear mount, alloy (M, L, XL), Adjustable length alloy kickstand (M, L, XL)\n- Cargo rack: SwiftVolt integrated rear rack, aluminum\n- Fender: Swift custom aluminum\n\nWeight\n- Weight: M - 25.54 kg / 56.3 lbs\n- Weight limit: This bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\n\n## Sizing\n| Size | Rider Height | Inseam |\n|:----:|:---------------------:|:-------------:|\n| M | 165 - 175 cm 5'5\" - 5'9\" | 77 - 83 cm 30\" - 33\" |\n| L | 175 - 186 cm 5'9\" - 6'1\" | 82 - 88 cm 32\" - 35\" |\n| XL | 186 - 197 cm 6'1\" - 6'6\" | 87 - 93 cm 34\" - 37\" |\n\n## Geometry\n| Frame size letter | M | L | XL |\n|---------------------------|-------|-------|-------|\n| Wheel size | 27.5\" | 27.5\" | 27.5\" |\n| A — Seat tube | 44.6 | 49.1 | 53.4 |\n| B — Seat tube angle | 73.0° | 73.0° | 73.0° |\n| C — Head tube length | 16.5 | 19.5 | 23.0 |\n| D — Head angle | 69.5° | 70.0° | 70.5° |\n| E — Effective top tube | 59.5 | 60.7 | 62.2 |\n| F — Bottom bracket height | 29.5 | 29.5 | 29.5 |\n| G — Bottom bracket drop | 6.0 | 6.0 | 6.0 |\n| H — Chainstay length | 48.7 | 48.7 | 48.7 |\n| I — Offset | 4.4 | 4.4 | 4.4 |\n| J — Trail | 8.6 | 8.1 | 7.9 |\n| K — Wheelbase | 114.6 | 115.0 | 116.4 |\n| L — Standover | 79.5 | 83.7 | 87.9 |\n| M — Frame reach | 40.5 | 40.8 | 41.2 |\n| N — Frame stack | 62.3 | 65.2 | 68.8 |",
"price": 2499.99,
"tags": [
"bicycle",
"city bike",
"professional"
]
},
{
"name": "AgileEon 9X",
"shortDescription": "AgileEon 9X is a high-performance e-bike designed for riders seeking speed and endurance. Equipped with a robust motor and an extended battery life, this bike is perfect for long-distance commuters and avid e-bike enthusiasts. It boasts innovative features tailored for individuals who prioritize cycling over driving. Additionally, the bike integrates seamlessly with your smartphone, allowing you to access navigation, music, and more.",
"description": "## Overview\nIt's right for you if...\nYou crave speed and want to cover long distances efficiently. The AgileEon 9X features a sleek hydroformed aluminum frame that houses a powerful motor, along with a large-capacity battery for extended rides. It comes equipped with a 10-speed drivetrain, front and rear lighting, fenders, and a rear rack.\n\nThe tech you get\nDesigned for those constantly on the move, this bike includes a state-of-the-art motor and a high-capacity battery, making it an excellent choice for lengthy commutes.\n\nThe final word\nWith the AgileEon 9X, you can push your boundaries and explore new horizons thanks to its powerful motor and long-lasting battery.\n\n## Features\n\nConnect Your Ride with RideMate App\nMake use of the RideMate app to transform your smartphone into an onboard computer. Simply attach it to the RideMate controller to dock and charge, then utilize the thumb pad on your handlebar to make calls, listen to music, receive turn-by-turn directions, and more. The bike also supports Bluetooth® wireless technology, enabling seamless connectivity with fitness and health apps for route syncing and ride data.\n\nGoodbye, car. Hello, Extended Range!\nEnhance your riding experience with the Extended Range option, which allows for the attachment of an additional high-capacity 500Wh battery to your bike's downtube. This doubles the distance and time between charges, enabling longer rides, extended commutes, and more significant adventures. The Extended Range feature is compatible with select AgileEon electric bike models.\n\nWhat is the range?\nTo determine how far you can ride on a single charge, you can utilize the range calculator provided by AgileEon. We have pre-filled the variables for this specific model and an average rider, but adjustments can be made for a more accurate estimation.\n\n## Specifications\nFrameset\nFrame: High-performance hydroformed alloy, Removable Integrated Battery, Extended Range-compatible, internal cable routing, Motor Armor, post-mount disc, 135x5 mm QR\nFork: AgileEon rigid alloy fork, 1-1/8'' steel steerer, 100x15mm thru-axle, post-mount disc brake\nMax compatible fork travel: 63mm\n\nWheels\nFront Hub: AgileEon sealed bearing, 32-hole 15mm alloy thru-axle\nFront Skewer: AgileEon Switch thru-axle, removable lever\nRear Hub: AgileEon alloy, sealed bearing, 6-bolt, 135x5mm QR\nRear Skewer: 148x5mm bolt-on\nRim: AgileEon MD35, tubeless compatible, 32-hole, 35mm width, Presta valve\nSpokes:\n- Size: M, L, XL: 14g stainless steel, black\nTire: AgileEon E6 Hard-Case Lite, reflective strip, 27.5x2.40''\nMax tire size: 27.5x2.40\"\n\nDrivetrain\nShifter: Shimano Deore M4100, 10-speed\nRear derailleur:\n- Size: M, L, XL: Shimano Deore M5120, long cage\nCrank:\n- Size: M: AgileEon alloy, 170mm length\n- Size: L, XL: AgileEon alloy, 175mm length\nChainring: AgileEon 46T narrow/wide alloy, with alloy guard\nCassette:\n- Size: M, L, XL: Shimano Deore M4100, 11-42, 10-speed\nChain:\n- Size: M, L, XL: KMC E10\nPedal:\n- Size: M, L, XL: AgileEon City pedals\nMax chainring size: 1x: 48T\n\nComponents\nSaddle: AgileEon Commuter Comp\nSeatpost: AgileEon Comp, 6061 alloy, 31.6mm, 8mm offset, 330mm length\nHandlebar:\n- Size: M: AgileEon alloy, 31.8mm, 15mm rise, 600mm width\n- Size: L, XL: AgileEon alloy, 31.8mm, 15mm rise, 660mm width\nGrips: AgileEon Satellite Elite, alloy lock-on\nStem:\n- Size: M: AgileEon alloy, 31.8mm, Blendr compatible, 7-degree, 70mm length\n- Size: L: AgileEon alloy, 31.8mm, Blendr compatible, 7-degree, 90mm length\n- Size: XL: AgileEon alloy, 31.8mm, Blendr compatible, 7-degree, 100mm length\nHeadset:\n- Size: M, L, XL: AgileEon IS-2 alloy, integrated, sealed cartridge bearing, 1-1/8'' top, 1.5'' bottom\nBrake: Shimano MT520 4-piston hydraulic disc, post-mount, 180mm rotor\nBrake rotor: Shimano RT56, 6-bolt, 180mm\nRotor size: Max brake rotor sizes: 180mm front & rear\n\nAccessories\nBattery: AgileEon PowerTube 625Wh\nCharger: AgileEon standard 4A, 100-240V\nMotor: AgileEon Performance Speed, 85 Nm, 28 mph / 45 kph\nLight:\n- Size: M, L, XL: AgileEon taillight, 50 lumens\n- Size: M, L, XL: AgileEon headlight, 500 lumens\nKickstand:\n- Size: M, L, XL: Rear mount, alloy\n- Size: M, L, XL: Adjustable length alloy kickstand\nCargo rack: AgileEon integrated rear rack, aluminum\nFender: AgileEon custom aluminum\n\nWeight\nWeight: M - 25.54 kg / 56.3 lbs\nWeight limit: This bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\n\n## Sizing\n| Size | Rider Height | Inseam |\n|:----:|:------------------------:|:--------------------:|\n| M | 165 - 175 cm 5'5\" - 5'9\" | 77 - 83 cm 30\" - 33\" |\n| L | 175 - 186 cm 5'9\" - 6'1\" | 82 - 88 cm 32\" - 35\" |\n| XL | 186 - 197 cm 6'1\" - 6'6\" | 87 - 93 cm 34\" - 37\" |\n\n## Geometry\n| Frame size letter | M | L | XL |\n|---------------------------|-------|-------|-------|\n| Wheel size | 27.5\" | 27.5\" | 27.5\" |\n| A — Seat tube | 44.6 | 49.1 | 53.4 |\n| B — Seat tube angle | 73.0° | 73.0° | 73.0° |\n| C — Head tube length | 16.5 | 19.5 | 23.0 |\n| D — Head angle | 69.5° | 70.0° | 70.5° |\n| E — Effective top tube | 59.5 | 60.7 | 62.2 |\n| F — Bottom bracket height | 29.5 | 29.5 | 29.5 |\n| G — Bottom bracket drop | 6.0 | 6.0 | 6.0 |\n| H — Chainstay length | 48.7 | 48.7 | 48.7 |\n| I — Offset | 4.4 | 4.4 | 4.4 |\n| J — Trail | 8.6 | 8.1 | 7.9 |\n| K — Wheelbase | 114.6 | 115.0 | 116.4 |\n| L — Standover | 79.5 | 83.7 | 87.9 |\n| M — Frame reach | 40.5 | 40.8 | 41.2 |\n| N — Frame stack | 62.3 | 65.2 | 68.8 |",
"price": 3499.99,
"tags": [
"bicycle",
"road bike",
"professional"
]
},
{
"name": "Stealth R1X Pro",
"shortDescription": "Stealth R1X Pro is a high-performance carbon road bike designed for riders who crave speed and exceptional handling. With its aerodynamic tube shaping, disc brakes, and lightweight carbon wheels, the Stealth R1X Pro offers unparalleled performance for competitive road cycling.",
"description": "## Overview\nIt's right for you if...\nYou're a competitive cyclist looking for a road bike that offers superior performance in terms of speed, handling, and aerodynamics. You want a complete package that includes lightweight carbon wheels, without the need for future upgrades.\n\nThe tech you get\nThe Stealth R1X Pro features a lightweight and aerodynamic carbon frame, an advanced carbon fork, high-performance Shimano Ultegra 11-speed drivetrain, and powerful Ultegra disc brakes. The bike also comes equipped with cutting-edge Bontrager Aeolus Elite 35 carbon wheels.\n\nThe final word\nThe Stealth R1X Pro stands out with its combination of a fast and aerodynamic frame, high-end drivetrain, and top-of-the-line carbon wheels. Whether you're racing on local roads, participating in pro stage races, or engaging in hill climbing competitions, this bike is a formidable choice that delivers an exceptional riding experience.\n\n## Features\nSleek and aerodynamic design\nThe Stealth R1X Pro's aero tube shapes maximize speed and performance, making it faster on climbs and flats alike. The bike also features a streamlined Aeolus RSL bar/stem for improved front-end aerodynamics.\n\nDesigned for all riders\nThe Stealth R1X Pro is designed to provide an outstanding fit for riders of all genders, body types, riding styles, and abilities. It comes equipped with size-specific components to ensure a comfortable and efficient riding position for competitive riders.\n\n## Specifications\nFrameset\n- Frame: Ultralight carbon frame constructed with high-performance 500 Series ADV Carbon. It features Ride Tuned performance tube optimization, a tapered head tube, internal routing, DuoTrap S compatibility, flat mount disc brake mounts, and a 142x12mm thru axle.\n- Fork: Full carbon fork (Émonda SL) with a tapered carbon steerer, internal brake routing, flat mount disc brake mounts, and a 12x100mm thru axle.\n- Frame fit: H1.5 Race geometry.\n\nWheels\n- Front wheel: Bontrager Aeolus Elite 35 carbon wheel with a 35mm rim depth, ADV Carbon construction, Tubeless Ready compatibility, and a 100x12mm thru axle.\n- Rear wheel: Bontrager Aeolus Elite 35 carbon wheel with a 35mm rim depth, ADV Carbon construction, Tubeless Ready compatibility, Shimano 11/12-speed freehub, and a 142x12mm thru axle.\n- Front skewer: Bontrager Switch thru axle with a removable lever.\n- Rear skewer: Bontrager Switch thru axle with a removable lever.\n- Tire: Bontrager R2 Hard-Case Lite with an aramid bead, 60 tpi, and a size of 700x25c.\n- Maximum tire size: 28mm.\n\nDrivetrain\n- Shifter:\n - Size 47, 50, 52: Shimano Ultegra R8025 with short-reach levers, 11-speed.\n - Size 54, 56, 58, 60, 62: Shimano Ultegra R8020, 11-speed.\n- Front derailleur: Shimano Ultegra R8000, braze-on.\n- Rear derailleur: Shimano Ultegra R8000, short cage, with a maximum cog size of 30T.\n- Crank:\n - Size 47: Shimano Ultegra R8000 with 52/36 chainrings and a 165mm length.\n - Size 50, 52: Shimano Ultegra R8000 with 52/36 chainrings and a 170mm length.\n - Size 54, 56, 58: Shimano Ultegra R8000 with 52/36 chainrings and a 172.5mm length.\n - Size 60, 62: Shimano Ultegra R8000 with 52/36 chainrings and a 175mm length.\n- Bottom bracket: Praxis T47 threaded bottom bracket with internal bearings.\n- Cassette: Shimano Ultegra R8000, 11-30, 11-speed.\n- Chain: Shimano Ultegra HG701, 11-speed.\n- Maximum chainring size: 1x - 50T, 2x - 53/39.\n\nComponents\n- Saddle: Bontrager Aeolus Comp with steel rails and a width of 145mm.\n- Seatpost:\n - Size 47, 50, 52, 54: Bontrager carbon seatmast cap with a 20mm offset and a short length.\n - Size 56, 58, 60, 62: Bontrager carbon seatmast cap with a 20mm offset and a tall length.\n- Handlebar:\n - Size 47, 50: Bontrager Elite VR-C alloy handlebar with a 31.8mm clamp, 100mm reach, 124mm drop, and a width of 38cm.\n - Size 52: Bontrager Elite VR-C alloy handlebar with a 31.8mm clamp, 100mm reach, 124mm drop, and a width of 40cm.\n - Size 54, 56, 58: Bontrager Elite VR-C alloy handlebar with a 31.8mm clamp, 100mm reach, 124mm drop, and a width of 42cm.\n - Size 60, 62: Bontrager Elite VR-C alloy handlebar with a 31.8mm clamp, 100mm reach, 124mm drop, and a width of 44cm.\n- Handlebar tape: Bontrager Supertack Perf tape.\n- Stem:\n - Size 47: Bontrager Pro alloy stem with a 31.8mm clamp, Blendr compatibility, 7-degree rise, and a length of 70mm.\n - Size 50: Bontrager Pro alloy stem with a 31.8mm clamp, Blendr compatibility, 7-degree rise, and a length of 80mm.\n - Size 52, 54: Bontrager Pro alloy stem with a 31.8mm clamp, Blendr compatibility, 7-degree rise, and a length of 90mm.\n - Size 56: Bontrager Pro alloy stem with a 31.8mm clamp, Blendr compatibility, 7-degree rise, and a length of 100mm.\n - Size 58, 60, 62: Bontrager Pro alloy stem with a 31.8mm clamp, Blendr compatibility, 7-degree rise, and a length of 110mm.\n- Brake: Shimano Ultegra hydraulic disc brakes with flat mount calipers.\n- Brake rotor: Shimano RT800 with centerlock mounting, 160mm diameter.\n\nWeight\n- Weight: 8.03 kg (17.71 lbs) for the 56cm frame.\n- Weight limit: The bike has a maximum total weight limit (combined weight of the bicycle, rider, and cargo) of 275 pounds (125 kg).\n\n## Sizing\nPlease refer to the table below for the corresponding Stealth R1X Pro frame sizes, recommended rider height range, and inseam measurements:\n\n| Size | Rider Height | Inseam |\n|:----:|:---------------------:|:--------------:|\n| 47 | 152 - 158 cm (5'0\") | 71 - 75 cm |\n| 50 | 158 - 163 cm (5'2\") | 74 - 77 cm |\n| 52 | 163 - 168 cm (5'4\") | 76 - 79 cm |\n| 54 | 168 - 174 cm (5'6\") | 78 - 82 cm |\n| 56 | 174 - 180 cm (5'9\") | 81 - 85 cm |\n| 58 | 180 - 185 cm (5'11\") | 84 - 87 cm |\n| 60 | 185 - 190 cm (6'1\") | 86 - 90 cm |\n| 62 | 190 - 195 cm (6'3\") | 89 - 92 cm |\n\n## Geometry\nThe table below provides the geometry measurements for each frame size of the Stealth R1X Pro:\n\n| Frame size number | 47 cm | 50 cm | 52 cm | 54 cm | 56 cm | 58 cm | 60 cm | 62 cm |\n|-------------------------------|-------|-------|-------|-------|-------|-------|-------|-------|\n| Wheel size | 700c | 700c | 700c | 700c | 700c | 700c | 700c | 700c |\n| A — Seat tube | 42.4 | 45.3 | 48.3 | 49.6 | 52.5 | 55.3 | 57.3 | 59.3 |\n| B — Seat tube angle | 74.6° | 74.6° | 74.2° | 73.7° | 73.3° | 73.0° | 72.8° | 72.5° |\n| C — Head tube length | 10.0 | 11.1 | 12.1 | 13.1 | 15.1 | 17.1 | 19.1 | 21.1 |\n| D — Head angle | 72.1° | 72.1° | 72.8° | 73.0° | 73.5° | 73.8° | 73.9° | 73.9° |\n| E — Effective top tube | 51.2 | 52.1 | 53.4 | 54.3 | 55.9 | 57.4 | 58.6 | 59.8 |\n| G — Bottom bracket drop | 7.2 | 7.2 | 7.2 | 7.0 | 7.0 | 6.8 | 6.8 | 6.8 |\n| H — Chainstay length | 41.0 | 41.0 | 41.0 | 41.0 | 41.0 | 41.1 | 41.1 | 41.2 |\n| I — Offset | 4.5 | 4.5 | 4.5 | 4.5 | 4.0 | 4.0 | 4.0 | 4.0 |\n| J — Trail | 6.8 | 6.2 | 5.8 | 5.6 | 5.8 | 5.7 | 5.6 | 5.6 |\n| K — Wheelbase | 97.2 | 97.4 | 97.7 | 98.1 | 98.3 | 99.2 | 100.1 | 101.0 |\n| L — Standover | 69.2 | 71.1 | 73.2 | 74.4 | 76.8 | 79.3 | 81.1 | 82.9 |\n| M — Frame reach | 37.3 | 37.8 | 38.3 | 38.6 | 39.1 | 39.6 | 39.9 | 40.3 |\n| N — Frame stack | 50.7 | 52.1 | 53.3 | 54.1 | 56.3 | 58.1 | 60.1 | 62.0 |\n| Saddle rail height min (short mast) | 55.5 | 58.5 | 61.5 | 64.0 | 67.0 | 69.0 | 71.0 | 73.0 |\n| Saddle rail height max (short mast) | 61.5 | 64.5 | 67.5 | 70.0 | 73.0 | 75.0 | 77.0 | 79.0 |\n| Saddle rail height min (tall mast) | 59.0 | 62.0 | 65.0 | 67.5 | 70.5 | 72.5 | 74.5 | 76.5 |\n| Saddle rail height max (tall mast) | 65.0 | 68.0 | 71.0 | 73.5 | 76.5 | 78.5 | 80.5 | 82.5 |",
"price": 2999.99,
"tags": [
"bicycle",
"mountain bike",
"professional"
]
},
{
"name": "Avant SLR 6 Disc Pro",
"shortDescription": "Avant SLR 6 Disc Pro is a high-performance carbon road bike designed for riders who prioritize speed and handling. With its aero tube shaping, disc brakes, and lightweight carbon wheels, it offers the perfect balance of speed and control.",
"description": "## Overview\nIt's right for you if...\nYou're a rider who values exceptional performance on fast group rides and races, and you want a complete package that includes lightweight carbon wheels. The Avant SLR 6 Disc Pro is designed to provide the speed and aerodynamics you need to excel on any road.\n\nThe tech you get\nThe Avant SLR 6 Disc Pro features a lightweight 500 Series ADV Carbon frame and fork, Bontrager Aeolus Elite 35 carbon wheels, a full Shimano Ultegra 11-speed drivetrain, and powerful Ultegra disc brakes.\n\nThe final word\nThe standout feature of this bike is the combination of its aero frame, high-performance drivetrain, and top-quality carbon wheels. Whether you're racing, tackling challenging climbs, or participating in professional stage races, the Avant SLR 6 Disc Pro is a worthy choice that will enhance your performance.\n\n## Features\nAll-new aero design\nThe Avant SLR 6 Disc Pro features innovative aero tube shapes that provide an advantage in all riding conditions, whether it's climbing or riding on flat roads. Additionally, it is equipped with a sleek new Aeolus RSL bar/stem that enhances front-end aero performance.\n\nAwesome bikes for everyone\nThe Avant SLR 6 Disc Pro is designed with the belief that every rider, regardless of gender, body type, riding style, or ability, deserves a great bike. It is equipped with size-specific components that ensure a perfect fit for competitive riders of all genders.\n\n## Specifications\nFrameset\n- Frame: Ultralight 500 Series ADV Carbon, Ride Tuned performance tube optimization, tapered head tube, internal routing, DuoTrap S compatible, flat mount disc, 142x12mm thru axle\n- Fork: Avant SL full carbon, tapered carbon steerer, internal brake routing, flat mount disc, 12x100mm thru axle\n- Frame fit: H1.5 Race\n\nWheels\n- Front wheel: Bontrager Aeolus Elite 35, ADV Carbon, Tubeless Ready, 35mm rim depth, 100x12mm thru axle\n- Rear wheel: Bontrager Aeolus Elite 35, ADV Carbon, Tubeless Ready, 35mm rim depth, Shimano 11/12-speed freehub, 142x12mm thru axle\n- Front skewer: Bontrager Switch thru axle, removable lever\n- Rear skewer: Bontrager Switch thru axle, removable lever\n- Tire: Bontrager R2 Hard-Case Lite, aramid bead, 60 tpi, 700x25c\n- Max tire size: 28mm\n\nDrivetrain\n- Shifter: \n - Size 47, 50, 52: Shimano Ultegra R8025, short-reach lever, 11-speed\n - Size 54, 56, 58, 60, 62: Shimano Ultegra R8020, 11-speed\n- Front derailleur: Shimano Ultegra R8000, braze-on\n- Rear derailleur: Shimano Ultegra R8000, short cage, 30T max cog\n- Crank: \n - Size 47: Shimano Ultegra R8000, 52/36, 165mm length\n - Size 50, 52: Shimano Ultegra R8000, 52/36, 170mm length\n - Size 54, 56, 58: Shimano Ultegra R8000, 52/36, 172.5mm length\n - Size 60, 62: Shimano Ultegra R8000, 52/36, 175mm length\n- Bottom bracket: Praxis, T47 threaded, internal bearing\n- Cassette: Shimano Ultegra R8000, 11-30, 11-speed\n- Chain: Shimano Ultegra HG701, 11-speed\n- Max chainring size: 1x: 50T, 2x: 53/39\n\nComponents\n- Saddle: Bontrager Aeolus Comp, steel rails, 145mm width\n- Seatpost: \n - Size 47, 50, 52, 54: Bontrager carbon seatmast cap, 20mm offset, short length\n - Size 56, 58, 60, 62: Bontrager carbon seatmast cap, 20mm offset, tall length\n- Handlebar: \n - Size 47, 50: Bontrager Elite VR-C, alloy, 31.8mm, 100mm reach, 124mm drop, 38cm width\n - Size 52: Bontrager Elite VR-C, alloy, 31.8mm, 100mm reach, 124mm drop, 40cm width\n - Size 54, 56, 58: Bontrager Elite VR-C, alloy, 31.8mm, 100mm reach, 124mm drop, 42cm width\n - Size 60, 62: Bontrager Elite VR-C, alloy, 31.8mm, 100mm reach, 124mm drop, 44cm width\n- Handlebar tape: Bontrager Supertack Perf tape\n- Stem: \n - Size 47: Bontrager Pro, 31.8mm, Blendr compatible, 7-degree, 70mm length\n - Size 50: Bontrager Pro, 31.8mm, Blendr compatible, 7-degree, 80mm length\n - Size 52, 54: Bontrager Pro, 31.8mm, Blendr compatible, 7-degree, 90mm length\n - Size 56: Bontrager Pro, 31.8mm, Blendr compatible, 7-degree, 100mm length\n - Size 58, 60, 62: Bontrager Pro, 31.8mm, Blendr compatible, 7-degree, 110mm length\n- Brake: Shimano Ultegra hydraulic disc, flat mount\n- Brake rotor: Shimano RT800, centerlock, 160mm\n\nWeight\n- Weight: 56 - 8.03 kg / 17.71 lbs\n- Weight limit: This bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 275 pounds (125 kg).\n\n## Sizing\n| Size | Rider Height | Inseam |\n|:----:|:-------------------------:|:--------------------:|\n| 47 | 152 - 158 cm 5'0\" - 5'2\" | 71 - 75 cm 28\" - 30\" |\n| 50 | 158 - 163 cm 5'2\" - 5'4\" | 74 - 77 cm 29\" - 30\" |\n| 52 | 163 - 168 cm 5'4\" - 5'6\" | 76 - 79 cm 30\" - 31\" |\n| 54 | 168 - 174 cm 5'6\" - 5'9\" | 78 - 82 cm 31\" - 32\" |\n| 56 | 174 - 180 cm 5'9\" - 5'11\" | 81 - 85 cm 32\" - 33\" |\n| 58 | 180 - 185 cm 5'11\" - 6'1\" | 84 - 87 cm 33\" - 34\" |\n| 60 | 185 - 190 cm 6'1\" - 6'3\" | 86 - 90 cm 34\" - 35\" |\n| 62 | 190 - 195 cm 6'3\" - 6'5\" | 89 - 92 cm 35\" - 36\" |\n\n## Geometry\n| Frame size number | 47 cm | 50 cm | 52 cm | 54 cm | 56 cm | 58 cm | 60 cm | 62 cm |\n|---------------------------------------|-------|-------|-------|-------|-------|-------|-------|-------|\n| Wheel size | 700c | 700c | 700c | 700c | 700c | 700c | 700c | 700c |\n| A — Seat tube | 42.4 | 45.3 | 48.3 | 49.6 | 52.5 | 55.3 | 57.3 | 59.3 |\n| B — Seat tube angle | 74.6° | 74.6° | 74.2° | 73.7° | 73.3° | 73.0° | 72.8° | 72.5° |\n| C — Head tube length | 10.0 | 11.1 | 12.1 | 13.1 | 15.1 | 17.1 | 19.1 | 21.1 |\n| D — Head angle | 72.1° | 72.1° | 72.8° | 73.0° | 73.5° | 73.8° | 73.9° | 73.9° |\n| E — Effective top tube | 51.2 | 52.1 | 53.4 | 54.3 | 55.9 | 57.4 | 58.6 | 59.8 |\n| G — Bottom bracket drop | 7.2 | 7.2 | 7.2 | 7.0 | 7.0 | 6.8 | 6.8 | 6.8 |\n| H — Chainstay length | 41.0 | 41.0 | 41.0 | 41.0 | 41.0 | 41.1 | 41.1 | 41.2 |\n| I — Offset | 4.5 | 4.5 | 4.5 | 4.5 | 4.0 | 4.0 | 4.0 | 4.0 |\n| J — Trail | 6.8 | 6.2 | 5.8 | 5.6 | 5.8 | 5.7 | 5.6 | 5.6 |\n| K — Wheelbase | 97.2 | 97.4 | 97.7 | 98.1 | 98.3 | 99.2 | 100.1 | 101.0 |\n| L — Standover | 69.2 | 71.1 | 73.2 | 74.4 | 76.8 | 79.3 | 81.1 | 82.9 |\n| M — Frame reach | 37.3 | 37.8 | 38.3 | 38.6 | 39.1 | 39.6 | 39.9 | 40.3 |\n| N — Frame stack | 50.7 | 52.1 | 53.3 | 54.1 | 56.3 | 58.1 | 60.1 | 62.0 |\n| Saddle rail height min (w/short mast) | 55.5 | 58.5 | 61.5 | 64.0 | 67.0 | 69.0 | 71.0 | 73.0 |\n| Saddle rail height max (w/short mast) | 61.5 | 64.5 | 67.5 | 70.0 | 73.0 | 75.0 | 77.0 | 79.0 |\n| Saddle rail height min (w/tall mast) | 59.0 | 62.0 | 65.0 | 67.5 | 70.5 | 72.5 | 74.5 | 76.5 |\n| Saddle rail height max (w/tall mast) | 65.0 | 68.0 | 71.0 | 73.5 | 76.5 | 78.5 | 80.5 | 82.5 |",
"price": 999.99,
"tags": [
"bicycle",
"city bike",
"professional"
]
}
]
Spring Ai Client Chat/Src/Test/Resources/Text Source (spring-ai-client-chat/src/test/resources/text_source.txt)
Spring Framework Documentation
Version 6.0.0
Chapter 1. Spring Framework Overview
Spring makes it easy to create Java enterprise applications. It provides everything you need to
embrace the Java language in an enterprise environment, with support for Groovy and Kotlin as
alternative languages on the JVM, and with the flexibility to create many kinds of architectures
depending on an application’s needs. As of Spring Framework 5.1, Spring requires JDK 8+ (Java SE
8+) and provides out-of-the-box support for JDK 11 LTS. Java SE 8 update 60 is suggested as the
minimum patch release for Java 8, but it is generally recommended to use a recent patch release.
Spring supports a wide range of application scenarios. In a large enterprise, applications often exist
for a long time and have to run on a JDK and application server whose upgrade cycle is beyond
developer control. Others may run as a single jar with the server embedded, possibly in a cloud
environment. Yet others may be standalone applications (such as batch or integration workloads)
that do not need a server.
Spring is open source. It has a large and active community that provides continuous feedback based
on a diverse range of real-world use cases. This has helped Spring to successfully evolve over a very
long time.
1.1. What We Mean by "Spring"
The term "Spring" means different things in different contexts. It can be used to refer to the Spring
Framework project itself, which is where it all started. Over time, other Spring projects have been
built on top of the Spring Framework. Most often, when people say "Spring", they mean the entire
family of projects. This reference documentation focuses on the foundation: the Spring Framework
itself.
The Spring Framework is divided into modules. Applications can choose which modules they need.
At the heart are the modules of the core container, including a configuration model and a
dependency injection mechanism. Beyond that, the Spring Framework provides foundational
support for different application architectures, including messaging, transactional data and
persistence, and web. It also includes the Servlet-based Spring MVC web framework and, in
parallel, the Spring WebFlux reactive web framework.
A note about modules: Spring’s framework jars allow for deployment to JDK 9’s module path
("Jigsaw"). For use in Jigsaw-enabled applications, the Spring Framework 5 jars come with
"Automatic-Module-Name" manifest entries which define stable language-level module names
("spring.core", "spring.context", etc.) independent from jar artifact names (the jars follow the same
naming pattern with "-" instead of ".", e.g. "spring-core" and "spring-context"). Of course, Spring’s
framework jars keep working fine on the classpath on both JDK 8 and 9+.
1.2. History of Spring and the Spring Framework
Spring came into being in 2003 as a response to the complexity of the early J2EE specifications.
While some consider Java EE and its modern-day successor Jakarta EE to be in competition with
Spring, they are in fact complementary. The Spring programming model does not embrace the
Jakarta EE platform specification; rather, it integrates with carefully selected individual
specifications from the traditional EE umbrella:
• Servlet API (JSR 340)
• WebSocket API (JSR 356)
• Concurrency Utilities (JSR 236)
• JSON Binding API (JSR 367)
• Bean Validation (JSR 303)
• JPA (JSR 338)
• JMS (JSR 914)
• as well as JTA/JCA setups for transaction coordination, if necessary.
The Spring Framework also supports the Dependency Injection (JSR 330) and Common Annotations
(JSR 250) specifications, which application developers may choose to use instead of the Spring-
specific mechanisms provided by the Spring Framework. Originally, those were based on common
javax packages.
As of Spring Framework 6.0, Spring has been upgraded to the Jakarta EE 9 level (e.g. Servlet 5.0+,
JPA 3.0+), based on the jakarta namespace instead of the traditional javax packages. With EE 9 as
the minimum and EE 10 supported already, Spring is prepared to provide out-of-the-box support
for the further evolution of the Jakarta EE APIs. Spring Framework 6.0 is fully compatible with
Tomcat 10.1, Jetty 11 and Undertow 2.3 as web servers, and also with Hibernate ORM 6.1.
Over time, the role of Java/Jakarta EE in application development has evolved. In the early days of
J2EE and Spring, applications were created to be deployed to an application server. Today, with the
help of Spring Boot, applications are created in a devops- and cloud-friendly way, with the Servlet
container embedded and trivial to change. As of Spring Framework 5, a WebFlux application does
not even use the Servlet API directly and can run on servers (such as Netty) that are not Servlet
containers.
Spring continues to innovate and to evolve. Beyond the Spring Framework, there are other projects,
such as Spring Boot, Spring Security, Spring Data, Spring Cloud, Spring Batch, among others. It’s
important to remember that each project has its own source code repository, issue tracker, and
release cadence. See spring.io/projects for the complete list of Spring projects.
1.3. Design Philosophy
When you learn about a framework, it’s important to know not only what it does but what
principles it follows. Here are the guiding principles of the Spring Framework:
• Provide choice at every level. Spring lets you defer design decisions as late as possible. For
example, you can switch persistence providers through configuration without changing your
code. The same is true for many other infrastructure concerns and integration with third-party
APIs.
• Accommodate diverse perspectives. Spring embraces flexibility and is not opinionated about
how things should be done. It supports a wide range of application needs with different
perspectives.
• Maintain strong backward compatibility. Spring’s evolution has been carefully managed to
force few breaking changes between versions. Spring supports a carefully chosen range of JDK
versions and third-party libraries to facilitate maintenance of applications and libraries that
depend on Spring.
• Care about API design. The Spring team puts a lot of thought and time into making APIs that are
intuitive and that hold up across many versions and many years.
• Set high standards for code quality. The Spring Framework puts a strong emphasis on
meaningful, current, and accurate javadoc. It is one of very few projects that can claim clean
code structure with no circular dependencies between packages.
1.4. Feedback and Contributions
For how-to questions or diagnosing or debugging issues, we suggest using Stack Overflow. Click
here for a list of the suggested tags to use on Stack Overflow. If you’re fairly certain that there is a
problem in the Spring Framework or would like to suggest a feature, please use the GitHub Issues.
If you have a solution in mind or a suggested fix, you can submit a pull request on Github.
However, please keep in mind that, for all but the most trivial issues, we expect a ticket to be filed
in the issue tracker, where discussions take place and leave a record for future reference.
For more details see the guidelines at the CONTRIBUTING, top-level project page.
1.5. Getting Started
If you are just getting started with Spring, you may want to begin using the Spring Framework by
creating a Spring Boot-based application. Spring Boot provides a quick (and opinionated) way to
create a production-ready Spring-based application. It is based on the Spring Framework, favors
convention over configuration, and is designed to get you up and running as quickly as possible.
You can use start.spring.io to generate a basic project or follow one of the "Getting Started" guides,
such as Getting Started Building a RESTful Web Service. As well as being easier to digest, these
guides are very task focused, and most of them are based on Spring Boot. They also cover other
projects from the Spring portfolio that you might want to consider when solving a particular
problem.
Chapter 2. Core Technologies
This part of the reference documentation covers all the technologies that are absolutely integral to
the Spring Framework.
Foremost amongst these is the Spring Framework’s Inversion of Control (IoC) container. A thorough
treatment of the Spring Framework’s IoC container is closely followed by comprehensive coverage
of Spring’s Aspect-Oriented Programming (AOP) technologies. The Spring Framework has its own
AOP framework, which is conceptually easy to understand and which successfully addresses the
80% sweet spot of AOP requirements in Java enterprise programming.
Coverage of Spring’s integration with AspectJ (currently the richest — in terms of features — and
certainly most mature AOP implementation in the Java enterprise space) is also provided.
AOT processing can be used to optimize your application ahead-of-time. It is typically used for
native image deployment using GraalVM.
2.1. The IoC Container
This chapter covers Spring’s Inversion of Control (IoC) container.
2.1.1. Introduction to the Spring IoC Container and Beans
This chapter covers the Spring Framework implementation of the Inversion of Control (IoC)
principle. IoC is also known as dependency injection (DI). It is a process whereby objects define
their dependencies (that is, the other objects they work with) only through constructor arguments,
arguments to a factory method, or properties that are set on the object instance after it is
constructed or returned from a factory method. The container then injects those dependencies
when it creates the bean. This process is fundamentally the inverse (hence the name, Inversion of
Control) of the bean itself controlling the instantiation or location of its dependencies by using
direct construction of classes or a mechanism such as the Service Locator pattern.
The org.springframework.beans and org.springframework.context packages are the basis for Spring
Framework’s IoC container. The BeanFactory interface provides an advanced configuration
mechanism capable of managing any type of object. ApplicationContext is a sub-interface of
BeanFactory. It adds:
• Easier integration with Spring’s AOP features
• Message resource handling (for use in internationalization)
• Event publication
• Application-layer specific contexts such as the WebApplicationContext for use in web
applications.
In short, the BeanFactory provides the configuration framework and basic functionality, and the
ApplicationContext adds more enterprise-specific functionality. The ApplicationContext is a
complete superset of the BeanFactory and is used exclusively in this chapter in descriptions of
Spring’s IoC container. For more information on using the BeanFactory instead of the
ApplicationContext, see the section covering the BeanFactory API.
In Spring, the objects that form the backbone of your application and that are managed by the
Spring IoC container are called beans. A bean is an object that is instantiated, assembled, and
managed by a Spring IoC container. Otherwise, a bean is simply one of many objects in your
application. Beans, and the dependencies among them, are reflected in the configuration metadata
used by a container.
2.1.2. Container Overview
The org.springframework.context.ApplicationContext interface represents the Spring IoC container
and is responsible for instantiating, configuring, and assembling the beans. The container gets its
instructions on what objects to instantiate, configure, and assemble by reading configuration
metadata. The configuration metadata is represented in XML, Java annotations, or Java code. It lets
you express the objects that compose your application and the rich interdependencies between
those objects.
Several implementations of the ApplicationContext interface are supplied with Spring. In stand-
alone applications, it is common to create an instance of ClassPathXmlApplicationContext or
FileSystemXmlApplicationContext. While XML has been the traditional format for defining
configuration metadata, you can instruct the container to use Java annotations or code as the
metadata format by providing a small amount of XML configuration to declaratively enable support
for these additional metadata formats.
In most application scenarios, explicit user code is not required to instantiate one or more
instances of a Spring IoC container. For example, in a web application scenario, a simple eight (or
so) lines of boilerplate web descriptor XML in the web.xml file of the application typically suffices
(see Convenient ApplicationContext Instantiation for Web Applications). If you use the Spring Tools
for Eclipse (an Eclipse-powered development environment), you can easily create this boilerplate
configuration with a few mouse clicks or keystrokes.
The following diagram shows a high-level view of how Spring works. Your application classes are
combined with configuration metadata so that, after the ApplicationContext is created and
initialized, you have a fully configured and executable system or application.
Figure 1. The Spring IoC container
Configuration Metadata
As the preceding diagram shows, the Spring IoC container consumes a form of configuration
metadata. This configuration metadata represents how you, as an application developer, tell the
Spring container to instantiate, configure, and assemble the objects in your application.
Configuration metadata is traditionally supplied in a simple and intuitive XML format, which is
what most of this chapter uses to convey key concepts and features of the Spring IoC container.
XML-based metadata is not the only allowed form of configuration metadata. The
Spring IoC container itself is totally decoupled from the format in which this
configuration metadata is actually written. These days, many developers choose
Java-based configuration for their Spring applications.
For information about using other forms of metadata with the Spring container, see:
• Annotation-based configuration: Spring 2.5 introduced support for annotation-based
configuration metadata.
• Java-based configuration: Starting with Spring 3.0, many features provided by the Spring
JavaConfig project became part of the core Spring Framework. Thus, you can define beans
external to your application classes by using Java rather than XML files. To use these new
features, see the @Configuration, @Bean, @Import, and @DependsOn annotations.
Spring configuration consists of at least one and typically more than one bean definition that the
container must manage. XML-based configuration metadata configures these beans as
elements inside a top-level element. Java configuration typically uses @Bean-annotated
methods within a @Configuration class.
These bean definitions correspond to the actual objects that make up your application. Typically,
you define service layer objects, data access objects (DAOs), presentation objects such as Struts
Action instances, infrastructure objects such as Hibernate SessionFactories, JMS Queues, and so
forth. Typically, one does not configure fine-grained domain objects in the container, because it is
usually the responsibility of DAOs and business logic to create and load domain objects. However,
you can use Spring’s integration with AspectJ to configure objects that have been created outside
the control of an IoC container. See Using AspectJ to dependency-inject domain objects with Spring.
The following example shows the basic structure of XML-based configuration metadata:
<?xml version="1.0" encoding="UTF-8"?>
① ②
① The id attribute is a string that identifies the individual bean definition.
② The class attribute defines the type of the bean and uses the fully qualified classname.
The value of the id attribute refers to collaborating objects. The XML for referring to collaborating
objects is not shown in this example. See Dependencies for more information.
Instantiating a Container
The location path or paths supplied to an ApplicationContext constructor are resource strings that
let the container load configuration metadata from a variety of external resources, such as the local
file system, the Java CLASSPATH, and so on.
Java
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml",
"daos.xml");
Kotlin
val context = ClassPathXmlApplicationContext("services.xml", "daos.xml")
After you learn about Spring’s IoC container, you may want to know more about
Spring’s Resource abstraction (as described in Resources), which provides a
convenient mechanism for reading an InputStream from locations defined in a
URI syntax. In particular, Resource paths are used to construct applications
contexts, as described in Application Contexts and Resource Paths.
The following example shows the service layer objects (services.xml) configuration file:
<?xml version="1.0" encoding="UTF-8"?>
The following example shows the data access objects daos.xml file:
<?xml version="1.0" encoding="UTF-8"?>
In the preceding example, the service layer consists of the PetStoreServiceImpl class and two data
access objects of the types JpaAccountDao and JpaItemDao (based on the JPA Object-Relational
Mapping standard). The property name element refers to the name of the JavaBean property, and the
ref element refers to the name of another bean definition. This linkage between id and ref
elements expresses the dependency between collaborating objects. For details of configuring an
object’s dependencies, see Dependencies.
Composing XML-based Configuration Metadata
It can be useful to have bean definitions span multiple XML files. Often, each individual XML
configuration file represents a logical layer or module in your architecture.
You can use the application context constructor to load bean definitions from all these XML
fragments. This constructor takes multiple Resource locations, as was shown in the previous section.
Alternatively, use one or more occurrences of the element to load bean definitions from
another file or files. The following example shows how to do so:
In the preceding example, external bean definitions are loaded from three files: services.xml,
messageSource.xml, and themeSource.xml. All location paths are relative to the definition file doing
the importing, so services.xml must be in the same directory or classpath location as the file doing
the importing, while messageSource.xml and themeSource.xml must be in a resources location below
the location of the importing file. As you can see, a leading slash is ignored. However, given that
these paths are relative, it is better form not to use the slash at all. The contents of the files being
imported, including the top level element, must be valid XML bean definitions, according
to the Spring Schema.
It is possible, but not recommended, to reference files in parent directories using a
relative "../" path. Doing so creates a dependency on a file that is outside the
current application. In particular, this reference is not recommended for
classpath: URLs (for example, classpath:../services.xml), where the runtime
resolution process chooses the “nearest” classpath root and then looks into its
parent directory. Classpath configuration changes may lead to the choice of a
different, incorrect directory.
You can always use fully qualified resource locations instead of relative paths: for
example, file:C:/config/services.xml or classpath:/config/services.xml.
However, be aware that you are coupling your application’s configuration to
specific absolute locations. It is generally preferable to keep an indirection for such
absolute locations — for example, through "${…}" placeholders that are resolved
against JVM system properties at runtime.
The namespace itself provides the import directive feature. Further configuration features beyond
plain bean definitions are available in a selection of XML namespaces provided by Spring — for
example, the context and util namespaces.
The Groovy Bean Definition DSL
As a further example for externalized configuration metadata, bean definitions can also be
expressed in Spring’s Groovy Bean Definition DSL, as known from the Grails framework. Typically,
such configuration live in a ".groovy" file with the structure shown in the following example:
beans {
dataSource(BasicDataSource) {
driverClassName = "org.hsqldb.jdbcDriver"
url = "jdbc:hsqldb:mem:grailsDB"
username = "sa"
password = ""
settings = [mynew:"setting"]
}
sessionFactory(SessionFactory) {
dataSource = dataSource
}
myService(MyService) {
nestedBean = { AnotherBean bean ->
dataSource = dataSource
}
}
}
This configuration style is largely equivalent to XML bean definitions and even supports Spring’s
XML configuration namespaces. It also allows for importing XML bean definition files through an
importBeans directive.
Using the Container
The ApplicationContext is the interface for an advanced factory capable of maintaining a registry of
different beans and their dependencies. By using the method T getBean(String name, Class<T>
requiredType), you can retrieve instances of your beans.
The ApplicationContext lets you read bean definitions and access them, as the following example
shows:
Java
// create and configure beans
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml",
"daos.xml");
// retrieve configured instance
PetStoreService service = context.getBean("petStore", PetStoreService.class);
// use configured instance
List<String> userList = service.getUsernameList();
Kotlin
import org.springframework.beans.factory.getBean
// create and configure beans
val context = ClassPathXmlApplicationContext("services.xml", "daos.xml")
// retrieve configured instance
val service = context.getBean("petStore")
// use configured instance
var userList = service.getUsernameList()
With Groovy configuration, bootstrapping looks very similar. It has a different context
implementation class which is Groovy-aware (but also understands XML bean definitions). The
following example shows Groovy configuration:
Java
ApplicationContext context = new GenericGroovyApplicationContext("services.groovy",
"daos.groovy");
Kotlin
val context = GenericGroovyApplicationContext("services.groovy", "daos.groovy")
The most flexible variant is GenericApplicationContext in combination with reader delegates — for
example, with XmlBeanDefinitionReader for XML files, as the following example shows:
Java
GenericApplicationContext context = new GenericApplicationContext();
new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml");
context.refresh();
Kotlin
val context = GenericApplicationContext()
XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml")
context.refresh()
You can also use the GroovyBeanDefinitionReader for Groovy files, as the following example shows:
Java
GenericApplicationContext context = new GenericApplicationContext();
new GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy",
"daos.groovy");
context.refresh();
Kotlin
val context = GenericApplicationContext()
GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy",
"daos.groovy")
context.refresh()
You can mix and match such reader delegates on the same ApplicationContext, reading bean
definitions from diverse configuration sources.
You can then use getBean to retrieve instances of your beans. The ApplicationContext interface has a
few other methods for retrieving beans, but, ideally, your application code should never use them.
Indeed, your application code should have no calls to the getBean() method at all and thus have no
dependency on Spring APIs at all. For example, Spring’s integration with web frameworks provides
dependency injection for various web framework components such as controllers and JSF-managed
beans, letting you declare a dependency on a specific bean through metadata (such as an
autowiring annotation).
2.1.3. Bean Overview
A Spring IoC container manages one or more beans. These beans are created with the configuration
metadata that you supply to the container (for example, in the form of XML definitions).
Within the container itself, these bean definitions are represented as BeanDefinition objects, which
contain (among other information) the following metadata:
• A package-qualified class name: typically, the actual implementation class of the bean being
defined.
• Bean behavioral configuration elements, which state how the bean should behave in the
container (scope, lifecycle callbacks, and so forth).
• References to other beans that are needed for the bean to do its work. These references are also
called collaborators or dependencies.
• Other configuration settings to set in the newly created object — for example, the size limit of
the pool or the number of connections to use in a bean that manages a connection pool.
This metadata translates to a set of properties that make up each bean definition. The following
table describes these properties:
Table 1. The bean definition
Property Explained in…
Class Instantiating Beans
Name Naming Beans
Scope Bean Scopes
Constructor arguments Dependency Injection
Properties Dependency Injection
Autowiring mode Autowiring Collaborators
Lazy initialization mode Lazy-initialized Beans
Initialization method Initialization Callbacks
Destruction method Destruction Callbacks
In addition to bean definitions that contain information on how to create a specific bean, the
ApplicationContext implementations also permit the registration of existing objects that are created
outside the container (by users). This is done by accessing the ApplicationContext’s BeanFactory
through the getBeanFactory() method, which returns the DefaultListableBeanFactory
implementation. DefaultListableBeanFactory supports this registration through the
registerSingleton(..) and registerBeanDefinition(..) methods. However, typical applications
work solely with beans defined through regular bean definition metadata.
Bean metadata and manually supplied singleton instances need to be registered as
early as possible, in order for the container to properly reason about them during
autowiring and other introspection steps. While overriding existing metadata and
existing singleton instances is supported to some degree, the registration of new
beans at runtime (concurrently with live access to the factory) is not officially
supported and may lead to concurrent access exceptions, inconsistent state in the
bean container, or both.
Naming Beans
Every bean has one or more identifiers. These identifiers must be unique within the container that
hosts the bean. A bean usually has only one identifier. However, if it requires more than one, the
extra ones can be considered aliases.
In XML-based configuration metadata, you use the id attribute, the name attribute, or both to specify
the bean identifiers. The id attribute lets you specify exactly one id. Conventionally, these names
are alphanumeric ('myBean', 'someService', etc.), but they can contain special characters as well. If
you want to introduce other aliases for the bean, you can also specify them in the name attribute,
separated by a comma (,), semicolon (;), or white space. As a historical note, in versions prior to
Spring 3.1, the id attribute was defined as an xsd:ID type, which constrained possible characters. As
of 3.1, it is defined as an xsd:string type. Note that bean id uniqueness is still enforced by the
container, though no longer by XML parsers.
You are not required to supply a name or an id for a bean. If you do not supply a name or id explicitly,
the container generates a unique name for that bean. However, if you want to refer to that bean by
name, through the use of the ref element or a Service Locator style lookup, you must provide a
name. Motivations for not supplying a name are related to using inner beans and autowiring
collaborators.
Bean Naming Conventions
The convention is to use the standard Java convention for instance field names when naming
beans. That is, bean names start with a lowercase letter and are camel-cased from there.
Examples of such names include accountManager, accountService, userDao, loginController, and
so forth.
Naming beans consistently makes your configuration easier to read and understand. Also, if
you use Spring AOP, it helps a lot when applying advice to a set of beans related by name.
With component scanning in the classpath, Spring generates bean names for
unnamed components, following the rules described earlier: essentially, taking the
simple class name and turning its initial character to lower-case. However, in the
(unusual) special case when there is more than one character and both the first
and second characters are upper case, the original casing gets preserved. These are
the same rules as defined by java.beans.Introspector.decapitalize (which Spring
uses here).
Aliasing a Bean outside the Bean Definition
In a bean definition itself, you can supply more than one name for the bean, by using a
combination of up to one name specified by the id attribute and any number of other names in the
name attribute. These names can be equivalent aliases to the same bean and are useful for some
situations, such as letting each component in an application refer to a common dependency by
using a bean name that is specific to that component itself.
Specifying all aliases where the bean is actually defined is not always adequate, however. It is
sometimes desirable to introduce an alias for a bean that is defined elsewhere. This is commonly
the case in large systems where configuration is split amongst each subsystem, with each
subsystem having its own set of object definitions. In XML-based configuration metadata, you can
use the <alias/> element to accomplish this. The following example shows how to do so:
<alias name="fromName" alias="toName"/>
In this case, a bean (in the same container) named fromName may also, after the use of this alias
definition, be referred to as toName.
For example, the configuration metadata for subsystem A may refer to a DataSource by the name of
subsystemA-dataSource. The configuration metadata for subsystem B may refer to a DataSource by
the name of subsystemB-dataSource. When composing the main application that uses both these
subsystems, the main application refers to the DataSource by the name of myApp-dataSource. To have
all three names refer to the same object, you can add the following alias definitions to the
configuration metadata:
<alias name="myApp-dataSource" alias="subsystemA-dataSource"/>
<alias name="myApp-dataSource" alias="subsystemB-dataSource"/>
Now each component and the main application can refer to the dataSource through a name that is
unique and guaranteed not to clash with any other definition (effectively creating a namespace),
yet they refer to the same bean.
Java-configuration
If you use Javaconfiguration, the @Bean annotation can be used to provide aliases. See Using
the @Bean Annotation for details.
Instantiating Beans
A bean definition is essentially a recipe for creating one or more objects. The container looks at the
recipe for a named bean when asked and uses the configuration metadata encapsulated by that
bean definition to create (or acquire) an actual object.
If you use XML-based configuration metadata, you specify the type (or class) of object that is to be
instantiated in the class attribute of the element. This class attribute (which, internally, is a
Class property on a BeanDefinition instance) is usually mandatory. (For exceptions, see
Instantiation by Using an Instance Factory Method and Bean Definition Inheritance.) You can use
the Class property in one of two ways:
• Typically, to specify the bean class to be constructed in the case where the container itself
directly creates the bean by calling its constructor reflectively, somewhat equivalent to Java
code with the new operator.
• To specify the actual class containing the static factory method that is invoked to create the
object, in the less common case where the container invokes a static factory method on a class
to create the bean. The object type returned from the invocation of the static factory method
may be the same class or another class entirely.
Nested class names
If you want to configure a bean definition for a nested class, you may use either the binary
name or the source name of the nested class.
For example, if you have a class called SomeThing in the com.example package, and this
SomeThing class has a static nested class called OtherThing, they can be separated by a dollar
sign ($) or a dot (.). So the value of the class attribute in a bean definition would be
com.example.SomeThing$OtherThing or com.example.SomeThing.OtherThing.
Instantiation with a Constructor
When you create a bean by the constructor approach, all normal classes are usable by and
compatible with Spring. That is, the class being developed does not need to implement any specific
interfaces or to be coded in a specific fashion. Simply specifying the bean class should suffice.
However, depending on what type of IoC you use for that specific bean, you may need a default
(empty) constructor.
The Spring IoC container can manage virtually any class you want it to manage. It is not limited to
managing true JavaBeans. Most Spring users prefer actual JavaBeans with only a default (no-
argument) constructor and appropriate setters and getters modeled after the properties in the
container. You can also have more exotic non-bean-style classes in your container. If, for example,
you need to use a legacy connection pool that absolutely does not adhere to the JavaBean
specification, Spring can manage it as well.
With XML-based configuration metadata you can specify your bean class as follows:
For details about the mechanism for supplying arguments to the constructor (if required) and
setting object instance properties after the object is constructed, see Injecting Dependencies.
Instantiation with a Static Factory Method
When defining a bean that you create with a static factory method, use the class attribute to specify
the class that contains the static factory method and an attribute named factory-method to specify
the name of the factory method itself. You should be able to call this method (with optional
arguments, as described later) and return a live object, which subsequently is treated as if it had
been created through a constructor. One use for such a bean definition is to call static factories in
legacy code.
The following bean definition specifies that the bean will be created by calling a factory method.
The definition does not specify the type (class) of the returned object, but rather the class
containing the factory method. In this example, the createInstance() method must be a static
method. The following example shows how to specify a factory method:
The following example shows a class that would work with the preceding bean definition:
Java
public class ClientService {
private static ClientService clientService = new ClientService();
private ClientService() {}
public static ClientService createInstance() {
return clientService;
}
}
Kotlin
class ClientService private constructor() {
companion object {
private val clientService = ClientService()
@JvmStatic
fun createInstance() = clientService
}
}
For details about the mechanism for supplying (optional) arguments to the factory method and
setting object instance properties after the object is returned from the factory, see Dependencies
and Configuration in Detail.
Instantiation by Using an Instance Factory Method
Similar to instantiation through a static factory method, instantiation with an instance factory
method invokes a non-static method of an existing bean from the container to create a new bean.
To use this mechanism, leave the class attribute empty and, in the factory-bean attribute, specify
the name of a bean in the current (or parent or ancestor) container that contains the instance
method that is to be invoked to create the object. Set the name of the factory method itself with the
factory-method attribute. The following example shows how to configure such a bean:
The following example shows the corresponding class:
Java
public class DefaultServiceLocator {
private static ClientService clientService = new ClientServiceImpl();
public ClientService createClientServiceInstance() {
return clientService;
}
}
Kotlin
class DefaultServiceLocator {
companion object {
private val clientService = ClientServiceImpl()
}
fun createClientServiceInstance(): ClientService {
return clientService
}
}
One factory class can also hold more than one factory method, as the following example shows:
The following example shows the corresponding class:
Java
public class DefaultServiceLocator {
private static ClientService clientService = new ClientServiceImpl();
private static AccountService accountService = new AccountServiceImpl();
public ClientService createClientServiceInstance() {
return clientService;
}
public AccountService createAccountServiceInstance() {
return accountService;
}
}
Kotlin
class DefaultServiceLocator {
companion object {
private val clientService = ClientServiceImpl()
private val accountService = AccountServiceImpl()
}
fun createClientServiceInstance(): ClientService {
return clientService
}
fun createAccountServiceInstance(): AccountService {
return accountService
}
}
This approach shows that the factory bean itself can be managed and configured through
dependency injection (DI). See Dependencies and Configuration in Detail.
In Spring documentation, "factory bean" refers to a bean that is configured in the
Spring container and that creates objects through an instance or static factory
method. By contrast, FactoryBean (notice the capitalization) refers to a Spring-
specific FactoryBean implementation class.
Determining a Bean’s Runtime Type
The runtime type of a specific bean is non-trivial to determine. A specified class in the bean
metadata definition is just an initial class reference, potentially combined with a declared factory
method or being a FactoryBean class which may lead to a different runtime type of the bean, or not
being set at all in case of an instance-level factory method (which is resolved via the specified
factory-bean name instead). Additionally, AOP proxying may wrap a bean instance with an
interface-based proxy with limited exposure of the target bean’s actual type (just its implemented
interfaces).
The recommended way to find out about the actual runtime type of a particular bean is a
BeanFactory.getType call for the specified bean name. This takes all of the above cases into account
and returns the type of object that a BeanFactory.getBean call is going to return for the same bean
name.
2.1.4. Dependencies
A typical enterprise application does not consist of a single object (or bean in the Spring parlance).
Even the simplest application has a few objects that work together to present what the end-user
sees as a coherent application. This next section explains how you go from defining a number of
bean definitions that stand alone to a fully realized application where objects collaborate to achieve
a goal.
Dependency Injection
Dependency injection (DI) is a process whereby objects define their dependencies (that is, the other
objects with which they work) only through constructor arguments, arguments to a factory method,
or properties that are set on the object instance after it is constructed or returned from a factory
method. The container then injects those dependencies when it creates the bean. This process is
fundamentally the inverse (hence the name, Inversion of Control) of the bean itself controlling the
instantiation or location of its dependencies on its own by using direct construction of classes or the
Service Locator pattern.
Code is cleaner with the DI principle, and decoupling is more effective when objects are provided
with their dependencies. The object does not look up its dependencies and does not know the
location or class of the dependencies. As a result, your classes become easier to test, particularly
when the dependencies are on interfaces or abstract base classes, which allow for stub or mock
implementations to be used in unit tests.
DI exists in two major variants: Constructor-based dependency injection and Setter-based
dependency injection.
Constructor-based Dependency Injection
Constructor-based DI is accomplished by the container invoking a constructor with a number of
arguments, each representing a dependency. Calling a static factory method with specific
arguments to construct the bean is nearly equivalent, and this discussion treats arguments to a
constructor and to a static factory method similarly. The following example shows a class that can
only be dependency-injected with constructor injection:
Java
public class SimpleMovieLister {
// the SimpleMovieLister has a dependency on a MovieFinder
private final MovieFinder movieFinder;
// a constructor so that the Spring container can inject a MovieFinder
public SimpleMovieLister(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// business logic that actually uses the injected MovieFinder is omitted...
}
Kotlin
// a constructor so that the Spring container can inject a MovieFinder
class SimpleMovieLister(private val movieFinder: MovieFinder) {
// business logic that actually uses the injected MovieFinder is omitted...
}
Notice that there is nothing special about this class. It is a POJO that has no dependencies on
container specific interfaces, base classes, or annotations.
Constructor Argument Resolution
Constructor argument resolution matching occurs by using the argument’s type. If no potential
ambiguity exists in the constructor arguments of a bean definition, the order in which the
constructor arguments are defined in a bean definition is the order in which those arguments are
supplied to the appropriate constructor when the bean is being instantiated. Consider the following
class:
Java
package x.y;
public class ThingOne {
public ThingOne(ThingTwo thingTwo, ThingThree thingThree) {
// ...
}
}
Kotlin
package x.y
class ThingOne(thingTwo: ThingTwo, thingThree: ThingThree)
Assuming that the ThingTwo and ThingThree classes are not related by inheritance, no potential
ambiguity exists. Thus, the following configuration works fine, and you do not need to specify the
constructor argument indexes or types explicitly in the <constructor-arg/> element.
<constructor-arg ref="beanTwo"/>
<constructor-arg ref="beanThree"/>
When another bean is referenced, the type is known, and matching can occur (as was the case with
the preceding example). When a simple type is used, such as <value>true</value>, Spring cannot
determine the type of the value, and so cannot match by type without help. Consider the following
class:
Java
package examples;
public class ExampleBean {
// Number of years to calculate the Ultimate Answer
private final int years;
// The Answer to Life, the Universe, and Everything
private final String ultimateAnswer;
public ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
}
}
Kotlin
package examples
class ExampleBean(
private val years: Int, // Number of years to calculate the Ultimate Answer
private val ultimateAnswer: String // The Answer to Life, the Universe, and
Everything
)
Constructor argument type matching
In the preceding scenario, the container can use type matching with simple types if you explicitly
specify the type of the constructor argument by using the type attribute, as the following example
shows:
<constructor-arg type="int" value="7500000"/>
<constructor-arg type="java.lang.String" value="42"/>
Constructor argument index
You can use the index attribute to specify explicitly the index of constructor arguments, as the
following example shows:
<constructor-arg index="0" value="7500000"/>
<constructor-arg index="1" value="42"/>
In addition to resolving the ambiguity of multiple simple values, specifying an index resolves
ambiguity where a constructor has two arguments of the same type.
The index is 0-based.
Constructor argument name
You can also use the constructor parameter name for value disambiguation, as the following
example shows:
<constructor-arg name="years" value="7500000"/>
<constructor-arg name="ultimateAnswer" value="42"/>
Keep in mind that, to make this work out of the box, your code must be compiled with the debug
flag enabled so that Spring can look up the parameter name from the constructor. If you cannot or
do not want to compile your code with the debug flag, you can use the @ConstructorProperties JDK
annotation to explicitly name your constructor arguments. The sample class would then have to
look as follows:
Java
package examples;
public class ExampleBean {
// Fields omitted
@ConstructorProperties({"years", "ultimateAnswer"})
public ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
}
}
Kotlin
package examples
class ExampleBean
@ConstructorProperties("years", "ultimateAnswer")
constructor(val years: Int, val ultimateAnswer: String)
Setter-based Dependency Injection
Setter-based DI is accomplished by the container calling setter methods on your beans after
invoking a no-argument constructor or a no-argument static factory method to instantiate your
bean.
The following example shows a class that can only be dependency-injected by using pure setter
injection. This class is conventional Java. It is a POJO that has no dependencies on container specific
interfaces, base classes, or annotations.
Java
public class SimpleMovieLister {
// the SimpleMovieLister has a dependency on the MovieFinder
private MovieFinder movieFinder;
// a setter method so that the Spring container can inject a MovieFinder
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// business logic that actually uses the injected MovieFinder is omitted...
}
Kotlin
class SimpleMovieLister {
// a late-initialized property so that the Spring container can inject a
MovieFinder
lateinit var movieFinder: MovieFinder
// business logic that actually uses the injected MovieFinder is omitted...
}
The ApplicationContext supports constructor-based and setter-based DI for the beans it manages. It
also supports setter-based DI after some dependencies have already been injected through the
constructor approach. You configure the dependencies in the form of a BeanDefinition, which you
use in conjunction with PropertyEditor instances to convert properties from one format to another.
However, most Spring users do not work with these classes directly (that is, programmatically) but
rather with XML bean definitions, annotated components (that is, classes annotated with @Component,
@Controller, and so forth), or @Bean methods in Java-based @Configuration classes. These sources are
then converted internally into instances of BeanDefinition and used to load an entire Spring IoC
container instance.
Constructor-based or setter-based DI?
Since you can mix constructor-based and setter-based DI, it is a good rule of thumb to use
constructors for mandatory dependencies and setter methods or configuration methods for
optional dependencies. Note that use of the @Autowired annotation on a setter method can
be used to make the property be a required dependency; however, constructor injection with
programmatic validation of arguments is preferable.
The Spring team generally advocates constructor injection, as it lets you implement
application components as immutable objects and ensures that required dependencies are
not null. Furthermore, constructor-injected components are always returned to the client
(calling) code in a fully initialized state. As a side note, a large number of constructor
arguments is a bad code smell, implying that the class likely has too many responsibilities and
should be refactored to better address proper separation of concerns.
Setter injection should primarily only be used for optional dependencies that can be assigned
reasonable default values within the class. Otherwise, not-null checks must be performed
everywhere the code uses the dependency. One benefit of setter injection is that setter
methods make objects of that class amenable to reconfiguration or re-injection later.
Management through JMX MBeans is therefore a compelling use case for setter injection.
Use the DI style that makes the most sense for a particular class. Sometimes, when dealing
with third-party classes for which you do not have the source, the choice is made for you. For
example, if a third-party class does not expose any setter methods, then constructor injection
may be the only available form of DI.
Dependency Resolution Process
The container performs bean dependency resolution as follows:
• The ApplicationContext is created and initialized with configuration metadata that describes all
the beans. Configuration metadata can be specified by XML, Java code, or annotations.
• For each bean, its dependencies are expressed in the form of properties, constructor arguments,
or arguments to the static-factory method (if you use that instead of a normal constructor).
These dependencies are provided to the bean, when the bean is actually created.
• Each property or constructor argument is an actual definition of the value to set, or a reference
to another bean in the container.
• Each property or constructor argument that is a value is converted from its specified format to
the actual type of that property or constructor argument. By default, Spring can convert a value
supplied in string format to all built-in types, such as int, long, String, boolean, and so forth.
The Spring container validates the configuration of each bean as the container is created. However,
the bean properties themselves are not set until the bean is actually created. Beans that are
singleton-scoped and set to be pre-instantiated (the default) are created when the container is
created. Scopes are defined in Bean Scopes. Otherwise, the bean is created only when it is
requested. Creation of a bean potentially causes a graph of beans to be created, as the bean’s
dependencies and its dependencies' dependencies (and so on) are created and assigned. Note that
resolution mismatches among those dependencies may show up late — that is, on first creation of
the affected bean.
Circular dependencies
If you use predominantly constructor injection, it is possible to create an unresolvable
circular dependency scenario.
For example: Class A requires an instance of class B through constructor injection, and class B
requires an instance of class A through constructor injection. If you configure beans for
classes A and B to be injected into each other, the Spring IoC container detects this circular
reference at runtime, and throws a BeanCurrentlyInCreationException.
One possible solution is to edit the source code of some classes to be configured by setters
rather than constructors. Alternatively, avoid constructor injection and use setter injection
only. In other words, although it is not recommended, you can configure circular
dependencies with setter injection.
Unlike the typical case (with no circular dependencies), a circular dependency between bean
A and bean B forces one of the beans to be injected into the other prior to being fully
initialized itself (a classic chicken-and-egg scenario).
You can generally trust Spring to do the right thing. It detects configuration problems, such as
references to non-existent beans and circular dependencies, at container load-time. Spring sets
properties and resolves dependencies as late as possible, when the bean is actually created. This
means that a Spring container that has loaded correctly can later generate an exception when you
request an object if there is a problem creating that object or one of its dependencies — for
example, the bean throws an exception as a result of a missing or invalid property. This potentially
delayed visibility of some configuration issues is why ApplicationContext implementations by
default pre-instantiate singleton beans. At the cost of some upfront time and memory to create
these beans before they are actually needed, you discover configuration issues when the
ApplicationContext is created, not later. You can still override this default behavior so that singleton
beans initialize lazily, rather than being eagerly pre-instantiated.
If no circular dependencies exist, when one or more collaborating beans are being injected into a
dependent bean, each collaborating bean is totally configured prior to being injected into the
dependent bean. This means that, if bean A has a dependency on bean B, the Spring IoC container
completely configures bean B prior to invoking the setter method on bean A. In other words, the
bean is instantiated (if it is not a pre-instantiated singleton), its dependencies are set, and the
relevant lifecycle methods (such as a configured init method or the InitializingBean callback
method) are invoked.
Examples of Dependency Injection
The following example uses XML-based configuration metadata for setter-based DI. A small part of
a Spring XML configuration file specifies some bean definitions as follows:
<ref bean="anotherExampleBean"/>
The following example shows the corresponding ExampleBean class:
Java
public class ExampleBean {
private AnotherBean beanOne;
private YetAnotherBean beanTwo;
private int i;
public void setBeanOne(AnotherBean beanOne) {
this.beanOne = beanOne;
}
public void setBeanTwo(YetAnotherBean beanTwo) {
this.beanTwo = beanTwo;
}
public void setIntegerProperty(int i) {
this.i = i;
}
}
Kotlin
class ExampleBean {
lateinit var beanOne: AnotherBean
lateinit var beanTwo: YetAnotherBean
var i: Int = 0
}
In the preceding example, setters are declared to match against the properties specified in the XML
file. The following example uses constructor-based DI:
<constructor-arg>
<ref bean="anotherExampleBean"/>
</constructor-arg>
<constructor-arg ref="yetAnotherBean"/>
<constructor-arg type="int" value="1"/>
The following example shows the corresponding ExampleBean class:
Java
public class ExampleBean {
private AnotherBean beanOne;
private YetAnotherBean beanTwo;
private int i;
public ExampleBean(
AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
this.beanOne = anotherBean;
this.beanTwo = yetAnotherBean;
this.i = i;
}
}
Kotlin
class ExampleBean(
private val beanOne: AnotherBean,
private val beanTwo: YetAnotherBean,
private val i: Int)
The constructor arguments specified in the bean definition are used as arguments to the
constructor of the ExampleBean.
Now consider a variant of this example, where, instead of using a constructor, Spring is told to call
a static factory method to return an instance of the object:
<constructor-arg ref="anotherExampleBean"/>
<constructor-arg ref="yetAnotherBean"/>
<constructor-arg value="1"/>
The following example shows the corresponding ExampleBean class:
Java
public class ExampleBean {
// a private constructor
private ExampleBean(...) {
...
}
// a static factory method; the arguments to this method can be
// considered the dependencies of the bean that is returned,
// regardless of how those arguments are actually used.
public static ExampleBean createInstance (
AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
ExampleBean eb = new ExampleBean (...);
// some other operations...
return eb;
}
}
Kotlin
class ExampleBean private constructor() {
companion object {
// a static factory method; the arguments to this method can be
// considered the dependencies of the bean that is returned,
// regardless of how those arguments are actually used.
@JvmStatic
fun createInstance(anotherBean: AnotherBean, yetAnotherBean: YetAnotherBean,
i: Int): ExampleBean {
val eb = ExampleBean (...)
// some other operations...
return eb
}
}
}
Arguments to the static factory method are supplied by <constructor-arg/> elements, exactly the
same as if a constructor had actually been used. The type of the class being returned by the factory
method does not have to be of the same type as the class that contains the static factory method
(although, in this example, it is). An instance (non-static) factory method can be used in an
essentially identical fashion (aside from the use of the factory-bean attribute instead of the class
attribute), so we do not discuss those details here.
Dependencies and Configuration in Detail
As mentioned in the previous section, you can define bean properties and constructor arguments as
references to other managed beans (collaborators) or as values defined inline. Spring’s XML-based
configuration metadata supports sub-element types within its and <constructor-arg/>
elements for this purpose.
Straight Values (Primitives, Strings, and so on)
The value attribute of the element specifies a property or constructor argument as a
human-readable string representation. Spring’s conversion service is used to convert these values
from a String to the actual type of the property or argument. The following example shows various
values being set:
The following example uses the p-namespace for even more succinct XML configuration:
The preceding XML is more succinct. However, typos are discovered at runtime rather than design
time, unless you use an IDE (such as IntelliJ IDEA or the Spring Tools for Eclipse) that supports
automatic property completion when you create bean definitions. Such IDE assistance is highly
recommended.
You can also configure a java.util.Properties instance, as follows:
<value>
jdbc.driver.className=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mydb
</value>
The Spring container converts the text inside the <value/> element into a java.util.Properties
instance by using the JavaBeans PropertyEditor mechanism. This is a nice shortcut, and is one of a
few places where the Spring team do favor the use of the nested <value/> element over the value
attribute style.
The idref element
The idref element is simply an error-proof way to pass the id (a string value - not a reference) of
another bean in the container to a <constructor-arg/> or element. The following
example shows how to use it:
The preceding bean definition snippet is exactly equivalent (at runtime) to the following snippet:
The first form is preferable to the second, because using the idref tag lets the container validate at
deployment time that the referenced, named bean actually exists. In the second variation, no
validation is performed on the value that is passed to the targetName property of the client bean.
Typos are only discovered (with most likely fatal results) when the client bean is actually
instantiated. If the client bean is a prototype bean, this typo and the resulting exception may only
be discovered long after the container is deployed.
The local attribute on the idref element is no longer supported in the 4.0 beans
XSD, since it does not provide value over a regular bean reference any more.
Change your existing idref local references to idref bean when upgrading to the
4.0 schema.
A common place (at least in versions earlier than Spring 2.0) where the element brings
value is in the configuration of AOP interceptors in a ProxyFactoryBean bean definition. Using
elements when you specify the interceptor names prevents you from misspelling an
interceptor ID.
References to Other Beans (Collaborators)
The ref element is the final element inside a <constructor-arg/> or definition element.
Here, you set the value of the specified property of a bean to be a reference to another bean (a
collaborator) managed by the container. The referenced bean is a dependency of the bean whose
property is to be set, and it is initialized on demand as needed before the property is set. (If the
collaborator is a singleton bean, it may already be initialized by the container.) All references are
ultimately a reference to another object. Scoping and validation depend on whether you specify the
ID or name of the other object through the bean or parent attribute.
Specifying the target bean through the bean attribute of the <ref/> tag is the most general form and
allows creation of a reference to any bean in the same container or parent container, regardless of
whether it is in the same XML file. The value of the bean attribute may be the same as the id
attribute of the target bean or be the same as one of the values in the name attribute of the target
bean. The following example shows how to use a ref element:
<ref bean="someBean"/>
Specifying the target bean through the parent attribute creates a reference to a bean that is in a
parent container of the current container. The value of the parent attribute may be the same as
either the id attribute of the target bean or one of the values in the name attribute of the target bean.
The target bean must be in a parent container of the current one. You should use this bean
reference variant mainly when you have a hierarchy of containers and you want to wrap an
existing bean in a parent container with a proxy that has the same name as the parent bean. The
following pair of listings shows how to use the parent attribute:
<ref parent="accountService"/>
The local attribute on the ref element is no longer supported in the 4.0 beans XSD,
since it does not provide value over a regular bean reference any more. Change
your existing ref local references to ref bean when upgrading to the 4.0 schema.
Inner Beans
A element inside the or <constructor-arg/> elements defines an inner bean, as
the following example shows:
An inner bean definition does not require a defined ID or name. If specified, the container does not
use such a value as an identifier. The container also ignores the scope flag on creation, because
inner beans are always anonymous and are always created with the outer bean. It is not possible to
access inner beans independently or to inject them into collaborating beans other than into the
enclosing bean.
As a corner case, it is possible to receive destruction callbacks from a custom scope — for example,
for a request-scoped inner bean contained within a singleton bean. The creation of the inner bean
instance is tied to its containing bean, but destruction callbacks let it participate in the request
scope’s lifecycle. This is not a common scenario. Inner beans typically simply share their containing
bean’s scope.
Collections
The <list/>, <set/>, <map/>, and elements set the properties and arguments of the Java
Collection types List, Set, Map, and Properties, respectively. The following example shows how to
use them:
[email protected]
[email protected]
[email protected]
<list>
<value>a list element followed by a reference</value>
<ref bean="myDataSource" />
</list>
<map>
<entry key="an entry" value="just some string"/>
<entry key="a ref" value-ref="myDataSource"/>
</map>
<set>
<value>just some string</value>
<ref bean="myDataSource" />
</set>
The value of a map key or value, or a set value, can also be any of the following elements:
bean | ref | idref | list | set | map | props | value | null
Collection Merging
The Spring container also supports merging collections. An application developer can define a
parent <list/>, <map/>, <set/> or element and have child <list/>, <map/>, <set/> or
elements inherit and override values from the parent collection. That is, the child collection’s
values are the result of merging the elements of the parent and child collections, with the child’s
collection elements overriding values specified in the parent collection.
This section on merging discusses the parent-child bean mechanism. Readers unfamiliar with
parent and child bean definitions may wish to read the relevant section before continuing.
The following example demonstrates collection merging:
[email protected]
[email protected]
[email protected]
[email protected]
Notice the use of the merge=true attribute on the element of the adminEmails property of the
child bean definition. When the child bean is resolved and instantiated by the container, the
resulting instance has an adminEmails Properties collection that contains the result of merging the
child’s adminEmails collection with the parent’s adminEmails collection. The following listing shows
the result:
[email protected]
[email protected]
[email protected]
The child Properties collection’s value set inherits all property elements from the parent ,
and the child’s value for the support value overrides the value in the parent collection.
This merging behavior applies similarly to the <list/>, <map/>, and <set/> collection types. In the
specific case of the <list/> element, the semantics associated with the List collection type (that is,
the notion of an ordered collection of values) is maintained. The parent’s values precede all of the
child list’s values. In the case of the Map, Set, and Properties collection types, no ordering exists.
Hence, no ordering semantics are in effect for the collection types that underlie the associated Map,
Set, and Properties implementation types that the container uses internally.
Limitations of Collection Merging
You cannot merge different collection types (such as a Map and a List). If you do attempt to do so, an
appropriate Exception is thrown. The merge attribute must be specified on the lower, inherited, child
definition. Specifying the merge attribute on a parent collection definition is redundant and does not
result in the desired merging.
Strongly-typed collection
Thanks to Java’s support for generic types, you can use strongly typed collections. That is, it is
possible to declare a Collection type such that it can only contain (for example) String elements. If
you use Spring to dependency-inject a strongly-typed Collection into a bean, you can take
advantage of Spring’s type-conversion support such that the elements of your strongly-typed
Collection instances are converted to the appropriate type prior to being added to the Collection.
The following Java class and bean definition show how to do so:
Java
public class SomeClass {
private Map<String, Float> accounts;
public void setAccounts(Map<String, Float> accounts) {
this.accounts = accounts;
}
}
Kotlin
class SomeClass {
lateinit var accounts: Map<String, Float>
}
<map>
<entry key="one" value="9.99"/>
<entry key="two" value="2.75"/>
<entry key="six" value="3.99"/>
</map>
When the accounts property of the something bean is prepared for injection, the generics
information about the element type of the strongly-typed Map<String, Float> is available by
reflection. Thus, Spring’s type conversion infrastructure recognizes the various value elements as
being of type Float, and the string values (9.99, 2.75, and 3.99) are converted into an actual Float
type.
Null and Empty String Values
Spring treats empty arguments for properties and the like as empty Strings. The following XML-
based configuration metadata snippet sets the email property to the empty String value ("").
The preceding example is equivalent to the following Java code:
Java
exampleBean.setEmail("");
Kotlin
exampleBean.email = ""
The <null/> element handles null values. The following listing shows an example:
<null/>
The preceding configuration is equivalent to the following Java code:
Java
exampleBean.setEmail(null);
Kotlin
exampleBean.email = null
XML Shortcut with the p-namespace
The p-namespace lets you use the bean element’s attributes (instead of nested elements)
to describe your property values collaborating beans, or both.
Spring supports extensible configuration formats with namespaces, which are based on an XML
Schema definition. The beans configuration format discussed in this chapter is defined in an XML
Schema document. However, the p-namespace is not defined in an XSD file and exists only in the
core of Spring.
The following example shows two XML snippets (the first uses standard XML format and the
second uses the p-namespace) that resolve to the same result:
The example shows an attribute in the p-namespace called email in the bean definition. This tells
Spring to include a property declaration. As previously mentioned, the p-namespace does not have
a schema definition, so you can set the name of the attribute to the property name.
This next example includes two more bean definitions that both have a reference to another bean:
This example includes not only a property value using the p-namespace but also uses a special
format to declare property references. Whereas the first bean definition uses to create a reference from bean john to bean jane, the second bean
definition uses p:spouse-ref="jane" as an attribute to do the exact same thing. In this case, spouse is
the property name, whereas the -ref part indicates that this is not a straight value but rather a
reference to another bean.
The p-namespace is not as flexible as the standard XML format. For example, the
format for declaring property references clashes with properties that end in Ref,
whereas the standard XML format does not. We recommend that you choose your
approach carefully and communicate this to your team members to avoid
producing XML documents that use all three approaches at the same time.
XML Shortcut with the c-namespace
Similar to the XML Shortcut with the p-namespace, the c-namespace, introduced in Spring 3.1,
allows inlined attributes for configuring the constructor arguments rather then nested constructor-
arg elements.
The following example uses the c: namespace to do the same thing as the from Constructor-based
Dependency Injection:
<constructor-arg name="thingTwo" ref="beanTwo"/>
<constructor-arg name="thingThree" ref="beanThree"/>
<constructor-arg name="email" value="[email protected]"/>
The c: namespace uses the same conventions as the p: one (a trailing -ref for bean references) for
setting the constructor arguments by their names. Similarly, it needs to be declared in the XML file
even though it is not defined in an XSD schema (it exists inside the Spring core).
For the rare cases where the constructor argument names are not available (usually if the bytecode
was compiled without debugging information), you can use fallback to the argument indexes, as
follows:
Due to the XML grammar, the index notation requires the presence of the leading
_, as XML attribute names cannot start with a number (even though some IDEs
allow it). A corresponding index notation is also available for <constructor-arg>
elements but not commonly used since the plain order of declaration is usually
sufficient there.
In practice, the constructor resolution mechanism is quite efficient in matching arguments, so
unless you really need to, we recommend using the name notation throughout your configuration.
Compound Property Names
You can use compound or nested property names when you set bean properties, as long as all
components of the path except the final property name are not null. Consider the following bean
definition:
The something bean has a fred property, which has a bob property, which has a sammy property, and
that final sammy property is being set to a value of 123. In order for this to work, the fred property of
something and the bob property of fred must not be null after the bean is constructed. Otherwise, a
NullPointerException is thrown.
Using depends-on
If a bean is a dependency of another bean, that usually means that one bean is set as a property of
another. Typically you accomplish this with the <ref/> element in XML-based configuration
metadata. However, sometimes dependencies between beans are less direct. An example is when a
static initializer in a class needs to be triggered, such as for database driver registration. The
depends-on attribute can explicitly force one or more beans to be initialized before the bean using
this element is initialized. The following example uses the depends-on attribute to express a
dependency on a single bean:
To express a dependency on multiple beans, supply a list of bean names as the value of the depends-
on attribute (commas, whitespace, and semicolons are valid delimiters):
The depends-on attribute can specify both an initialization-time dependency and, in
the case of singleton beans only, a corresponding destruction-time dependency.
Dependent beans that define a depends-on relationship with a given bean are
destroyed first, prior to the given bean itself being destroyed. Thus, depends-on can
also control shutdown order.
Lazy-initialized Beans
By default, ApplicationContext implementations eagerly create and configure all singleton beans as
part of the initialization process. Generally, this pre-instantiation is desirable, because errors in the
configuration or surrounding environment are discovered immediately, as opposed to hours or
even days later. When this behavior is not desirable, you can prevent pre-instantiation of a
singleton bean by marking the bean definition as being lazy-initialized. A lazy-initialized bean tells
the IoC container to create a bean instance when it is first requested, rather than at startup.
In XML, this behavior is controlled by the lazy-init attribute on the element, as the
following example shows:
When the preceding configuration is consumed by an ApplicationContext, the lazy bean is not
eagerly pre-instantiated when the ApplicationContext starts, whereas the not.lazy bean is eagerly
pre-instantiated.
However, when a lazy-initialized bean is a dependency of a singleton bean that is not lazy-
initialized, the ApplicationContext creates the lazy-initialized bean at startup, because it must
satisfy the singleton’s dependencies. The lazy-initialized bean is injected into a singleton bean
elsewhere that is not lazy-initialized.
You can also control lazy-initialization at the container level by using the default-lazy-init
attribute on the element, as the following example shows:
Autowiring Collaborators
The Spring container can autowire relationships between collaborating beans. You can let Spring
resolve collaborators (other beans) automatically for your bean by inspecting the contents of the
ApplicationContext. Autowiring has the following advantages:
• Autowiring can significantly reduce the need to specify properties or constructor arguments.
(Other mechanisms such as a bean template discussed elsewhere in this chapter are also
valuable in this regard.)
• Autowiring can update a configuration as your objects evolve. For example, if you need to add a
dependency to a class, that dependency can be satisfied automatically without you needing to
modify the configuration. Thus autowiring can be especially useful during development,
without negating the option of switching to explicit wiring when the code base becomes more
stable.
When using XML-based configuration metadata (see Dependency Injection), you can specify the
autowire mode for a bean definition with the autowire attribute of the element. The
autowiring functionality has four modes. You specify autowiring per bean and can thus choose
which ones to autowire. The following table describes the four autowiring modes:
Table 2. Autowiring modes
Mode Explanation
no (Default) No autowiring. Bean references must be defined by ref elements.
Changing the default setting is not recommended for larger deployments,
because specifying collaborators explicitly gives greater control and clarity. To
some extent, it documents the structure of a system.
byName Autowiring by property name. Spring looks for a bean with the same name as
the property that needs to be autowired. For example, if a bean definition is
set to autowire by name and it contains a master property (that is, it has a
setMaster(..) method), Spring looks for a bean definition named master and
uses it to set the property.
byType Lets a property be autowired if exactly one bean of the property type exists in
the container. If more than one exists, a fatal exception is thrown, which
indicates that you may not use byType autowiring for that bean. If there are no
matching beans, nothing happens (the property is not set).
constructor Analogous to byType but applies to constructor arguments. If there is not
exactly one bean of the constructor argument type in the container, a fatal
error is raised.
With byType or constructor autowiring mode, you can wire arrays and typed collections. In such
cases, all autowire candidates within the container that match the expected type are provided to
satisfy the dependency. You can autowire strongly-typed Map instances if the expected key type is
String. An autowired Map instance’s values consist of all bean instances that match the expected
type, and the Map instance’s keys contain the corresponding bean names.
Limitations and Disadvantages of Autowiring
Autowiring works best when it is used consistently across a project. If autowiring is not used in
general, it might be confusing to developers to use it to wire only one or two bean definitions.
Consider the limitations and disadvantages of autowiring:
• Explicit dependencies in property and constructor-arg settings always override autowiring. You
cannot autowire simple properties such as primitives, Strings, and Classes (and arrays of such
simple properties). This limitation is by-design.
• Autowiring is less exact than explicit wiring. Although, as noted in the earlier table, Spring is
careful to avoid guessing in case of ambiguity that might have unexpected results. The
relationships between your Spring-managed objects are no longer documented explicitly.
• Wiring information may not be available to tools that may generate documentation from a
Spring container.
• Multiple bean definitions within the container may match the type specified by the setter
method or constructor argument to be autowired. For arrays, collections, or Map instances, this is
not necessarily a problem. However, for dependencies that expect a single value, this ambiguity
is not arbitrarily resolved. If no unique bean definition is available, an exception is thrown.
In the latter scenario, you have several options:
• Abandon autowiring in favor of explicit wiring.
• Avoid autowiring for a bean definition by setting its autowire-candidate attributes to false, as
described in the next section.
• Designate a single bean definition as the primary candidate by setting the primary attribute of its
element to true.
• Implement the more fine-grained control available with annotation-based configuration, as
described in Annotation-based Container Configuration.
Excluding a Bean from Autowiring
On a per-bean basis, you can exclude a bean from autowiring. In Spring’s XML format, set the
autowire-candidate attribute of the element to false. The container makes that specific bean
definition unavailable to the autowiring infrastructure (including annotation style configurations
such as @Autowired).
The autowire-candidate attribute is designed to only affect type-based autowiring.
It does not affect explicit references by name, which get resolved even if the
specified bean is not marked as an autowire candidate. As a consequence,
autowiring by name nevertheless injects a bean if the name matches.
You can also limit autowire candidates based on pattern-matching against bean names. The top-
level element accepts one or more patterns within its default-autowire-candidates
attribute. For example, to limit autowire candidate status to any bean whose name ends with
Repository, provide a value of *Repository. To provide multiple patterns, define them in a comma-
separated list. An explicit value of true or false for a bean definition’s autowire-candidate attribute
always takes precedence. For such beans, the pattern matching rules do not apply.
These techniques are useful for beans that you never want to be injected into other beans by
autowiring. It does not mean that an excluded bean cannot itself be configured by using
autowiring. Rather, the bean itself is not a candidate for autowiring other beans.
Method Injection
In most application scenarios, most beans in the container are singletons. When a singleton bean
needs to collaborate with another singleton bean or a non-singleton bean needs to collaborate with
another non-singleton bean, you typically handle the dependency by defining one bean as a
property of the other. A problem arises when the bean lifecycles are different. Suppose singleton
bean A needs to use non-singleton (prototype) bean B, perhaps on each method invocation on A.
The container creates the singleton bean A only once, and thus only gets one opportunity to set the
properties. The container cannot provide bean A with a new instance of bean B every time one is
needed.
A solution is to forego some inversion of control. You can make bean A aware of the container by
implementing the ApplicationContextAware interface, and by making a getBean("B") call to the
container ask for (a typically new) bean B instance every time bean A needs it. The following
example shows this approach:
Java
// a class that uses a stateful Command-style class to perform some processing
package fiona.apple;
// Spring-API imports
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class CommandManager implements ApplicationContextAware {
private ApplicationContext applicationContext;
public Object process(Map commandState) {
// grab a new instance of the appropriate Command
Command command = createCommand();
// set the state on the (hopefully brand new) Command instance
command.setState(commandState);
return command.execute();
}
protected Command createCommand() {
// notice the Spring API dependency!
return this.applicationContext.getBean("command", Command.class);
}
public void setApplicationContext(
ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
Kotlin
// a class that uses a stateful Command-style class to perform some processing
package fiona.apple
// Spring-API imports
import org.springframework.context.ApplicationContext
import org.springframework.context.ApplicationContextAware
class CommandManager : ApplicationContextAware {
private lateinit var applicationContext: ApplicationContext
fun process(commandState: Map<, >): Any {
// grab a new instance of the appropriate Command
val command = createCommand()
// set the state on the (hopefully brand new) Command instance
command.state = commandState
return command.execute()
}
// notice the Spring API dependency!
protected fun createCommand() =
applicationContext.getBean("command", Command::class.java)
override fun setApplicationContext(applicationContext: ApplicationContext) {
this.applicationContext = applicationContext
}
}
The preceding is not desirable, because the business code is aware of and coupled to the Spring
Framework. Method Injection, a somewhat advanced feature of the Spring IoC container, lets you
handle this use case cleanly.
You can read more about the motivation for Method Injection in this blog entry.
Lookup Method Injection
Lookup method injection is the ability of the container to override methods on container-managed
beans and return the lookup result for another named bean in the container. The lookup typically
involves a prototype bean, as in the scenario described in the preceding section. The Spring
Framework implements this method injection by using bytecode generation from the CGLIB library
to dynamically generate a subclass that overrides the method.
• For this dynamic subclassing to work, the class that the Spring bean container
subclasses cannot be final, and the method to be overridden cannot be final,
either.
• Unit-testing a class that has an abstract method requires you to subclass the
class yourself and to supply a stub implementation of the abstract method.
• Concrete methods are also necessary for component scanning, which requires
concrete classes to pick up.
• A further key limitation is that lookup methods do not work with factory
methods and in particular not with @Bean methods in configuration classes,
since, in that case, the container is not in charge of creating the instance and
therefore cannot create a runtime-generated subclass on the fly.
In the case of the CommandManager class in the previous code snippet, the Spring container
dynamically overrides the implementation of the createCommand() method. The CommandManager class
does not have any Spring dependencies, as the reworked example shows:
Java
package fiona.apple;
// no more Spring imports!
public abstract class CommandManager {
public Object process(Object commandState) {
// grab a new instance of the appropriate Command interface
Command command = createCommand();
// set the state on the (hopefully brand new) Command instance
command.setState(commandState);
return command.execute();
}
// okay... but where is the implementation of this method?
protected abstract Command createCommand();
}
Kotlin
package fiona.apple
// no more Spring imports!
abstract class CommandManager {
fun process(commandState: Any): Any {
// grab a new instance of the appropriate Command interface
val command = createCommand()
// set the state on the (hopefully brand new) Command instance
command.state = commandState
return command.execute()
}
// okay... but where is the implementation of this method?
protected abstract fun createCommand(): Command
}
In the client class that contains the method to be injected (the CommandManager in this case), the
method to be injected requires a signature of the following form:
[abstract] <return-type> theMethodName(no-arguments);
If the method is abstract, the dynamically-generated subclass implements the method. Otherwise,
the dynamically-generated subclass overrides the concrete method defined in the original class.
Consider the following example:
<lookup-method name="createCommand" bean="myCommand"/>
The bean identified as commandManager calls its own createCommand() method whenever it needs a
new instance of the myCommand bean. You must be careful to deploy the myCommand bean as a prototype
if that is actually what is needed. If it is a singleton, the same instance of the myCommand bean is
returned each time.
Alternatively, within the annotation-based component model, you can declare a lookup method
through the @Lookup annotation, as the following example shows:
Java
public abstract class CommandManager {
public Object process(Object commandState) {
Command command = createCommand();
command.setState(commandState);
return command.execute();
}
@Lookup("myCommand")
protected abstract Command createCommand();
}
Kotlin
abstract class CommandManager {
fun process(commandState: Any): Any {
val command = createCommand()
command.state = commandState
return command.execute()
}
@Lookup("myCommand")
protected abstract fun createCommand(): Command
}
Or, more idiomatically, you can rely on the target bean getting resolved against the declared return
type of the lookup method:
Java
public abstract class CommandManager {
public Object process(Object commandState) {
Command command = createCommand();
command.setState(commandState);
return command.execute();
}
@Lookup
protected abstract Command createCommand();
}
Kotlin
abstract class CommandManager {
fun process(commandState: Any): Any {
val command = createCommand()
command.state = commandState
return command.execute()
}
@Lookup
protected abstract fun createCommand(): Command
}
Note that you should typically declare such annotated lookup methods with a concrete stub
implementation, in order for them to be compatible with Spring’s component scanning rules where
abstract classes get ignored by default. This limitation does not apply to explicitly registered or
explicitly imported bean classes.
Another way of accessing differently scoped target beans is an ObjectFactory/
Provider injection point. See Scoped Beans as Dependencies.
You may also find the ServiceLocatorFactoryBean (in the
org.springframework.beans.factory.config package) to be useful.
Arbitrary Method Replacement
A less useful form of method injection than lookup method injection is the ability to replace
arbitrary methods in a managed bean with another method implementation. You can safely skip
the rest of this section until you actually need this functionality.
With XML-based configuration metadata, you can use the replaced-method element to replace an
existing method implementation with another, for a deployed bean. Consider the following class,
which has a method called computeValue that we want to override:
Java
public class MyValueCalculator {
public String computeValue(String input) {
// some real code...
}
// some other methods...
}
Kotlin
class MyValueCalculator {
fun computeValue(input: String): String {
// some real code...
}
// some other methods...
}
A class that implements the org.springframework.beans.factory.support.MethodReplacer interface
provides the new method definition, as the following example shows:
Java
/
* meant to be used to override the existing computeValue(String)
* implementation in MyValueCalculator
*/
public class ReplacementComputeValue implements MethodReplacer {
public Object reimplement(Object o, Method m, Object[] args) throws Throwable {
// get the input value, work with it, and return a computed result
String input = (String) args[0];
...
return ...;
}
}
Kotlin
/
* meant to be used to override the existing computeValue(String)
* implementation in MyValueCalculator
*/
class ReplacementComputeValue : MethodReplacer {
override fun reimplement(obj: Any, method: Method, args: Array<out Any>): Any {
// get the input value, work with it, and return a computed result
val input = args[0] as String;
...
return ...;
}
}
The bean definition to deploy the original class and specify the method override would resemble
the following example:
<replaced-method name="computeValue" replacer="replacementComputeValue">
<arg-type>String</arg-type>
</replaced-method>
You can use one or more <arg-type/> elements within the <replaced-method/> element to indicate
the method signature of the method being overridden. The signature for the arguments is
necessary only if the method is overloaded and multiple variants exist within the class. For
convenience, the type string for an argument may be a substring of the fully qualified type name.
For example, the following all match java.lang.String:
java.lang.String
String
Str
Because the number of arguments is often enough to distinguish between each possible choice, this
shortcut can save a lot of typing, by letting you type only the shortest string that matches an
argument type.
2.1.5. Bean Scopes
When you create a bean definition, you create a recipe for creating actual instances of the class
defined by that bean definition. The idea that a bean definition is a recipe is important, because it
means that, as with a class, you can create many object instances from a single recipe.
You can control not only the various dependencies and configuration values that are to be plugged
into an object that is created from a particular bean definition but also control the scope of the
objects created from a particular bean definition. This approach is powerful and flexible, because
you can choose the scope of the objects you create through configuration instead of having to bake
in the scope of an object at the Java class level. Beans can be defined to be deployed in one of a
number of scopes. The Spring Framework supports six scopes, four of which are available only if
you use a web-aware ApplicationContext. You can also create a custom scope.
The following table describes the supported scopes:
Table 3. Bean scopes
Scope Description
singleton (Default) Scopes a single bean definition to a single object instance for each
Spring IoC container.
prototype Scopes a single bean definition to any number of object instances.
Scope Description
request Scopes a single bean definition to the lifecycle of a single HTTP request. That
is, each HTTP request has its own instance of a bean created off the back of a
single bean definition. Only valid in the context of a web-aware Spring
ApplicationContext.
session Scopes a single bean definition to the lifecycle of an HTTP Session. Only valid
in the context of a web-aware Spring ApplicationContext.
application Scopes a single bean definition to the lifecycle of a ServletContext. Only valid
in the context of a web-aware Spring ApplicationContext.
websocket Scopes a single bean definition to the lifecycle of a WebSocket. Only valid in the
context of a web-aware Spring ApplicationContext.
As of Spring 3.0, a thread scope is available but is not registered by default. For
more information, see the documentation for SimpleThreadScope. For instructions
on how to register this or any other custom scope, see Using a Custom Scope.
The Singleton Scope
Only one shared instance of a singleton bean is managed, and all requests for beans with an ID or
IDs that match that bean definition result in that one specific bean instance being returned by the
Spring container.
To put it another way, when you define a bean definition and it is scoped as a singleton, the Spring
IoC container creates exactly one instance of the object defined by that bean definition. This single
instance is stored in a cache of such singleton beans, and all subsequent requests and references
for that named bean return the cached object. The following image shows how the singleton scope
works:
Spring’s concept of a singleton bean differs from the singleton pattern as defined in the Gang of
Four (GoF) patterns book. The GoF singleton hard-codes the scope of an object such that one and
only one instance of a particular class is created per ClassLoader. The scope of the Spring singleton
is best described as being per-container and per-bean. This means that, if you define one bean for a
particular class in a single Spring container, the Spring container creates one and only one instance
of the class defined by that bean definition. The singleton scope is the default scope in Spring. To
define a bean as a singleton in XML, you can define a bean as shown in the following example:
The Prototype Scope
The non-singleton prototype scope of bean deployment results in the creation of a new bean
instance every time a request for that specific bean is made. That is, the bean is injected into
another bean or you request it through a getBean() method call on the container. As a rule, you
should use the prototype scope for all stateful beans and the singleton scope for stateless beans.
The following diagram illustrates the Spring prototype scope:
(A data access object (DAO) is not typically configured as a prototype, because a typical DAO does
not hold any conversational state. It was easier for us to reuse the core of the singleton diagram.)
The following example defines a bean as a prototype in XML:
In contrast to the other scopes, Spring does not manage the complete lifecycle of a prototype bean.
The container instantiates, configures, and otherwise assembles a prototype object and hands it to
the client, with no further record of that prototype instance. Thus, although initialization lifecycle
callback methods are called on all objects regardless of scope, in the case of prototypes, configured
destruction lifecycle callbacks are not called. The client code must clean up prototype-scoped
objects and release expensive resources that the prototype beans hold. To get the Spring container
to release resources held by prototype-scoped beans, try using a custom bean post-processor, which
holds a reference to beans that need to be cleaned up.
In some respects, the Spring container’s role in regard to a prototype-scoped bean is a replacement
for the Java new operator. All lifecycle management past that point must be handled by the client.
(For details on the lifecycle of a bean in the Spring container, see Lifecycle Callbacks.)
Singleton Beans with Prototype-bean Dependencies
When you use singleton-scoped beans with dependencies on prototype beans, be aware that
dependencies are resolved at instantiation time. Thus, if you dependency-inject a prototype-scoped
bean into a singleton-scoped bean, a new prototype bean is instantiated and then dependency-
injected into the singleton bean. The prototype instance is the sole instance that is ever supplied to
the singleton-scoped bean.
However, suppose you want the singleton-scoped bean to acquire a new instance of the prototype-
scoped bean repeatedly at runtime. You cannot dependency-inject a prototype-scoped bean into
your singleton bean, because that injection occurs only once, when the Spring container
instantiates the singleton bean and resolves and injects its dependencies. If you need a new
instance of a prototype bean at runtime more than once, see Method Injection.
Request, Session, Application, and WebSocket Scopes
The request, session, application, and websocket scopes are available only if you use a web-aware
Spring ApplicationContext implementation (such as XmlWebApplicationContext). If you use these
scopes with regular Spring IoC containers, such as the ClassPathXmlApplicationContext, an
IllegalStateException that complains about an unknown bean scope is thrown.
Initial Web Configuration
To support the scoping of beans at the request, session, application, and websocket levels (web-
scoped beans), some minor initial configuration is required before you define your beans. (This
initial setup is not required for the standard scopes: singleton and prototype.)
How you accomplish this initial setup depends on your particular Servlet environment.
If you access scoped beans within Spring Web MVC, in effect, within a request that is processed by
the Spring DispatcherServlet, no special setup is necessary. DispatcherServlet already exposes all
relevant state.
If you use a Servlet web container, with requests processed outside of Spring’s DispatcherServlet
(for example, when using JSF or Struts), you need to register the
org.springframework.web.context.request.RequestContextListener ServletRequestListener. This can
be done programmatically by using the WebApplicationInitializer interface. Alternatively, add the
following declaration to your web application’s web.xml file:
<web-app>
...
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
...
</web-app>
Alternatively, if there are issues with your listener setup, consider using Spring’s
RequestContextFilter. The filter mapping depends on the surrounding web application
configuration, so you have to change it as appropriate. The following listing shows the filter part of
a web application:
<web-app>
...
<filter>
<filter-name>requestContextFilter</filter-name>
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-
class>
</filter>
<filter-mapping>
<filter-name>requestContextFilter</filter-name>
/*
</filter-mapping>
...
</web-app>
DispatcherServlet, RequestContextListener, and RequestContextFilter all do exactly the same thing,
namely bind the HTTP request object to the Thread that is servicing that request. This makes beans
that are request- and session-scoped available further down the call chain.
Request scope
Consider the following XML configuration for a bean definition:
The Spring container creates a new instance of the LoginAction bean by using the loginAction bean
definition for each and every HTTP request. That is, the loginAction bean is scoped at the HTTP
request level. You can change the internal state of the instance that is created as much as you want,
because other instances created from the same loginAction bean definition do not see these
changes in state. They are particular to an individual request. When the request completes
processing, the bean that is scoped to the request is discarded.
When using annotation-driven components or Java configuration, the @RequestScope annotation can
be used to assign a component to the request scope. The following example shows how to do so:
Java
@RequestScope
@Component
public class LoginAction {
// ...
}
Kotlin
@RequestScope
@Component
class LoginAction {
// ...
}
Session Scope
Consider the following XML configuration for a bean definition:
The Spring container creates a new instance of the UserPreferences bean by using the
userPreferences bean definition for the lifetime of a single HTTP Session. In other words, the
userPreferences bean is effectively scoped at the HTTP Session level. As with request-scoped beans,
you can change the internal state of the instance that is created as much as you want, knowing that
other HTTP Session instances that are also using instances created from the same userPreferences
bean definition do not see these changes in state, because they are particular to an individual HTTP
Session. When the HTTP Session is eventually discarded, the bean that is scoped to that particular
HTTP Session is also discarded.
When using annotation-driven components or Java configuration, you can use the @SessionScope
annotation to assign a component to the session scope.
Java
@SessionScope
@Component
public class UserPreferences {
// ...
}
Kotlin
@SessionScope
@Component
class UserPreferences {
// ...
}
Application Scope
Consider the following XML configuration for a bean definition:
The Spring container creates a new instance of the AppPreferences bean by using the appPreferences
bean definition once for the entire web application. That is, the appPreferences bean is scoped at the
ServletContext level and stored as a regular ServletContext attribute. This is somewhat similar to a
Spring singleton bean but differs in two important ways: It is a singleton per ServletContext, not per
Spring ApplicationContext (for which there may be several in any given web application), and it is
actually exposed and therefore visible as a ServletContext attribute.
When using annotation-driven components or Java configuration, you can use the
@ApplicationScope annotation to assign a component to the application scope. The following
example shows how to do so:
Java
@ApplicationScope
@Component
public class AppPreferences {
// ...
}
Kotlin
@ApplicationScope
@Component
class AppPreferences {
// ...
}
WebSocket Scope
WebSocket scope is associated with the lifecycle of a WebSocket session and applies to STOMP over
WebSocket applications, see WebSocket scope for more details.
Scoped Beans as Dependencies
The Spring IoC container manages not only the instantiation of your objects (beans), but also the
wiring up of collaborators (or dependencies). If you want to inject (for example) an HTTP request-
scoped bean into another bean of a longer-lived scope, you may choose to inject an AOP proxy in
place of the scoped bean. That is, you need to inject a proxy object that exposes the same public
interface as the scoped object but that can also retrieve the real target object from the relevant
scope (such as an HTTP request) and delegate method calls onto the real object.
You may also use <aop:scoped-proxy/> between beans that are scoped as singleton,
with the reference then going through an intermediate proxy that is serializable
and therefore able to re-obtain the target singleton bean on deserialization.
When declaring <aop:scoped-proxy/> against a bean of scope prototype, every
method call on the shared proxy leads to the creation of a new target instance to
which the call is then being forwarded.
Also, scoped proxies are not the only way to access beans from shorter scopes in a
lifecycle-safe fashion. You may also declare your injection point (that is, the
constructor or setter argument or autowired field) as ObjectFactory<MyTargetBean>,
allowing for a getObject() call to retrieve the current instance on demand every
time it is needed — without holding on to the instance or storing it separately.
As an extended variant, you may declare ObjectProvider<MyTargetBean> which
delivers several additional access variants, including getIfAvailable and
getIfUnique.
The JSR-330 variant of this is called Provider and is used with a
Provider<MyTargetBean> declaration and a corresponding get() call for every
retrieval attempt. See here for more details on JSR-330 overall.
The configuration in the following example is only one line, but it is important to understand the
“why” as well as the “how” behind it:
<?xml version="1.0" encoding="UTF-8"?>
<aop:scoped-proxy/> ①
① The line that defines the proxy.
To create such a proxy, you insert a child <aop:scoped-proxy/> element into a scoped bean definition
(see Choosing the Type of Proxy to Create and XML Schema-based configuration). Why do
definitions of beans scoped at the request, session and custom-scope levels require the <aop:scoped-
proxy/> element? Consider the following singleton bean definition and contrast it with what you
need to define for the aforementioned scopes (note that the following userPreferences bean
definition as it stands is incomplete):
In the preceding example, the singleton bean (userManager) is injected with a reference to the HTTP
Session-scoped bean (userPreferences). The salient point here is that the userManager bean is a
singleton: it is instantiated exactly once per container, and its dependencies (in this case only one,
the userPreferences bean) are also injected only once. This means that the userManager bean
operates only on the exact same userPreferences object (that is, the one with which it was originally
injected).
This is not the behavior you want when injecting a shorter-lived scoped bean into a longer-lived
scoped bean (for example, injecting an HTTP Session-scoped collaborating bean as a dependency
into singleton bean). Rather, you need a single userManager object, and, for the lifetime of an HTTP
Session, you need a userPreferences object that is specific to the HTTP Session. Thus, the container
creates an object that exposes the exact same public interface as the UserPreferences class (ideally
an object that is a UserPreferences instance), which can fetch the real UserPreferences object from
the scoping mechanism (HTTP request, Session, and so forth). The container injects this proxy
object into the userManager bean, which is unaware that this UserPreferences reference is a proxy. In
this example, when a UserManager instance invokes a method on the dependency-injected
UserPreferences object, it is actually invoking a method on the proxy. The proxy then fetches the
real UserPreferences object from (in this case) the HTTP Session and delegates the method
invocation onto the retrieved real UserPreferences object.
Thus, you need the following (correct and complete) configuration when injecting request- and
session-scoped beans into collaborating objects, as the following example shows:
<aop:scoped-proxy/>
Choosing the Type of Proxy to Create
By default, when the Spring container creates a proxy for a bean that is marked up with the
<aop:scoped-proxy/> element, a CGLIB-based class proxy is created.
CGLIB proxies intercept only public method calls! Do not call non-public methods
on such a proxy. They are not delegated to the actual scoped target object.
Alternatively, you can configure the Spring container to create standard JDK interface-based
proxies for such scoped beans, by specifying false for the value of the proxy-target-class attribute
of the <aop:scoped-proxy/> element. Using JDK interface-based proxies means that you do not need
additional libraries in your application classpath to affect such proxying. However, it also means
that the class of the scoped bean must implement at least one interface and that all collaborators
into which the scoped bean is injected must reference the bean through one of its interfaces. The
following example shows a proxy based on an interface:
<aop:scoped-proxy proxy-target-class="false"/>
For more detailed information about choosing class-based or interface-based proxying, see
Proxying Mechanisms.
Custom Scopes
The bean scoping mechanism is extensible. You can define your own scopes or even redefine
existing scopes, although the latter is considered bad practice and you cannot override the built-in
singleton and prototype scopes.
Creating a Custom Scope
To integrate your custom scopes into the Spring container, you need to implement the
org.springframework.beans.factory.config.Scope interface, which is described in this section. For an
idea of how to implement your own scopes, see the Scope implementations that are supplied with
the Spring Framework itself and the Scope javadoc, which explains the methods you need to
implement in more detail.
The Scope interface has four methods to get objects from the scope, remove them from the scope,
and let them be destroyed.
The session scope implementation, for example, returns the session-scoped bean (if it does not
exist, the method returns a new instance of the bean, after having bound it to the session for future
reference). The following method returns the object from the underlying scope:
Java
Object get(String name, ObjectFactory<?> objectFactory)
Kotlin
fun get(name: String, objectFactory: ObjectFactory<*>): Any
The session scope implementation, for example, removes the session-scoped bean from the
underlying session. The object should be returned, but you can return null if the object with the
specified name is not found. The following method removes the object from the underlying scope:
Java
Object remove(String name)
Kotlin
fun remove(name: String): Any
The following method registers a callback that the scope should invoke when it is destroyed or
when the specified object in the scope is destroyed:
Java
void registerDestructionCallback(String name, Runnable destructionCallback)
Kotlin
fun registerDestructionCallback(name: String, destructionCallback: Runnable)
See the javadoc or a Spring scope implementation for more information on destruction callbacks.
The following method obtains the conversation identifier for the underlying scope:
Java
String getConversationId()
Kotlin
fun getConversationId(): String
This identifier is different for each scope. For a session scoped implementation, this identifier can
be the session identifier.
Using a Custom Scope
After you write and test one or more custom Scope implementations, you need to make the Spring
container aware of your new scopes. The following method is the central method to register a new
Scope with the Spring container:
Java
void registerScope(String scopeName, Scope scope);
Kotlin
fun registerScope(scopeName: String, scope: Scope)
This method is declared on the ConfigurableBeanFactory interface, which is available through the
BeanFactory property on most of the concrete ApplicationContext implementations that ship with
Spring.
The first argument to the registerScope(..) method is the unique name associated with a scope.
Examples of such names in the Spring container itself are singleton and prototype. The second
argument to the registerScope(..) method is an actual instance of the custom Scope
implementation that you wish to register and use.
Suppose that you write your custom Scope implementation, and then register it as shown in the
next example.
The next example uses SimpleThreadScope, which is included with Spring but is not
registered by default. The instructions would be the same for your own custom
Scope implementations.
Java
Scope threadScope = new SimpleThreadScope();
beanFactory.registerScope("thread", threadScope);
Kotlin
val threadScope = SimpleThreadScope()
beanFactory.registerScope("thread", threadScope)
You can then create bean definitions that adhere to the scoping rules of your custom Scope, as
follows:
With a custom Scope implementation, you are not limited to programmatic registration of the scope.
You can also do the Scope registration declaratively, by using the CustomScopeConfigurer class, as the
following example shows:
<?xml version="1.0" encoding="UTF-8"?>
<map>
<entry key="thread">
</entry>
</map>
<aop:scoped-proxy/>
When you place <aop:scoped-proxy/> within a declaration for a FactoryBean
implementation, it is the factory bean itself that is scoped, not the object returned
from getObject().
2.1.6. Customizing the Nature of a Bean
The Spring Framework provides a number of interfaces you can use to customize the nature of a
bean. This section groups them as follows:
• Lifecycle Callbacks
• ApplicationContextAware and BeanNameAware
• Other Aware Interfaces
Lifecycle Callbacks
To interact with the container’s management of the bean lifecycle, you can implement the Spring
InitializingBean and DisposableBean interfaces. The container calls afterPropertiesSet() for the
former and destroy() for the latter to let the bean perform certain actions upon initialization and
destruction of your beans.
The JSR-250 @PostConstruct and @PreDestroy annotations are generally considered
best practice for receiving lifecycle callbacks in a modern Spring application. Using
these annotations means that your beans are not coupled to Spring-specific
interfaces. For details, see Using @PostConstruct and @PreDestroy.
If you do not want to use the JSR-250 annotations but you still want to remove
coupling, consider init-method and destroy-method bean definition metadata.
Internally, the Spring Framework uses BeanPostProcessor implementations to process any callback
interfaces it can find and call the appropriate methods. If you need custom features or other
lifecycle behavior Spring does not by default offer, you can implement a BeanPostProcessor yourself.
For more information, see Container Extension Points.
In addition to the initialization and destruction callbacks, Spring-managed objects may also
implement the Lifecycle interface so that those objects can participate in the startup and shutdown
process, as driven by the container’s own lifecycle.
The lifecycle callback interfaces are described in this section.
Initialization Callbacks
The org.springframework.beans.factory.InitializingBean interface lets a bean perform
initialization work after the container has set all necessary properties on the bean. The
InitializingBean interface specifies a single method:
void afterPropertiesSet() throws Exception;
We recommend that you do not use the InitializingBean interface, because it unnecessarily couples
the code to Spring. Alternatively, we suggest using the @PostConstruct annotation or specifying a
POJO initialization method. In the case of XML-based configuration metadata, you can use the init-
method attribute to specify the name of the method that has a void no-argument signature. With
Java configuration, you can use the initMethod attribute of @Bean. See Receiving Lifecycle Callbacks.
Consider the following example:
Java
public class ExampleBean {
public void init() {
// do some initialization work
}
}
Kotlin
class ExampleBean {
fun init() {
// do some initialization work
}
}
The preceding example has almost exactly the same effect as the following example (which consists
of two listings):
Java
public class AnotherExampleBean implements InitializingBean {
@Override
public void afterPropertiesSet() {
// do some initialization work
}
}
Kotlin
class AnotherExampleBean : InitializingBean {
override fun afterPropertiesSet() {
// do some initialization work
}
}
However, the first of the two preceding examples does not couple the code to Spring.
Destruction Callbacks
Implementing the org.springframework.beans.factory.DisposableBean interface lets a bean get a
callback when the container that contains it is destroyed. The DisposableBean interface specifies a
single method:
void destroy() throws Exception;
We recommend that you do not use the DisposableBean callback interface, because it unnecessarily
couples the code to Spring. Alternatively, we suggest using the @PreDestroy annotation or specifying
a generic method that is supported by bean definitions. With XML-based configuration metadata,
you can use the destroy-method attribute on the . With Java configuration, you can use the
destroyMethod attribute of @Bean. See Receiving Lifecycle Callbacks. Consider the following
definition:
Java
public class ExampleBean {
public void cleanup() {
// do some destruction work (like releasing pooled connections)
}
}
Kotlin
class ExampleBean {
fun cleanup() {
// do some destruction work (like releasing pooled connections)
}
}
The preceding definition has almost exactly the same effect as the following definition:
Java
public class AnotherExampleBean implements DisposableBean {
@Override
public void destroy() {
// do some destruction work (like releasing pooled connections)
}
}
Kotlin
class AnotherExampleBean : DisposableBean {
override fun destroy() {
// do some destruction work (like releasing pooled connections)
}
}
However, the first of the two preceding definitions does not couple the code to Spring.
You can assign the destroy-method attribute of a element a special (inferred)
value, which instructs Spring to automatically detect a public close or shutdown
method on the specific bean class. (Any class that implements
java.lang.AutoCloseable or java.io.Closeable would therefore match.) You can
also set this special (inferred) value on the default-destroy-method attribute of a
element to apply this behavior to an entire set of beans (see Default
Initialization and Destroy Methods). Note that this is the default behavior with Java
configuration.
Default Initialization and Destroy Methods
When you write initialization and destroy method callbacks that do not use the Spring-specific
InitializingBean and DisposableBean callback interfaces, you typically write methods with names
such as init(), initialize(), dispose(), and so on. Ideally, the names of such lifecycle callback
methods are standardized across a project so that all developers use the same method names and
ensure consistency.
You can configure the Spring container to “look” for named initialization and destroy callback
method names on every bean. This means that you, as an application developer, can write your
application classes and use an initialization callback called init(), without having to configure an
init-method="init" attribute with each bean definition. The Spring IoC container calls that method
when the bean is created (and in accordance with the standard lifecycle callback contract described
previously). This feature also enforces a consistent naming convention for initialization and destroy
method callbacks.
Suppose that your initialization callback methods are named init() and your destroy callback
methods are named destroy(). Your class then resembles the class in the following example:
Java
public class DefaultBlogService implements BlogService {
private BlogDao blogDao;
public void setBlogDao(BlogDao blogDao) {
this.blogDao = blogDao;
}
// this is (unsurprisingly) the initialization callback method
public void init() {
if (this.blogDao == null) {
throw new IllegalStateException("The [blogDao] property must be set.");
}
}
}
Kotlin
class DefaultBlogService : BlogService {
private var blogDao: BlogDao? = null
// this is (unsurprisingly) the initialization callback method
fun init() {
if (blogDao == null) {
throw IllegalStateException("The [blogDao] property must be set.")
}
}
}
You could then use that class in a bean resembling the following:
The presence of the default-init-method attribute on the top-level element attribute causes
the Spring IoC container to recognize a method called init on the bean class as the initialization
method callback. When a bean is created and assembled, if the bean class has such a method, it is
invoked at the appropriate time.
You can configure destroy method callbacks similarly (in XML, that is) by using the default-
destroy-method attribute on the top-level element.
Where existing bean classes already have callback methods that are named at variance with the
convention, you can override the default by specifying (in XML, that is) the method name by using
the init-method and destroy-method attributes of the itself.
The Spring container guarantees that a configured initialization callback is called immediately after
a bean is supplied with all dependencies. Thus, the initialization callback is called on the raw bean
reference, which means that AOP interceptors and so forth are not yet applied to the bean. A target
bean is fully created first and then an AOP proxy (for example) with its interceptor chain is applied.
If the target bean and the proxy are defined separately, your code can even interact with the raw
target bean, bypassing the proxy. Hence, it would be inconsistent to apply the interceptors to the
init method, because doing so would couple the lifecycle of the target bean to its proxy or
interceptors and leave strange semantics when your code interacts directly with the raw target
bean.
Spring Ai Commons/Src/Test/Resources/Bikes.Json (spring-ai-commons/src/test/resources/bikes.json)
[
{
"name": "E-Adrenaline 8.0 EX1",
"shortDescription": "a versatile and comfortable e-MTB designed for adrenaline enthusiasts who want to explore all types of terrain. It features a powerful motor and advanced suspension to provide a smooth and responsive ride, with a variety of customizable settings to fit any rider's needs.",
"description": "## Overview\r\nIt's right for you if...\r\nYou want to push your limits on challenging trails and terrain, with the added benefit of an electric assist to help you conquer steep climbs and rough terrain. You also want a bike with a comfortable and customizable fit, loaded with high-quality components and technology.\r\n\r\nThe tech you get\r\nA lightweight, full ADV Mountain Carbon frame with a customizable geometry, including an adjustable head tube and chainstay length. A powerful and efficient motor with a 375Wh battery that can assist up to 28 mph when it's on, and provides a smooth and seamless transition when it's off. A SRAM EX1 8-speed drivetrain, a RockShox Lyrik Ultimate fork, and a RockShox Super Deluxe Ultimate rear shock.\r\n\r\nThe final word\r\nOur E-Adrenaline 8.0 EX1 is the perfect bike for adrenaline enthusiasts who want to explore all types of terrain. It's versatile, comfortable, and loaded with advanced technology to provide a smooth and responsive ride, no matter where your adventures take you.\r\n\r\n\r\n## Features\r\nVersatile and customizable\r\nThe E-Adrenaline 8.0 EX1 features a customizable geometry, including an adjustable head tube and chainstay length, so you can fine-tune your ride to fit your needs and preferences. It also features a variety of customizable settings, including suspension tuning, motor assistance levels, and more.\r\n\r\nPowerful and efficient\r\nThe bike is equipped with a powerful and efficient motor that provides a smooth and seamless transition between human power and electric assist. It can assist up to 28 mph when it's on, and provides zero drag when it's off.\r\n\r\nAdvanced suspension\r\nThe E-Adrenaline 8.0 EX1 features a RockShox Lyrik Ultimate fork and a RockShox Super Deluxe Ultimate rear shock, providing advanced suspension technology to absorb shocks and bumps on any terrain. The suspension is also customizable to fit your riding style and preferences.\r\n\r\n\r\n## Specs\r\nFrameset\r\nFrame ADV Mountain Carbon main frame & stays, adjustable head tube and chainstay length, tapered head tube, Knock Block, Control Freak internal routing, Boost148, 150mm travel\r\nFork RockShox Lyrik Ultimate, DebonAir spring, Charger 2.1 RC2 damper, remote lockout, tapered steerer, 42mm offset, Boost110, 15mm Maxle Stealth, 160mm travel\r\nShock RockShox Super Deluxe Ultimate, DebonAir spring, Thru Shaft 3-position damper, 230x57.5mm\r\n\r\nWheels\r\nWheel front Bontrager Line Elite 30, ADV Mountain Carbon, Tubeless Ready, 6-bolt, Boost110, 15mm thru axle\r\nWheel rear Bontrager Line Elite 30, ADV Mountain Carbon, Tubeless Ready, 54T Rapid Drive, 6-bolt, Shimano MicroSpline freehub, Boost148, 12mm thru axle\r\nSkewer rear Bontrager Switch thru axle, removable lever\r\nTire Bontrager XR5 Team Issue, Tubeless Ready, Inner Strength sidewall, aramid bead, 120tpi, 29x2.50''\r\nTire part Bontrager TLR sealant, 6oz\r\n\r\nDrivetrain\r\nShifter SRAM EX1, 8 speed\r\nRear derailleur SRAM EX1, 8 speed\r\nCrank Bosch Performance CX, magnesium motor body, 250 watt, 75 Nm torque\r\nChainring SRAM EX1, 18T, steel\r\nCassette SRAM EX1, 11-48, 8 speed\r\nChain SRAM EX1, 8 speed\r\n\r\nComponents\r\nSaddle Bontrager Arvada, hollow chromoly rails, 138mm width\r\nSeatpost Bontrager Line Elite Dropper, internal routing, 31.6mm\r\nHandlebar Bontrager Line Pro, ADV Carbon, 35mm, 27.5mm rise, 780mm width\r\nGrips Bontrager XR Trail Elite, alloy lock-on\r\nStem Bontrager Line Pro, 35mm, Knock Block, Blendr compatible, 0 degree, 50mm length\r\nHeadset Knock Block Integrated, 62-degree radius, cartridge bearing, 1-1\/8'' top, 1.5'' bottom\r\nBrake SRAM G2 RSC hydraulic disc, carbon levers\r\nBrake rotor SRAM Centerline, centerlock, round edge, 200mm\r\n\r\nAccessories\r\nE-bike system Bosch Performance CX, magnesium motor body, 250 watt, 75 Nm torque\r\nBattery Bosch PowerTube 625, 625Wh\r\nCharger Bosch 4A standard charger\r\nController Bosch Kiox with Anti-theft solution, Bluetooth connectivity, 1.9'' display\r\nTool Bontrager Switch thru axle, removable lever\r\n\r\nWeight\r\nWeight M - 20.25 kg \/ 44.6 lbs (with TLR sealant, no tubes)\r\nWeight limit This bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\r\n\r\n## Sizing & fit\r\n\r\n| Size | Rider Height | Inseam |\r\n|:----:|:------------------------:|:--------------------:|\r\n| S | 155 - 170 cm 5'1\" - 5'7\" | 73 - 80 cm 29\" - 31.5\" |\r\n| M | 163 - 178 cm 5'4\" - 5'10\" | 77 - 83 cm 30.5\" - 32.5\" |\r\n| L | 176 - 191 cm 5'9\" - 6'3\" | 83 - 89 cm 32.5\" - 35\" |\r\n| XL | 188 - 198 cm 6'2\" - 6'6\" | 88 - 93 cm 34.5\" - 36.5\" |\r\n\r\n\r\n## Geometry\r\n\r\nAll measurements provided in cm unless otherwise noted.\r\nSizing table\r\n| Frame size letter | S | M | L | XL |\r\n|---------------------------|-------|-------|-------|-------|\r\n| Actual frame size | 15.8 | 17.8 | 19.8 | 21.8 |\r\n| Wheel size | 29\" | 29\" | 29\" | 29\" |\r\n| A \u2014 Seat tube | 40.0 | 42.5 | 47.5 | 51.0 |\r\n| B \u2014 Seat tube angle | 72.5\u00B0 | 72.8\u00B0 | 73.0\u00B0 | 73.0\u00B0 |\r\n| C \u2014 Head tube length | 9.5 | 10.5 | 11.0 | 11.5 |\r\n| D \u2014 Head angle | 67.8\u00B0 | 67.8\u00B0 | 67.8\u00B0 | 67.8\u00B0 |\r\n| E \u2014 Effective top tube | 59.0 | 62.0 | 65.0 | 68.0 |\r\n| F \u2014 Bottom bracket height | 32.5 | 32.5 | 32.5 | 32.5 |\r\n| G \u2014 Bottom bracket drop | 5.5 | 5.5 | 5.5 | 5.5 |\r\n| H \u2014 Chainstay length | 45.0 | 45.0 | 45.0 | 45.0 |\r\n| I \u2014 Offset | 4.5 | 4.5 | 4.5 | 4.5 |\r\n| J \u2014 Trail | 11.0 | 11.0 | 11.0 | 11.0 |\r\n| K \u2014 Wheelbase | 113.0 | 117.0 | 120.0 | 123.0 |\r\n| L \u2014 Standover | 77.0 | 77.0 | 77.0 | 77.0 |\r\n| M \u2014 Frame reach | 41.0 | 44.5 | 47.5 | 50.0 |\r\n| N \u2014 Frame stack | 61.0 | 62.0 | 62.5 | 63.0 |",
"price": 1499.99,
"tags": [
"bicycle"
]
},
{
"name": "Enduro X Pro",
"shortDescription": "The Enduro X Pro is the ultimate mountain bike for riders who demand the best. With its full carbon frame and top-of-the-line components, this bike is ready to tackle any trail, from technical downhill descents to grueling uphill climbs.",
"text": "## Overview\nIt's right for you if...\nYou're an experienced mountain biker who wants a high-performance bike that can handle any terrain. You want a bike with the best components available, including a full carbon frame, suspension system, and hydraulic disc brakes.\n\nThe tech you get\nOur top-of-the-line full carbon frame with aggressive geometry and a slack head angle for maximum control. It's equipped with a Fox Factory suspension system with 170mm of travel in the front and 160mm in the rear, a Shimano XTR 12-speed drivetrain, and hydraulic disc brakes for maximum stopping power. The bike also features a dropper seatpost for easy adjustments on the fly.\n\nThe final word\nThe Enduro X Pro is the ultimate mountain bike for riders who demand the best. With its full carbon frame, top-of-the-line components, and aggressive geometry, this bike is ready to take on any trail. Whether you're a seasoned pro or just starting out, the Enduro X Pro will help you take your riding to the next level.\n\n## Features\nFull carbon frame\nAggressive geometry with a slack head angle\nFox Factory suspension system with 170mm of travel in the front and 160mm in the rear\nShimano XTR 12-speed drivetrain\nHydraulic disc brakes for maximum stopping power\nDropper seatpost for easy adjustments on the fly\n\n## Specifications\nFrameset\nFrame\tFull carbon frame\nFork\tFox Factory suspension system with 170mm of travel\nRear suspension\tFox Factory suspension system with 160mm of travel\n\nWheels\nWheel size\t27.5\" or 29\"\nTires\tTubeless-ready Maxxis tires\n\nDrivetrain\nShifters\tShimano XTR 12-speed\nFront derailleur\tN/A\nRear derailleur\tShimano XTR\nCrankset\tShimano XTR\nCassette\tShimano XTR 12-speed\nChain\tShimano XTR\n\nComponents\nBrakes\tHydraulic disc brakes\nHandlebar\tAlloy handlebar\nStem\tAlloy stem\nSeatpost\tDropper seatpost\n\nAccessories\nPedals\tNot included\n\nWeight\nWeight\tApproximately 27-29 lbs\n\n## Sizing\n| Size | Rider Height |\n|:----:|:-------------------------:|\n| S | 5'4\" - 5'8\" (162-172cm) |\n| M | 5'8\" - 5'11\" (172-180cm) |\n| L | 5'11\" - 6'3\" (180-191cm) |\n| XL | 6'3\" - 6'6\" (191-198cm) |\n\n## Geometry\n| Size | S | M | L | XL |\n|:----:|:---------------:|:---------------:|:-----------------:|:---------------:|\n| A - Seat tube length | 390mm | 425mm | 460mm | 495mm |\n| B - Effective top tube length | 585mm | 610mm | 635mm | 660mm |\n| C - Head tube angle | 65.5° | 65.5° | 65.5° | 65.5° |\n| D - Seat tube angle | 76° | 76° | 76° | 76° |\n| E - Chainstay length | 435mm | 435mm | 435mm | 435mm |\n| F - Head tube length | 100mm | 110mm | 120mm | 130mm |\n| G - BB drop | 20mm | 20mm | 20mm | 20mm |\n| H - Wheelbase | 1155mm | 1180mm | 1205mm | 1230mm |\n| I - Standover height | 780mm | 800mm | 820mm | 840mm |\n| J - Reach | 425mm | 450mm | 475mm | 500mm |\n| K - Stack | 610mm | 620mm | 630mm | 640mm |",
"price": 599.99,
"tags": [
"bicycle"
]
},
{
"name": "Blaze X1",
"shortDescription": "Blaze X1 is a high-performance road bike that offers superior speed and agility, making it perfect for competitive racing or fast-paced group rides. The bike features a lightweight carbon frame, aerodynamic tube shapes, a 12-speed Shimano Ultegra drivetrain, and hydraulic disc brakes for precise stopping power. With its sleek design and cutting-edge technology, Blaze X1 is a bike that is built to perform and dominate on any road.",
"description": "## Overview\nIt's right for you if...\nYou're a competitive road cyclist or an enthusiast who enjoys fast-paced group rides. You want a bike that is lightweight, agile, and delivers exceptional speed.\n\nThe tech you get\nBlaze X1 features a lightweight carbon frame with a tapered head tube and aerodynamic tube shapes for maximum speed and efficiency. The bike is equipped with a 12-speed Shimano Ultegra drivetrain for smooth and precise shifting, Shimano hydraulic disc brakes for powerful and reliable stopping power, and Bontrager Aeolus Elite 35 carbon wheels for increased speed and agility.\n\nThe final word\nBlaze X1 is a high-performance road bike that is designed to deliver exceptional speed and agility. With its cutting-edge technology and top-of-the-line components, it's a bike that is built to perform and dominate on any road.\n\n## Features\nSpeed and efficiency\nBlaze X1's lightweight carbon frame and aerodynamic tube shapes offer maximum speed and efficiency, allowing you to ride faster and farther with ease.\n\nPrecision stopping power\nShimano hydraulic disc brakes provide precise and reliable stopping power, even in wet or muddy conditions.\n\nAgility and control\nBontrager Aeolus Elite 35 carbon wheels make Blaze X1 incredibly agile and responsive, allowing you to navigate tight turns and corners with ease.\n\nSmooth and precise shifting\nThe 12-speed Shimano Ultegra drivetrain offers smooth and precise shifting, so you can easily find the right gear for any terrain.\n\n## Specifications\nFrameset\nFrame\tADV Carbon, tapered head tube, BB90, direct mount rim brakes, internal cable routing, DuoTrap S compatible, 130x9mm QR\nFork\tADV Carbon, tapered steerer, direct mount rim brakes, internal brake routing, 100x9mm QR\n\nWheels\nWheel front\tBontrager Aeolus Elite 35, ADV Carbon, Tubeless Ready, 35mm rim depth, 100x9mm QR\nWheel rear\tBontrager Aeolus Elite 35, ADV Carbon, Tubeless Ready, 35mm rim depth, Shimano 11-speed freehub, 130x9mm QR\nTire front\tBontrager R3 Hard-Case Lite, aramid bead, 120 tpi, 700x25c\nTire rear\tBontrager R3 Hard-Case Lite, aramid bead, 120 tpi, 700x25c\nMax tire size\t25c Bontrager tires (with at least 4mm of clearance to frame)\n\nDrivetrain\nShifter\tShimano Ultegra R8020, 12 speed\nFront derailleur\tShimano Ultegra R8000, braze-on\nRear derailleur\tShimano Ultegra R8000, short cage, 30T max cog\nCrank\tSize: 50, 52, 54\nShimano Ultegra R8000, 50/34 (compact), 170mm length\nSize: 56, 58, 60, 62\nShimano Ultegra R8000, 50/34 (compact), 172.5mm length\nBottom bracket\tBB90, Shimano press-fit\nCassette\tShimano Ultegra R8000, 11-30, 12 speed\nChain\tShimano Ultegra HG701, 12 speed\n\nComponents\nSaddle\tBontrager Montrose Elite, titanium rails, 138mm width\nSeatpost\tBontrager carbon seatmast cap, 20mm offset\nHandlebar\tBontrager Elite Aero VR-CF, alloy, 31.8mm, internal cable routing, 40cm width\nGrips\tBontrager Supertack Perf tape\nStem\tBontrager Elite, 31.8mm, Blendr-compatible, 7 degree, 80mm length\nBrake Shimano Ultegra hydraulic disc brake\n\nWeight\nWeight\t56 - 8.91 kg / 19.63 lbs (with tubes)\nWeight limit\tThis bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 275 pounds (125 kg).\n\n## Sizing\n| Size | Rider height |\n|------|-------------|\n| 50 | 162-166cm |\n| 52 | 165-170cm |\n| 54 | 168-174cm |\n| 56 | 174-180cm |\n| 58 | 179-184cm |\n| 60 | 184-189cm |\n| 62 | 189-196cm |\n\n## Geometry\n| Frame size | 50cm | 52cm | 54cm | 56cm | 58cm | 60cm | 62cm |\n|------------|-------|-------|-------|-------|-------|-------|-------|\n| Wheel size | 700c | 700c | 700c | 700c | 700c | 700c | 700c |\n| A - Seat tube | 443mm | 460mm | 478mm | 500mm | 520mm | 540mm | 560mm |\n| B - Seat tube angle | 74.1° | 73.9° | 73.7° | 73.4° | 73.2° | 73.0° | 72.8° |\n| C - Head tube length | 100mm | 110mm | 130mm | 150mm | 170mm | 190mm | 210mm |\n| D - Head angle | 71.4° | 72.0° | 72.5° | 73.0° | 73.3° | 73.6° | 73.8° |\n| E - Effective top tube | 522mm | 535mm | 547mm | 562mm | 577mm | 593mm | 610mm |\n| F - Bottom bracket height | 268mm | 268mm | 268mm | 268mm | 268mm | 268mm | 268mm |\n| G - Bottom bracket drop | 69mm | 69mm | 69mm | 69mm | 69mm | 69mm | 69mm |\n| H - Chainstay length | 410mm | 410mm | 410mm | 410mm | 410mm | 410mm | 410mm |\n| I - Offset | 50mm | 50mm | 50mm | 50mm | 50mm | 50mm | 50mm |\n| J - Trail | 65mm | 62mm | 59mm | 56mm | 55mm | 53mm | 52mm |\n| K - Wheelbase | 983mm | 983mm | 990mm | 1005mm | 1019mm | 1036mm | 1055mm |\n| L - Standover | 741mm | 765mm | 787mm | 806mm | 825mm | 847mm | 869mm |",
"price": 799.99,
"tags": [
"bicycle",
"mountain bike"
]
},
{
"name": "Celerity X5",
"shortDescription": "Celerity X5 is a versatile and reliable road bike that is designed for experienced and amateur riders alike. It's designed to provide smooth and comfortable rides over long distances. With an ultra-lightweight and responsive carbon fiber frame, Shimano 105 groupset, hydraulic disc brakes, and 28mm wide tires, this bike ensures efficient power transfer, precise handling, and superior stopping power.",
"description": "## Overview\n\nIt's right for you if... \nYou are looking for a high-performance road bike that offers a perfect balance of speed, comfort, and control. You enjoy long-distance rides and need a bike that is designed to handle various road conditions with ease. You also appreciate the latest technology and reliable components that make your riding experience more enjoyable.\n\nThe tech you get \nCelerity X5 is equipped with a full carbon fiber frame that ensures maximum strength and durability while keeping the weight down. It features a Shimano 105 groupset with 11-speed gearing for precise and efficient shifting. Hydraulic disc brakes offer superior stopping power, and 28mm wide tires provide comfort and stability on various road surfaces. Internal cable routing enhances the bike's sleek appearance.\n\nThe final word \nIf you are looking for a high-performance road bike that offers comfort, speed, and control, Celerity X5 is the perfect choice. With its lightweight carbon fiber frame, reliable components, and advanced technology, this bike is designed to help you enjoy long-distance rides with ease.\n\n## Features \n\nLightweight and responsive \nCelerity X5 comes with a full carbon fiber frame that is not only lightweight but also responsive, providing excellent handling and control.\n\nHydraulic disc brakes \nThis bike is equipped with hydraulic disc brakes that provide superior stopping power in all weather conditions, ensuring your safety and confidence on the road.\n\nComfortable rides \nThe 28mm wide tires and carbon seat post provide ample cushioning, ensuring a smooth and comfortable ride over long distances.\n\nSleek appearance \nThe bike's internal cable routing enhances its sleek appearance while also protecting the cables from the elements, ensuring smooth shifting for longer periods.\n\n## Specifications \n\nFrameset \nFrame\tCelerity X5 Full Carbon Fiber Frame, Internal Cable Routing, Tapered Headtube, Press Fit Bottom Bracket, 12x142mm Thru-Axle \nFork\tCelerity X5 Full Carbon Fiber Fork, Internal Brake Routing, 12x100mm Thru-Axle \n\nWheels \nWheelset\tAlexRims CXD7 Wheelset \nTire\tSchwalbe Durano Plus 700x28mm \nInner Tubes\tSchwalbe SV15 700x18-28mm \nSkewers\tCelerity X5 Thru-Axle Skewers \n\nDrivetrain \nShifter\tShimano 105 R7025 Hydraulic Disc Shifters \nFront Derailleur\tShimano 105 R7000 \nRear Derailleur\tShimano 105 R7000 \nCrankset\tShimano 105 R7000 50-34T \nBottom Bracket\tShimano BB72-41B \nCassette\tShimano 105 R7000 11-30T \nChain\tShimano HG601 11-Speed Chain \n\nComponents \nSaddle\tSelle Royal Asphalt Saddle \nSeatpost\tCelerity X5 Carbon Seatpost \nHandlebar\tCelerity X5 Compact Handlebar \nStem\tCelerity X5 Aluminum Stem \nHeadset\tFSA Orbit IS-2 \n\nBrakes \nBrakes\tShimano 105 R7025 Hydraulic Disc Brakes \nRotors\tShimano SM-RT70 160mm Rotors \n\nAccessories \nPedals\tCelerity X5 Road Pedals \n\nWeight \nWeight\t8.2 kg / 18.1 lbs \nWeight Limit\tThis bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 120 kg (265 lbs).\n\n## Sizing \n| Size | Rider Height | Inseam |\n|:----:|:-------------------------:|:--------------------:|\n| 49 | 155 - 162 cm 5'1\" - 5'4\" | 71 - 76 cm 28\" - 30\" |\n| 52 | 162 - 170 cm 5'4\" - 5'7\" | 74 - 79 cm 29\" - 31\" |\n| 54 | 170 - 178 cm 5'7\" - 5'10\" | 77 - 83 cm 30\" - 32\" |\n| 56 | 178 - 185 cm 5'10\" - 6'1\" | 82 - 88 cm 32\" - 34\" |\n| 58 | 185 - 193 cm 6'1\" - 6'4\" | 86 - 92 cm 34\" - 36\" |\n| 61 | 193 - 200 cm 6'4\" - 6'7\" | 90 - 95 cm 35\" - 37\" |\n\n## Geometry \n| Frame size number | 49 cm | 52 cm | 54 cm | 56 cm | 58 cm | 61 cm |\n|---------------------------------------|-------|-------|-------|-------|-------|-------|\n| Wheel size | 700c | 700c | 700c | 700c | 700c | 700c |\n| A — Seat tube | 47.5 | 50.0 | 52.0 | 54.0 | 56.0 | 58.5 |\n| B — Seat tube angle | 75.0° | 74.5° | 74.0° | 73.5° | 73.0° | 72.5° |\n| C — Head tube length | 12.0 | 14.5 | 16.5 | 18.5 | 20.5 | 23.5 |\n| D — Head angle | 70.0° | 71.0° | 71.5° | 72.0° | 72.5° | 72.5° |\n| E — Effective top tube | 52.5 | 53.5 | 54.5 | 56.0 | 57.5 | 59.5 |\n| G — Bottom bracket drop | 7.0 | 7.0 | 7.0 | 7.0 | 7.0 | 7.0 |\n| H — Chainstay length | 41.5 | 41.5 | 41.5 | 41.5 | 41.5 | 41.5 |\n| K — Wheelbase | 98.4 | 98.9 | 99.8 | 100.8 | 101.7 | 103.6 |\n| L — Standover | 72.0 | 74.0 | 76.0 | 78.0 | 80.0 | 82.0 |\n| M — Frame reach | 36.2 | 36.8 | 37.3 | 38.1 | 38.6 | 39.4 |\n| N — Frame stack | 52.0 | 54.3 | 56.2 | 58.1 | 59.8 | 62.4 |\n| Saddle rail height min | 67.0 | 69.5 | 71.5 | 74.0 | 76.0 | 78.0 |\n| Saddle rail height max | 75.0 | 77.5 | 79.5 | 82.0 | 84.0 | 86.0 |",
"price": 399.99,
"tags": [
"bicycle",
"city bike"
]
},
{
"name": "Velocity V8",
"shortDescription": "Velocity V8 is a high-performance road bike that is designed to deliver speed, agility, and control on the road. With its lightweight aluminum frame, carbon fiber fork, Shimano Tiagra groupset, and hydraulic disc brakes, this bike is perfect for experienced riders who are looking for a fast and responsive bike that can handle various road conditions.",
"description": "## Overview\n\nIt's right for you if... \nYou are an experienced rider who is looking for a high-performance road bike that is lightweight, agile, and responsive. You want a bike that can handle long-distance rides, steep climbs, and fast descents with ease. You also appreciate the latest technology and reliable components that make your riding experience more enjoyable.\n\nThe tech you get \nVelocity V8 features a lightweight aluminum frame with a carbon fiber fork that ensures a comfortable ride without sacrificing stiffness and power transfer. It comes with a Shimano Tiagra groupset with 10-speed gearing for precise and efficient shifting. Hydraulic disc brakes offer superior stopping power in all weather conditions, while 28mm wide tires provide comfort and stability on various road surfaces. Internal cable routing enhances the bike's sleek appearance.\n\nThe final word \nIf you are looking for a high-performance road bike that is lightweight, fast, and responsive, Velocity V8 is the perfect choice. With its lightweight aluminum frame, reliable components, and advanced technology, this bike is designed to help you enjoy fast and comfortable rides on the road.\n\n## Features \n\nLightweight and responsive \nVelocity V8 comes with a lightweight aluminum frame that is not only lightweight but also responsive, providing excellent handling and control.\n\nHydraulic disc brakes \nThis bike is equipped with hydraulic disc brakes that provide superior stopping power in all weather conditions, ensuring your safety and confidence on the road.\n\nComfortable rides \nThe 28mm wide tires and carbon fork provide ample cushioning, ensuring a smooth and comfortable ride over long distances.\n\nSleek appearance \nThe bike's internal cable routing enhances its sleek appearance while also protecting the cables from the elements, ensuring smooth shifting for longer periods.\n\n## Specifications \n\nFrameset \nFrame\tVelocity V8 Aluminum Frame, Internal Cable Routing, Tapered Headtube, Press Fit Bottom Bracket, 12x142mm Thru-Axle \nFork\tVelocity V8 Carbon Fiber Fork, Internal Brake Routing, 12x100mm Thru-Axle \n\nWheels \nWheelset\tAlexRims CXD7 Wheelset \nTire\tSchwalbe Durano Plus 700x28mm \nInner Tubes\tSchwalbe SV15 700x18-28mm \nSkewers\tVelocity V8 Thru-Axle Skewers \n\nDrivetrain \nShifter\tShimano Tiagra Hydraulic Disc Shifters \nFront Derailleur\tShimano Tiagra \nRear Derailleur\tShimano Tiagra \nCrankset\tShimano Tiagra 50-34T \nBottom Bracket\tShimano BB-RS500-PB \nCassette\tShimano Tiagra 11-32T \nChain\tShimano HG54 10-Speed Chain \n\nComponents \nSaddle\tVelocity V8 Saddle \nSeatpost\tVelocity V8 Aluminum Seatpost \nHandlebar\tVelocity V8 Compact Handlebar \nStem\tVelocity V8 Aluminum Stem \nHeadset\tFSA Orbit IS-2 \n\nBrakes \nBrakes\tShimano Tiagra Hydraulic Disc Brakes \nRotors\tShimano SM-RT64 160mm Rotors \n\nAccessories \nPedals\tVelocity V8 Road Pedals \n\nWeight \nWeight\t9.4 kg / 20.7 lbs \nWeight Limit\tThis bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 120 kg (265 lbs).\n\n## Sizing \n| Size | Rider Height | Inseam |\n|:----:|:-------------------------:|:--------------------:|\n| 49 | 155 - 162 cm 5'1\" - 5'4\" | 71 - 76 cm 28\" - 30\" |\n| 52 | 162 - 170 cm 5'4\" - 5'7\" | 74 - 79 cm 29\" - 31\" |\n| 54 | 170 - 178 cm 5'7\" - 5'10\" | 77 - 83 cm 30\" - 32\" |\n| 56 | 178 - 185 cm 5'10\" - 6'1\" | 82 - 88 cm 32\" - 34\" |\n| 58 | 185 - 193 cm 6'1\" - 6'4\" | 86 - 92 cm 34\" - 36\" |\n| 61 | 193 - 200 cm 6'4\" - 6'7\" | 90 - 95 cm 35\" - 37\" |\n\n## Geometry \n| Frame size number | 49 cm | 52 cm | 54 cm | 56 cm | 58 cm | 61 cm |\n|---------------------------------------|-------|-------|-------|-------|-------|-------|\n| Wheel size | 700c | 700c | 700c | 700c | 700c | 700c |\n| A — Seat tube | 47.5 | 50.0 | 52.0 | 54.0 | 56.0 | 58.5 |\n| B — Seat tube angle | 75.0° | 74.5° | 74.0° | 73.5° | 73.0° | 72.5° |\n| C — Head tube length | 12.0 | 14.5 | 16.5 | 18.5 | 20.5 | 23.5 |\n| D — Head angle | 70.0° | 71.0° | 71.5° | 72.0° | 72.5° | 72.5° |\n| E — Effective top tube | 52.5 | 53.5 | 54.5 | 56.0 | 57.5 | 59.5 |\n| G — Bottom bracket drop | 7.0 | 7.0 | 7.0 | 7.0 | 7.0 | 7.0 |\n| H — Chainstay length | 41.5 | 41.5 | 41.5 | 41.5 | 41.5 | 41.5 |\n| K — Wheelbase | 98.4 | 98.9 | 99.8 | 100.8 | 101.7 | 103.6 |\n| L — Standover | 72.0 | 74.0 | 76.0 | 78.0 | 80.0 | 82.0 |\n| M — Frame reach | 36.2 | 36.8 | 37.3 | 38.1 | 38.6 | 39.4 |\n| N — Frame stack | 52.0 | 54.3 | 56.2 | 58.1 | 59.8 | 62.4 |\n| Saddle rail height min | 67.0 | 69.5 | 71.5 | 74.0 | 76.0 | 78.0 |\n| Saddle rail height max | 75.0 | 77.5 | 79.5 | 82.0 | 84.0 | 86.0 |",
"price": 1899.99,
"tags": [
"bicycle",
"electric bike"
]
},
{
"name": "VeloCore X9 eMTB",
"shortDescription": "The VeloCore X9 eMTB is a light, agile and versatile electric mountain bike designed for adventure and performance. Its purpose-built frame and premium components offer an exhilarating ride experience on both technical terrain and smooth singletrack.",
"description": "## Overview\nIt's right for you if...\nYou love exploring new trails and testing your limits on challenging terrain. You want an electric mountain bike that offers power when you need it, without sacrificing performance or agility. You're looking for a high-quality bike with top-notch components and a sleek design.\n\nThe tech you get\nA lightweight, full carbon frame with custom geometry, a 140mm RockShox Pike Ultimate fork with Charger 2.1 damper, and a Fox Float DPS Performance shock. A Shimano STEPS E8000 motor and 504Wh battery that provide up to 62 miles of range and 20 mph assistance. A Shimano XT 12-speed drivetrain, Shimano SLX brakes, and DT Swiss wheels.\n\nThe final word\nThe VeloCore X9 eMTB delivers power and agility in equal measure. It's a versatile and capable electric mountain bike that can handle any trail with ease. With premium components, a custom carbon frame, and a sleek design, this bike is built for adventure.\n\n## Features\nAgile and responsive\n\nThe VeloCore X9 eMTB is designed to be nimble and responsive on the trail. Its custom carbon frame offers a perfect balance of stiffness and compliance, while the suspension system provides smooth and stable performance on technical terrain.\n\nPowerful and efficient\n\nThe Shimano STEPS E8000 motor and 504Wh battery provide up to 62 miles of range and 20 mph assistance. The motor delivers smooth and powerful performance, while the battery offers reliable and consistent power for long rides.\n\nCustomizable ride experience\n\nThe VeloCore X9 eMTB comes with an intuitive and customizable Shimano STEPS display that allows you to adjust the level of assistance, monitor your speed and battery life, and customize your ride experience to suit your needs.\n\nPremium components\n\nThe VeloCore X9 eMTB is equipped with high-end components, including a Shimano XT 12-speed drivetrain, Shimano SLX brakes, and DT Swiss wheels. These components offer reliable and precise performance, allowing you to push your limits with confidence.\n\n## Specs\nFrameset\nFrame\tVeloCore carbon fiber frame, Boost, tapered head tube, internal cable routing, 140mm travel\nFork\tRockShox Pike Ultimate, Charger 2.1 damper, DebonAir spring, 15x110mm Boost Maxle Ultimate, 46mm offset, 140mm travel\nShock\tFox Float DPS Performance, EVOL, 3-position adjust, Kashima Coat, 210x50mm\n\nWheels\nWheel front\tDT Swiss XM1700 Spline, 30mm internal width, 15x110mm Boost axle\nWheel rear\tDT Swiss XM1700 Spline, 30mm internal width, Shimano Microspline driver, 12x148mm Boost axle\nTire front\tMaxxis Minion DHF, 29x2.5\", EXO+ casing, tubeless ready\nTire rear\tMaxxis Minion DHR II, 29x2.4\", EXO+ casing, tubeless ready\n\nDrivetrain\nShifter\tShimano XT M8100, 12-speed\nRear derailleur\tShimano XT M8100, Shadow Plus, long cage, 51T max cog\nCrankset\tShimano STEPS E8000, 165mm length, 34T chainring\nCassette\tShimano XT M8100, 10-51T, 12-speed\nChain\tShimano CN-M8100, 12-speed\nPedals\tNot included\n\nComponents\nSaddle\tBontrager Arvada, hollow chromoly rails\nSeatpost\tDrop Line, internal routing, 31.6mm (15.5: 100mm, 17.5 & 18.5: 125mm, 19.5 & 21.5: 150mm)\nHandlebar\tBontrager Line Pro, ADV Carbon, 35mm, 27.5mm rise, 780mm width\nStem\tBontrager Line Pro, 35mm, Knock Block, 0 degree, 50mm length\nGrips\tBontrager XR Trail Elite, alloy lock-on\nHeadset\tIntegrated, sealed cartridge bearing, 1-1/8\" top, 1.5\" bottom\nBrakeset\tShimano SLX M7120, 4-piston hydraulic disc\n\nAccessories\nBattery\tShimano STEPS BT-E8010, 504Wh\nCharger\tShimano STEPS EC-E8004, 4A\nController\tShimano STEPS E8000 display\nBike weight\tM - 22.5 kg / 49.6 lbs (with tubes)\n\n## Sizing & fit\n\n| Size | Rider Height |\n|:----:|:------------------------:|\n| S | 162 - 170 cm 5'4\" - 5'7\" |\n| M | 170 - 178 cm 5'7\" - 5'10\"|\n| L | 178 - 186 cm 5'10\" - 6'1\"|\n| XL | 186 - 196 cm 6'1\" - 6'5\" |\n\n## Geometry\n\nAll measurements provided in cm unless otherwise noted.\n\n| Frame size | S | M | L | XL |\n|---------------------------|-------|-------|-------|-------|\n| A — Seat tube | 40.6 | 43.2 | 47.0 | 51.0 |\n| B — Seat tube angle | 75.0° | 75.0° | 75.0° | 75.0° |\n| C — Head tube length | 9.6 | 10.6 | 11.6 | 12.6 |\n| D — Head angle | 66.5° | 66.5° | 66.5° | 66.5° |\n| E — Effective top tube | 60.4 | 62.6 | 64.8 | 66.9 |\n| F — Bottom bracket height | 33.2 | 33.2 | 33.2 | 33.2 |\n| G — Bottom bracket drop | 3.0 | 3.0 | 3.0 | 3.0 |\n| H — Chainstay length | 45.5 | 45.5 | 45.5 | 45.5 |\n| I — Offset | 4.6 | 4.6 | 4.6 | 4.6 |\n| J — Trail | 11.9 | 11.9 | 11.9 | 11.9 |\n| K — Wheelbase | 117.0 | 119.3 | 121.6 | 123.9 |\n| L — Standover | 75.9 | 75.9 | 78.6 | 78.6 |\n| M — Frame reach | 43.6 | 45.6 | 47.6 | 49.6 |\n| N — Frame stack | 60.5 | 61.5 | 62.4 | 63.4 |",
"price": 1299.99,
"tags": [
"bicycle",
"touring bike"
]
},
{
"name": "Zephyr 8.8 GX Eagle AXS Gen 3",
"shortDescription": "Zephyr 8.8 GX Eagle AXS is a light and nimble full-suspension mountain bike. It's designed to handle technical terrain with ease and has a smooth and efficient ride feel. The sleek and powerful Bosch Performance Line CX motor and removable Powertube battery provide a boost to your pedaling and give you long-lasting riding time. The bike also features high-end components and advanced technology for an ultimate mountain biking experience.",
"description": "## Overview\nIt's right for you if...\nYou're an avid mountain biker looking for a high-performance e-MTB that can tackle challenging trails. You want a bike with a powerful motor, efficient suspension, and advanced technology to enhance your riding experience. You also need a bike that's reliable and durable for long-lasting use.\n\nThe tech you get\nA lightweight, full carbon frame with 150mm of rear travel and a 160mm RockShox Pike Ultimate fork with Charger 2.1 RCT3 damper, remote lockout, and DebonAir spring. A Bosch Performance Line CX motor and removable Powertube 625Wh battery that can assist up to 20mph when it's on and gives zero drag when it's off, plus an easy-to-use handlebar-mounted Bosch Purion controller. A SRAM GX Eagle AXS wireless electronic drivetrain, a RockShox Reverb Stealth dropper, and DT Swiss HX1501 Spline One wheels.\n\nThe final word\nZephyr 8.8 GX Eagle AXS is a high-performance e-MTB that's designed to handle technical terrain with ease. With a powerful Bosch motor and long-lasting battery, you can conquer challenging climbs and enjoy long rides. The bike also features high-end components and advanced technology for an ultimate mountain biking experience.\n\n## Features\nPowerful motor\n\nThe Bosch Performance Line CX motor provides a boost to your pedaling and can assist up to 20mph. It has four power modes and a walk-assist function for easy navigation on steep climbs. The motor is also reliable and durable for long-lasting use.\n\nEfficient suspension\n\nZephyr 8.8 has a 150mm of rear travel and a 160mm RockShox Pike Ultimate fork with Charger 2.1 RCT3 damper, remote lockout, and DebonAir spring. The suspension is efficient and responsive, allowing you to handle technical terrain with ease.\n\nRemovable battery\n\nThe Powertube 625Wh battery is removable for easy charging and storage. It provides long-lasting riding time and can be replaced with a spare battery for even longer rides. The battery is also durable and weather-resistant for all-season riding.\n\nAdvanced technology\n\nZephyr 8.8 is equipped with advanced technology, including a Bosch Purion controller for easy motor control, a SRAM GX Eagle AXS wireless electronic drivetrain for precise shifting, and a RockShox Reverb Stealth dropper for adjustable saddle height. The bike also has DT Swiss HX1501 Spline One wheels for reliable performance on any terrain.\n\nCarbon frame\n\nThe full carbon frame is lightweight and durable, providing a smooth and efficient ride. It's also designed with a tapered head tube, internal cable routing, and Boost148 spacing for enhanced stiffness and responsiveness.\n\n## Specs\nFrameset\nFrame\tCarbon main frame & stays, tapered head tube, internal routing, Boost148, 150mm travel\nFork\tRockShox Pike Ultimate, Charger 2.1 RCT3 damper, DebonAir spring, remote lockout, tapered steerer, Boost110, 15mm Maxle Stealth, 160mm travel\nShock\tRockShox Deluxe RT3, DebonAir spring, 205mm x 57.5mm\nMax compatible fork travel\t170mm\n\nWheels\nWheel front\tDT Swiss HX1501 Spline One, Centerlock, 30mm inner width, 110x15mm Boost\nWheel rear\tDT Swiss HX1501 Spline One, Centerlock, 30mm inner width, SRAM XD driver, 148x12mm Boost\nTire\tBontrager XR4 Team Issue, Tubeless Ready, Inner Strength sidewall, aramid bead, 120tpi, 29x2.40''\nMax tire size\t29x2.60\"\n\nDrivetrain\nShifter\tSRAM GX Eagle AXS, wireless, 12 speed\nRear derailleur\tSRAM GX Eagle AXS\nCrank\tBosch Gen 4, 32T\nChainring\tSRAM X-Sync 2, 32T, direct-mount\nCassette\tSRAM PG-1275 Eagle, 10-52, 12 speed\nChain\tSRAM GX Eagle, 12 speed\n\nComponents\nSaddle\tBontrager Arvada, hollow titanium rails, 138mm width\nSeatpost\tRockShox Reverb Stealth, 31.6mm, internal routing, 150mm (S), 170mm (M/L), 200mm (XL)\nHandlebar\tBontrager Line Pro, ADV Carbon, 35mm, 27.5mm rise, 780mm width\nGrips\tBontrager XR Trail Elite, alloy lock-on\nStem\tBontrager Line Pro, Knock Block, 35mm, 0 degree, 50mm length\nHeadset\tIntegrated, sealed cartridge bearing, 1-1/8'' top, 1.5'' bottom\nBrake\tSRAM Code RSC hydraulic disc, 200mm (front), 180mm (rear)\nBrake rotor\tSRAM CenterLine, centerlock, round edge, 200mm (front), 180mm (rear)\n\nAccessories\nE-bike system\tBosch Performance Line CX\nBattery\tBosch Powertube 625Wh\nCharger\tBosch 4A compact charger\nController\tBosch Purion\nTool\tBontrager multi-tool, integrated storage bag\n\nWeight\nWeight\tM - 24.08 kg / 53.07 lbs (with TLR sealant, no tubes)\nWeight limit\tThis bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\n\n\n## Sizing & fit\n\n| Size | Rider Height | Inseam |\n|:----:|:------------------------:|:--------------------:|\n| S | 153 - 162 cm 5'0\" - 5'4\" | 67 - 74 cm 26\" - 29\" |\n| M | 161 - 172 cm 5'3\" - 5'8\" | 74 - 79 cm 29\" - 31\" |\n| L | 171 - 180 cm 5'7\" - 5'11\" | 79 - 84 cm 31\" - 33\" |\n| XL | 179 - 188 cm 5'10\" - 6'2\" | 84 - 89 cm 33\" - 35\" |\n\n\n## Geometry\n\nAll measurements provided in cm unless otherwise noted.\nSizing table\n| Frame size letter | S | M | L | XL |\n|---------------------------|-------|-------|-------|-------|\n| Actual frame size | 15.5 | 17.5 | 19.5 | 21.5 |\n| Wheel size | 29\" | 29\" | 29\" | 29\" |\n| A — Seat tube | 39.4 | 41.9 | 44.5 | 47.6 |\n| B — Seat tube angle | 76.1° | 76.1° | 76.1° | 76.1° |\n| C — Head tube length | 9.6 | 10.5 | 11.5 | 12.5 |\n| D — Head angle | 65.5° | 65.5° | 65.5° | 65.5° |\n| E — Effective top tube | 58.6 | 61.3 | 64.0 | 66.7 |\n| F — Bottom bracket height | 34.0 | 34.0 | 34.0 | 34.0 |\n| G — Bottom bracket drop | 1.0 | 1.0 | 1.0 | 1.0 |\n| H — Chainstay length | 45.0 | 45.0 | 45.0 | 45.0 |\n| I — Offset | 4.6 | 4.6 | 4.6 | 4.6 |\n| J — Trail | 10.5 | 10.5 | 10.5 | 10.5 |\n| K — Wheelbase | 119.5 | 122.3 | 125.0 | 127.8 |\n| L — Standover | 72.7 | 74.7 | 77.6 | 81.0 |\n|",
"price": 1499.99,
"tags": [
"bicycle",
"electric bike",
"city bike"
]
},
{
"name": "Velo 99 XR1 AXS",
"shortDescription": "Velo 99 XR1 AXS is a next-generation bike designed for fast-paced adventure seekers and speed enthusiasts. Built for high-performance racing, the bike boasts state-of-the-art technology and premium components. It is the ultimate bike for riders who want to push their limits and get their adrenaline pumping.",
"description": "## Overview\nIt's right for you if...\nYou are a passionate cyclist looking for a bike that can keep up with your speed, agility, and endurance. You are an adventurer who loves to explore new terrains and challenge yourself on the toughest courses. You want a bike that is lightweight, durable, and packed with the latest technology.\n\nThe tech you get\nA lightweight, full carbon frame with advanced aerodynamics and integrated cable routing for a clean look. A high-performance SRAM XX1 Eagle AXS wireless electronic drivetrain, featuring a 12-speed cassette and a 32T chainring. A RockShox SID Ultimate fork with a remote lockout, 120mm travel, and Charger Race Day damper. A high-end SRAM G2 Ultimate hydraulic disc brake with carbon levers. A FOX Transfer SL dropper post for quick and easy height adjustments. DT Swiss XRC 1501 carbon wheels for superior speed and handling.\n\nThe final word\nVelo 99 XR1 AXS is a premium racing bike that can help you achieve your goals and reach new heights. It is designed for speed, agility, and performance, and it is packed with the latest technology and premium components. If you are a serious cyclist who wants the best, this is the bike for you.\n\n## Features\nAerodynamic design\n\nThe Velo 99 XR1 AXS features a state-of-the-art frame design that reduces drag and improves speed. It has an aerodynamic seatpost, integrated cable routing, and a sleek, streamlined look that sets it apart from other bikes.\n\nWireless electronic drivetrain\n\nThe SRAM XX1 Eagle AXS drivetrain features a wireless electronic system that provides precise, instant shifting and unmatched efficiency. It eliminates the need for cables and makes the bike lighter and faster.\n\nHigh-performance suspension\n\nThe RockShox SID Ultimate fork and Charger Race Day damper provide 120mm of smooth, responsive suspension that can handle any terrain. The fork also has a remote lockout for quick adjustments on the fly.\n\nSuperior braking power\n\nThe SRAM G2 Ultimate hydraulic disc brake system delivers unmatched stopping power and control. It has carbon levers for a lightweight, ergonomic design and precision control.\n\nCarbon wheels\n\nThe DT Swiss XRC 1501 carbon wheels are ultra-lightweight, yet incredibly strong and durable. They provide superior speed and handling, making the bike more agile and responsive.\n\n## Specs\nFrameset\nFrame\tFull carbon frame, integrated cable routing, aerodynamic design, Boost148\nFork\tRockShox SID Ultimate, Charger Race Day damper, remote lockout, tapered steerer, Boost110, 15mm Maxle Stealth, 120mm travel\n\nWheels\nWheel front\tDT Swiss XRC 1501 carbon wheel, Boost110, 15mm thru axle\nWheel rear\tDT Swiss XRC 1501 carbon wheel, SRAM XD driver, Boost148, 12mm thru axle\nTire\tSchwalbe Racing Ray, Performance Line, Addix, 29x2.25\"\nTire part\tSchwalbe Doc Blue Professional, 500ml\nMax tire size\t29x2.3\"\n\nDrivetrain\nShifter\tSRAM Eagle AXS, wireless, 12-speed\nRear derailleur\tSRAM XX1 Eagle AXS\nCrank\tSRAM XX1 Eagle, 32T, carbon\nChainring\tSRAM X-SYNC, 32T, alloy\nCassette\tSRAM Eagle XG-1299, 10-52, 12-speed\nChain\tSRAM XX1 Eagle, 12-speed\nMax chainring size\t1x: 32T\n\nComponents\nSaddle\tBontrager Montrose Elite, carbon rails, 138mm width\nSeatpost\tFOX Transfer SL, 125mm travel, internal routing, 31.6mm\nHandlebar\tBontrager Kovee Pro, ADV Carbon, 35mm, 5mm rise, 720mm width\nGrips\tBontrager XR Endurance Elite\nStem\tBontrager Kovee Pro, 35mm, Blendr compatible, 7 degree, 60mm length\nHeadset\tIntegrated, cartridge bearing, 1-1/8\" top, 1.5\" bottom\nBrake\tSRAM G2 Ultimate hydraulic disc, carbon levers, 180mm rotors\n\nAccessories\nBike computer\tBontrager Trip 300\nTool\tBontrager Flatline Pro pedal wrench, T25 Torx\n\n\n## Sizing & fit\n\n| Size | Rider Height | Inseam |\n|:----:|:------------------------:|:--------------------:|\n| S | 158 - 168 cm 5'2\" - 5'6\" | 74 - 78 cm 29\" - 31\" |\n| M | 165 - 175 cm 5'5\" - 5'9\" | 78 - 82 cm 31\" - 32\" |\n| L | 173 - 183 cm 5'8\" - 6'0\" | 82 - 86 cm 32\" - 34\" |\n| XL | 180 - 193 cm 5'11\" - 6'4\" | 86 - 90 cm 34\" - 35\" |\n\n\n## Geometry\n\nAll measurements provided in cm unless otherwise noted.\nSizing table\n| Frame size letter | S | M | L | XL |\n|---------------------------|-------|-------|-------|-------|\n| Actual frame size | 15.5 | 17.5 | 19.5 | 21.5 |\n| Wheel size | 29\" | 29\" | 29\" | 29\" |\n| A — Seat tube | 39.9 | 43.0 | 47.0 | 51.0 |\n| B — Seat tube angle | 74.5° | 74.5° | 74.5° | 74.5° |\n| C — Head tube length | 9.0 | 10.0 | 11.0 | 12.0 |\n| D — Head angle | 68.0° | 68.0° | 68.0° | 68.0° |\n| E — Effective top tube | 57.8 | 59.7 | 61.6 | 63.6 |\n| F — Bottom bracket height | 33.0 | 33.0 | 33.0 | 33.0 |\n| G — Bottom bracket drop | 5.0 | 5.0 | 5.0 | 5.0 |\n| H — Chainstay length | 43.0 | 43.0 | 43.0 | 43.0 |\n| I — Offset | 4.2 | 4.2 | 4.2 | 4.2 |\n| J — Trail | 9.7 | 9.7 | 9.7 | 9.7 |\n| K — Wheelbase | 112.5 | 114.5 | 116.5 | 118.6 |\n| L — Standover | 75.9 | 77.8 | 81.5 | 84.2 |\n| M — Frame reach | 41.6 | 43.4 | 45.2 | 47.1 |\n| N — Frame stack | 58.2 | 58.9 | 59.3 | 59.9 |",
"price": 1099.99,
"tags": [
"bicycle",
"mountain bike"
]
},
{
"name": "AURORA 11S E-MTB",
"shortDescription": "The AURORA 11S is a powerful and stylish electric mountain bike designed to take you on thrilling off-road adventures. With its sturdy frame and premium components, this bike is built to handle any terrain. It features a high-performance motor, long-lasting battery, and advanced suspension system that guarantee a smooth and comfortable ride.",
"description": "## Overview\nIt's right for you if...\nYou want a top-of-the-line e-MTB that is both powerful and stylish. You also want a bike that can handle any terrain, from steep climbs to rocky descents. With its advanced features and premium components, the AURORA 11S is designed for serious off-road riders who demand the best.\n\nThe tech you get\nA sturdy aluminum frame with advanced suspension system that provides 120mm of travel. A 750W brushless motor that delivers up to 28mph, and a 48V/14Ah lithium-ion battery that provides up to 60 miles of range on a single charge. An advanced 11-speed Shimano drivetrain with hydraulic disc brakes for precise shifting and reliable stopping power. \n\nThe final word\nThe AURORA 11S is a top-of-the-line e-MTB that delivers exceptional performance and style. Whether you're tackling steep climbs or hitting rocky descents, this bike is built to handle any terrain with ease. With its advanced features and premium components, the AURORA 11S is the perfect choice for serious off-road riders who demand the best.\n\n## Features\nPowerful and efficient\n\nThe AURORA 11S is equipped with a high-performance 750W brushless motor that delivers up to 28mph. The motor is powered by a long-lasting 48V/14Ah lithium-ion battery that provides up to 60 miles of range on a single charge.\n\nAdvanced suspension system\n\nThe bike's advanced suspension system provides 120mm of travel, ensuring a smooth and comfortable ride on any terrain. The front suspension is a Suntour XCR32 Air fork, while the rear suspension is a KS-281 hydraulic shock absorber.\n\nPremium components\n\nThe AURORA 11S features an advanced 11-speed Shimano drivetrain with hydraulic disc brakes. The bike is also equipped with a Tektro HD-E725 hydraulic disc brake system that provides reliable stopping power.\n\nSleek and stylish design\n\nWith its sleek and stylish design, the AURORA 11S is sure to turn heads on the trail. The bike's sturdy aluminum frame is available in a range of colors, including black, blue, and red.\n\n## Specs\nFrameset\nFrame Material: Aluminum\nFrame Size: S, M, L\nFork: Suntour XCR32 Air, 120mm Travel\nShock Absorber: KS-281 Hydraulic Shock Absorber\n\nWheels\nWheel Size: 27.5 inches\nTires: Kenda K1151 Nevegal, 27.5x2.35\nRims: Alloy Double Wall\nSpokes: 32H, Stainless Steel\n\nDrivetrain\nShifters: Shimano SL-M7000\nRear Derailleur: Shimano RD-M8000\nCrankset: Prowheel 42T, Alloy Crank Arm\nCassette: Shimano CS-M7000, 11-42T\nChain: KMC X11EPT\n\nBrakes\nBrake System: Tektro HD-E725 Hydraulic Disc Brake\nBrake Rotors: 180mm Front, 160mm Rear\n\nE-bike system\nMotor: 750W Brushless\nBattery: 48V/14Ah Lithium-Ion\nCharger: 48V/3A Smart Charger\nController: Intelligent Sinusoidal Wave\n\nWeight\nWeight: 59.5 lbs\n\n## Sizing & fit\n| Size | Rider Height | Standover Height |\n|------|-------------|-----------------|\n| S | 5'2\"-5'6\" | 28.5\" |\n| M | 5'7\"-6'0\" | 29.5\" |\n| L | 6'0\"-6'4\" | 30.5\" |\n\n## Geometry\nAll measurements provided in cm.\nSizing table\n| Frame size letter | S | M | L |\n|-------------------|-----|-----|-----|\n| Wheel Size | 27.5\"| 27.5\"| 27.5\"|\n| Seat tube length | 44.5| 48.5| 52.5|\n| Head tube angle | 68° | 68° | 68° |\n| Seat tube angle | 74.5°| 74.5°| 74.5°|\n| Effective top tube | 57.5| 59.5| 61.5|\n| Head tube length | 12.0| 12.0| 13.0|\n| Chainstay length | 45.5| 45.5| 45.5|\n| Bottom bracket height | 30.0| 30.0| 30.0|\n| Wheelbase | 115.0|116.5|118.5|",
"price": 1999.99,
"tags": [
"bicycle",
"road bike"
]
},
{
"name": "VeloTech V9.5 AXS Gen 3",
"shortDescription": "VeloTech V9.5 AXS is a sleek and fast carbon bike that combines high-end tech with a comfortable ride. It's designed to provide the ultimate experience for the most serious riders. The bike comes with a lightweight and powerful motor that can be activated when needed, and you get a spec filled with premium parts.",
"description": "## Overview\nIt's right for you if...\nYou want a bike that is fast, efficient, and delivers an adrenaline-filled experience. You are looking for a bike that is built with cutting-edge technology, and you want a ride that is both comfortable and exciting.\n\nThe tech you get\nA lightweight and durable full carbon frame with a fork that has 100mm of travel. The bike comes with a powerful motor that can deliver up to 20 mph of assistance. The drivetrain is a wireless electronic system that is precise and reliable. The bike is also equipped with hydraulic disc brakes, tubeless-ready wheels, and comfortable grips.\n\nThe final word\nThe VeloTech V9.5 AXS is a high-end bike that delivers an incredible experience for serious riders. It combines the latest technology with a comfortable ride, making it perfect for long rides, tough climbs, and fast descents.\n\n## Features\nFast and efficient\nThe VeloTech V9.5 AXS comes with a powerful motor that can provide up to 20 mph of assistance. The motor is lightweight and efficient, providing a boost when you need it without adding bulk. The bike's battery is removable, allowing you to ride without assistance when you don't need it.\n\nSmart software for the trail\nThe VeloTech V9.5 AXS is equipped with intelligent software that delivers a smooth and responsive ride. The software allows the motor to respond immediately as you start to pedal, delivering more power over a wider cadence range. You can also customize your user settings to suit your preferences.\n\nComfortable ride\nThe VeloTech V9.5 AXS is designed to provide a comfortable ride, even on long rides. The bike's fork has 100mm of travel, providing ample cushioning for rough terrain. The bike's grips are also designed to provide a comfortable and secure grip, even on the most challenging rides.\n\n## Specs\nFrameset\nFrame\tCarbon fiber frame with internal cable routing and Boost148\nFork\t100mm of travel with remote lockout\nShock\tN/A\n\nWheels\nWheel front\tCarbon fiber tubeless-ready wheel\nWheel rear\tCarbon fiber tubeless-ready wheel\nSkewer rear\t12mm thru-axle\nTire\tTubeless-ready tire\nTire part\tTubeless sealant\n\nDrivetrain\nShifter\tWireless electronic shifter\nRear derailleur\tWireless electronic derailleur\nCrank\tCarbon fiber crankset with chainring\nCrank arm\tCarbon fiber crank arm\nChainring\tAlloy chainring\nCassette\t12-speed cassette\nChain\t12-speed chain\n\nComponents\nSaddle\tCarbon fiber saddle\nSeatpost\tCarbon fiber seatpost\nHandlebar\tCarbon fiber handlebar\nGrips\tComfortable and secure grips\nStem\tCarbon fiber stem\nHeadset\tCarbon fiber headset\nBrake\tHydraulic disc brakes\nBrake rotor\tDisc brake rotor\n\nAccessories\nE-bike system\tPowerful motor with removable battery\nBattery\tLithium-ion battery\nCharger\tFast charging adapter\nController\tHandlebar-mounted controller\nTool\tBasic toolkit\n\nWeight\nWeight\tM - 17.5 kg / 38.5 lbs (with tubeless sealant)\n\nWeight limit\nThis bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\n\n## Sizing & fit\n| Size | Rider Height | Inseam |\n|:----:|:------------------------:|:--------------------:|\n| S | 160 - 170 cm 5'3\" - 5'7\" | 74 - 79 cm 29\" - 31\" |\n| M | 170 - 180 cm 5'7\" - 5'11\" | 79 - 84 cm 31\" - 33\" |\n| L | 180 - 190 cm 5'11\" - 6'3\" | 84 - 89 cm 33\" - 35\" |\n| XL | 190 - 200 cm 6'3\" - 6'7\" | 89 - 94 cm 35\" - 37\" |\n\n## Geometry\nAll measurements provided in cm unless otherwise noted.\nSizing table\n| Frame size letter | S | M | L | XL |\n|---------------------------|-------|-------|-------|-------|\n| Actual frame size | 50.0 | 53.3 | 55.6 | 58.8 |\n| Wheel size | 29\" | 29\" | 29\" | 29\" |\n| A — Seat tube | 39.4 | 43.2 | 48.3 | 53.3 |\n| B — Seat tube angle | 72.3° | 72.6° | 72.8° | 72.8° |\n| C — Head tube length | 9.0 | 10.0 | 10.5 | 11.0 |\n| D — Head angle | 67.5° | 67.5° | 67.5° | 67.5° |\n| E — Effective top tube | 58.0 | 61.7 | 64.8 | 67.0 |\n| F — Bottom bracket height | 32.3 | 32.3 | 32.3 | 32.3 |\n| G — Bottom bracket drop | 5.0 | 5.0 | 5.0 | 5.0 |\n| H — Chainstay length | 44.7 | 44.7 | 44.7 | 44.7 |\n| I — Offset | 4.2 | 4.2 | 4.2 | 4.2 |\n| J — Trail | 10.9 | 10.9 | 10.9 | 10.9 |\n| K — Wheelbase | 112.6 | 116.5 | 119.7 | 121.9 |\n| L — Standover | 76.8 | 76.8 | 76.8 | 76.8 |\n| M — Frame reach | 40.5 | 44.0 | 47.0 | 49.0 |\n| N — Frame stack | 60.9 | 61.8 | 62.2 | 62.7 |",
"price": 1699.99,
"tags": [
"bicycle",
"electric bike",
"city bike"
]
},
{
"name": "Axiom D8 E-Mountain Bike",
"shortDescription": "The Axiom D8 is an electrifying mountain bike that is built for adventure. It boasts a light aluminum frame, a powerful motor and the latest tech to tackle the toughest of terrains. The D8 provides assistance without adding bulk to the bike, giving you the flexibility to ride like a traditional mountain bike or have an extra push when you need it.",
"description": "## Overview \nIt's right for you if... \nYou're looking for an electric mountain bike that can handle a wide variety of terrain, from flowing singletrack to technical descents. You also want a bike that offers a powerful motor that provides assistance without adding bulk to the bike. The D8 is designed to take you anywhere, quickly and comfortably.\n\nThe tech you get \nA lightweight aluminum frame with 140mm of travel, a Suntour fork with hydraulic lockout, and a reliable and powerful Bafang M400 mid-motor that provides a boost up to 20 mph. The bike features a Shimano Deore drivetrain, hydraulic disc brakes, and a dropper seat post. With the latest tech on-board, the D8 is designed to take you to new heights.\n\nThe final word \nThe Axiom D8 is an outstanding electric mountain bike that is designed for adventure. It's built with the latest tech and provides the flexibility to ride like a traditional mountain bike or have an extra push when you need it. Whether you're a beginner or an experienced rider, the D8 is the perfect companion for your next adventure.\n\n## Features \nBuilt for Adventure \n\nThe D8 features a lightweight aluminum frame that is built to withstand rugged terrain. It comes equipped with 140mm of travel and a Suntour fork that can handle even the toughest of trails. With this bike, you're ready to take on anything the mountain can throw at you.\n\nPowerful Motor \n\nThe Bafang M400 mid-motor provides reliable and powerful assistance without adding bulk to the bike. You can quickly and easily switch between the different assistance levels to find the perfect balance between range and power.\n\nShimano Deore Drivetrain \n\nThe Shimano Deore drivetrain is reliable and offers smooth shifting on any terrain. You can easily adjust the gears to match your riding style and maximize your performance on the mountain.\n\nDropper Seat Post \n\nThe dropper seat post allows you to easily adjust your seat height on the fly, so you can maintain the perfect position for any terrain. With the flick of a switch, you can quickly and easily lower or raise your seat to match the terrain.\n\nHydraulic Disc Brakes \n\nThe D8 features powerful hydraulic disc brakes that offer reliable stopping power in any weather condition. You can ride with confidence knowing that you have the brakes to stop on a dime.\n\n## Specs \nFrameset \nFrame\tAluminum frame with 140mm of travel \nFork\tSuntour fork with hydraulic lockout, 140mm of travel \nShock\tN/A \nMax compatible fork travel\t140mm \n \nWheels \nWheel front\tAlloy wheel \nWheel rear\tAlloy wheel \nSkewer rear\tThru axle \nTire\t29\" x 2.35\" \nTire part\tN/A \nMax tire size\t29\" x 2.6\" \n \nDrivetrain \nShifter\tShimano Deore \nRear derailleur\tShimano Deore \nCrank\tBafang M400 \nCrank arm\tN/A \nChainring\tN/A \nCassette\tShimano Deore \nChain\tShimano Deore \nMax chainring size\tN/A \n \nComponents \nSaddle\tAxiom D8 saddle \nSeatpost\tDropper seat post \nHandlebar\tAxiom D8 handlebar \nGrips\tAxiom D8 grips \nStem\tAxiom D8 stem \nHeadset\tAxiom D8 headset \nBrake\tHydraulic disc brakes \nBrake rotor\t180mm \n\nAccessories \nE-bike system\tBafang M400 mid-motor \nBattery\tLithium-ion battery, 500Wh \nCharger\tLithium-ion charger \nController\tBafang M400 controller \nTool\tN/A \n \nWeight \nWeight\tM - 22 kg / 48.5 lbs \nWeight limit\tThis bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 136 kg (300 lbs). \n \n \n## Sizing & fit \n \n| Size | Rider Height | Inseam | \n|:----:|:------------------------:|:--------------------:| \n| S | 152 - 165 cm 5'0\" - 5'5\" | 70 - 76 cm 27\" - 30\" | \n| M | 165 - 178 cm 5'5\" - 5'10\" | 76 - 81 cm 30\" - 32\" | \n| L | 178 - 185 cm 5'10\" - 6'1\" | 81 - 86 cm 32\" - 34\" | \n| XL | 185 - 193 cm 6'1\" - 6'4\" | 86 - 91 cm 34\" - 36\" | \n \n \n## Geometry \n \nAll measurements provided in cm unless otherwise noted. \nSizing table \n| Frame size letter | S | M | L | XL | \n|---------------------------|-------|-------|-------|-------| \n| Actual frame size | 41.9 | 46.5 | 50.8 | 55.9 | \n| Wheel size | 29\" | 29\" | 29\" | 29\" | \n| A — Seat tube | 42.0 | 46.5 | 51.0 | 56.0 | \n| B — Seat tube angle | 74.0° | 74.0° | 74.0° | 74.0° | \n| C — Head tube length | 11.0 | 12.0 | 13.0 | 15.0 | \n| D — Head angle | 68.0° | 68.0° | 68.0° | 68.0° | \n| E — Effective top tube | 57.0 | 60.0 | 62.0 | 65.0 | \n| F — Bottom bracket height | 33.0 | 33.0 | 33.0 | 33.0 | \n| G — Bottom bracket drop | 3.0 | 3.0 | 3.0 | 3.0 | \n| H — Chainstay length | 46.0 | 46.0 | 46.0 | 46.0 | \n| I — Offset | 4.5 | 4.5 | 4.5 | 4.5 | \n| J — Trail | 10.9 | 10.9 | 10.9 | 10.9 | \n| K — Wheelbase | 113.0 | 116.0 | 117.5 | 120.5 | \n| L — Standover | 73.5 | 75.5 | 76.5 | 79.5 | \n| M — Frame reach | 41.0 | 43.5 | 45.0 | 47.5 | \n| N — Frame stack | 60.5 | 61.5 | 62.5 | 64.5 |",
"price": 1399.99,
"tags": [
"bicycle",
"electric bike",
"mountain bike"
]
},
{
"name": "Velocity X1",
"shortDescription": "Velocity X1 is a high-performance road bike designed for speed enthusiasts. It features a lightweight yet durable frame, aerodynamic design, and top-quality components, making it the perfect choice for those who want to take their cycling experience to the next level.",
"description": "## Overview\nIt's right for you if...\nYou're an experienced cyclist looking for a bike that can keep up with your need for speed. You want a bike that's lightweight, aerodynamic, and built to perform, whether you're training for a race or just pushing yourself to go faster.\n\nThe tech you get\nA lightweight aluminum frame with a carbon fork, Shimano Ultegra groupset with a wide range of gearing, hydraulic disc brakes, aerodynamic carbon wheels, and a vibration-absorbing handlebar with ergonomic grips.\n\nThe final word\nVelocity X1 is the ultimate road bike for speed enthusiasts. Its lightweight frame, aerodynamic design, and top-quality components make it the perfect choice for those who want to take their cycling experience to the next level.\n\n\n## Features\n\nAerodynamic design\nVelocity X1 is built with an aerodynamic design to help you go faster with less effort. It features a sleek profile, hidden cables, and a carbon fork that cuts through the wind, reducing drag and increasing speed.\n\nHydraulic disc brakes\nVelocity X1 comes equipped with hydraulic disc brakes, providing excellent stopping power in all weather conditions. They're also low maintenance, with minimal adjustments needed over time.\n\nCarbon wheels\nThe Velocity X1's aerodynamic carbon wheels provide excellent speed and responsiveness, helping you achieve your fastest times yet. They're also lightweight, reducing overall bike weight and making acceleration and handling even easier.\n\nShimano Ultegra groupset\nThe Shimano Ultegra groupset provides smooth shifting and reliable performance, ensuring you get the most out of every ride. With a wide range of gearing options, it's ideal for tackling any terrain, from steep climbs to fast descents.\n\n\n## Specifications\nFrameset\nFrame with Fork\tAluminium frame, internal cable routing, 135x9mm QR\nFork\tCarbon, hidden cable routing, 100x9mm QR\n\nWheels\nWheel front\tCarbon, 30mm deep rim, 23mm width, 100x9mm QR\nWheel rear\tCarbon, 30mm deep rim, 23mm width, 135x9mm QR\nSkewer front\t100x9mm QR\nSkewer rear\t135x9mm QR\nTire\tContinental Grand Prix 5000, 700x25mm, folding bead\nMax tire size\t700x28mm without fenders\n\nDrivetrain\nShifter\tShimano Ultegra R8020, 11 speed\nRear derailleur\tShimano Ultegra R8000, 11 speed\nCrank\tSize: S, M\nShimano Ultegra R8000, 50/34T, 170mm length\nSize: L, XL\nShimano Ultegra R8000, 50/34T, 175mm length\nBottom bracket\tShimano BB-RS500-PB, PressFit\nCassette\tShimano Ultegra R8000, 11-30T, 11 speed\nChain\tShimano Ultegra HG701, 11 speed\nPedal\tNot included\nMax chainring size\t50/34T\n\nComponents\nSaddle\tBontrager Montrose Comp, steel rails, 138mm width\nSeatpost\tBontrager Comp, 6061 alloy, 27.2mm, 8mm offset, 330mm length\nHandlebar\tSize: S, M, L\nBontrager Elite Aero VR-CF, alloy, 31.8mm, 93mm reach, 123mm drop, 400mm width\nSize: XL\nBontrager Elite Aero VR-CF, alloy, 31.8mm, 93mm reach, 123mm drop, 420mm width\nGrips\tBontrager Supertack Perf tape\n*Stem\tSize: S, M, L\nBontrager Elite Blendr, 31.8mm clamp, 7 degree, 90mm length\nSize: XL\nBontrager Elite Blendr, 31.8mm clamp, 7 degree, 100mm length\nBrake\tShimano Ultegra R8070 hydraulic disc, flat mount\nBrake rotor\tShimano RT800, centerlock, 160mm\nRotor size\tMax brake rotor sizes: 160mm front & rear\n\nWeight\nWeight\tM - 8.15 kg / 17.97 lbs\nWeight limit\tThis bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 275 pounds (125 kg).\n\n\n## Sizing\n| Size | Rider Height | Inseam |\n|:----:|:-------------------------:|:--------------------:|\n| S | 162 - 170 cm 5'4\" - 5'7\" | 74 - 78 cm 29\" - 31\" |\n| M | 170 - 178 cm 5'7\" - 5'10\" | 77 - 82 cm 30\" - 32\" |\n| L | 178 - 186 cm 5'10\" - 6'1\" | 82 - 86 cm 32\" - 34\" |\n| XL | 186 - 196 cm 6'1\" - 6'5\" | 87 - 92 cm 34\" - 36\" |\n\n\n## Geometry\n| Frame size letter | S | M | L | XL |\n|---------------------------|-------|-------|-------|-------|\n| Wheel size | 700c | 700c | 700c | 700c |\n| A — Seat tube | 50.0 | 52.0 | 54.0 | 56.0 |\n| B — Seat tube angle | 74.0° | 73.5° | 73.0° | 72.5° |\n| C — Head tube length | 13.0 | 15.0 | 17.0 | 19.0 |\n| D — Head angle | 71.0° | 72.0° | 72.0° | 72.5° |\n| E — Effective top tube | 53.7 | 55.0 | 56.5 | 58.0 |\n| F — Bottom bracket height | 27.5 | 27.5 | 27.5 | 27.5 |\n| G — Bottom bracket drop | 7.3 | 7.3 | 7.3 | 7.3 |\n| H — Chainstay length | 41.0 | 41.0 | 41.0 | 41.0 |\n| I — Offset | 4.5 | 4.5 | 4.5 | 4.5 |\n| J — Trail | 6.0 | 6.0 | 6.0 | 5.8 |\n| K — Wheelbase | 98.2 | 99.1 | 100.1 | 101.0 |\n| L — Standover | 75.2 | 78.2 | 81.1 | 84.1 |\n| M — Frame reach | 37.5 | 38.3 | 39.1 | 39.9 |\n| N — Frame stack | 53.3 | 55.4 | 57.4 | 59.5 |",
"price": 1799.99,
"tags": [
"bicycle",
"touring bike"
]
},
{
"name": "Velocity V9",
"shortDescription": "Velocity V9 is a high-performance hybrid bike that combines speed and comfort for riders who demand the best of both worlds. The lightweight aluminum frame, along with the carbon fork and seat post, provide optimal stiffness and absorption to tackle any terrain. A 2x Shimano Deore drivetrain, hydraulic disc brakes, and 700c wheels with high-quality tires make it a versatile ride for commuters, fitness riders, and weekend adventurers alike.",
"description": "## Overview\nIt's right for you if...\nYou want a fast, versatile bike that can handle anything from commuting to weekend adventures. You value comfort as much as speed and performance. You want a reliable and durable bike that will last for years to come.\n\nThe tech you get\nA lightweight aluminum frame with a carbon fork and seat post, a 2x Shimano Deore drivetrain with a wide range of gearing, hydraulic disc brakes, and 700c wheels with high-quality tires. The Velocity V9 is designed for riders who demand both performance and comfort in one package.\n\nThe final word\nThe Velocity V9 is the perfect bike for riders who want speed and performance without sacrificing comfort. The lightweight aluminum frame and carbon components provide optimal stiffness and absorption, while the 2x Shimano Deore drivetrain and hydraulic disc brakes ensure precise shifting and stopping power. Whether you're commuting, hitting the trails, or training for your next race, the Velocity V9 has everything you need to achieve your goals.\n\n## Features\n\n2x drivetrain\nA 2x drivetrain means more versatility and a wider range of gearing options. Whether you're climbing hills or sprinting on the flats, the Velocity V9 has the perfect gear for any situation.\n\nCarbon components\nThe Velocity V9 features a carbon fork and seat post to provide optimal stiffness and absorption. This means you can ride faster and more comfortably over any terrain.\n\nHydraulic disc brakes\nHydraulic disc brakes provide unparalleled stopping power and modulation in any weather condition. You'll feel confident and in control no matter where you ride.\n\n## Specifications\nFrameset\nFrame with Fork\tAluminum frame with carbon fork and seat post, internal cable routing, fender mounts, 135x5mm ThruSkew\nFork\tCarbon fork, hidden fender mounts, flat mount disc, 5x100mm thru-skew\n\nWheels\nWheel front\tDouble wall aluminum rims, 700c, quick release hub\nWheel rear\tDouble wall aluminum rims, 700c, quick release hub\nTire\tKenda Kwick Tendril, puncture resistant, reflective sidewall, 700x32c\nMax tire size\t700x35c without fenders, 700x32c with fenders\n\nDrivetrain\nShifter\tShimano Deore, 10 speed\nFront derailleur\tShimano Deore\nRear derailleur\tShimano Deore\nCrank\tShimano Deore, 46-30T, 170mm (S/M), 175mm (L/XL)\nBottom bracket\tShimano BB52, 68mm, threaded\nCassette\tShimano Deore, 11-36T, 10 speed\nChain\tShimano HG54, 10 speed\nPedal\tWellgo alloy platform\n\nComponents\nSaddle\tVelo VL-2158, steel rails\nSeatpost\tCarbon seat post, 27.2mm\nHandlebar\tAluminum, 31.8mm clamp, 15mm rise, 680mm width\nGrips\tVelo ergonomic grips\nStem\tAluminum, 31.8mm clamp, 7 degree, 90mm length\nBrake\tShimano hydraulic disc, MT200 lever, MT200 caliper\nBrake rotor\tShimano RT56, centerlock, 160mm\nRotor size\tMax brake rotor sizes: 160mm front & rear\n\nWeight\nWeight\tM - 11.5 kg / 25.35 lbs\nWeight limit\tThis bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\n\n## Sizing\n| Size | Rider Height | Inseam |\n|:----:|:-------------------------:|:--------------------:|\n| S | 155 - 165 cm 5'1\" - 5'5\" | 72 - 78 cm 28\" - 31\" |\n| M | 165 - 175 cm 5'5\" - 5'9\" | 77 - 83 cm 30\" - 33\" |\n| L | 175 - 186 cm 5'9\" - 6'1\" | 82 - 88 cm 32\" - 35\" |\n| XL | 186 - 197 cm 6'1\" - 6'6\" | 87 - 93 cm 34\" - 37\" |\n\n## Geometry\n| Frame size | S | M | L | XL |\n|--------------------|-------|-------|-------|-------|\n| Wheel size | 700c | 700c | 700c | 700c |\n| A — Seat tube | 44.0 | 48.0 | 52.0 | 56.0 |\n| B — Seat tube angle | 74.5° | 74.0° | 73.5° | 73.0° |\n| C — Head tube length | 14.5 | 16.0 | 18.0 | 20.0 |\n| D — Head angle | 71.0° | 71.0° | 71.5° | 71.5° |\n| E — Effective top tube | 56.5 | 57.5 | 58.5 | 59.5 |\n| F — Bottom bracket height | 27.0 | 27.0 | 27.0 | 27.0 |\n| G — Bottom bracket drop | 7.0 | 7.0 | 7.0 | 7.0 |\n| H — Chainstay length | 43.0 | 43.0 | 43.0 | 43.0 |\n| I — Offset | 4.5 | 4.5 | 4.5 | 4.5 |\n| J — Trail | 7.0 | 7.0 | 6.6 | 6.6 |\n| K — Wheelbase | 105.4 | 106.3 | 107.2 | 108.2 |\n| L — Standover | 73.2 | 77.1 | 81.2 | 85.1 |\n| M — Frame reach | 39.0 | 39.8 | 40.4 | 41.3 |\n| N — Frame stack | 57.0 | 58.5 | 60.0 | 61.5 |",
"price": 2199.99,
"tags": [
"bicycle",
"electric bike",
"mountain bike"
]
},
{
"name": "Aero Pro X",
"shortDescription": "Aero Pro X is a high-end racing bike designed for serious cyclists who demand speed, agility, and superior performance. The lightweight carbon frame and fork, combined with the aerodynamic design, provide optimal stiffness and efficiency to maximize your speed. The bike features a 2x Shimano Ultegra drivetrain, hydraulic disc brakes, and 700c wheels with high-quality tires. Whether you're competing in a triathlon or climbing steep hills, Aero Pro X delivers exceptional performance and precision handling.",
"description": "## Overview\nIt's right for you if...\nYou are a competitive cyclist looking for a bike that is designed for racing. You want a bike that delivers exceptional speed, agility, and precision handling. You demand superior performance and reliability from your equipment.\n\nThe tech you get\nA lightweight carbon frame with an aerodynamic design, a carbon fork with hidden fender mounts, a 2x Shimano Ultegra drivetrain with a wide range of gearing, hydraulic disc brakes, and 700c wheels with high-quality tires. Aero Pro X is designed for serious cyclists who demand nothing but the best.\n\nThe final word\nAero Pro X is the ultimate racing bike for serious cyclists. The lightweight carbon frame and aerodynamic design deliver maximum speed and efficiency, while the 2x Shimano Ultegra drivetrain and hydraulic disc brakes ensure precise shifting and stopping power. Whether you're competing in a triathlon or a criterium race, Aero Pro X delivers the performance you need to win.\n\n## Features\n\nAerodynamic design\nThe Aero Pro X features an aerodynamic design that reduces drag and maximizes efficiency. The bike is optimized for speed and agility, so you can ride faster and farther with less effort.\n\nHydraulic disc brakes\nHydraulic disc brakes provide unrivaled stopping power and modulation in any weather condition. You'll feel confident and in control no matter where you ride.\n\nCarbon components\nThe Aero Pro X features a carbon fork with hidden fender mounts to provide optimal stiffness and absorption. This means you can ride faster and more comfortably over any terrain.\n\n## Specifications\nFrameset\nFrame with Fork\tCarbon frame with an aerodynamic design, internal cable routing, 3s chain keeper, 142x12mm thru-axle\nFork\tCarbon fork with hidden fender mounts, flat mount disc, 100x12mm thru-axle\n\nWheels\nWheel front\tDouble wall carbon rims, 700c, thru-axle hub\nWheel rear\tDouble wall carbon rims, 700c, thru-axle hub\nTire\tContinental Grand Prix 5000, folding bead, 700x25c\nMax tire size\t700x28c without fenders, 700x25c with fenders\n\nDrivetrain\nShifter\tShimano Ultegra, 11 speed\nFront derailleur\tShimano Ultegra\nRear derailleur\tShimano Ultegra\nCrank\tShimano Ultegra, 52-36T, 170mm (S), 172.5mm (M), 175mm (L/XL)\nBottom bracket\tShimano BB72, 68mm, PressFit\nCassette\tShimano Ultegra, 11-30T, 11 speed\nChain\tShimano HG701, 11 speed\nPedal\tNot included\n\nComponents\nSaddle\tBontrager Montrose Elite, carbon rails, 138mm width\nSeatpost\tCarbon seat post, 27.2mm, 20mm offset\nHandlebar\tBontrager XXX Aero, carbon, 31.8mm clamp, 75mm reach, 125mm drop\nGrips\tBontrager Supertack Perf tape\nStem\tBontrager Pro, 31.8mm clamp, 7 degree, 90mm length\nBrake\tShimano hydraulic disc, Ultegra lever, Ultegra caliper\nBrake rotor\tShimano RT800, centerlock, 160mm\nRotor size\tMax brake rotor sizes: 160mm front & rear\n\nWeight\nWeight\tM - 8.36 kg / 18.42 lbs\nWeight limit\tThis bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 275 pounds (125 kg).\n\n## Sizing\n| Size | Rider Height |\n|:----:|:-------------------------:|\n| S | 155 - 165 cm 5'1\" - 5'5\" |\n| M | 165 - 175 cm 5'5\" - 5'9\" |\n| L | 175 - 186 cm 5'9\" - 6'1\" |\n| XL | 186 - 197 cm 6'1\" - 6'6\" |\n\n## Geometry\n| Frame size | S | M | L | XL |\n|--------------------|-------|-------|-------|-------|\n| Wheel size | 700c | 700c | 700c | 700c |\n| A — Seat tube | 50.6 | 52.4 | 54.3 | 56.2 |\n| B — Seat tube angle | 75.5° | 74.5° | 73.5° | 72.5° |\n| C — Head tube length | 12.0 | 14.0 | 16.0 | 18.0 |\n| D — Head angle | 72.5° | 73.0° | 73.5° | 74.0° |\n| E — Effective top tube | 53.8 | 55.4 | 57.0 | 58.6 |\n| F — Bottom bracket height | 26.5 | 26.5 | 26.5 | 26.5 |\n| G — Bottom bracket drop | 7.0 | 7.0 | 7.0 | 7.0 |\n| H — Chainstay length | 41.0 | 41.0 | 41.0 | 41.0 |\n| I — Offset | 4.5 | 4.5 | 4.5 | 4.5 |\n| J — Trail | 6.0 | 6.0 | 6.0 | 6.0 |\n| K — Wheelbase | 97.1 | 98.7 | 100.2 | 101.8 |\n| L — Standover | 73.8 | 76.2 | 78.5 | 80.8 |\n| M — Frame reach | 38.8 | 39.5 | 40.2 | 40.9 |\n| N — Frame stack | 52.8 | 54.7 | 56.6 | 58.5 |",
"price": 1599.99,
"tags": [
"bicycle",
"road bike"
]
},
{
"name": "Voltex+ Ultra Lowstep",
"shortDescription": "Voltex+ Ultra Lowstep is a high-performance electric hybrid bike designed for riders who seek speed, comfort, and reliability during their everyday rides. Equipped with a powerful and efficient Voltex Drive Pro motor and a fully-integrated 600Wh battery, this e-bike allows you to cover longer distances on a single charge. The Voltex+ Ultra Lowstep comes with premium components that prioritize comfort and safety, such as a suspension seatpost, wide and stable tires, and integrated lights.",
"description": "## Overview\n\nIt's right for you if...\nYou want an e-bike that provides a boost for faster rides and effortless usage. Durability is crucial, and you need a bike with one of the most powerful and efficient motors.\n\nThe tech you get\nA lightweight Delta Carbon Fiber frame with an ultra-lowstep design, a Voltex Drive Pro (350W, 75Nm) motor capable of maintaining speeds up to 30 mph, an extended range 600Wh battery integrated into the frame, and a Voltex Control Panel. Additionally, it features a 12-speed Shimano drivetrain, hydraulic disc brakes for optimal all-weather stopping power, a suspension seatpost, wide puncture-resistant tires for added stability, ergonomic grips, a kickstand, lights, and a cargo rack.\n\nThe final word\nThis bike offers enhanced enjoyment and ease of use on long commutes, leisure rides, and adventures. With its extended-range battery, powerful Voltex motor, user-friendly controller, and a seatpost that smooths out road vibrations, it guarantees an exceptional riding experience.\n\n## Features\n\nUltra-fast assistance\n\nExperience speeds up to 30 mph with the cutting-edge Voltex Drive Pro motor, allowing you to breeze through errands, commutes, and joyrides.\n\n## Specs\n\nFrameset\n- Frame: Delta Carbon Fiber, Removable Integrated Battery (RIB), sleek welds, rack & fender mounts, internal routing, kickstand mount, 135x5mm QR\n- Fork: Voltex Alloy, threaded steel steerer, rack mounts, post mount disc, 460mm axle-to-crown, ThruSkew 5mm QR\n- Max compatible fork travel: 50mm\n\nWheels\n- Hub front: Formula DC-20, alloy, 6-bolt, 5x100mm QR\n- Skewer front: 132x5mm QR, ThruSkew\n- Hub rear: Formula DC-22, alloy, 6-bolt, Shimano 8/9/10 freehub, 135x5mm QR\n- Skewer rear: 153x5mm bolt-on\n- Rim: Voltex Connection, double-wall, 32-hole, 20 mm width, Schrader valve\n- Tire: Voltex E6 Hard-Case Lite, reflective, wire bead, 60tpi, 700x50c\n- Max tire size: 700x50mm with or without fenders\n\nDrivetrain\n- Shifter: Shimano Deore XT M8100, 12-speed\n- Rear derailleur: Shimano Deore XT M8100, long cage\n- Crank: Voltex alloy, 170mm length\n- Chainring: FSA, 44T, aluminum with guard\n- Cassette: Shimano Deore XT M8100, 10-51, 12-speed\n- Chain: KMC E12 Turbo\n- Pedal: Voltex Urban pedals\n\nComponents\n- Saddle: Voltex Boulevard\n- Seatpost: Alloy, suspension, 31.6mm, 300mm length\n- Handlebar: Voltex alloy, 31.8mm, comfort sweep, 620mm width (XS, S, M), 660mm width (L)\n- Grips: Voltex Satellite Elite, alloy lock-on\n- Stem: Voltex alloy quill, 31.8mm clamp, adjustable rise, Blendr compatible, 85mm length (XS, S), 105mm length (M, L)\n- Headset: VP sealed cartridge, 1-1/8'', threaded\n- Brake: Shimano MT520 hydraulic disc\n- Brake rotor: Shimano RT56, 6-bolt, 180mm (XS, S, M, L), 160mm (XS, S, M, L)\n\nAccessories\n- Battery: Voltex PowerTube 600Wh\n- Charger: Voltex compact 2A, 100-240V\n- Computer: Voltex Control Panel\n- Motor: Voltex Drive Pro, 75Nm, 30mph\n- Light: Voltex Solo for e-bike, taillight (XS, S, M, L), Voltex MR8, 180 lumen, 60 lux, LED, headlight (XS, S, M, L)\n- Kickstand: Adjustable length rear mount alloy kickstand\n- Cargo rack: Voltex-compatible alloy rear rack, maximum load 25 kg / 55 lbs\n- Fender: Voltex wide (XS, S, M, L), Voltex plastic (XS, S, M, L)\n\nWeight\n- Weight: M - 20.50 kg / 45.19 lbs\n- Weight limit: This bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 330 pounds (150 kg).\n\n## Sizing\n\n| Size | Rider Height | Inseam |\n|:----:|:-------------------------:|:--------------------:|\n| XS | 147 - 155 cm 4'10\" - 5'1\" | 69 - 73 cm 27\" - 29\" |\n| S | 155 - 165 cm 5'1\" - 5'5\" | 72 - 78 cm 28\" - 31\" |\n| M | 165 - 175 cm 5'5\" - 5'9\" | 77 - 83 cm 30\" - 33\" |\n| L | 175 - 186 cm 5'9\" - 6'1\" | 82 - 88 cm 32\" - 35\" |\n\n## Geometry\n\nAll measurements provided in cm unless otherwise noted.\n\nSizing table\n\n| Frame size number | 40 cm | 45 cm | 50 cm | 55 cm |\n|---------------------------|-------|-------|-------|-------|\n| Frame size letter | XS | S | M | L |\n| Wheel size | 700c | 700c | 700c | 700c |\n| A — Seat tube | 38.0 | 43.0 | 48.0 | 53.0 |\n| B — Seat tube angle | 70.5° | 70.5° | 70.5° | 70.5° |\n| C — Head tube length | 15.0 | 15.0 | 17.0 | 19.0 |\n| D — Head angle | 69.2° | 69.2° | 69.2° | 69.2° |\n| E — Effective top tube | 57.2 | 57.7 | 58.8 | 60.0 |\n| F — Bottom bracket height | 30.3 | 30.3 | 30.3 | 30.3 |\n| G — Bottom bracket drop | 6.0 | 6.0 | 6.0 | 6.0 |\n| H — Chainstay length | 48.5 | 48.5 | 48.5 | 48.5 |\n| I — Offset | 5.0 | 5.0 | 5.0 | 5.0 |\n| J — Trail | 9.0 | 9.0 | 9.0 | 9.0 |\n| K — Wheelbase | 111.8 | 112.3 | 113.6 | 114.8 |\n| L — Standover | 42.3 | 42.3 | 42.3 | 42.3 |\n| M — Frame reach | 36.0 | 38.0 | 38.0 | 38.0 |\n| N — Frame stack | 62.0 | 62.0 | 63.9 | 65.8 |\n| Stem length | 8.0 | 8.5 | 8.5 | 10.5 |\n\nPlease note that the specifications and features listed above are subject to change and may vary based on different models and versions of the Voltex+ Ultra Lowstep bike.",
"price": 2999.99,
"tags": [
"bicycle",
"road bike",
"professional"
]
},
{
"name": "SwiftRide Hybrid",
"shortDescription": "SwiftRide Hybrid is a versatile and efficient bike designed for riders who want a smooth and enjoyable ride on various terrains. It incorporates advanced technology and high-quality components to provide a comfortable and reliable cycling experience.",
"description": "## Overview\n\nIt's right for you if...\nYou are looking for a bike that combines the benefits of an electric bike with the versatility of a hybrid. You value durability, speed, and ease of use.\n\nThe tech you get\nThe SwiftRide Hybrid features a lightweight and durable aluminum frame, making it easy to handle and maneuver. It is equipped with a powerful electric motor that offers a speedy assist, helping you reach speeds of up to 25 mph. The bike comes with a removable and fully-integrated 500Wh battery, providing a long-range capacity for extended rides. It also includes a 10-speed Shimano drivetrain, hydraulic disc brakes for precise stopping power, wide puncture-resistant tires for stability, and integrated lights for enhanced visibility.\n\nThe final word\nThe SwiftRide Hybrid is designed for riders who want a bike that can handle daily commutes, recreational rides, and adventures. With its efficient motor, intuitive controls, and comfortable features, it offers an enjoyable and hassle-free riding experience.\n\n## Features\n\nEfficient electric assist\nExperience the thrill of effortless riding with the powerful electric motor that provides a speedy assist, making your everyday rides faster and more enjoyable.\n\n## Specs\n\nFrameset\n- Frame: Lightweight Aluminum, Removable Integrated Battery (RIB), rack & fender mounts, internal routing, 135x5mm QR\n- Fork: SwiftRide Alloy, threaded steel steerer, rack mounts, post mount disc, 460mm axle-to-crown, ThruSkew 5mm QR\n- Max compatible fork travel: 50mm\n\nWheels\n- Hub front: Formula DC-20, alloy, 6-bolt, 5x100mm QR\n- Skewer front: 132x5mm QR, ThruSkew\n- Hub rear: Formula DC-22, alloy, 6-bolt, Shimano 8/9/10 freehub, 135x5mm QR\n- Skewer rear: 153x5mm bolt-on\n- Rim: SwiftRide Connection, double-wall, 32-hole, 20 mm width, Schrader valve\n- Tire: SwiftRide E6 Hard-Case Lite, reflective, wire bead, 60tpi, 700x50c\n- Max tire size: 700x50mm with or without fenders\n\nDrivetrain\n- Shifter: Shimano Deore M4100, 10 speed\n- Rear derailleur: Shimano Deore M5120, long cage\n- Crank: ProWheel alloy, 170mm length\n- Chainring: FSA, 42T, steel w/guard\n- Cassette: Shimano Deore M4100, 11-42, 10 speed\n- Chain: KMC E10\n- Pedal: SwiftRide City pedals\n\nComponents\n- Saddle: SwiftRide Boulevard\n- Seatpost: Alloy, suspension, 31.6mm, 300mm length\n- Handlebar:\n - Size: XS, S, M - SwiftRide alloy, 31.8mm, comfort sweep, 620mm width\n - Size: L - SwiftRide alloy, 31.8mm, comfort sweep, 660mm width\n- Grips: SwiftRide Satellite Elite, alloy lock-on\n- Stem:\n - Size: XS, S - SwiftRide alloy quill, 31.8mm clamp, adjustable rise, 85mm length\n - Size: M, L - SwiftRide alloy quill, 31.8mm clamp, adjustable rise, 105mm length\n- Headset: VP sealed cartridge, 1-1/8'', threaded\n- Brake: Shimano MT200 hydraulic disc\n- Brake rotor:\n - Size: XS, S, M, L - Shimano RT26, 6-bolt, 180mm\n - Size: XS, S, M, L - Shimano RT26, 6-bolt, 160mm\n\nAccessories\n- Battery: SwiftRide PowerTube 500Wh\n- Charger: SwiftRide compact 2A, 100-240V\n- Computer: SwiftRide Purion\n- Motor: SwiftRide Performance Line Sport, 65Nm, 25mph\n- Light:\n - Size: XS, S, M, L - SwiftRide SOLO for e-bike, taillight\n - Size: XS, S, M, L - SwiftRide MR8, 180 lumen, 60 lux, LED, headlight\n- Kickstand: Adjustable length rear mount alloy kickstand\n- Cargo rack: SwiftRide-compatible alloy rear rack, maximum load 25 kg / 55 lbs\n- Fender:\n - Size: XS, S, M, L - SwiftRide wide\n - Size: XS, S, M, L - SwiftRide plastic\n\nWeight\n- Weight: M - 22.30 kg / 49.17 lbs\n- Weight limit: This bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\n\n## Sizing\n\n| Size | Rider Height | Inseam |\n|:----:|:-------------------------:|:--------------------:|\n| XS | 147 - 155 cm (4'10\" - 5'1\") | 69 - 73 cm (27\" - 29\") |\n| S | 155 - 165 cm (5'1\" - 5'5\") | 72 - 78 cm (28\" - 31\") |\n| M | 165 - 175 cm (5'5\" - 5'9\") | 77 - 83 cm (30\" - 33\") |\n| L | 175 - 186 cm (5'9\" - 6'1\") | 82 - 88 cm (32\" - 35\") |\n\n## Geometry\n\nAll measurements provided in cm unless otherwise noted.\n\nSizing table\n| Frame size number | 40 cm | 45 cm | 50 cm | 55 cm |\n|---------------------------|-------|-------|-------|-------|\n| Frame size letter | XS | S | M | L |\n| Wheel size | 700c | 700c | 700c | 700c |\n| A — Seat tube | 39.0 | 44.0 | 50.0 | 55.0 |\n| B — Seat tube angle | 71.0° | 71.0° | 71.0° | 71.0° |\n| C — Head tube length | 16.0 | 16.0 | 18.0 | 20.0 |\n| D — Head angle | 68.2° | 68.2° | 68.2° | 68.2° |\n| E — Effective top tube | 58.2 | 58.7 | 59.8 | 61.0 |\n| F — Bottom bracket height | 29.4 | 29.4 | 29.4 | 29.4 |\n| G — Bottom bracket drop | 6.5 | 6.5 | 6.5 | 6.5 |\n| H — Chainstay length | 48.7 | 48.7 | 48.7 | 48.7 |\n| I — Offset | 4.5 | 4.5 | 4.5 | 4.5 |\n| J — Trail | 9.5 | 9.5 | 9.5 | 9.5 |\n| K — Wheelbase | 112.2 | 112.7 | 114.0 | 115.2 |\n| L — Standover | 43.3 | 43.3 | 43.3 | 43.3 |\n| M — Frame reach | 36.5 | 38.5 | 38.5 | 38.5 |\n| N — Frame stack | 63.0 | 63.0 | 64.9 | 66.8 |\n| Stem length | 8.5 | 9.0 | 9.0 | 11.0 |",
"price": 3999.99,
"tags": [
"bicycle",
"mountain bike",
"professional"
]
},
{
"name": "RoadRunner E-Speed Lowstep",
"shortDescription": "RoadRunner E-Speed Lowstep is a high-performance electric hybrid designed for riders seeking speed and excitement on their daily rides. It is equipped with a powerful and reliable ThunderBolt drive unit that offers exceptional acceleration. The bike features a fully-integrated 500Wh battery, allowing riders to cover longer distances on a single charge. With its comfortable and safe components, including a suspension seatpost, wide and stable tires, and integrated lights, the RoadRunner E-Speed Lowstep ensures a smooth and enjoyable ride.",
"description": "## Overview\n\nIt's right for you if...\nYou're looking for an e-bike that provides an extra boost to reach your destination quickly and effortlessly. You prioritize durability and want a bike with one of the fastest motors available.\n\nThe tech you get\nA lightweight and sturdy ThunderBolt aluminum frame with a lowstep geometry. The bike is equipped with a ThunderBolt Performance Sport (250W, 65Nm) drive unit capable of reaching speeds up to 28 mph. It features a long-range 500Wh battery fully integrated into the frame and a ThunderBolt controller. Additionally, the bike has a 10-speed Shimano drivetrain, hydraulic disc brakes for reliable stopping power in all weather conditions, a suspension seatpost, wide puncture-resistant tires for stability, ergonomic grips, a kickstand, lights, and a rack and fenders.\n\nThe final word\nThe RoadRunner E-Speed Lowstep is designed to provide enjoyment and ease of use on longer commutes, recreational rides, and adventurous journeys. Its long-range battery, fast ThunderBolt motor, intuitive controller, and road-smoothing suspension seatpost make it the perfect choice for riders seeking both comfort and speed.\n\n## Features\n\nSuper speedy assist\n\nThe ThunderBolt Performance Sport drive unit allows you to accelerate up to 28mph, making errands, commutes, and joyrides a breeze.\n\n## Specs\n\nFrameset\n- Frame: ThunderBolt Smooth Aluminum, Removable Integrated Battery (RIB), sleek welds, rack & fender mounts, internal routing, kickstand mount, 135x5mm QR\n- Fork: RoadRunner Alloy, threaded steel steerer, rack mounts, post mount disc, 460mm axle-to-crown, ThruSkew 5mm QR\n- Max compatible fork travel: 50mm\n\nWheels\n- Hub front: ThunderBolt DC-20, alloy, 6-bolt, 5x100mm QR\n- Skewer front: 132x5mm QR, ThruSkew\n- Hub rear: ThunderBolt DC-22, alloy, 6-bolt, Shimano 8/9/10 freehub, 135x5mm QR\n- Skewer rear: 153x5mm bolt-on\n- Rim: ThunderBolt Connection, double-wall, 32-hole, 20 mm width, Schrader valve\n- Tire: ThunderBolt E6 Hard-Case Lite, reflective, wire bead, 60tpi, 700x50c\n- Max tire size: 700x50mm with or without fenders\n\nDrivetrain\n- Shifter: Shimano Deore M4100, 10 speed\n- Rear derailleur: Shimano Deore M5120, long cage\n- Crank: ProWheel alloy, 170mm length\n- Chainring: FSA, 42T, steel w/guard\n- Cassette: Shimano Deore M4100, 11-42, 10 speed\n- Chain: KMC E10\n- Pedal: RoadRunner City pedals\n\nComponents\n- Saddle: RoadRunner Boulevard\n- Seatpost: Alloy, suspension, 31.6mm, 300mm length\n- Handlebar:\n - Size: XS, S, M - RoadRunner alloy, 31.8mm, comfort sweep, 620mm width\n - Size: L - RoadRunner alloy, 31.8mm, comfort sweep, 660mm width\n- Grips: RoadRunner Satellite Elite, alloy lock-on\n- Stem:\n - Size: XS, S - RoadRunner alloy quill, 31.8mm clamp, adjustable rise, Blendr compatible, 85mm length\n - Size: M, L - RoadRunner alloy quill, 31.8mm clamp, adjustable rise, Blendr compatible, 105mm length\n- Headset: VP sealed cartridge, 1-1/8'', threaded\n- Brake: Shimano MT200 hydraulic disc\n- Brake rotor:\n - Size: XS, S, M, L - Shimano RT26, 6-bolt, 180mm\n - Size: XS, S, M, L - Shimano RT26, 6-bolt, 160mm\n\nAccessories\n- Battery: ThunderBolt PowerTube 500Wh\n- Charger: ThunderBolt compact 2A, 100-240V\n- Computer: ThunderBolt Purion\n- Motor: ThunderBolt Performance Line Sport, 65Nm, 28mph\n- Light:\n - Size: XS, S, M, L - ThunderBolt SOLO for e-bike, taillight\n - Size: XS, S, M, L - ThunderBolt MR8, 180 lumen, 60 lux, LED, headlight\n- Kickstand: Adjustable length rear mount alloy kickstand\n- Cargo rack: MIK-compatible alloy rear rack, maximum load 25 kg / 55 lbs\n- Fender:\n - Size: XS, S, M, L - RoadRunner wide\n - Size: XS, S, M, L - RoadRunner plastic\n\nWeight\n- Weight: M - 22.30 kg / 49.17 lbs\n- Weight limit: This bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\n\n## Sizing\n\n| Size | Rider Height | Inseam |\n|:----:|:-------------------------:|:--------------------:|\n| XS | 147 - 155 cm 4'10\" - 5'1\" | 69 - 73 cm 27\" - 29\" |\n| S | 155 - 165 cm 5'1\" - 5'5\" | 72 - 78 cm 28\" - 31\" |\n| M | 165 - 175 cm 5'5\" - 5'9\" | 77 - 83 cm 30\" - 33\" |\n| L | 175 - 186 cm 5'9\" - 6'1\" | 82 - 88 cm 32\" - 35\" |\n\n## Geometry\n\nAll measurements provided in cm unless otherwise noted.\n\nSizing table\n| Frame size number | 40 cm | 45 cm | 50 cm | 55 cm |\n|---------------------------|-------|-------|-------|-------|\n| Frame size letter | XS | S | M | L |\n| Wheel size | 700c | 700c | 700c | 700c |\n| A — Seat tube | 39.0 | 44.0 | 50.0 | 55.0 |\n| B — Seat tube angle | 71.0° | 71.0° | 71.0° | 71.0° |\n| C — Head tube length | 16.0 | 16.0 | 18.0 | 20.0 |\n| D — Head angle | 68.2° | 68.2° | 68.2° | 68.2° |\n| E — Effective top tube | 58.2 | 58.7 | 59.8 | 61.0 |\n| F — Bottom bracket height | 29.4 | 29.4 | 29.4 | 29.4 |\n| G — Bottom bracket drop | 6.5 | 6.5 | 6.5 | 6.5 |\n| H — Chainstay length | 48.7 | 48.7 | 48.7 | 48.7 |\n| I — Offset | 4.5 | 4.5 | 4.5 | 4.5 |\n| J — Trail | 9.5 | 9.5 | 9.5 | 9.5 |\n| K — Wheelbase | 112.2 | 112.7 | 114.0 | 115.2 |\n| L — Standover | 43.3 | 43.3 | 43.3 | 43.3 |\n| M — Frame reach | 36.5 | 38.5 | 38.5 | 38.5 |\n| N — Frame stack | 63.0 | 63.0 | 64.9 | 66.8 |\n| Stem length | 8.5 | 9.0 | 9.0 | 11.0 |",
"price": 4999.99,
"tags": [
"bicycle",
"road bike",
"professional"
]
},
{
"name": "Hyperdrive Turbo X1",
"shortDescription": "Hyperdrive Turbo X1 is a high-performance electric bike designed for riders seeking an exhilarating experience on their daily rides. It features a powerful and efficient Hyperdrive Sport drive unit and a sleek, integrated 500Wh battery for extended range. This e-bike is equipped with top-of-the-line components prioritizing comfort and safety, including a suspension seatpost, wide and stable tires, and integrated lights.",
"description": "## Overview\n\nIt's right for you if...\nYou crave the thrill of an e-bike that can accelerate rapidly, reaching high speeds effortlessly. You value durability and are looking for a bike that is equipped with one of the fastest motors available.\n\nThe tech you get\nA lightweight Hyper Alloy frame with a lowstep geometry, a Hyperdrive Sport (300W, 70Nm) drive unit capable of maintaining speeds up to 30 mph, a long-range 500Wh battery seamlessly integrated into the frame, and an intuitive Hyper Control controller. Additionally, it features a 10-speed Shimano drivetrain, hydraulic disc brakes for reliable stopping power in all weather conditions, a suspension seatpost, wide puncture-resistant tires for enhanced stability, ergonomic grips, a kickstand, lights, and a rack and fenders.\n\nThe final word\nThis bike is designed for riders seeking enjoyment and convenience on longer commutes, recreational rides, and thrilling adventures. With its long-range battery, high-speed motor, user-friendly controller, and smooth-riding suspension seatpost, the Hyperdrive Turbo X1 guarantees an exceptional e-biking experience.\n\n## Features\n\nHyperboost Acceleration\nExperience adrenaline-inducing rides with the powerful Hyperdrive Sport drive unit that enables quick acceleration and effortless cruising through errands, commutes, and joyrides.\n\n## Specs\n\nFrameset\nFrame\tHyper Alloy, Removable Integrated Battery (RIB), seamless welds, rack & fender mounts, internal routing, kickstand mount, 135x5mm QR\nFork\tHyper Alloy, threaded steel steerer, rack mounts, post mount disc, 460mm axle-to-crown, ThruSkew 5mm QR\nMax compatible fork travel\t50mm\n\nWheels\nHub front\tFormula DC-20, alloy, 6-bolt, 5x100mm QR\nSkewer front\t132x5mm QR, ThruSkew\nHub rear\tFormula DC-22, alloy, 6-bolt, Shimano 8/9/10 freehub, 135x5mm QR\nSkewer rear\t153x5mm bolt-on\nRim\tHyper Connection, double-wall, 32-hole, 20 mm width, Schrader valve\nTire\tHyper E6 Hard-Case Lite, reflective, wire bead, 60tpi, 700x50c\nMax tire size\t700x50mm with or without fenders\n\nDrivetrain\nShifter\tShimano Deore M4100, 10 speed\nRear derailleur\tShimano Deore M5120, long cage\nCrank\tProWheel alloy, 170mm length\nChainring\tFSA, 42T, steel w/guard\nCassette\tShimano Deore M4100, 11-42, 10 speed\nChain\tKMC E10\nPedal\tHyper City pedals\n\nComponents\nSaddle\tHyper Boulevard\nSeatpost\tAlloy, suspension, 31.6mm, 300mm length\nHandlebar\tSize: XS, S, M\nHyper alloy, 31.8mm, comfort sweep, 620mm width\nSize: L\nHyper alloy, 31.8mm, comfort sweep, 660mm width\nGrips\tHyper Satellite Elite, alloy lock-on\nStem\tSize: XS, S\nHyper alloy quill, 31.8mm clamp, adjustable rise, Blendr compatible, 85mm length\nSize: M, L\nHyper alloy quill, 31.8mm clamp, adjustable rise, Blendr compatible, 105mm length\nHeadset\tVP sealed cartridge, 1-1/8'', threaded\nBrake\tShimano MT200 hydraulic disc\nBrake rotor\tSize: XS, S, M, L\nShimano RT26, 6-bolt,180mm\nSize: XS, S, M, L\nShimano RT26, 6-bolt,160mm\n\nAccessories\nBattery\tHyper PowerTube 500Wh\nCharger\tHyper compact 2A, 100-240V\nComputer\tHyper Control\nMotor\tHyperdrive Sport, 70Nm, 30mph\nLight\tSize: XS, S, M, L\nSpanninga SOLO for e-bike, taillight\nSize: XS, S, M, L\nHerrmans MR8, 180 lumen, 60 lux, LED, headlight\nKickstand\tAdjustable length rear mount alloy kickstand\nCargo rack\tMIK-compatible alloy rear rack, maximum load 25 kg / 55 lbs\n*Fender\tSize: XS, S, M, L\nSKS wide\nSize: XS, S, M, L\nSKS plastic\n\nWeight\nWeight\tM - 22.30 kg / 49.17 lbs\nWeight limit\tThis bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\n\n## Sizing\n\n| Size | Rider Height | Inseam |\n|:----:|:-------------------------:|:--------------------:|\n| XS | 147 - 155 cm 4'10\" - 5'1\" | 69 - 73 cm 27\" - 29\" |\n| S | 155 - 165 cm 5'1\" - 5'5\" | 72 - 78 cm 28\" - 31\" |\n| M | 165 - 175 cm 5'5\" - 5'9\" | 77 - 83 cm 30\" - 33\" |\n| L | 175 - 186 cm 5'9\" - 6'1\" | 82 - 88 cm 32\" - 35\" |\n\n## Geometry\n\nAll measurements provided in cm unless otherwise noted.\n\n| Frame size number | 40 cm | 45 cm | 50 cm | 55 cm |\n|---------------------------|-------|-------|-------|-------|\n| Frame size letter | XS | S | M | L |\n| Wheel size | 700c | 700c | 700c | 700c |\n| A — Seat tube | 39.0 | 44.0 | 50.0 | 55.0 |\n| B — Seat tube angle | 71.0° | 71.0° | 71.0° | 71.0° |\n| C — Head tube length | 16.0 | 16.0 | 18.0 | 20.0 |\n| D — Head angle | 68.2° | 68.2° | 68.2° | 68.2° |\n| E — Effective top tube | 58.2 | 58.7 | 59.8 | 61.0 |\n| F — Bottom bracket height | 29.4 | 29.4 | 29.4 | 29.4 |\n| G — Bottom bracket drop | 6.5 | 6.5 | 6.5 | 6.5 |\n| H — Chainstay length | 48.7 | 48.7 | 48.7 | 48.7 |\n| I — Offset | 4.5 | 4.5 | 4.5 | 4.5 |\n| J — Trail | 9.5 | 9.5 | 9.5 | 9.5 |\n| K — Wheelbase | 112.2 | 112.7 | 114.0 | 115.2 |\n| L — Standover | 43.3 | 43.3 | 43.3 | 43.3 |\n| M — Frame reach | 36.5 | 38.5 | 38.5 | 38.5 |\n| N — Frame stack | 63.0 | 63.0 | 64.9 | 66.8 |\n| Stem length | 8.5 | 9.0 | 9.0 | 11.0 |",
"price": 1999.99,
"tags": [
"bicycle",
"city bike",
"professional"
]
},
{
"name": "Horizon+ Evo Lowstep",
"shortDescription": "The Horizon+ Evo Lowstep is a versatile electric hybrid bike designed for riders seeking a thrilling and efficient riding experience on a variety of terrains. With its powerful Bosch Performance Line Sport drive unit and integrated 500Wh battery, this e-bike enables riders to cover long distances with ease. Equipped with features prioritizing comfort and safety, such as a suspension seatpost, stable tires, and integrated lights, the Horizon+ Evo Lowstep is a reliable companion for everyday rides.",
"description": "## Overview\n\nIt's right for you if...\nYou desire the convenience and speed of an e-bike to enhance your riding, and you want an intuitive and durable bicycle. You prioritize having one of the fastest motors developed by Bosch.\n\nThe tech you get\nA lightweight Alpha Smooth Aluminum frame with a lowstep geometry, a Bosch Performance Line Sport (250W, 65Nm) drive unit capable of sustaining speeds up to 28 mph, a fully encased 500Wh battery integrated into the frame, and a Bosch Purion controller. Additionally, it features a 10-speed Shimano drivetrain, hydraulic disc brakes for reliable stopping power in all weather conditions, a suspension seatpost, wide puncture-resistant tires for improved stability, ergonomic grips, a kickstand, lights, and a rack and fenders.\n\nThe final word\nThe Horizon+ Evo Lowstep offers an enjoyable and user-friendly riding experience for longer commutes, recreational rides, and adventures. It boasts an extended range battery, a high-performance Bosch motor, an intuitive controller, and a suspension seatpost for a smooth ride on various road surfaces.\n\n## Features\n\nSuper speedy assist\nExperience effortless cruising through errands, commutes, and joyrides with the new Bosch Performance Sport drive unit, allowing acceleration of up to 28 mph.\n\n## Specs\n\nFrameset\n- Frame: Alpha Platinum Aluminum, Removable Integrated Battery (RIB), smooth welds, rack & fender mounts, internal routing, kickstand mount, 135x5mm QR\n- Fork: Horizon Alloy, threaded steel steerer, rack mounts, post mount disc, 460mm axle-to-crown, ThruSkew 5mm QR\n- Max compatible fork travel: 50mm\n\nWheels\n- Front Hub: Formula DC-20, alloy, 6-bolt, 5x100mm QR\n- Front Skewer: 132x5mm QR, ThruSkew\n- Rear Hub: Formula DC-22, alloy, 6-bolt, Shimano 8/9/10 freehub, 135x5mm QR\n- Rear Skewer: 153x5mm bolt-on\n- Rim: Bontrager Connection, double-wall, 32-hole, 20mm width, Schrader valve\n- Tire: Bontrager E6 Hard-Case Lite, reflective, wire bead, 60tpi, 700x50c\n- Max tire size: 700x50mm with or without fenders\n\nDrivetrain\n- Shifter: Shimano Deore M4100, 10-speed\n- Rear Derailleur: Shimano Deore M5120, long cage\n- Crank: ProWheel alloy, 170mm length\n- Chainring: FSA, 42T, steel w/guard\n- Cassette: Shimano Deore M4100, 11-42, 10-speed\n- Chain: KMC E10\n- Pedal: Bontrager City pedals\n\nComponents\n- Saddle: Bontrager Boulevard\n- Seatpost: Alloy, suspension, 31.6mm, 300mm length\n- Handlebar:\n - Size: XS, S, M - Bontrager alloy, 31.8mm, comfort sweep, 620mm width\n - Size: L - Bontrager alloy, 31.8mm, comfort sweep, 660mm width\n- Grips: Bontrager Satellite Elite, alloy lock-on\n- Stem:\n - Size: XS, S - Bontrager alloy quill, 31.8mm clamp, adjustable rise, Blendr compatible, 85mm length\n - Size: M, L - Bontrager alloy quill, 31.8mm clamp, adjustable rise, Blendr compatible, 105mm length\n- Headset: VP sealed cartridge, 1-1/8\", threaded\n- Brake: Shimano MT200 hydraulic disc\n- Brake rotor:\n - Size: XS, S, M, L - Shimano RT26, 6-bolt, 180mm\n - Size: XS, S, M, L - Shimano RT26, 6-bolt, 160mm\n\nAccessories\n- Battery: Bosch PowerTube 500Wh\n- Charger: Bosch compact 2A, 100-240V\n- Computer: Bosch Purion\n- Motor: Bosch Performance Line Sport, 65Nm, 28mph\n- Light:\n - Size: XS, S, M, L - Spanninga SOLO for e-bike, taillight\n - Size: XS, S, M, L - Herrmans MR8, 180 lumen, 60 lux, LED, headlight\n- Kickstand: Adjustable length rear mount alloy kickstand\n- Cargo rack: MIK-compatible alloy rear rack, maximum load 25 kg / 55 lbs\n- Fender:\n - Size: XS, S, M, L - SKS wide\n - Size: XS, S, M, L - SKS plastic\n\nWeight\n- Weight: M - 22.30 kg / 49.17 lbs\n- Weight limit: This bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\n\n## Sizing\n\n| Size | Rider Height | Inseam |\n|:----:|:-------------------------:|:--------------------:|\n| XS | 147 - 155 cm 4'10\" - 5'1\" | 69 - 73 cm 27\" - 29\" |\n| S | 155 - 165 cm 5'1\" - 5'5\" | 72 - 78 cm 28\" - 31\" |\n| M | 165 - 175 cm 5'5\" - 5'9\" | 77 - 83 cm 30\" - 33\" |\n| L | 175 - 186 cm 5'9\" - 6'1\" | 82 - 88 cm 32\" - 35\" |\n\n## Geometry\n\nAll measurements provided in cm unless otherwise noted.\nSizing table\n| Frame size number | 40 cm | 45 cm | 50 cm | 55 cm |\n|---------------------------|-------|-------|-------|-------|\n| Frame size letter | XS | S | M | L |\n| Wheel size | 700c | 700c | 700c | 700c |\n| A — Seat tube | 39.0 | 44.0 | 50.0 | 55.0 |\n| B — Seat tube angle | 71.0° | 71.0° | 71.0° | 71.0° |\n| C — Head tube length | 16.0 | 16.0 | 18.0 | 20.0 |\n| D — Head angle | 68.2° | 68.2° | 68.2° | 68.2° |\n| E — Effective top tube | 58.2 | 58.7 | 59.8 | 61.0 |\n| F — Bottom bracket height | 29.4 | 29.4 | 29.4 | 29.4 |\n| G — Bottom bracket drop | 6.5 | 6.5 | 6.5 | 6.5 |\n| H — Chainstay length | 48.7 | 48.7 | 48.7 | 48.7 |\n| I — Offset | 4.5 | 4.5 | 4.5 | 4.5 |\n| J — Trail | 9.5 | 9.5 | 9.5 | 9.5 |\n| K — Wheelbase | 112.2 | 112.7 | 114.0 | 115.2 |\n| L — Standover | 43.3 | 43.3 | 43.3 | 43.3 |\n| M — Frame reach | 36.5 | 38.5 | 38.5 | 38.5 |\n| N — Frame stack | 63.0 | 63.0 | 64.9 | 66.8 |\n| Stem length | 8.5 | 9.0 | 9.0 | 11.0 |",
"price": 4499.99,
"tags": [
"bicycle",
"road bike",
"professional"
]
},
{
"name": "FastRider X1",
"shortDescription": "FastRider X1 is a high-performance e-bike designed for riders seeking speed and long-distance capabilities. Equipped with a powerful motor and a high-capacity battery, the FastRider X1 is perfect for daily commuters and e-bike enthusiasts. It boasts a sleek and functional design, making it a great alternative to car transportation. The bike also features a smartphone controller for easy navigation and entertainment options.",
"description": "## Overview\nIt's right for you if...\nYou're looking for an e-bike that offers both speed and endurance. The FastRider X1 comes with a high-performance motor and a long-lasting battery, making it ideal for long-distance rides.\n\nThe tech you get\nThe FastRider X1 features a state-of-the-art motor and a spacious battery, ensuring a fast and efficient ride.\n\nThe final word\nWith the powerful motor and long-range battery, the FastRider X1 allows you to cover more distance at higher speeds.\n\n## Features\nConnect Your Ride with the FastRider App\nDownload the FastRider app and transform your smartphone into an on-board computer. Easily dock and charge your phone with the smartphone controller, and use the thumb pad on your handlebar to make calls, listen to music, get turn-by-turn directions, and more. The app also allows you to connect with fitness and health apps, syncing your routes and ride data.\n\nGoodbye, Car. Hello, Extended Range!\nWith the option to add the Range Boost feature, you can attach a second long-range battery to your FastRider X1, doubling the distance and time between charges. This enhancement allows you to ride longer, commute farther, and take on more adventurous routes.\n\nWhat is the range?\nTo estimate the distance you can travel on a single charge, use our range calculator tool. It automatically fills in the variables for this specific bike model and assumes an average rider, but you can adjust the settings to get the most accurate estimate for your needs.\n\n## Specifications\nFrameset\n- Frame: High-performance hydroformed alloy, Removable Integrated Battery, Range Boost-compatible, internal cable routing, Motor Armour, post-mount disc, 135x5 mm QR\n- Fork: FastRider rigid alloy fork, 1-1/8'' steel steerer, 100x15mm thru axle, post mount disc brake\n- Max compatible fork travel: 63mm\n\nWheels\n- Front Hub: FastRider sealed bearing, 32-hole 15mm alloy thru-axle\n- Front Skewer: FastRider Switch thru axle, removable lever\n- Rear Hub: FastRider alloy, sealed bearing, 6-bolt, 135x5mm QR\n- Rear Skewer: 148x5mm bolt-on\n- Rim: FastRider MD35, tubeless compatible, 32-hole, 35mm width, Presta valve\n- Spokes: Size: M, L, XL - 14g stainless steel, black\n- Tire: FastRider E6 Hard-Case Lite, reflective strip, 27.5x2.40''\n- Max tire size: 27.5x2.40\"\n\nDrivetrain\n- Shifter: Shimano Deore M4100, 10 speed\n- Rear derailleur: Size: M, L, XL - Shimano Deore M5120, long cage\n- Crank: Size: M - FastRider alloy, 170mm length / Size: L, XL - FastRider alloy, 175mm length\n- Chainring: FastRider 46T narrow/wide alloy, w/alloy guard\n- Cassette: Size: M, L, XL - Shimano Deore M4100, 11-42, 10 speed\n- Chain: Size: M, L, XL - KMC E10 / Size: M, L, XL - KMC X10e\n- Pedal: Size: M, L, XL - FastRider City pedals / Size: M, L, XL - Wellgo C157, boron axle, plastic body / Size: M, L, XL - slip-proof aluminum pedals with reflectors\n- Max chainring size: 1x: 48T\n\nComponents\n- Saddle: FastRider Commuter Comp\n- Seatpost: FastRider Comp, 6061 alloy, 31.6mm, 8mm offset, 330mm length\n- Handlebar: Size: M - FastRider alloy, 31.8mm, 15mm rise, 600mm width / Size: L, XL - FastRider alloy, 31.8mm, 15mm rise, 660mm width\n- Grips: FastRider Satellite Elite, alloy lock-on\n- Stem: Size: M - FastRider alloy, 31.8mm, Blendr compatible, 7-degree, 70mm length / Size: L - FastRider alloy, 31.8mm, Blendr compatible, 7-degree, 90mm length / Size: XL - FastRider alloy, 31.8mm, Blendr compatible, 7-degree, 100mm length\n- Headset: Size: M, L, XL - FSA IS-2 alloy, integrated, sealed cartridge bearing, 1-1/8'' top, 1.5'' bottom / Size: M, L, XL - FSA Integrated, sealed cartridge bearing, 1-1/8'' top, 1.5'' bottom\n- Brake: Shimano MT520 4-piston hydraulic disc, post-mount, 180mm rotor\n- Brake rotor: Shimano RT56, 6-bolt, 180mm\n- Rotor size: Max brake rotor sizes: 180mm front & rear\n\nAccessories\n- Battery: FastRider PowerTube 625Wh\n- Charger: FastRider standard 4A, 100-240V\n- Motor: FastRider Performance Speed, 85 Nm, 28 mph / 45 kph\n- Light: Size: M, L, XL - FastRider taillight, 50 lumens / Size: M, L, XL - FastRider headlight, 500 lumens\n- Kickstand: Size: M, L, XL - Rear mount, alloy / Size: M, L, XL - Adjustable length alloy kickstand\n- Cargo rack: FastRider integrated rear rack, aluminum\n- Fender: FastRider custom aluminum\n\nWeight\n- Weight: M - 25.54 kg / 56.3 lbs\n\nWeight limit\n- This bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\n\n## Sizing\n| Size | Rider Height | Inseam |\n|:----:|:------------------------:|:--------------------:|\n| M | 165 - 175 cm 5'5\" - 5'9\" | 77 - 83 cm 30\" - 33\" |\n| L | 175 - 186 cm 5'9\" - 6'1\" | 82 - 88 cm 32\" - 35\" |\n| XL | 186 - 197 cm 6'1\" - 6'6\" | 87 - 93 cm 34\" - 37\" |\n\n## Geometry\n| Frame size letter | M | L | XL |\n|---------------------------|-------|-------|-------|\n| Wheel size | 27.5\" | 27.5\" | 27.5\" |\n| A — Seat tube | 44.6 | 49.1 | 53.4 |\n| B — Seat tube angle | 73.0° | 73.0° | 73.0° |\n| C — Head tube length | 16.5 | 19.5 | 23.0 |\n| D — Head angle | 69.5° | 70.0° | 70.5° |\n| E — Effective top tube | 59.5 | 60.7 | 62.2 |\n| F — Bottom bracket height | 29.5 | 29.5 | 29.5 |\n| G — Bottom bracket drop | 6.0 | 6.0 | 6.0 |\n| H — Chainstay length | 48.7 | 48.7 | 48.7 |\n| I — Offset | 4.4 | 4.4 | 4.4 |\n| J — Trail | 8.6 | 8.1 | 7.9 |\n| K — Wheelbase | 114.6 | 115.0 | 116.4 |\n| L — Standover | 79.5 | 83.7 | 87.9 |\n| M — Frame reach | 40.5 | 40.8 | 41.2 |\n| N — Frame stack | 62.3 | 65.2 | 68.8 |",
"price": 5499.99,
"tags": [
"bicycle",
"mountain bike",
"professional"
]
},
{
"name": "SonicRide 8S",
"shortDescription": "SonicRide 8S is a high-performance e-bike designed for riders who crave speed and long-distance capabilities. The advanced SonicDrive motor provides powerful assistance up to 28 mph, combined with a durable and long-lasting battery for extended rides. With its sleek design and thoughtful features, the SonicRide 8S is perfect for those who prefer the freedom of riding a bike over driving a car. Plus, it comes equipped with a smartphone controller for easy navigation, music, and more.",
"description": "## Overview\nIt's right for you if...\nYou want a fast and efficient e-bike that can take you long distances. The SonicRide 8S features a hydroformed aluminum frame with a concealed 625Wh battery, a high-powered SonicDrive motor, and a Smartphone Controller. It also includes essential accessories such as lights, fenders, and a rear rack.\n\nThe tech you get\nThe SonicRide 8S is equipped with the fastest SonicDrive motor, ensuring exhilarating rides at high speeds. The long-range battery is perfect for commuters and riders looking to explore new horizons.\n\nThe final word\nWith the SonicDrive motor and long-lasting battery, you can enjoy extended rides at higher speeds.\n\n## Features\n\nConnect Your Ride with SonicRide App\nDownload the SonicRide app and transform your phone into an onboard computer. Simply attach it to the Smartphone Controller for docking and charging. Use the thumb pad on your handlebar to control calls, music, directions, and more. The Bluetooth® wireless technology allows you to connect with fitness and health apps, syncing your routes and ride data.\n\nSay Goodbye to Limited Range with Range Boost!\nExperience the convenience of Range Boost, an additional long-range 500Wh battery that seamlessly attaches to your bike's down tube. This upgrade allows you to double your distance and time between charges, enabling longer commutes and more adventurous rides. Range Boost is compatible with select SonicRide electric bike models.\n\nWhat is the range?\nFor an accurate estimate of how far you can ride on a single charge, use SonicRide's range calculator. We have pre-filled the variables for this specific bike model and the average rider, but you can adjust them to obtain the most accurate estimate.\n\n## Specifications\nFrameset\n- Frame: High-performance hydroformed alloy, Removable Integrated Battery, Range Boost-compatible, internal cable routing, Motor Armour, post-mount disc, 135x5 mm QR\n- Fork: SonicRide rigid alloy fork, 1-1/8'' steel steerer, 100x15mm thru axle, post mount disc brake\n- Max compatible fork travel: 63mm\n\nWheels\n- Front Hub: SonicRide sealed bearing, 32-hole 15mm alloy thru-axle\n- Front Skewer: SonicRide Switch thru axle, removable lever\n- Rear Hub: SonicRide alloy, sealed bearing, 6-bolt, 135x5mm QR\n- Rear Skewer: 148x5mm bolt-on\n- Rim: SonicRide MD35, tubeless compatible, 32-hole, 35mm width, Presta valve\n- Spokes: Size: M, L, XL - 14g stainless steel, black\n- Tire: SonicRide E6 Hard-Case Lite, reflective strip, 27.5x2.40''\n- Max tire size: 27.5x2.40\"\n\nDrivetrain\n- Shifter: Shimano Deore M4100, 10 speed\n- Rear Derailleur: Size: M, L, XL - Shimano Deore M5120, long cage\n- Crank: Size: M - SonicRide alloy, 170mm length; Size: L, XL - SonicRide alloy, 175mm length\n- Chainring: SonicRide 46T narrow/wide alloy, with alloy guard\n- Cassette: Size: M, L, XL - Shimano Deore M4100, 11-42, 10 speed\n- Chain: Size: M, L, XL - KMC E10; Size: M, L, XL - KMC X10e\n- Pedal: Size: M, L, XL - SonicRide City pedals; Size: M, L, XL - Wellgo C157, boron axle, plastic body; Size: M, L, XL - slip-proof aluminum pedals with reflectors\n- Max chainring size: 1x: 48T\n\nComponents\n- Saddle: SonicRide Commuter Comp\n- Seatpost: SonicRide Comp, 6061 alloy, 31.6mm, 8mm offset, 330mm length\n- Handlebar: Size: M - SonicRide alloy, 31.8mm, 15mm rise, 600mm width; Size: L, XL - SonicRide alloy, 31.8mm, 15mm rise, 660mm width\n- Grips: SonicRide Satellite Elite, alloy lock-on\n- Stem: Size: M - SonicRide alloy, 31.8mm, Blendr compatible, 7-degree, 70mm length; Size: L - SonicRide alloy, 31.8mm, Blendr compatible, 7-degree, 90mm length; Size: XL - SonicRide alloy, 31.8mm, Blendr compatible, 7-degree, 100mm length\n- Headset: Size: M, L, XL - SonicRide IS-2 alloy, integrated, sealed cartridge bearing, 1-1/8'' top, 1.5'' bottom; Size: M, L, XL - SonicRide Integrated, sealed cartridge bearing, 1-1/8'' top, 1.5'' bottom\n- Brake: Shimano MT520 4-piston hydraulic disc, post-mount, 180mm rotor\n- Brake rotor: Shimano RT56, 6-bolt, 180mm\n- Rotor size: Max brake rotor sizes: 180mm front & rear\n\nAccessories\n- Battery: SonicRide PowerTube 625Wh\n- Charger: SonicRide standard 4A, 100-240V\n- Motor: SonicRide Performance Speed, 85 Nm, 28 mph / 45 kph\n- Light: Size: M, L, XL - SonicRide Lync taillight, 50 lumens; Size: M, L, XL - SonicRide Lync headlight, 500 lumens\n- Kickstand: Size: M, L, XL - Rear mount, alloy; Size: M, L, XL - Adjustable length alloy kickstand\n- Cargo rack: SonicRide integrated rear rack, aluminum\n- Fender: SonicRide custom aluminum\n\nWeight\n- Weight: M - 25.54 kg / 56.3 lbs\n- Weight limit: This bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\n\n## Sizing\n| Size | Rider Height | Inseam |\n|:----:|:------------------------:|:--------------------:|\n| M | 165 - 175 cm / 5'5\" - 5'9\" | 77 - 83 cm / 30\" - 33\" |\n| L | 175 - 186 cm / 5'9\" - 6'1\" | 82 - 88 cm / 32\" - 35\" |\n| XL | 186 - 197 cm / 6'1\" - 6'6\" | 87 - 93 cm / 34\" - 37\" |\n\n## Geometry\n| Frame size letter | M | L | XL |\n|---------------------------|-------|-------|-------|\n| Wheel size | 27.5\" | 27.5\" | 27.5\" |\n| A — Seat tube | 44.6 | 49.1 | 53.4 |\n| B — Seat tube angle | 73.0° | 73.0° | 73.0° |\n| C — Head tube length | 16.5 | 19.5 | 23.0 |\n| D — Head angle | 69.5° | 70.0° | 70.5° |\n| E — Effective top tube | 59.5 | 60.7 | 62.2 |\n| F — Bottom bracket height | 29.5 | 29.5 | 29.5 |\n| G — Bottom bracket drop | 6.0 | 6.0 | 6.0 |\n| H — Chainstay length | 48.7 | 48.7 | 48.7 |\n| I — Offset | 4.4 | 4.4 | 4.4 |\n| J — Trail | 8.6 | 8.1 | 7.9 |\n| K — Wheelbase | 114.6 | 115.0 | 116.4 |\n| L — Standover | 79.5 | 83.7 | 87.9 |\n| M — Frame reach | 40.5 | 40.8 | 41.2 |",
"price": 5999.99,
"tags": [
"bicycle",
"road bike",
"professional"
]
},
{
"name": "SwiftVolt Pro",
"shortDescription": "SwiftVolt Pro is a high-performance e-bike designed for riders seeking a thrilling and fast riding experience. Equipped with a powerful SwiftDrive motor that provides assistance up to 30 mph and a long-lasting battery, this bike is perfect for long-distance commuting and passionate e-bike enthusiasts. The sleek and innovative design features cater specifically to individuals who prioritize cycling over driving. Additionally, the bike is seamlessly integrated with your smartphone, allowing you to use it for navigation, music, and more.",
"description": "## Overview\nThis bike is ideal for you if:\n- You desire a sleek and modern hydroformed aluminum frame that houses a 700Wh battery.\n- You want to maintain high speeds of up to 30 mph with the assistance of the SwiftDrive motor.\n- You appreciate the convenience of using your smartphone as a controller, which can be docked and charged on the handlebar.\n\n## Features\n\nConnect with SwiftSync App\nBy downloading the SwiftSync app, your smartphone becomes an interactive on-board computer. Attach it to the handlebar-mounted controller for easy access and charging. With the thumb pad, you can make calls, listen to music, receive turn-by-turn directions, and connect with fitness and health apps to track your routes and ride data via Bluetooth® wireless technology.\n\nEnhanced Range with BoostMax\nBoostMax offers the capability to attach a second 700Wh Swift battery to the downtube of your bike, effectively doubling the distance and time between charges. This allows for extended rides, longer commutes, and more significant adventures. BoostMax is compatible with select Swift electric bike models.\n\nRange Estimation\nFor an estimate of how far you can ride on a single charge, consult the Swift range calculator. The variables are automatically populated based on this bike model and the average rider, but you can modify them to obtain the most accurate estimate.\n\n## Specifications\nFrameset\n- Frame: Lightweight hydroformed alloy, Removable Integrated Battery, BoostMax-compatible, internal cable routing, post-mount disc, 135x5 mm QR\n- Fork: SwiftVolt rigid alloy fork, 1-1/8'' steel steerer, 100x15mm thru-axle, post-mount disc brake\n- Max compatible fork travel: 63mm\n\nWheels\n- Front Hub: Swift sealed bearing, 32-hole 15mm alloy thru-axle\n- Front Skewer: Swift Switch thru-axle, removable lever\n- Rear Hub: Swift alloy, sealed bearing, 6-bolt, 135x5mm QR\n- Rear Skewer: 148x5mm bolt-on\n- Rim: SwiftRim, tubeless compatible, 32-hole, 35mm width, Presta valve\n- Spokes: 14g stainless steel, black\n- Tire: Swift E6 Hard-Case Lite, reflective strip, 27.5x2.40''\n- Max tire size: 27.5x2.40\"\n\nDrivetrain\n- Shifter: Shimano Deore M4100, 10 speed\n- Rear Derailleur: Shimano Deore M5120, long cage\n- Crank: Swift alloy, 170mm length\n- Chainring: Swift 46T narrow/wide alloy, w/alloy guard\n- Cassette: Shimano Deore M4100, 11-42, 10 speed\n- Chain: KMC E10\n- Pedal: Swift City pedals\n- Max chainring size: 1x: 48T\n\nComponents\n- Saddle: Swift Commuter Comp\n- Seatpost: Swift Comp, 6061 alloy, 31.6mm, 8mm offset, 330mm length\n- Handlebar: Swift alloy, 31.8mm, 15mm rise, 600mm width (M), 660mm width (L, XL)\n- Grips: Swift Satellite Elite, alloy lock-on\n- Stem: Swift alloy, 31.8mm, Blendr compatible, 7 degree, 70mm length (M), 90mm length (L), 100mm length (XL)\n- Headset: FSA IS-2 alloy, integrated, sealed cartridge bearing, 1-1/8'' top, 1.5'' bottom\n- Brakes: Shimano MT520 4-piston hydraulic disc, post-mount, 180mm rotor\n- Brake Rotor: Shimano RT56, 6-bolt, 180mm\n- Rotor size: Max 180mm front & rear\n\nAccessories\n- Battery: Swift PowerTube 700Wh\n- Charger: Swift standard 4A, 100-240V\n- Motor: SwiftDrive, 90 Nm, 30 mph / 48 kph\n- Light: Swift Lync taillight, 50 lumens (M, L, XL), Swift Lync headlight, 500 lumens (M, L, XL)\n- Kickstand: Rear mount, alloy (M, L, XL), Adjustable length alloy kickstand (M, L, XL)\n- Cargo rack: SwiftVolt integrated rear rack, aluminum\n- Fender: Swift custom aluminum\n\nWeight\n- Weight: M - 25.54 kg / 56.3 lbs\n- Weight limit: This bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\n\n## Sizing\n| Size | Rider Height | Inseam |\n|:----:|:---------------------:|:-------------:|\n| M | 165 - 175 cm 5'5\" - 5'9\" | 77 - 83 cm 30\" - 33\" |\n| L | 175 - 186 cm 5'9\" - 6'1\" | 82 - 88 cm 32\" - 35\" |\n| XL | 186 - 197 cm 6'1\" - 6'6\" | 87 - 93 cm 34\" - 37\" |\n\n## Geometry\n| Frame size letter | M | L | XL |\n|---------------------------|-------|-------|-------|\n| Wheel size | 27.5\" | 27.5\" | 27.5\" |\n| A — Seat tube | 44.6 | 49.1 | 53.4 |\n| B — Seat tube angle | 73.0° | 73.0° | 73.0° |\n| C — Head tube length | 16.5 | 19.5 | 23.0 |\n| D — Head angle | 69.5° | 70.0° | 70.5° |\n| E — Effective top tube | 59.5 | 60.7 | 62.2 |\n| F — Bottom bracket height | 29.5 | 29.5 | 29.5 |\n| G — Bottom bracket drop | 6.0 | 6.0 | 6.0 |\n| H — Chainstay length | 48.7 | 48.7 | 48.7 |\n| I — Offset | 4.4 | 4.4 | 4.4 |\n| J — Trail | 8.6 | 8.1 | 7.9 |\n| K — Wheelbase | 114.6 | 115.0 | 116.4 |\n| L — Standover | 79.5 | 83.7 | 87.9 |\n| M — Frame reach | 40.5 | 40.8 | 41.2 |\n| N — Frame stack | 62.3 | 65.2 | 68.8 |",
"price": 2499.99,
"tags": [
"bicycle",
"city bike",
"professional"
]
},
{
"name": "AgileEon 9X",
"shortDescription": "AgileEon 9X is a high-performance e-bike designed for riders seeking speed and endurance. Equipped with a robust motor and an extended battery life, this bike is perfect for long-distance commuters and avid e-bike enthusiasts. It boasts innovative features tailored for individuals who prioritize cycling over driving. Additionally, the bike integrates seamlessly with your smartphone, allowing you to access navigation, music, and more.",
"description": "## Overview\nIt's right for you if...\nYou crave speed and want to cover long distances efficiently. The AgileEon 9X features a sleek hydroformed aluminum frame that houses a powerful motor, along with a large-capacity battery for extended rides. It comes equipped with a 10-speed drivetrain, front and rear lighting, fenders, and a rear rack.\n\nThe tech you get\nDesigned for those constantly on the move, this bike includes a state-of-the-art motor and a high-capacity battery, making it an excellent choice for lengthy commutes.\n\nThe final word\nWith the AgileEon 9X, you can push your boundaries and explore new horizons thanks to its powerful motor and long-lasting battery.\n\n## Features\n\nConnect Your Ride with RideMate App\nMake use of the RideMate app to transform your smartphone into an onboard computer. Simply attach it to the RideMate controller to dock and charge, then utilize the thumb pad on your handlebar to make calls, listen to music, receive turn-by-turn directions, and more. The bike also supports Bluetooth® wireless technology, enabling seamless connectivity with fitness and health apps for route syncing and ride data.\n\nGoodbye, car. Hello, Extended Range!\nEnhance your riding experience with the Extended Range option, which allows for the attachment of an additional high-capacity 500Wh battery to your bike's downtube. This doubles the distance and time between charges, enabling longer rides, extended commutes, and more significant adventures. The Extended Range feature is compatible with select AgileEon electric bike models.\n\nWhat is the range?\nTo determine how far you can ride on a single charge, you can utilize the range calculator provided by AgileEon. We have pre-filled the variables for this specific model and an average rider, but adjustments can be made for a more accurate estimation.\n\n## Specifications\nFrameset\nFrame: High-performance hydroformed alloy, Removable Integrated Battery, Extended Range-compatible, internal cable routing, Motor Armor, post-mount disc, 135x5 mm QR\nFork: AgileEon rigid alloy fork, 1-1/8'' steel steerer, 100x15mm thru-axle, post-mount disc brake\nMax compatible fork travel: 63mm\n\nWheels\nFront Hub: AgileEon sealed bearing, 32-hole 15mm alloy thru-axle\nFront Skewer: AgileEon Switch thru-axle, removable lever\nRear Hub: AgileEon alloy, sealed bearing, 6-bolt, 135x5mm QR\nRear Skewer: 148x5mm bolt-on\nRim: AgileEon MD35, tubeless compatible, 32-hole, 35mm width, Presta valve\nSpokes:\n- Size: M, L, XL: 14g stainless steel, black\nTire: AgileEon E6 Hard-Case Lite, reflective strip, 27.5x2.40''\nMax tire size: 27.5x2.40\"\n\nDrivetrain\nShifter: Shimano Deore M4100, 10-speed\nRear derailleur:\n- Size: M, L, XL: Shimano Deore M5120, long cage\nCrank:\n- Size: M: AgileEon alloy, 170mm length\n- Size: L, XL: AgileEon alloy, 175mm length\nChainring: AgileEon 46T narrow/wide alloy, with alloy guard\nCassette:\n- Size: M, L, XL: Shimano Deore M4100, 11-42, 10-speed\nChain:\n- Size: M, L, XL: KMC E10\nPedal:\n- Size: M, L, XL: AgileEon City pedals\nMax chainring size: 1x: 48T\n\nComponents\nSaddle: AgileEon Commuter Comp\nSeatpost: AgileEon Comp, 6061 alloy, 31.6mm, 8mm offset, 330mm length\nHandlebar:\n- Size: M: AgileEon alloy, 31.8mm, 15mm rise, 600mm width\n- Size: L, XL: AgileEon alloy, 31.8mm, 15mm rise, 660mm width\nGrips: AgileEon Satellite Elite, alloy lock-on\nStem:\n- Size: M: AgileEon alloy, 31.8mm, Blendr compatible, 7-degree, 70mm length\n- Size: L: AgileEon alloy, 31.8mm, Blendr compatible, 7-degree, 90mm length\n- Size: XL: AgileEon alloy, 31.8mm, Blendr compatible, 7-degree, 100mm length\nHeadset:\n- Size: M, L, XL: AgileEon IS-2 alloy, integrated, sealed cartridge bearing, 1-1/8'' top, 1.5'' bottom\nBrake: Shimano MT520 4-piston hydraulic disc, post-mount, 180mm rotor\nBrake rotor: Shimano RT56, 6-bolt, 180mm\nRotor size: Max brake rotor sizes: 180mm front & rear\n\nAccessories\nBattery: AgileEon PowerTube 625Wh\nCharger: AgileEon standard 4A, 100-240V\nMotor: AgileEon Performance Speed, 85 Nm, 28 mph / 45 kph\nLight:\n- Size: M, L, XL: AgileEon taillight, 50 lumens\n- Size: M, L, XL: AgileEon headlight, 500 lumens\nKickstand:\n- Size: M, L, XL: Rear mount, alloy\n- Size: M, L, XL: Adjustable length alloy kickstand\nCargo rack: AgileEon integrated rear rack, aluminum\nFender: AgileEon custom aluminum\n\nWeight\nWeight: M - 25.54 kg / 56.3 lbs\nWeight limit: This bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 300 pounds (136 kg).\n\n## Sizing\n| Size | Rider Height | Inseam |\n|:----:|:------------------------:|:--------------------:|\n| M | 165 - 175 cm 5'5\" - 5'9\" | 77 - 83 cm 30\" - 33\" |\n| L | 175 - 186 cm 5'9\" - 6'1\" | 82 - 88 cm 32\" - 35\" |\n| XL | 186 - 197 cm 6'1\" - 6'6\" | 87 - 93 cm 34\" - 37\" |\n\n## Geometry\n| Frame size letter | M | L | XL |\n|---------------------------|-------|-------|-------|\n| Wheel size | 27.5\" | 27.5\" | 27.5\" |\n| A — Seat tube | 44.6 | 49.1 | 53.4 |\n| B — Seat tube angle | 73.0° | 73.0° | 73.0° |\n| C — Head tube length | 16.5 | 19.5 | 23.0 |\n| D — Head angle | 69.5° | 70.0° | 70.5° |\n| E — Effective top tube | 59.5 | 60.7 | 62.2 |\n| F — Bottom bracket height | 29.5 | 29.5 | 29.5 |\n| G — Bottom bracket drop | 6.0 | 6.0 | 6.0 |\n| H — Chainstay length | 48.7 | 48.7 | 48.7 |\n| I — Offset | 4.4 | 4.4 | 4.4 |\n| J — Trail | 8.6 | 8.1 | 7.9 |\n| K — Wheelbase | 114.6 | 115.0 | 116.4 |\n| L — Standover | 79.5 | 83.7 | 87.9 |\n| M — Frame reach | 40.5 | 40.8 | 41.2 |\n| N — Frame stack | 62.3 | 65.2 | 68.8 |",
"price": 3499.99,
"tags": [
"bicycle",
"road bike",
"professional"
]
},
{
"name": "Stealth R1X Pro",
"shortDescription": "Stealth R1X Pro is a high-performance carbon road bike designed for riders who crave speed and exceptional handling. With its aerodynamic tube shaping, disc brakes, and lightweight carbon wheels, the Stealth R1X Pro offers unparalleled performance for competitive road cycling.",
"description": "## Overview\nIt's right for you if...\nYou're a competitive cyclist looking for a road bike that offers superior performance in terms of speed, handling, and aerodynamics. You want a complete package that includes lightweight carbon wheels, without the need for future upgrades.\n\nThe tech you get\nThe Stealth R1X Pro features a lightweight and aerodynamic carbon frame, an advanced carbon fork, high-performance Shimano Ultegra 11-speed drivetrain, and powerful Ultegra disc brakes. The bike also comes equipped with cutting-edge Bontrager Aeolus Elite 35 carbon wheels.\n\nThe final word\nThe Stealth R1X Pro stands out with its combination of a fast and aerodynamic frame, high-end drivetrain, and top-of-the-line carbon wheels. Whether you're racing on local roads, participating in pro stage races, or engaging in hill climbing competitions, this bike is a formidable choice that delivers an exceptional riding experience.\n\n## Features\nSleek and aerodynamic design\nThe Stealth R1X Pro's aero tube shapes maximize speed and performance, making it faster on climbs and flats alike. The bike also features a streamlined Aeolus RSL bar/stem for improved front-end aerodynamics.\n\nDesigned for all riders\nThe Stealth R1X Pro is designed to provide an outstanding fit for riders of all genders, body types, riding styles, and abilities. It comes equipped with size-specific components to ensure a comfortable and efficient riding position for competitive riders.\n\n## Specifications\nFrameset\n- Frame: Ultralight carbon frame constructed with high-performance 500 Series ADV Carbon. It features Ride Tuned performance tube optimization, a tapered head tube, internal routing, DuoTrap S compatibility, flat mount disc brake mounts, and a 142x12mm thru axle.\n- Fork: Full carbon fork (Émonda SL) with a tapered carbon steerer, internal brake routing, flat mount disc brake mounts, and a 12x100mm thru axle.\n- Frame fit: H1.5 Race geometry.\n\nWheels\n- Front wheel: Bontrager Aeolus Elite 35 carbon wheel with a 35mm rim depth, ADV Carbon construction, Tubeless Ready compatibility, and a 100x12mm thru axle.\n- Rear wheel: Bontrager Aeolus Elite 35 carbon wheel with a 35mm rim depth, ADV Carbon construction, Tubeless Ready compatibility, Shimano 11/12-speed freehub, and a 142x12mm thru axle.\n- Front skewer: Bontrager Switch thru axle with a removable lever.\n- Rear skewer: Bontrager Switch thru axle with a removable lever.\n- Tire: Bontrager R2 Hard-Case Lite with an aramid bead, 60 tpi, and a size of 700x25c.\n- Maximum tire size: 28mm.\n\nDrivetrain\n- Shifter:\n - Size 47, 50, 52: Shimano Ultegra R8025 with short-reach levers, 11-speed.\n - Size 54, 56, 58, 60, 62: Shimano Ultegra R8020, 11-speed.\n- Front derailleur: Shimano Ultegra R8000, braze-on.\n- Rear derailleur: Shimano Ultegra R8000, short cage, with a maximum cog size of 30T.\n- Crank:\n - Size 47: Shimano Ultegra R8000 with 52/36 chainrings and a 165mm length.\n - Size 50, 52: Shimano Ultegra R8000 with 52/36 chainrings and a 170mm length.\n - Size 54, 56, 58: Shimano Ultegra R8000 with 52/36 chainrings and a 172.5mm length.\n - Size 60, 62: Shimano Ultegra R8000 with 52/36 chainrings and a 175mm length.\n- Bottom bracket: Praxis T47 threaded bottom bracket with internal bearings.\n- Cassette: Shimano Ultegra R8000, 11-30, 11-speed.\n- Chain: Shimano Ultegra HG701, 11-speed.\n- Maximum chainring size: 1x - 50T, 2x - 53/39.\n\nComponents\n- Saddle: Bontrager Aeolus Comp with steel rails and a width of 145mm.\n- Seatpost:\n - Size 47, 50, 52, 54: Bontrager carbon seatmast cap with a 20mm offset and a short length.\n - Size 56, 58, 60, 62: Bontrager carbon seatmast cap with a 20mm offset and a tall length.\n- Handlebar:\n - Size 47, 50: Bontrager Elite VR-C alloy handlebar with a 31.8mm clamp, 100mm reach, 124mm drop, and a width of 38cm.\n - Size 52: Bontrager Elite VR-C alloy handlebar with a 31.8mm clamp, 100mm reach, 124mm drop, and a width of 40cm.\n - Size 54, 56, 58: Bontrager Elite VR-C alloy handlebar with a 31.8mm clamp, 100mm reach, 124mm drop, and a width of 42cm.\n - Size 60, 62: Bontrager Elite VR-C alloy handlebar with a 31.8mm clamp, 100mm reach, 124mm drop, and a width of 44cm.\n- Handlebar tape: Bontrager Supertack Perf tape.\n- Stem:\n - Size 47: Bontrager Pro alloy stem with a 31.8mm clamp, Blendr compatibility, 7-degree rise, and a length of 70mm.\n - Size 50: Bontrager Pro alloy stem with a 31.8mm clamp, Blendr compatibility, 7-degree rise, and a length of 80mm.\n - Size 52, 54: Bontrager Pro alloy stem with a 31.8mm clamp, Blendr compatibility, 7-degree rise, and a length of 90mm.\n - Size 56: Bontrager Pro alloy stem with a 31.8mm clamp, Blendr compatibility, 7-degree rise, and a length of 100mm.\n - Size 58, 60, 62: Bontrager Pro alloy stem with a 31.8mm clamp, Blendr compatibility, 7-degree rise, and a length of 110mm.\n- Brake: Shimano Ultegra hydraulic disc brakes with flat mount calipers.\n- Brake rotor: Shimano RT800 with centerlock mounting, 160mm diameter.\n\nWeight\n- Weight: 8.03 kg (17.71 lbs) for the 56cm frame.\n- Weight limit: The bike has a maximum total weight limit (combined weight of the bicycle, rider, and cargo) of 275 pounds (125 kg).\n\n## Sizing\nPlease refer to the table below for the corresponding Stealth R1X Pro frame sizes, recommended rider height range, and inseam measurements:\n\n| Size | Rider Height | Inseam |\n|:----:|:---------------------:|:--------------:|\n| 47 | 152 - 158 cm (5'0\") | 71 - 75 cm |\n| 50 | 158 - 163 cm (5'2\") | 74 - 77 cm |\n| 52 | 163 - 168 cm (5'4\") | 76 - 79 cm |\n| 54 | 168 - 174 cm (5'6\") | 78 - 82 cm |\n| 56 | 174 - 180 cm (5'9\") | 81 - 85 cm |\n| 58 | 180 - 185 cm (5'11\") | 84 - 87 cm |\n| 60 | 185 - 190 cm (6'1\") | 86 - 90 cm |\n| 62 | 190 - 195 cm (6'3\") | 89 - 92 cm |\n\n## Geometry\nThe table below provides the geometry measurements for each frame size of the Stealth R1X Pro:\n\n| Frame size number | 47 cm | 50 cm | 52 cm | 54 cm | 56 cm | 58 cm | 60 cm | 62 cm |\n|-------------------------------|-------|-------|-------|-------|-------|-------|-------|-------|\n| Wheel size | 700c | 700c | 700c | 700c | 700c | 700c | 700c | 700c |\n| A — Seat tube | 42.4 | 45.3 | 48.3 | 49.6 | 52.5 | 55.3 | 57.3 | 59.3 |\n| B — Seat tube angle | 74.6° | 74.6° | 74.2° | 73.7° | 73.3° | 73.0° | 72.8° | 72.5° |\n| C — Head tube length | 10.0 | 11.1 | 12.1 | 13.1 | 15.1 | 17.1 | 19.1 | 21.1 |\n| D — Head angle | 72.1° | 72.1° | 72.8° | 73.0° | 73.5° | 73.8° | 73.9° | 73.9° |\n| E — Effective top tube | 51.2 | 52.1 | 53.4 | 54.3 | 55.9 | 57.4 | 58.6 | 59.8 |\n| G — Bottom bracket drop | 7.2 | 7.2 | 7.2 | 7.0 | 7.0 | 6.8 | 6.8 | 6.8 |\n| H — Chainstay length | 41.0 | 41.0 | 41.0 | 41.0 | 41.0 | 41.1 | 41.1 | 41.2 |\n| I — Offset | 4.5 | 4.5 | 4.5 | 4.5 | 4.0 | 4.0 | 4.0 | 4.0 |\n| J — Trail | 6.8 | 6.2 | 5.8 | 5.6 | 5.8 | 5.7 | 5.6 | 5.6 |\n| K — Wheelbase | 97.2 | 97.4 | 97.7 | 98.1 | 98.3 | 99.2 | 100.1 | 101.0 |\n| L — Standover | 69.2 | 71.1 | 73.2 | 74.4 | 76.8 | 79.3 | 81.1 | 82.9 |\n| M — Frame reach | 37.3 | 37.8 | 38.3 | 38.6 | 39.1 | 39.6 | 39.9 | 40.3 |\n| N — Frame stack | 50.7 | 52.1 | 53.3 | 54.1 | 56.3 | 58.1 | 60.1 | 62.0 |\n| Saddle rail height min (short mast) | 55.5 | 58.5 | 61.5 | 64.0 | 67.0 | 69.0 | 71.0 | 73.0 |\n| Saddle rail height max (short mast) | 61.5 | 64.5 | 67.5 | 70.0 | 73.0 | 75.0 | 77.0 | 79.0 |\n| Saddle rail height min (tall mast) | 59.0 | 62.0 | 65.0 | 67.5 | 70.5 | 72.5 | 74.5 | 76.5 |\n| Saddle rail height max (tall mast) | 65.0 | 68.0 | 71.0 | 73.5 | 76.5 | 78.5 | 80.5 | 82.5 |",
"price": 2999.99,
"tags": [
"bicycle",
"mountain bike",
"professional"
]
},
{
"name": "Avant SLR 6 Disc Pro",
"shortDescription": "Avant SLR 6 Disc Pro is a high-performance carbon road bike designed for riders who prioritize speed and handling. With its aero tube shaping, disc brakes, and lightweight carbon wheels, it offers the perfect balance of speed and control.",
"description": "## Overview\nIt's right for you if...\nYou're a rider who values exceptional performance on fast group rides and races, and you want a complete package that includes lightweight carbon wheels. The Avant SLR 6 Disc Pro is designed to provide the speed and aerodynamics you need to excel on any road.\n\nThe tech you get\nThe Avant SLR 6 Disc Pro features a lightweight 500 Series ADV Carbon frame and fork, Bontrager Aeolus Elite 35 carbon wheels, a full Shimano Ultegra 11-speed drivetrain, and powerful Ultegra disc brakes.\n\nThe final word\nThe standout feature of this bike is the combination of its aero frame, high-performance drivetrain, and top-quality carbon wheels. Whether you're racing, tackling challenging climbs, or participating in professional stage races, the Avant SLR 6 Disc Pro is a worthy choice that will enhance your performance.\n\n## Features\nAll-new aero design\nThe Avant SLR 6 Disc Pro features innovative aero tube shapes that provide an advantage in all riding conditions, whether it's climbing or riding on flat roads. Additionally, it is equipped with a sleek new Aeolus RSL bar/stem that enhances front-end aero performance.\n\nAwesome bikes for everyone\nThe Avant SLR 6 Disc Pro is designed with the belief that every rider, regardless of gender, body type, riding style, or ability, deserves a great bike. It is equipped with size-specific components that ensure a perfect fit for competitive riders of all genders.\n\n## Specifications\nFrameset\n- Frame: Ultralight 500 Series ADV Carbon, Ride Tuned performance tube optimization, tapered head tube, internal routing, DuoTrap S compatible, flat mount disc, 142x12mm thru axle\n- Fork: Avant SL full carbon, tapered carbon steerer, internal brake routing, flat mount disc, 12x100mm thru axle\n- Frame fit: H1.5 Race\n\nWheels\n- Front wheel: Bontrager Aeolus Elite 35, ADV Carbon, Tubeless Ready, 35mm rim depth, 100x12mm thru axle\n- Rear wheel: Bontrager Aeolus Elite 35, ADV Carbon, Tubeless Ready, 35mm rim depth, Shimano 11/12-speed freehub, 142x12mm thru axle\n- Front skewer: Bontrager Switch thru axle, removable lever\n- Rear skewer: Bontrager Switch thru axle, removable lever\n- Tire: Bontrager R2 Hard-Case Lite, aramid bead, 60 tpi, 700x25c\n- Max tire size: 28mm\n\nDrivetrain\n- Shifter: \n - Size 47, 50, 52: Shimano Ultegra R8025, short-reach lever, 11-speed\n - Size 54, 56, 58, 60, 62: Shimano Ultegra R8020, 11-speed\n- Front derailleur: Shimano Ultegra R8000, braze-on\n- Rear derailleur: Shimano Ultegra R8000, short cage, 30T max cog\n- Crank: \n - Size 47: Shimano Ultegra R8000, 52/36, 165mm length\n - Size 50, 52: Shimano Ultegra R8000, 52/36, 170mm length\n - Size 54, 56, 58: Shimano Ultegra R8000, 52/36, 172.5mm length\n - Size 60, 62: Shimano Ultegra R8000, 52/36, 175mm length\n- Bottom bracket: Praxis, T47 threaded, internal bearing\n- Cassette: Shimano Ultegra R8000, 11-30, 11-speed\n- Chain: Shimano Ultegra HG701, 11-speed\n- Max chainring size: 1x: 50T, 2x: 53/39\n\nComponents\n- Saddle: Bontrager Aeolus Comp, steel rails, 145mm width\n- Seatpost: \n - Size 47, 50, 52, 54: Bontrager carbon seatmast cap, 20mm offset, short length\n - Size 56, 58, 60, 62: Bontrager carbon seatmast cap, 20mm offset, tall length\n- Handlebar: \n - Size 47, 50: Bontrager Elite VR-C, alloy, 31.8mm, 100mm reach, 124mm drop, 38cm width\n - Size 52: Bontrager Elite VR-C, alloy, 31.8mm, 100mm reach, 124mm drop, 40cm width\n - Size 54, 56, 58: Bontrager Elite VR-C, alloy, 31.8mm, 100mm reach, 124mm drop, 42cm width\n - Size 60, 62: Bontrager Elite VR-C, alloy, 31.8mm, 100mm reach, 124mm drop, 44cm width\n- Handlebar tape: Bontrager Supertack Perf tape\n- Stem: \n - Size 47: Bontrager Pro, 31.8mm, Blendr compatible, 7-degree, 70mm length\n - Size 50: Bontrager Pro, 31.8mm, Blendr compatible, 7-degree, 80mm length\n - Size 52, 54: Bontrager Pro, 31.8mm, Blendr compatible, 7-degree, 90mm length\n - Size 56: Bontrager Pro, 31.8mm, Blendr compatible, 7-degree, 100mm length\n - Size 58, 60, 62: Bontrager Pro, 31.8mm, Blendr compatible, 7-degree, 110mm length\n- Brake: Shimano Ultegra hydraulic disc, flat mount\n- Brake rotor: Shimano RT800, centerlock, 160mm\n\nWeight\n- Weight: 56 - 8.03 kg / 17.71 lbs\n- Weight limit: This bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 275 pounds (125 kg).\n\n## Sizing\n| Size | Rider Height | Inseam |\n|:----:|:-------------------------:|:--------------------:|\n| 47 | 152 - 158 cm 5'0\" - 5'2\" | 71 - 75 cm 28\" - 30\" |\n| 50 | 158 - 163 cm 5'2\" - 5'4\" | 74 - 77 cm 29\" - 30\" |\n| 52 | 163 - 168 cm 5'4\" - 5'6\" | 76 - 79 cm 30\" - 31\" |\n| 54 | 168 - 174 cm 5'6\" - 5'9\" | 78 - 82 cm 31\" - 32\" |\n| 56 | 174 - 180 cm 5'9\" - 5'11\" | 81 - 85 cm 32\" - 33\" |\n| 58 | 180 - 185 cm 5'11\" - 6'1\" | 84 - 87 cm 33\" - 34\" |\n| 60 | 185 - 190 cm 6'1\" - 6'3\" | 86 - 90 cm 34\" - 35\" |\n| 62 | 190 - 195 cm 6'3\" - 6'5\" | 89 - 92 cm 35\" - 36\" |\n\n## Geometry\n| Frame size number | 47 cm | 50 cm | 52 cm | 54 cm | 56 cm | 58 cm | 60 cm | 62 cm |\n|---------------------------------------|-------|-------|-------|-------|-------|-------|-------|-------|\n| Wheel size | 700c | 700c | 700c | 700c | 700c | 700c | 700c | 700c |\n| A — Seat tube | 42.4 | 45.3 | 48.3 | 49.6 | 52.5 | 55.3 | 57.3 | 59.3 |\n| B — Seat tube angle | 74.6° | 74.6° | 74.2° | 73.7° | 73.3° | 73.0° | 72.8° | 72.5° |\n| C — Head tube length | 10.0 | 11.1 | 12.1 | 13.1 | 15.1 | 17.1 | 19.1 | 21.1 |\n| D — Head angle | 72.1° | 72.1° | 72.8° | 73.0° | 73.5° | 73.8° | 73.9° | 73.9° |\n| E — Effective top tube | 51.2 | 52.1 | 53.4 | 54.3 | 55.9 | 57.4 | 58.6 | 59.8 |\n| G — Bottom bracket drop | 7.2 | 7.2 | 7.2 | 7.0 | 7.0 | 6.8 | 6.8 | 6.8 |\n| H — Chainstay length | 41.0 | 41.0 | 41.0 | 41.0 | 41.0 | 41.1 | 41.1 | 41.2 |\n| I — Offset | 4.5 | 4.5 | 4.5 | 4.5 | 4.0 | 4.0 | 4.0 | 4.0 |\n| J — Trail | 6.8 | 6.2 | 5.8 | 5.6 | 5.8 | 5.7 | 5.6 | 5.6 |\n| K — Wheelbase | 97.2 | 97.4 | 97.7 | 98.1 | 98.3 | 99.2 | 100.1 | 101.0 |\n| L — Standover | 69.2 | 71.1 | 73.2 | 74.4 | 76.8 | 79.3 | 81.1 | 82.9 |\n| M — Frame reach | 37.3 | 37.8 | 38.3 | 38.6 | 39.1 | 39.6 | 39.9 | 40.3 |\n| N — Frame stack | 50.7 | 52.1 | 53.3 | 54.1 | 56.3 | 58.1 | 60.1 | 62.0 |\n| Saddle rail height min (w/short mast) | 55.5 | 58.5 | 61.5 | 64.0 | 67.0 | 69.0 | 71.0 | 73.0 |\n| Saddle rail height max (w/short mast) | 61.5 | 64.5 | 67.5 | 70.0 | 73.0 | 75.0 | 77.0 | 79.0 |\n| Saddle rail height min (w/tall mast) | 59.0 | 62.0 | 65.0 | 67.5 | 70.5 | 72.5 | 74.5 | 76.5 |\n| Saddle rail height max (w/tall mast) | 65.0 | 68.0 | 71.0 | 73.5 | 76.5 | 78.5 | 80.5 | 82.5 |",
"price": 999.99,
"tags": [
"bicycle",
"city bike",
"professional"
]
}
]
Spring Ai Commons/Src/Test/Resources/Events.Json (spring-ai-commons/src/test/resources/events.json)
[
{
"sessions": [
{
"description": "Session one"
},
{
"description": "Session two"
},
{
"description": "Session three"
}
]
}
]
Spring Ai Commons/Src/Test/Resources/Person.Json (spring-ai-commons/src/test/resources/person.json)
{
"name": "Avant SLR 6 Disc Pro",
"shortDescription": "Avant SLR 6 Disc Pro is a high-performance carbon road bike designed for riders who prioritize speed and handling. With its aero tube shaping, disc brakes, and lightweight carbon wheels, it offers the perfect balance of speed and control.",
"description": "## Overview\nIt's right for you if...\nYou're a rider who values exceptional performance on fast group rides and races, and you want a complete package that includes lightweight carbon wheels. The Avant SLR 6 Disc Pro is designed to provide the speed and aerodynamics you need to excel on any road.\n\nThe tech you get\nThe Avant SLR 6 Disc Pro features a lightweight 500 Series ADV Carbon frame and fork, Bontrager Aeolus Elite 35 carbon wheels, a full Shimano Ultegra 11-speed drivetrain, and powerful Ultegra disc brakes.\n\nThe final word\nThe standout feature of this bike is the combination of its aero frame, high-performance drivetrain, and top-quality carbon wheels. Whether you're racing, tackling challenging climbs, or participating in professional stage races, the Avant SLR 6 Disc Pro is a worthy choice that will enhance your performance.\n\n## Features\nAll-new aero design\nThe Avant SLR 6 Disc Pro features innovative aero tube shapes that provide an advantage in all riding conditions, whether it's climbing or riding on flat roads. Additionally, it is equipped with a sleek new Aeolus RSL bar/stem that enhances front-end aero performance.\n\nAwesome bikes for everyone\nThe Avant SLR 6 Disc Pro is designed with the belief that every rider, regardless of gender, body type, riding style, or ability, deserves a great bike. It is equipped with size-specific components that ensure a perfect fit for competitive riders of all genders.\n\n## Specifications\nFrameset\n- Frame: Ultralight 500 Series ADV Carbon, Ride Tuned performance tube optimization, tapered head tube, internal routing, DuoTrap S compatible, flat mount disc, 142x12mm thru axle\n- Fork: Avant SL full carbon, tapered carbon steerer, internal brake routing, flat mount disc, 12x100mm thru axle\n- Frame fit: H1.5 Race\n\nWheels\n- Front wheel: Bontrager Aeolus Elite 35, ADV Carbon, Tubeless Ready, 35mm rim depth, 100x12mm thru axle\n- Rear wheel: Bontrager Aeolus Elite 35, ADV Carbon, Tubeless Ready, 35mm rim depth, Shimano 11/12-speed freehub, 142x12mm thru axle\n- Front skewer: Bontrager Switch thru axle, removable lever\n- Rear skewer: Bontrager Switch thru axle, removable lever\n- Tire: Bontrager R2 Hard-Case Lite, aramid bead, 60 tpi, 700x25c\n- Max tire size: 28mm\n\nDrivetrain\n- Shifter: \n - Size 47, 50, 52: Shimano Ultegra R8025, short-reach lever, 11-speed\n - Size 54, 56, 58, 60, 62: Shimano Ultegra R8020, 11-speed\n- Front derailleur: Shimano Ultegra R8000, braze-on\n- Rear derailleur: Shimano Ultegra R8000, short cage, 30T max cog\n- Crank: \n - Size 47: Shimano Ultegra R8000, 52/36, 165mm length\n - Size 50, 52: Shimano Ultegra R8000, 52/36, 170mm length\n - Size 54, 56, 58: Shimano Ultegra R8000, 52/36, 172.5mm length\n - Size 60, 62: Shimano Ultegra R8000, 52/36, 175mm length\n- Bottom bracket: Praxis, T47 threaded, internal bearing\n- Cassette: Shimano Ultegra R8000, 11-30, 11-speed\n- Chain: Shimano Ultegra HG701, 11-speed\n- Max chainring size: 1x: 50T, 2x: 53/39\n\nComponents\n- Saddle: Bontrager Aeolus Comp, steel rails, 145mm width\n- Seatpost: \n - Size 47, 50, 52, 54: Bontrager carbon seatmast cap, 20mm offset, short length\n - Size 56, 58, 60, 62: Bontrager carbon seatmast cap, 20mm offset, tall length\n- Handlebar: \n - Size 47, 50: Bontrager Elite VR-C, alloy, 31.8mm, 100mm reach, 124mm drop, 38cm width\n - Size 52: Bontrager Elite VR-C, alloy, 31.8mm, 100mm reach, 124mm drop, 40cm width\n - Size 54, 56, 58: Bontrager Elite VR-C, alloy, 31.8mm, 100mm reach, 124mm drop, 42cm width\n - Size 60, 62: Bontrager Elite VR-C, alloy, 31.8mm, 100mm reach, 124mm drop, 44cm width\n- Handlebar tape: Bontrager Supertack Perf tape\n- Stem: \n - Size 47: Bontrager Pro, 31.8mm, Blendr compatible, 7-degree, 70mm length\n - Size 50: Bontrager Pro, 31.8mm, Blendr compatible, 7-degree, 80mm length\n - Size 52, 54: Bontrager Pro, 31.8mm, Blendr compatible, 7-degree, 90mm length\n - Size 56: Bontrager Pro, 31.8mm, Blendr compatible, 7-degree, 100mm length\n - Size 58, 60, 62: Bontrager Pro, 31.8mm, Blendr compatible, 7-degree, 110mm length\n- Brake: Shimano Ultegra hydraulic disc, flat mount\n- Brake rotor: Shimano RT800, centerlock, 160mm\n\nWeight\n- Weight: 56 - 8.03 kg / 17.71 lbs\n- Weight limit: This bike has a maximum total weight limit (combined weight of bicycle, rider, and cargo) of 275 pounds (125 kg).\n\n## Sizing\n| Size | Rider Height | Inseam |\n|:----:|:-------------------------:|:--------------------:|\n| 47 | 152 - 158 cm 5'0\" - 5'2\" | 71 - 75 cm 28\" - 30\" |\n| 50 | 158 - 163 cm 5'2\" - 5'4\" | 74 - 77 cm 29\" - 30\" |\n| 52 | 163 - 168 cm 5'4\" - 5'6\" | 76 - 79 cm 30\" - 31\" |\n| 54 | 168 - 174 cm 5'6\" - 5'9\" | 78 - 82 cm 31\" - 32\" |\n| 56 | 174 - 180 cm 5'9\" - 5'11\" | 81 - 85 cm 32\" - 33\" |\n| 58 | 180 - 185 cm 5'11\" - 6'1\" | 84 - 87 cm 33\" - 34\" |\n| 60 | 185 - 190 cm 6'1\" - 6'3\" | 86 - 90 cm 34\" - 35\" |\n| 62 | 190 - 195 cm 6'3\" - 6'5\" | 89 - 92 cm 35\" - 36\" |\n\n## Geometry\n| Frame size number | 47 cm | 50 cm | 52 cm | 54 cm | 56 cm | 58 cm | 60 cm | 62 cm |\n|---------------------------------------|-------|-------|-------|-------|-------|-------|-------|-------|\n| Wheel size | 700c | 700c | 700c | 700c | 700c | 700c | 700c | 700c |\n| A — Seat tube | 42.4 | 45.3 | 48.3 | 49.6 | 52.5 | 55.3 | 57.3 | 59.3 |\n| B — Seat tube angle | 74.6° | 74.6° | 74.2° | 73.7° | 73.3° | 73.0° | 72.8° | 72.5° |\n| C — Head tube length | 10.0 | 11.1 | 12.1 | 13.1 | 15.1 | 17.1 | 19.1 | 21.1 |\n| D — Head angle | 72.1° | 72.1° | 72.8° | 73.0° | 73.5° | 73.8° | 73.9° | 73.9° |\n| E — Effective top tube | 51.2 | 52.1 | 53.4 | 54.3 | 55.9 | 57.4 | 58.6 | 59.8 |\n| G — Bottom bracket drop | 7.2 | 7.2 | 7.2 | 7.0 | 7.0 | 6.8 | 6.8 | 6.8 |\n| H — Chainstay length | 41.0 | 41.0 | 41.0 | 41.0 | 41.0 | 41.1 | 41.1 | 41.2 |\n| I — Offset | 4.5 | 4.5 | 4.5 | 4.5 | 4.0 | 4.0 | 4.0 | 4.0 |\n| J — Trail | 6.8 | 6.2 | 5.8 | 5.6 | 5.8 | 5.7 | 5.6 | 5.6 |\n| K — Wheelbase | 97.2 | 97.4 | 97.7 | 98.1 | 98.3 | 99.2 | 100.1 | 101.0 |\n| L — Standover | 69.2 | 71.1 | 73.2 | 74.4 | 76.8 | 79.3 | 81.1 | 82.9 |\n| M — Frame reach | 37.3 | 37.8 | 38.3 | 38.6 | 39.1 | 39.6 | 39.9 | 40.3 |\n| N — Frame stack | 50.7 | 52.1 | 53.3 | 54.1 | 56.3 | 58.1 | 60.1 | 62.0 |\n| Saddle rail height min (w/short mast) | 55.5 | 58.5 | 61.5 | 64.0 | 67.0 | 69.0 | 71.0 | 73.0 |\n| Saddle rail height max (w/short mast) | 61.5 | 64.5 | 67.5 | 70.0 | 73.0 | 75.0 | 77.0 | 79.0 |\n| Saddle rail height min (w/tall mast) | 59.0 | 62.0 | 65.0 | 67.5 | 70.5 | 72.5 | 74.5 | 76.5 |\n| Saddle rail height max (w/tall mast) | 65.0 | 68.0 | 71.0 | 73.5 | 76.5 | 78.5 | 80.5 | 82.5 |",
"price": 999.99,
"tags": [
"bicycle",
"city bike",
"professional"
],
"store": {
"name": "Bike Shop",
"location": {
"city": "San Francisco",
"state": "CA",
"address": {
"street": "123 Market St",
"zipcode": "94103"
}
},
"products": [
{
"name": "Avant SLR 6 Disc Pro",
"price": 999.99,
"tags": [
"bicycle",
"city bike",
"professional"
],
"details": {
"weight": "7.5kg",
"color": "red"
}
},
{
"name": "Mountain Master 3000",
"price": 1299.99,
"tags": [
"bicycle",
"mountain bike",
"professional"
],
"details": {
"weight": "9kg",
"color": "blue"
}
}
]
},
"employees": [
{
"name": "John Doe",
"role": "Manager"
},
{
"name": "Jane Smith",
"role": "Sales"
}
]
}
Spring Ai Commons/Src/Test/Resources/Text Source (spring-ai-commons/src/test/resources/text_source.txt)
Spring Framework Documentation
Version 6.0.0
Chapter 1. Spring Framework Overview
Spring makes it easy to create Java enterprise applications. It provides everything you need to
embrace the Java language in an enterprise environment, with support for Groovy and Kotlin as
alternative languages on the JVM, and with the flexibility to create many kinds of architectures
depending on an application’s needs. As of Spring Framework 5.1, Spring requires JDK 8+ (Java SE
8+) and provides out-of-the-box support for JDK 11 LTS. Java SE 8 update 60 is suggested as the
minimum patch release for Java 8, but it is generally recommended to use a recent patch release.
Spring supports a wide range of application scenarios. In a large enterprise, applications often exist
for a long time and have to run on a JDK and application server whose upgrade cycle is beyond
developer control. Others may run as a single jar with the server embedded, possibly in a cloud
environment. Yet others may be standalone applications (such as batch or integration workloads)
that do not need a server.
Spring is open source. It has a large and active community that provides continuous feedback based
on a diverse range of real-world use cases. This has helped Spring to successfully evolve over a very
long time.
1.1. What We Mean by "Spring"
The term "Spring" means different things in different contexts. It can be used to refer to the Spring
Framework project itself, which is where it all started. Over time, other Spring projects have been
built on top of the Spring Framework. Most often, when people say "Spring", they mean the entire
family of projects. This reference documentation focuses on the foundation: the Spring Framework
itself.
The Spring Framework is divided into modules. Applications can choose which modules they need.
At the heart are the modules of the core container, including a configuration model and a
dependency injection mechanism. Beyond that, the Spring Framework provides foundational
support for different application architectures, including messaging, transactional data and
persistence, and web. It also includes the Servlet-based Spring MVC web framework and, in
parallel, the Spring WebFlux reactive web framework.
A note about modules: Spring’s framework jars allow for deployment to JDK 9’s module path
("Jigsaw"). For use in Jigsaw-enabled applications, the Spring Framework 5 jars come with
"Automatic-Module-Name" manifest entries which define stable language-level module names
("spring.core", "spring.context", etc.) independent from jar artifact names (the jars follow the same
naming pattern with "-" instead of ".", e.g. "spring-core" and "spring-context"). Of course, Spring’s
framework jars keep working fine on the classpath on both JDK 8 and 9+.
1.2. History of Spring and the Spring Framework
Spring came into being in 2003 as a response to the complexity of the early J2EE specifications.
While some consider Java EE and its modern-day successor Jakarta EE to be in competition with
Spring, they are in fact complementary. The Spring programming model does not embrace the
Jakarta EE platform specification; rather, it integrates with carefully selected individual
specifications from the traditional EE umbrella:
• Servlet API (JSR 340)
• WebSocket API (JSR 356)
• Concurrency Utilities (JSR 236)
• JSON Binding API (JSR 367)
• Bean Validation (JSR 303)
• JPA (JSR 338)
• JMS (JSR 914)
• as well as JTA/JCA setups for transaction coordination, if necessary.
The Spring Framework also supports the Dependency Injection (JSR 330) and Common Annotations
(JSR 250) specifications, which application developers may choose to use instead of the Spring-
specific mechanisms provided by the Spring Framework. Originally, those were based on common
javax packages.
As of Spring Framework 6.0, Spring has been upgraded to the Jakarta EE 9 level (e.g. Servlet 5.0+,
JPA 3.0+), based on the jakarta namespace instead of the traditional javax packages. With EE 9 as
the minimum and EE 10 supported already, Spring is prepared to provide out-of-the-box support
for the further evolution of the Jakarta EE APIs. Spring Framework 6.0 is fully compatible with
Tomcat 10.1, Jetty 11 and Undertow 2.3 as web servers, and also with Hibernate ORM 6.1.
Over time, the role of Java/Jakarta EE in application development has evolved. In the early days of
J2EE and Spring, applications were created to be deployed to an application server. Today, with the
help of Spring Boot, applications are created in a devops- and cloud-friendly way, with the Servlet
container embedded and trivial to change. As of Spring Framework 5, a WebFlux application does
not even use the Servlet API directly and can run on servers (such as Netty) that are not Servlet
containers.
Spring continues to innovate and to evolve. Beyond the Spring Framework, there are other projects,
such as Spring Boot, Spring Security, Spring Data, Spring Cloud, Spring Batch, among others. It’s
important to remember that each project has its own source code repository, issue tracker, and
release cadence. See spring.io/projects for the complete list of Spring projects.
1.3. Design Philosophy
When you learn about a framework, it’s important to know not only what it does but what
principles it follows. Here are the guiding principles of the Spring Framework:
• Provide choice at every level. Spring lets you defer design decisions as late as possible. For
example, you can switch persistence providers through configuration without changing your
code. The same is true for many other infrastructure concerns and integration with third-party
APIs.
• Accommodate diverse perspectives. Spring embraces flexibility and is not opinionated about
how things should be done. It supports a wide range of application needs with different
perspectives.
• Maintain strong backward compatibility. Spring’s evolution has been carefully managed to
force few breaking changes between versions. Spring supports a carefully chosen range of JDK
versions and third-party libraries to facilitate maintenance of applications and libraries that
depend on Spring.
• Care about API design. The Spring team puts a lot of thought and time into making APIs that are
intuitive and that hold up across many versions and many years.
• Set high standards for code quality. The Spring Framework puts a strong emphasis on
meaningful, current, and accurate javadoc. It is one of very few projects that can claim clean
code structure with no circular dependencies between packages.
1.4. Feedback and Contributions
For how-to questions or diagnosing or debugging issues, we suggest using Stack Overflow. Click
here for a list of the suggested tags to use on Stack Overflow. If you’re fairly certain that there is a
problem in the Spring Framework or would like to suggest a feature, please use the GitHub Issues.
If you have a solution in mind or a suggested fix, you can submit a pull request on Github.
However, please keep in mind that, for all but the most trivial issues, we expect a ticket to be filed
in the issue tracker, where discussions take place and leave a record for future reference.
For more details see the guidelines at the CONTRIBUTING, top-level project page.
1.5. Getting Started
If you are just getting started with Spring, you may want to begin using the Spring Framework by
creating a Spring Boot-based application. Spring Boot provides a quick (and opinionated) way to
create a production-ready Spring-based application. It is based on the Spring Framework, favors
convention over configuration, and is designed to get you up and running as quickly as possible.
You can use start.spring.io to generate a basic project or follow one of the "Getting Started" guides,
such as Getting Started Building a RESTful Web Service. As well as being easier to digest, these
guides are very task focused, and most of them are based on Spring Boot. They also cover other
projects from the Spring portfolio that you might want to consider when solving a particular
problem.
Chapter 2. Core Technologies
This part of the reference documentation covers all the technologies that are absolutely integral to
the Spring Framework.
Foremost amongst these is the Spring Framework’s Inversion of Control (IoC) container. A thorough
treatment of the Spring Framework’s IoC container is closely followed by comprehensive coverage
of Spring’s Aspect-Oriented Programming (AOP) technologies. The Spring Framework has its own
AOP framework, which is conceptually easy to understand and which successfully addresses the
80% sweet spot of AOP requirements in Java enterprise programming.
Coverage of Spring’s integration with AspectJ (currently the richest — in terms of features — and
certainly most mature AOP implementation in the Java enterprise space) is also provided.
AOT processing can be used to optimize your application ahead-of-time. It is typically used for
native image deployment using GraalVM.
2.1. The IoC Container
This chapter covers Spring’s Inversion of Control (IoC) container.
2.1.1. Introduction to the Spring IoC Container and Beans
This chapter covers the Spring Framework implementation of the Inversion of Control (IoC)
principle. IoC is also known as dependency injection (DI). It is a process whereby objects define
their dependencies (that is, the other objects they work with) only through constructor arguments,
arguments to a factory method, or properties that are set on the object instance after it is
constructed or returned from a factory method. The container then injects those dependencies
when it creates the bean. This process is fundamentally the inverse (hence the name, Inversion of
Control) of the bean itself controlling the instantiation or location of its dependencies by using
direct construction of classes or a mechanism such as the Service Locator pattern.
The org.springframework.beans and org.springframework.context packages are the basis for Spring
Framework’s IoC container. The BeanFactory interface provides an advanced configuration
mechanism capable of managing any type of object. ApplicationContext is a sub-interface of
BeanFactory. It adds:
• Easier integration with Spring’s AOP features
• Message resource handling (for use in internationalization)
• Event publication
• Application-layer specific contexts such as the WebApplicationContext for use in web
applications.
In short, the BeanFactory provides the configuration framework and basic functionality, and the
ApplicationContext adds more enterprise-specific functionality. The ApplicationContext is a
complete superset of the BeanFactory and is used exclusively in this chapter in descriptions of
Spring’s IoC container. For more information on using the BeanFactory instead of the
ApplicationContext, see the section covering the BeanFactory API.
In Spring, the objects that form the backbone of your application and that are managed by the
Spring IoC container are called beans. A bean is an object that is instantiated, assembled, and
managed by a Spring IoC container. Otherwise, a bean is simply one of many objects in your
application. Beans, and the dependencies among them, are reflected in the configuration metadata
used by a container.
2.1.2. Container Overview
The org.springframework.context.ApplicationContext interface represents the Spring IoC container
and is responsible for instantiating, configuring, and assembling the beans. The container gets its
instructions on what objects to instantiate, configure, and assemble by reading configuration
metadata. The configuration metadata is represented in XML, Java annotations, or Java code. It lets
you express the objects that compose your application and the rich interdependencies between
those objects.
Several implementations of the ApplicationContext interface are supplied with Spring. In stand-
alone applications, it is common to create an instance of ClassPathXmlApplicationContext or
FileSystemXmlApplicationContext. While XML has been the traditional format for defining
configuration metadata, you can instruct the container to use Java annotations or code as the
metadata format by providing a small amount of XML configuration to declaratively enable support
for these additional metadata formats.
In most application scenarios, explicit user code is not required to instantiate one or more
instances of a Spring IoC container. For example, in a web application scenario, a simple eight (or
so) lines of boilerplate web descriptor XML in the web.xml file of the application typically suffices
(see Convenient ApplicationContext Instantiation for Web Applications). If you use the Spring Tools
for Eclipse (an Eclipse-powered development environment), you can easily create this boilerplate
configuration with a few mouse clicks or keystrokes.
The following diagram shows a high-level view of how Spring works. Your application classes are
combined with configuration metadata so that, after the ApplicationContext is created and
initialized, you have a fully configured and executable system or application.
Figure 1. The Spring IoC container
Configuration Metadata
As the preceding diagram shows, the Spring IoC container consumes a form of configuration
metadata. This configuration metadata represents how you, as an application developer, tell the
Spring container to instantiate, configure, and assemble the objects in your application.
Configuration metadata is traditionally supplied in a simple and intuitive XML format, which is
what most of this chapter uses to convey key concepts and features of the Spring IoC container.
XML-based metadata is not the only allowed form of configuration metadata. The
Spring IoC container itself is totally decoupled from the format in which this
configuration metadata is actually written. These days, many developers choose
Java-based configuration for their Spring applications.
For information about using other forms of metadata with the Spring container, see:
• Annotation-based configuration: Spring 2.5 introduced support for annotation-based
configuration metadata.
• Java-based configuration: Starting with Spring 3.0, many features provided by the Spring
JavaConfig project became part of the core Spring Framework. Thus, you can define beans
external to your application classes by using Java rather than XML files. To use these new
features, see the @Configuration, @Bean, @Import, and @DependsOn annotations.
Spring configuration consists of at least one and typically more than one bean definition that the
container must manage. XML-based configuration metadata configures these beans as
elements inside a top-level element. Java configuration typically uses @Bean-annotated
methods within a @Configuration class.
These bean definitions correspond to the actual objects that make up your application. Typically,
you define service layer objects, data access objects (DAOs), presentation objects such as Struts
Action instances, infrastructure objects such as Hibernate SessionFactories, JMS Queues, and so
forth. Typically, one does not configure fine-grained domain objects in the container, because it is
usually the responsibility of DAOs and business logic to create and load domain objects. However,
you can use Spring’s integration with AspectJ to configure objects that have been created outside
the control of an IoC container. See Using AspectJ to dependency-inject domain objects with Spring.
The following example shows the basic structure of XML-based configuration metadata:
<?xml version="1.0" encoding="UTF-8"?>
① ②
① The id attribute is a string that identifies the individual bean definition.
② The class attribute defines the type of the bean and uses the fully qualified classname.
The value of the id attribute refers to collaborating objects. The XML for referring to collaborating
objects is not shown in this example. See Dependencies for more information.
Instantiating a Container
The location path or paths supplied to an ApplicationContext constructor are resource strings that
let the container load configuration metadata from a variety of external resources, such as the local
file system, the Java CLASSPATH, and so on.
Java
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml",
"daos.xml");
Kotlin
val context = ClassPathXmlApplicationContext("services.xml", "daos.xml")
After you learn about Spring’s IoC container, you may want to know more about
Spring’s Resource abstraction (as described in Resources), which provides a
convenient mechanism for reading an InputStream from locations defined in a
URI syntax. In particular, Resource paths are used to construct applications
contexts, as described in Application Contexts and Resource Paths.
The following example shows the service layer objects (services.xml) configuration file:
<?xml version="1.0" encoding="UTF-8"?>
The following example shows the data access objects daos.xml file:
<?xml version="1.0" encoding="UTF-8"?>
In the preceding example, the service layer consists of the PetStoreServiceImpl class and two data
access objects of the types JpaAccountDao and JpaItemDao (based on the JPA Object-Relational
Mapping standard). The property name element refers to the name of the JavaBean property, and the
ref element refers to the name of another bean definition. This linkage between id and ref
elements expresses the dependency between collaborating objects. For details of configuring an
object’s dependencies, see Dependencies.
Composing XML-based Configuration Metadata
It can be useful to have bean definitions span multiple XML files. Often, each individual XML
configuration file represents a logical layer or module in your architecture.
You can use the application context constructor to load bean definitions from all these XML
fragments. This constructor takes multiple Resource locations, as was shown in the previous section.
Alternatively, use one or more occurrences of the element to load bean definitions from
another file or files. The following example shows how to do so:
In the preceding example, external bean definitions are loaded from three files: services.xml,
messageSource.xml, and themeSource.xml. All location paths are relative to the definition file doing
the importing, so services.xml must be in the same directory or classpath location as the file doing
the importing, while messageSource.xml and themeSource.xml must be in a resources location below
the location of the importing file. As you can see, a leading slash is ignored. However, given that
these paths are relative, it is better form not to use the slash at all. The contents of the files being
imported, including the top level element, must be valid XML bean definitions, according
to the Spring Schema.
It is possible, but not recommended, to reference files in parent directories using a
relative "../" path. Doing so creates a dependency on a file that is outside the
current application. In particular, this reference is not recommended for
classpath: URLs (for example, classpath:../services.xml), where the runtime
resolution process chooses the “nearest” classpath root and then looks into its
parent directory. Classpath configuration changes may lead to the choice of a
different, incorrect directory.
You can always use fully qualified resource locations instead of relative paths: for
example, file:C:/config/services.xml or classpath:/config/services.xml.
However, be aware that you are coupling your application’s configuration to
specific absolute locations. It is generally preferable to keep an indirection for such
absolute locations — for example, through "${…}" placeholders that are resolved
against JVM system properties at runtime.
The namespace itself provides the import directive feature. Further configuration features beyond
plain bean definitions are available in a selection of XML namespaces provided by Spring — for
example, the context and util namespaces.
The Groovy Bean Definition DSL
As a further example for externalized configuration metadata, bean definitions can also be
expressed in Spring’s Groovy Bean Definition DSL, as known from the Grails framework. Typically,
such configuration live in a ".groovy" file with the structure shown in the following example:
beans {
dataSource(BasicDataSource) {
driverClassName = "org.hsqldb.jdbcDriver"
url = "jdbc:hsqldb:mem:grailsDB"
username = "sa"
password = ""
settings = [mynew:"setting"]
}
sessionFactory(SessionFactory) {
dataSource = dataSource
}
myService(MyService) {
nestedBean = { AnotherBean bean ->
dataSource = dataSource
}
}
}
This configuration style is largely equivalent to XML bean definitions and even supports Spring’s
XML configuration namespaces. It also allows for importing XML bean definition files through an
importBeans directive.
Using the Container
The ApplicationContext is the interface for an advanced factory capable of maintaining a registry of
different beans and their dependencies. By using the method T getBean(String name, Class<T>
requiredType), you can retrieve instances of your beans.
The ApplicationContext lets you read bean definitions and access them, as the following example
shows:
Java
// create and configure beans
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml",
"daos.xml");
// retrieve configured instance
PetStoreService service = context.getBean("petStore", PetStoreService.class);
// use configured instance
List<String> userList = service.getUsernameList();
Kotlin
import org.springframework.beans.factory.getBean
// create and configure beans
val context = ClassPathXmlApplicationContext("services.xml", "daos.xml")
// retrieve configured instance
val service = context.getBean("petStore")
// use configured instance
var userList = service.getUsernameList()
With Groovy configuration, bootstrapping looks very similar. It has a different context
implementation class which is Groovy-aware (but also understands XML bean definitions). The
following example shows Groovy configuration:
Java
ApplicationContext context = new GenericGroovyApplicationContext("services.groovy",
"daos.groovy");
Kotlin
val context = GenericGroovyApplicationContext("services.groovy", "daos.groovy")
The most flexible variant is GenericApplicationContext in combination with reader delegates — for
example, with XmlBeanDefinitionReader for XML files, as the following example shows:
Java
GenericApplicationContext context = new GenericApplicationContext();
new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml");
context.refresh();
Kotlin
val context = GenericApplicationContext()
XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml")
context.refresh()
You can also use the GroovyBeanDefinitionReader for Groovy files, as the following example shows:
Java
GenericApplicationContext context = new GenericApplicationContext();
new GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy",
"daos.groovy");
context.refresh();
Kotlin
val context = GenericApplicationContext()
GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy",
"daos.groovy")
context.refresh()
You can mix and match such reader delegates on the same ApplicationContext, reading bean
definitions from diverse configuration sources.
You can then use getBean to retrieve instances of your beans. The ApplicationContext interface has a
few other methods for retrieving beans, but, ideally, your application code should never use them.
Indeed, your application code should have no calls to the getBean() method at all and thus have no
dependency on Spring APIs at all. For example, Spring’s integration with web frameworks provides
dependency injection for various web framework components such as controllers and JSF-managed
beans, letting you declare a dependency on a specific bean through metadata (such as an
autowiring annotation).
2.1.3. Bean Overview
A Spring IoC container manages one or more beans. These beans are created with the configuration
metadata that you supply to the container (for example, in the form of XML definitions).
Within the container itself, these bean definitions are represented as BeanDefinition objects, which
contain (among other information) the following metadata:
• A package-qualified class name: typically, the actual implementation class of the bean being
defined.
• Bean behavioral configuration elements, which state how the bean should behave in the
container (scope, lifecycle callbacks, and so forth).
• References to other beans that are needed for the bean to do its work. These references are also
called collaborators or dependencies.
• Other configuration settings to set in the newly created object — for example, the size limit of
the pool or the number of connections to use in a bean that manages a connection pool.
This metadata translates to a set of properties that make up each bean definition. The following
table describes these properties:
Table 1. The bean definition
Property Explained in…
Class Instantiating Beans
Name Naming Beans
Scope Bean Scopes
Constructor arguments Dependency Injection
Properties Dependency Injection
Autowiring mode Autowiring Collaborators
Lazy initialization mode Lazy-initialized Beans
Initialization method Initialization Callbacks
Destruction method Destruction Callbacks
In addition to bean definitions that contain information on how to create a specific bean, the
ApplicationContext implementations also permit the registration of existing objects that are created
outside the container (by users). This is done by accessing the ApplicationContext’s BeanFactory
through the getBeanFactory() method, which returns the DefaultListableBeanFactory
implementation. DefaultListableBeanFactory supports this registration through the
registerSingleton(..) and registerBeanDefinition(..) methods. However, typical applications
work solely with beans defined through regular bean definition metadata.
Bean metadata and manually supplied singleton instances need to be registered as
early as possible, in order for the container to properly reason about them during
autowiring and other introspection steps. While overriding existing metadata and
existing singleton instances is supported to some degree, the registration of new
beans at runtime (concurrently with live access to the factory) is not officially
supported and may lead to concurrent access exceptions, inconsistent state in the
bean container, or both.
Naming Beans
Every bean has one or more identifiers. These identifiers must be unique within the container that
hosts the bean. A bean usually has only one identifier. However, if it requires more than one, the
extra ones can be considered aliases.
In XML-based configuration metadata, you use the id attribute, the name attribute, or both to specify
the bean identifiers. The id attribute lets you specify exactly one id. Conventionally, these names
are alphanumeric ('myBean', 'someService', etc.), but they can contain special characters as well. If
you want to introduce other aliases for the bean, you can also specify them in the name attribute,
separated by a comma (,), semicolon (;), or white space. As a historical note, in versions prior to
Spring 3.1, the id attribute was defined as an xsd:ID type, which constrained possible characters. As
of 3.1, it is defined as an xsd:string type. Note that bean id uniqueness is still enforced by the
container, though no longer by XML parsers.
You are not required to supply a name or an id for a bean. If you do not supply a name or id explicitly,
the container generates a unique name for that bean. However, if you want to refer to that bean by
name, through the use of the ref element or a Service Locator style lookup, you must provide a
name. Motivations for not supplying a name are related to using inner beans and autowiring
collaborators.
Bean Naming Conventions
The convention is to use the standard Java convention for instance field names when naming
beans. That is, bean names start with a lowercase letter and are camel-cased from there.
Examples of such names include accountManager, accountService, userDao, loginController, and
so forth.
Naming beans consistently makes your configuration easier to read and understand. Also, if
you use Spring AOP, it helps a lot when applying advice to a set of beans related by name.
With component scanning in the classpath, Spring generates bean names for
unnamed components, following the rules described earlier: essentially, taking the
simple class name and turning its initial character to lower-case. However, in the
(unusual) special case when there is more than one character and both the first
and second characters are upper case, the original casing gets preserved. These are
the same rules as defined by java.beans.Introspector.decapitalize (which Spring
uses here).
Aliasing a Bean outside the Bean Definition
In a bean definition itself, you can supply more than one name for the bean, by using a
combination of up to one name specified by the id attribute and any number of other names in the
name attribute. These names can be equivalent aliases to the same bean and are useful for some
situations, such as letting each component in an application refer to a common dependency by
using a bean name that is specific to that component itself.
Specifying all aliases where the bean is actually defined is not always adequate, however. It is
sometimes desirable to introduce an alias for a bean that is defined elsewhere. This is commonly
the case in large systems where configuration is split amongst each subsystem, with each
subsystem having its own set of object definitions. In XML-based configuration metadata, you can
use the <alias/> element to accomplish this. The following example shows how to do so:
<alias name="fromName" alias="toName"/>
In this case, a bean (in the same container) named fromName may also, after the use of this alias
definition, be referred to as toName.
For example, the configuration metadata for subsystem A may refer to a DataSource by the name of
subsystemA-dataSource. The configuration metadata for subsystem B may refer to a DataSource by
the name of subsystemB-dataSource. When composing the main application that uses both these
subsystems, the main application refers to the DataSource by the name of myApp-dataSource. To have
all three names refer to the same object, you can add the following alias definitions to the
configuration metadata:
<alias name="myApp-dataSource" alias="subsystemA-dataSource"/>
<alias name="myApp-dataSource" alias="subsystemB-dataSource"/>
Now each component and the main application can refer to the dataSource through a name that is
unique and guaranteed not to clash with any other definition (effectively creating a namespace),
yet they refer to the same bean.
Java-configuration
If you use Javaconfiguration, the @Bean annotation can be used to provide aliases. See Using
the @Bean Annotation for details.
Instantiating Beans
A bean definition is essentially a recipe for creating one or more objects. The container looks at the
recipe for a named bean when asked and uses the configuration metadata encapsulated by that
bean definition to create (or acquire) an actual object.
If you use XML-based configuration metadata, you specify the type (or class) of object that is to be
instantiated in the class attribute of the element. This class attribute (which, internally, is a
Class property on a BeanDefinition instance) is usually mandatory. (For exceptions, see
Instantiation by Using an Instance Factory Method and Bean Definition Inheritance.) You can use
the Class property in one of two ways:
• Typically, to specify the bean class to be constructed in the case where the container itself
directly creates the bean by calling its constructor reflectively, somewhat equivalent to Java
code with the new operator.
• To specify the actual class containing the static factory method that is invoked to create the
object, in the less common case where the container invokes a static factory method on a class
to create the bean. The object type returned from the invocation of the static factory method
may be the same class or another class entirely.
Nested class names
If you want to configure a bean definition for a nested class, you may use either the binary
name or the source name of the nested class.
For example, if you have a class called SomeThing in the com.example package, and this
SomeThing class has a static nested class called OtherThing, they can be separated by a dollar
sign ($) or a dot (.). So the value of the class attribute in a bean definition would be
com.example.SomeThing$OtherThing or com.example.SomeThing.OtherThing.
Instantiation with a Constructor
When you create a bean by the constructor approach, all normal classes are usable by and
compatible with Spring. That is, the class being developed does not need to implement any specific
interfaces or to be coded in a specific fashion. Simply specifying the bean class should suffice.
However, depending on what type of IoC you use for that specific bean, you may need a default
(empty) constructor.
The Spring IoC container can manage virtually any class you want it to manage. It is not limited to
managing true JavaBeans. Most Spring users prefer actual JavaBeans with only a default (no-
argument) constructor and appropriate setters and getters modeled after the properties in the
container. You can also have more exotic non-bean-style classes in your container. If, for example,
you need to use a legacy connection pool that absolutely does not adhere to the JavaBean
specification, Spring can manage it as well.
With XML-based configuration metadata you can specify your bean class as follows:
For details about the mechanism for supplying arguments to the constructor (if required) and
setting object instance properties after the object is constructed, see Injecting Dependencies.
Instantiation with a Static Factory Method
When defining a bean that you create with a static factory method, use the class attribute to specify
the class that contains the static factory method and an attribute named factory-method to specify
the name of the factory method itself. You should be able to call this method (with optional
arguments, as described later) and return a live object, which subsequently is treated as if it had
been created through a constructor. One use for such a bean definition is to call static factories in
legacy code.
The following bean definition specifies that the bean will be created by calling a factory method.
The definition does not specify the type (class) of the returned object, but rather the class
containing the factory method. In this example, the createInstance() method must be a static
method. The following example shows how to specify a factory method:
The following example shows a class that would work with the preceding bean definition:
Java
public class ClientService {
private static ClientService clientService = new ClientService();
private ClientService() {}
public static ClientService createInstance() {
return clientService;
}
}
Kotlin
class ClientService private constructor() {
companion object {
private val clientService = ClientService()
@JvmStatic
fun createInstance() = clientService
}
}
For details about the mechanism for supplying (optional) arguments to the factory method and
setting object instance properties after the object is returned from the factory, see Dependencies
and Configuration in Detail.
Instantiation by Using an Instance Factory Method
Similar to instantiation through a static factory method, instantiation with an instance factory
method invokes a non-static method of an existing bean from the container to create a new bean.
To use this mechanism, leave the class attribute empty and, in the factory-bean attribute, specify
the name of a bean in the current (or parent or ancestor) container that contains the instance
method that is to be invoked to create the object. Set the name of the factory method itself with the
factory-method attribute. The following example shows how to configure such a bean:
The following example shows the corresponding class:
Java
public class DefaultServiceLocator {
private static ClientService clientService = new ClientServiceImpl();
public ClientService createClientServiceInstance() {
return clientService;
}
}
Kotlin
class DefaultServiceLocator {
companion object {
private val clientService = ClientServiceImpl()
}
fun createClientServiceInstance(): ClientService {
return clientService
}
}
One factory class can also hold more than one factory method, as the following example shows:
The following example shows the corresponding class:
Java
public class DefaultServiceLocator {
private static ClientService clientService = new ClientServiceImpl();
private static AccountService accountService = new AccountServiceImpl();
public ClientService createClientServiceInstance() {
return clientService;
}
public AccountService createAccountServiceInstance() {
return accountService;
}
}
Kotlin
class DefaultServiceLocator {
companion object {
private val clientService = ClientServiceImpl()
private val accountService = AccountServiceImpl()
}
fun createClientServiceInstance(): ClientService {
return clientService
}
fun createAccountServiceInstance(): AccountService {
return accountService
}
}
This approach shows that the factory bean itself can be managed and configured through
dependency injection (DI). See Dependencies and Configuration in Detail.
In Spring documentation, "factory bean" refers to a bean that is configured in the
Spring container and that creates objects through an instance or static factory
method. By contrast, FactoryBean (notice the capitalization) refers to a Spring-
specific FactoryBean implementation class.
Determining a Bean’s Runtime Type
The runtime type of a specific bean is non-trivial to determine. A specified class in the bean
metadata definition is just an initial class reference, potentially combined with a declared factory
method or being a FactoryBean class which may lead to a different runtime type of the bean, or not
being set at all in case of an instance-level factory method (which is resolved via the specified
factory-bean name instead). Additionally, AOP proxying may wrap a bean instance with an
interface-based proxy with limited exposure of the target bean’s actual type (just its implemented
interfaces).
The recommended way to find out about the actual runtime type of a particular bean is a
BeanFactory.getType call for the specified bean name. This takes all of the above cases into account
and returns the type of object that a BeanFactory.getBean call is going to return for the same bean
name.
2.1.4. Dependencies
A typical enterprise application does not consist of a single object (or bean in the Spring parlance).
Even the simplest application has a few objects that work together to present what the end-user
sees as a coherent application. This next section explains how you go from defining a number of
bean definitions that stand alone to a fully realized application where objects collaborate to achieve
a goal.
Dependency Injection
Dependency injection (DI) is a process whereby objects define their dependencies (that is, the other
objects with which they work) only through constructor arguments, arguments to a factory method,
or properties that are set on the object instance after it is constructed or returned from a factory
method. The container then injects those dependencies when it creates the bean. This process is
fundamentally the inverse (hence the name, Inversion of Control) of the bean itself controlling the
instantiation or location of its dependencies on its own by using direct construction of classes or the
Service Locator pattern.
Code is cleaner with the DI principle, and decoupling is more effective when objects are provided
with their dependencies. The object does not look up its dependencies and does not know the
location or class of the dependencies. As a result, your classes become easier to test, particularly
when the dependencies are on interfaces or abstract base classes, which allow for stub or mock
implementations to be used in unit tests.
DI exists in two major variants: Constructor-based dependency injection and Setter-based
dependency injection.
Constructor-based Dependency Injection
Constructor-based DI is accomplished by the container invoking a constructor with a number of
arguments, each representing a dependency. Calling a static factory method with specific
arguments to construct the bean is nearly equivalent, and this discussion treats arguments to a
constructor and to a static factory method similarly. The following example shows a class that can
only be dependency-injected with constructor injection:
Java
public class SimpleMovieLister {
// the SimpleMovieLister has a dependency on a MovieFinder
private final MovieFinder movieFinder;
// a constructor so that the Spring container can inject a MovieFinder
public SimpleMovieLister(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// business logic that actually uses the injected MovieFinder is omitted...
}
Kotlin
// a constructor so that the Spring container can inject a MovieFinder
class SimpleMovieLister(private val movieFinder: MovieFinder) {
// business logic that actually uses the injected MovieFinder is omitted...
}
Notice that there is nothing special about this class. It is a POJO that has no dependencies on
container specific interfaces, base classes, or annotations.
Constructor Argument Resolution
Constructor argument resolution matching occurs by using the argument’s type. If no potential
ambiguity exists in the constructor arguments of a bean definition, the order in which the
constructor arguments are defined in a bean definition is the order in which those arguments are
supplied to the appropriate constructor when the bean is being instantiated. Consider the following
class:
Java
package x.y;
public class ThingOne {
public ThingOne(ThingTwo thingTwo, ThingThree thingThree) {
// ...
}
}
Kotlin
package x.y
class ThingOne(thingTwo: ThingTwo, thingThree: ThingThree)
Assuming that the ThingTwo and ThingThree classes are not related by inheritance, no potential
ambiguity exists. Thus, the following configuration works fine, and you do not need to specify the
constructor argument indexes or types explicitly in the <constructor-arg/> element.
<constructor-arg ref="beanTwo"/>
<constructor-arg ref="beanThree"/>
When another bean is referenced, the type is known, and matching can occur (as was the case with
the preceding example). When a simple type is used, such as <value>true</value>, Spring cannot
determine the type of the value, and so cannot match by type without help. Consider the following
class:
Java
package examples;
public class ExampleBean {
// Number of years to calculate the Ultimate Answer
private final int years;
// The Answer to Life, the Universe, and Everything
private final String ultimateAnswer;
public ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
}
}
Kotlin
package examples
class ExampleBean(
private val years: Int, // Number of years to calculate the Ultimate Answer
private val ultimateAnswer: String // The Answer to Life, the Universe, and
Everything
)
Constructor argument type matching
In the preceding scenario, the container can use type matching with simple types if you explicitly
specify the type of the constructor argument by using the type attribute, as the following example
shows:
<constructor-arg type="int" value="7500000"/>
<constructor-arg type="java.lang.String" value="42"/>
Constructor argument index
You can use the index attribute to specify explicitly the index of constructor arguments, as the
following example shows:
<constructor-arg index="0" value="7500000"/>
<constructor-arg index="1" value="42"/>
In addition to resolving the ambiguity of multiple simple values, specifying an index resolves
ambiguity where a constructor has two arguments of the same type.
The index is 0-based.
Constructor argument name
You can also use the constructor parameter name for value disambiguation, as the following
example shows:
<constructor-arg name="years" value="7500000"/>
<constructor-arg name="ultimateAnswer" value="42"/>
Keep in mind that, to make this work out of the box, your code must be compiled with the debug
flag enabled so that Spring can look up the parameter name from the constructor. If you cannot or
do not want to compile your code with the debug flag, you can use the @ConstructorProperties JDK
annotation to explicitly name your constructor arguments. The sample class would then have to
look as follows:
Java
package examples;
public class ExampleBean {
// Fields omitted
@ConstructorProperties({"years", "ultimateAnswer"})
public ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
}
}
Kotlin
package examples
class ExampleBean
@ConstructorProperties("years", "ultimateAnswer")
constructor(val years: Int, val ultimateAnswer: String)
Setter-based Dependency Injection
Setter-based DI is accomplished by the container calling setter methods on your beans after
invoking a no-argument constructor or a no-argument static factory method to instantiate your
bean.
The following example shows a class that can only be dependency-injected by using pure setter
injection. This class is conventional Java. It is a POJO that has no dependencies on container specific
interfaces, base classes, or annotations.
Java
public class SimpleMovieLister {
// the SimpleMovieLister has a dependency on the MovieFinder
private MovieFinder movieFinder;
// a setter method so that the Spring container can inject a MovieFinder
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// business logic that actually uses the injected MovieFinder is omitted...
}
Kotlin
class SimpleMovieLister {
// a late-initialized property so that the Spring container can inject a
MovieFinder
lateinit var movieFinder: MovieFinder
// business logic that actually uses the injected MovieFinder is omitted...
}
The ApplicationContext supports constructor-based and setter-based DI for the beans it manages. It
also supports setter-based DI after some dependencies have already been injected through the
constructor approach. You configure the dependencies in the form of a BeanDefinition, which you
use in conjunction with PropertyEditor instances to convert properties from one format to another.
However, most Spring users do not work with these classes directly (that is, programmatically) but
rather with XML bean definitions, annotated components (that is, classes annotated with @Component,
@Controller, and so forth), or @Bean methods in Java-based @Configuration classes. These sources are
then converted internally into instances of BeanDefinition and used to load an entire Spring IoC
container instance.
Constructor-based or setter-based DI?
Since you can mix constructor-based and setter-based DI, it is a good rule of thumb to use
constructors for mandatory dependencies and setter methods or configuration methods for
optional dependencies. Note that use of the @Autowired annotation on a setter method can
be used to make the property be a required dependency; however, constructor injection with
programmatic validation of arguments is preferable.
The Spring team generally advocates constructor injection, as it lets you implement
application components as immutable objects and ensures that required dependencies are
not null. Furthermore, constructor-injected components are always returned to the client
(calling) code in a fully initialized state. As a side note, a large number of constructor
arguments is a bad code smell, implying that the class likely has too many responsibilities and
should be refactored to better address proper separation of concerns.
Setter injection should primarily only be used for optional dependencies that can be assigned
reasonable default values within the class. Otherwise, not-null checks must be performed
everywhere the code uses the dependency. One benefit of setter injection is that setter
methods make objects of that class amenable to reconfiguration or re-injection later.
Management through JMX MBeans is therefore a compelling use case for setter injection.
Use the DI style that makes the most sense for a particular class. Sometimes, when dealing
with third-party classes for which you do not have the source, the choice is made for you. For
example, if a third-party class does not expose any setter methods, then constructor injection
may be the only available form of DI.
Dependency Resolution Process
The container performs bean dependency resolution as follows:
• The ApplicationContext is created and initialized with configuration metadata that describes all
the beans. Configuration metadata can be specified by XML, Java code, or annotations.
• For each bean, its dependencies are expressed in the form of properties, constructor arguments,
or arguments to the static-factory method (if you use that instead of a normal constructor).
These dependencies are provided to the bean, when the bean is actually created.
• Each property or constructor argument is an actual definition of the value to set, or a reference
to another bean in the container.
• Each property or constructor argument that is a value is converted from its specified format to
the actual type of that property or constructor argument. By default, Spring can convert a value
supplied in string format to all built-in types, such as int, long, String, boolean, and so forth.
The Spring container validates the configuration of each bean as the container is created. However,
the bean properties themselves are not set until the bean is actually created. Beans that are
singleton-scoped and set to be pre-instantiated (the default) are created when the container is
created. Scopes are defined in Bean Scopes. Otherwise, the bean is created only when it is
requested. Creation of a bean potentially causes a graph of beans to be created, as the bean’s
dependencies and its dependencies' dependencies (and so on) are created and assigned. Note that
resolution mismatches among those dependencies may show up late — that is, on first creation of
the affected bean.
Circular dependencies
If you use predominantly constructor injection, it is possible to create an unresolvable
circular dependency scenario.
For example: Class A requires an instance of class B through constructor injection, and class B
requires an instance of class A through constructor injection. If you configure beans for
classes A and B to be injected into each other, the Spring IoC container detects this circular
reference at runtime, and throws a BeanCurrentlyInCreationException.
One possible solution is to edit the source code of some classes to be configured by setters
rather than constructors. Alternatively, avoid constructor injection and use setter injection
only. In other words, although it is not recommended, you can configure circular
dependencies with setter injection.
Unlike the typical case (with no circular dependencies), a circular dependency between bean
A and bean B forces one of the beans to be injected into the other prior to being fully
initialized itself (a classic chicken-and-egg scenario).
You can generally trust Spring to do the right thing. It detects configuration problems, such as
references to non-existent beans and circular dependencies, at container load-time. Spring sets
properties and resolves dependencies as late as possible, when the bean is actually created. This
means that a Spring container that has loaded correctly can later generate an exception when you
request an object if there is a problem creating that object or one of its dependencies — for
example, the bean throws an exception as a result of a missing or invalid property. This potentially
delayed visibility of some configuration issues is why ApplicationContext implementations by
default pre-instantiate singleton beans. At the cost of some upfront time and memory to create
these beans before they are actually needed, you discover configuration issues when the
ApplicationContext is created, not later. You can still override this default behavior so that singleton
beans initialize lazily, rather than being eagerly pre-instantiated.
If no circular dependencies exist, when one or more collaborating beans are being injected into a
dependent bean, each collaborating bean is totally configured prior to being injected into the
dependent bean. This means that, if bean A has a dependency on bean B, the Spring IoC container
completely configures bean B prior to invoking the setter method on bean A. In other words, the
bean is instantiated (if it is not a pre-instantiated singleton), its dependencies are set, and the
relevant lifecycle methods (such as a configured init method or the InitializingBean callback
method) are invoked.
Examples of Dependency Injection
The following example uses XML-based configuration metadata for setter-based DI. A small part of
a Spring XML configuration file specifies some bean definitions as follows:
<ref bean="anotherExampleBean"/>
The following example shows the corresponding ExampleBean class:
Java
public class ExampleBean {
private AnotherBean beanOne;
private YetAnotherBean beanTwo;
private int i;
public void setBeanOne(AnotherBean beanOne) {
this.beanOne = beanOne;
}
public void setBeanTwo(YetAnotherBean beanTwo) {
this.beanTwo = beanTwo;
}
public void setIntegerProperty(int i) {
this.i = i;
}
}
Kotlin
class ExampleBean {
lateinit var beanOne: AnotherBean
lateinit var beanTwo: YetAnotherBean
var i: Int = 0
}
In the preceding example, setters are declared to match against the properties specified in the XML
file. The following example uses constructor-based DI:
<constructor-arg>
<ref bean="anotherExampleBean"/>
</constructor-arg>
<constructor-arg ref="yetAnotherBean"/>
<constructor-arg type="int" value="1"/>
The following example shows the corresponding ExampleBean class:
Java
public class ExampleBean {
private AnotherBean beanOne;
private YetAnotherBean beanTwo;
private int i;
public ExampleBean(
AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
this.beanOne = anotherBean;
this.beanTwo = yetAnotherBean;
this.i = i;
}
}
Kotlin
class ExampleBean(
private val beanOne: AnotherBean,
private val beanTwo: YetAnotherBean,
private val i: Int)
The constructor arguments specified in the bean definition are used as arguments to the
constructor of the ExampleBean.
Now consider a variant of this example, where, instead of using a constructor, Spring is told to call
a static factory method to return an instance of the object:
<constructor-arg ref="anotherExampleBean"/>
<constructor-arg ref="yetAnotherBean"/>
<constructor-arg value="1"/>
The following example shows the corresponding ExampleBean class:
Java
public class ExampleBean {
// a private constructor
private ExampleBean(...) {
...
}
// a static factory method; the arguments to this method can be
// considered the dependencies of the bean that is returned,
// regardless of how those arguments are actually used.
public static ExampleBean createInstance (
AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
ExampleBean eb = new ExampleBean (...);
// some other operations...
return eb;
}
}
Kotlin
class ExampleBean private constructor() {
companion object {
// a static factory method; the arguments to this method can be
// considered the dependencies of the bean that is returned,
// regardless of how those arguments are actually used.
@JvmStatic
fun createInstance(anotherBean: AnotherBean, yetAnotherBean: YetAnotherBean,
i: Int): ExampleBean {
val eb = ExampleBean (...)
// some other operations...
return eb
}
}
}
Arguments to the static factory method are supplied by <constructor-arg/> elements, exactly the
same as if a constructor had actually been used. The type of the class being returned by the factory
method does not have to be of the same type as the class that contains the static factory method
(although, in this example, it is). An instance (non-static) factory method can be used in an
essentially identical fashion (aside from the use of the factory-bean attribute instead of the class
attribute), so we do not discuss those details here.
Dependencies and Configuration in Detail
As mentioned in the previous section, you can define bean properties and constructor arguments as
references to other managed beans (collaborators) or as values defined inline. Spring’s XML-based
configuration metadata supports sub-element types within its and <constructor-arg/>
elements for this purpose.
Straight Values (Primitives, Strings, and so on)
The value attribute of the element specifies a property or constructor argument as a
human-readable string representation. Spring’s conversion service is used to convert these values
from a String to the actual type of the property or argument. The following example shows various
values being set:
The following example uses the p-namespace for even more succinct XML configuration:
The preceding XML is more succinct. However, typos are discovered at runtime rather than design
time, unless you use an IDE (such as IntelliJ IDEA or the Spring Tools for Eclipse) that supports
automatic property completion when you create bean definitions. Such IDE assistance is highly
recommended.
You can also configure a java.util.Properties instance, as follows:
<value>
jdbc.driver.className=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mydb
</value>
The Spring container converts the text inside the <value/> element into a java.util.Properties
instance by using the JavaBeans PropertyEditor mechanism. This is a nice shortcut, and is one of a
few places where the Spring team do favor the use of the nested <value/> element over the value
attribute style.
The idref element
The idref element is simply an error-proof way to pass the id (a string value - not a reference) of
another bean in the container to a <constructor-arg/> or element. The following
example shows how to use it:
The preceding bean definition snippet is exactly equivalent (at runtime) to the following snippet:
The first form is preferable to the second, because using the idref tag lets the container validate at
deployment time that the referenced, named bean actually exists. In the second variation, no
validation is performed on the value that is passed to the targetName property of the client bean.
Typos are only discovered (with most likely fatal results) when the client bean is actually
instantiated. If the client bean is a prototype bean, this typo and the resulting exception may only
be discovered long after the container is deployed.
The local attribute on the idref element is no longer supported in the 4.0 beans
XSD, since it does not provide value over a regular bean reference any more.
Change your existing idref local references to idref bean when upgrading to the
4.0 schema.
A common place (at least in versions earlier than Spring 2.0) where the element brings
value is in the configuration of AOP interceptors in a ProxyFactoryBean bean definition. Using
elements when you specify the interceptor names prevents you from misspelling an
interceptor ID.
References to Other Beans (Collaborators)
The ref element is the final element inside a <constructor-arg/> or definition element.
Here, you set the value of the specified property of a bean to be a reference to another bean (a
collaborator) managed by the container. The referenced bean is a dependency of the bean whose
property is to be set, and it is initialized on demand as needed before the property is set. (If the
collaborator is a singleton bean, it may already be initialized by the container.) All references are
ultimately a reference to another object. Scoping and validation depend on whether you specify the
ID or name of the other object through the bean or parent attribute.
Specifying the target bean through the bean attribute of the <ref/> tag is the most general form and
allows creation of a reference to any bean in the same container or parent container, regardless of
whether it is in the same XML file. The value of the bean attribute may be the same as the id
attribute of the target bean or be the same as one of the values in the name attribute of the target
bean. The following example shows how to use a ref element:
<ref bean="someBean"/>
Specifying the target bean through the parent attribute creates a reference to a bean that is in a
parent container of the current container. The value of the parent attribute may be the same as
either the id attribute of the target bean or one of the values in the name attribute of the target bean.
The target bean must be in a parent container of the current one. You should use this bean
reference variant mainly when you have a hierarchy of containers and you want to wrap an
existing bean in a parent container with a proxy that has the same name as the parent bean. The
following pair of listings shows how to use the parent attribute:
<ref parent="accountService"/>
The local attribute on the ref element is no longer supported in the 4.0 beans XSD,
since it does not provide value over a regular bean reference any more. Change
your existing ref local references to ref bean when upgrading to the 4.0 schema.
Inner Beans
A element inside the or <constructor-arg/> elements defines an inner bean, as
the following example shows:
An inner bean definition does not require a defined ID or name. If specified, the container does not
use such a value as an identifier. The container also ignores the scope flag on creation, because
inner beans are always anonymous and are always created with the outer bean. It is not possible to
access inner beans independently or to inject them into collaborating beans other than into the
enclosing bean.
As a corner case, it is possible to receive destruction callbacks from a custom scope — for example,
for a request-scoped inner bean contained within a singleton bean. The creation of the inner bean
instance is tied to its containing bean, but destruction callbacks let it participate in the request
scope’s lifecycle. This is not a common scenario. Inner beans typically simply share their containing
bean’s scope.
Collections
The <list/>, <set/>, <map/>, and elements set the properties and arguments of the Java
Collection types List, Set, Map, and Properties, respectively. The following example shows how to
use them:
[email protected]
[email protected]
[email protected]
<list>
<value>a list element followed by a reference</value>
<ref bean="myDataSource" />
</list>
<map>
<entry key="an entry" value="just some string"/>
<entry key="a ref" value-ref="myDataSource"/>
</map>
<set>
<value>just some string</value>
<ref bean="myDataSource" />
</set>
The value of a map key or value, or a set value, can also be any of the following elements:
bean | ref | idref | list | set | map | props | value | null
Collection Merging
The Spring container also supports merging collections. An application developer can define a
parent <list/>, <map/>, <set/> or element and have child <list/>, <map/>, <set/> or
elements inherit and override values from the parent collection. That is, the child collection’s
values are the result of merging the elements of the parent and child collections, with the child’s
collection elements overriding values specified in the parent collection.
This section on merging discusses the parent-child bean mechanism. Readers unfamiliar with
parent and child bean definitions may wish to read the relevant section before continuing.
The following example demonstrates collection merging:
[email protected]
[email protected]
[email protected]
[email protected]
Notice the use of the merge=true attribute on the element of the adminEmails property of the
child bean definition. When the child bean is resolved and instantiated by the container, the
resulting instance has an adminEmails Properties collection that contains the result of merging the
child’s adminEmails collection with the parent’s adminEmails collection. The following listing shows
the result:
[email protected]
[email protected]
[email protected]
The child Properties collection’s value set inherits all property elements from the parent ,
and the child’s value for the support value overrides the value in the parent collection.
This merging behavior applies similarly to the <list/>, <map/>, and <set/> collection types. In the
specific case of the <list/> element, the semantics associated with the List collection type (that is,
the notion of an ordered collection of values) is maintained. The parent’s values precede all of the
child list’s values. In the case of the Map, Set, and Properties collection types, no ordering exists.
Hence, no ordering semantics are in effect for the collection types that underlie the associated Map,
Set, and Properties implementation types that the container uses internally.
Limitations of Collection Merging
You cannot merge different collection types (such as a Map and a List). If you do attempt to do so, an
appropriate Exception is thrown. The merge attribute must be specified on the lower, inherited, child
definition. Specifying the merge attribute on a parent collection definition is redundant and does not
result in the desired merging.
Strongly-typed collection
Thanks to Java’s support for generic types, you can use strongly typed collections. That is, it is
possible to declare a Collection type such that it can only contain (for example) String elements. If
you use Spring to dependency-inject a strongly-typed Collection into a bean, you can take
advantage of Spring’s type-conversion support such that the elements of your strongly-typed
Collection instances are converted to the appropriate type prior to being added to the Collection.
The following Java class and bean definition show how to do so:
Java
public class SomeClass {
private Map<String, Float> accounts;
public void setAccounts(Map<String, Float> accounts) {
this.accounts = accounts;
}
}
Kotlin
class SomeClass {
lateinit var accounts: Map<String, Float>
}
<map>
<entry key="one" value="9.99"/>
<entry key="two" value="2.75"/>
<entry key="six" value="3.99"/>
</map>
When the accounts property of the something bean is prepared for injection, the generics
information about the element type of the strongly-typed Map<String, Float> is available by
reflection. Thus, Spring’s type conversion infrastructure recognizes the various value elements as
being of type Float, and the string values (9.99, 2.75, and 3.99) are converted into an actual Float
type.
Null and Empty String Values
Spring treats empty arguments for properties and the like as empty Strings. The following XML-
based configuration metadata snippet sets the email property to the empty String value ("").
The preceding example is equivalent to the following Java code:
Java
exampleBean.setEmail("");
Kotlin
exampleBean.email = ""
The <null/> element handles null values. The following listing shows an example:
<null/>
The preceding configuration is equivalent to the following Java code:
Java
exampleBean.setEmail(null);
Kotlin
exampleBean.email = null
XML Shortcut with the p-namespace
The p-namespace lets you use the bean element’s attributes (instead of nested elements)
to describe your property values collaborating beans, or both.
Spring supports extensible configuration formats with namespaces, which are based on an XML
Schema definition. The beans configuration format discussed in this chapter is defined in an XML
Schema document. However, the p-namespace is not defined in an XSD file and exists only in the
core of Spring.
The following example shows two XML snippets (the first uses standard XML format and the
second uses the p-namespace) that resolve to the same result:
The example shows an attribute in the p-namespace called email in the bean definition. This tells
Spring to include a property declaration. As previously mentioned, the p-namespace does not have
a schema definition, so you can set the name of the attribute to the property name.
This next example includes two more bean definitions that both have a reference to another bean:
This example includes not only a property value using the p-namespace but also uses a special
format to declare property references. Whereas the first bean definition uses to create a reference from bean john to bean jane, the second bean
definition uses p:spouse-ref="jane" as an attribute to do the exact same thing. In this case, spouse is
the property name, whereas the -ref part indicates that this is not a straight value but rather a
reference to another bean.
The p-namespace is not as flexible as the standard XML format. For example, the
format for declaring property references clashes with properties that end in Ref,
whereas the standard XML format does not. We recommend that you choose your
approach carefully and communicate this to your team members to avoid
producing XML documents that use all three approaches at the same time.
XML Shortcut with the c-namespace
Similar to the XML Shortcut with the p-namespace, the c-namespace, introduced in Spring 3.1,
allows inlined attributes for configuring the constructor arguments rather then nested constructor-
arg elements.
The following example uses the c: namespace to do the same thing as the from Constructor-based
Dependency Injection:
<constructor-arg name="thingTwo" ref="beanTwo"/>
<constructor-arg name="thingThree" ref="beanThree"/>
<constructor-arg name="email" value="[email protected]"/>
The c: namespace uses the same conventions as the p: one (a trailing -ref for bean references) for
setting the constructor arguments by their names. Similarly, it needs to be declared in the XML file
even though it is not defined in an XSD schema (it exists inside the Spring core).
For the rare cases where the constructor argument names are not available (usually if the bytecode
was compiled without debugging information), you can use fallback to the argument indexes, as
follows:
Due to the XML grammar, the index notation requires the presence of the leading
_, as XML attribute names cannot start with a number (even though some IDEs
allow it). A corresponding index notation is also available for <constructor-arg>
elements but not commonly used since the plain order of declaration is usually
sufficient there.
In practice, the constructor resolution mechanism is quite efficient in matching arguments, so
unless you really need to, we recommend using the name notation throughout your configuration.
Compound Property Names
You can use compound or nested property names when you set bean properties, as long as all
components of the path except the final property name are not null. Consider the following bean
definition:
The something bean has a fred property, which has a bob property, which has a sammy property, and
that final sammy property is being set to a value of 123. In order for this to work, the fred property of
something and the bob property of fred must not be null after the bean is constructed. Otherwise, a
NullPointerException is thrown.
Using depends-on
If a bean is a dependency of another bean, that usually means that one bean is set as a property of
another. Typically you accomplish this with the <ref/> element in XML-based configuration
metadata. However, sometimes dependencies between beans are less direct. An example is when a
static initializer in a class needs to be triggered, such as for database driver registration. The
depends-on attribute can explicitly force one or more beans to be initialized before the bean using
this element is initialized. The following example uses the depends-on attribute to express a
dependency on a single bean:
To express a dependency on multiple beans, supply a list of bean names as the value of the depends-
on attribute (commas, whitespace, and semicolons are valid delimiters):
The depends-on attribute can specify both an initialization-time dependency and, in
the case of singleton beans only, a corresponding destruction-time dependency.
Dependent beans that define a depends-on relationship with a given bean are
destroyed first, prior to the given bean itself being destroyed. Thus, depends-on can
also control shutdown order.
Lazy-initialized Beans
By default, ApplicationContext implementations eagerly create and configure all singleton beans as
part of the initialization process. Generally, this pre-instantiation is desirable, because errors in the
configuration or surrounding environment are discovered immediately, as opposed to hours or
even days later. When this behavior is not desirable, you can prevent pre-instantiation of a
singleton bean by marking the bean definition as being lazy-initialized. A lazy-initialized bean tells
the IoC container to create a bean instance when it is first requested, rather than at startup.
In XML, this behavior is controlled by the lazy-init attribute on the element, as the
following example shows:
When the preceding configuration is consumed by an ApplicationContext, the lazy bean is not
eagerly pre-instantiated when the ApplicationContext starts, whereas the not.lazy bean is eagerly
pre-instantiated.
However, when a lazy-initialized bean is a dependency of a singleton bean that is not lazy-
initialized, the ApplicationContext creates the lazy-initialized bean at startup, because it must
satisfy the singleton’s dependencies. The lazy-initialized bean is injected into a singleton bean
elsewhere that is not lazy-initialized.
You can also control lazy-initialization at the container level by using the default-lazy-init
attribute on the element, as the following example shows:
Autowiring Collaborators
The Spring container can autowire relationships between collaborating beans. You can let Spring
resolve collaborators (other beans) automatically for your bean by inspecting the contents of the
ApplicationContext. Autowiring has the following advantages:
• Autowiring can significantly reduce the need to specify properties or constructor arguments.
(Other mechanisms such as a bean template discussed elsewhere in this chapter are also
valuable in this regard.)
• Autowiring can update a configuration as your objects evolve. For example, if you need to add a
dependency to a class, that dependency can be satisfied automatically without you needing to
modify the configuration. Thus autowiring can be especially useful during development,
without negating the option of switching to explicit wiring when the code base becomes more
stable.
When using XML-based configuration metadata (see Dependency Injection), you can specify the
autowire mode for a bean definition with the autowire attribute of the element. The
autowiring functionality has four modes. You specify autowiring per bean and can thus choose
which ones to autowire. The following table describes the four autowiring modes:
Table 2. Autowiring modes
Mode Explanation
no (Default) No autowiring. Bean references must be defined by ref elements.
Changing the default setting is not recommended for larger deployments,
because specifying collaborators explicitly gives greater control and clarity. To
some extent, it documents the structure of a system.
byName Autowiring by property name. Spring looks for a bean with the same name as
the property that needs to be autowired. For example, if a bean definition is
set to autowire by name and it contains a master property (that is, it has a
setMaster(..) method), Spring looks for a bean definition named master and
uses it to set the property.
byType Lets a property be autowired if exactly one bean of the property type exists in
the container. If more than one exists, a fatal exception is thrown, which
indicates that you may not use byType autowiring for that bean. If there are no
matching beans, nothing happens (the property is not set).
constructor Analogous to byType but applies to constructor arguments. If there is not
exactly one bean of the constructor argument type in the container, a fatal
error is raised.
With byType or constructor autowiring mode, you can wire arrays and typed collections. In such
cases, all autowire candidates within the container that match the expected type are provided to
satisfy the dependency. You can autowire strongly-typed Map instances if the expected key type is
String. An autowired Map instance’s values consist of all bean instances that match the expected
type, and the Map instance’s keys contain the corresponding bean names.
Limitations and Disadvantages of Autowiring
Autowiring works best when it is used consistently across a project. If autowiring is not used in
general, it might be confusing to developers to use it to wire only one or two bean definitions.
Consider the limitations and disadvantages of autowiring:
• Explicit dependencies in property and constructor-arg settings always override autowiring. You
cannot autowire simple properties such as primitives, Strings, and Classes (and arrays of such
simple properties). This limitation is by-design.
• Autowiring is less exact than explicit wiring. Although, as noted in the earlier table, Spring is
careful to avoid guessing in case of ambiguity that might have unexpected results. The
relationships between your Spring-managed objects are no longer documented explicitly.
• Wiring information may not be available to tools that may generate documentation from a
Spring container.
• Multiple bean definitions within the container may match the type specified by the setter
method or constructor argument to be autowired. For arrays, collections, or Map instances, this is
not necessarily a problem. However, for dependencies that expect a single value, this ambiguity
is not arbitrarily resolved. If no unique bean definition is available, an exception is thrown.
In the latter scenario, you have several options:
• Abandon autowiring in favor of explicit wiring.
• Avoid autowiring for a bean definition by setting its autowire-candidate attributes to false, as
described in the next section.
• Designate a single bean definition as the primary candidate by setting the primary attribute of its
element to true.
• Implement the more fine-grained control available with annotation-based configuration, as
described in Annotation-based Container Configuration.
Excluding a Bean from Autowiring
On a per-bean basis, you can exclude a bean from autowiring. In Spring’s XML format, set the
autowire-candidate attribute of the element to false. The container makes that specific bean
definition unavailable to the autowiring infrastructure (including annotation style configurations
such as @Autowired).
The autowire-candidate attribute is designed to only affect type-based autowiring.
It does not affect explicit references by name, which get resolved even if the
specified bean is not marked as an autowire candidate. As a consequence,
autowiring by name nevertheless injects a bean if the name matches.
You can also limit autowire candidates based on pattern-matching against bean names. The top-
level element accepts one or more patterns within its default-autowire-candidates
attribute. For example, to limit autowire candidate status to any bean whose name ends with
Repository, provide a value of *Repository. To provide multiple patterns, define them in a comma-
separated list. An explicit value of true or false for a bean definition’s autowire-candidate attribute
always takes precedence. For such beans, the pattern matching rules do not apply.
These techniques are useful for beans that you never want to be injected into other beans by
autowiring. It does not mean that an excluded bean cannot itself be configured by using
autowiring. Rather, the bean itself is not a candidate for autowiring other beans.
Method Injection
In most application scenarios, most beans in the container are singletons. When a singleton bean
needs to collaborate with another singleton bean or a non-singleton bean needs to collaborate with
another non-singleton bean, you typically handle the dependency by defining one bean as a
property of the other. A problem arises when the bean lifecycles are different. Suppose singleton
bean A needs to use non-singleton (prototype) bean B, perhaps on each method invocation on A.
The container creates the singleton bean A only once, and thus only gets one opportunity to set the
properties. The container cannot provide bean A with a new instance of bean B every time one is
needed.
A solution is to forego some inversion of control. You can make bean A aware of the container by
implementing the ApplicationContextAware interface, and by making a getBean("B") call to the
container ask for (a typically new) bean B instance every time bean A needs it. The following
example shows this approach:
Java
// a class that uses a stateful Command-style class to perform some processing
package fiona.apple;
// Spring-API imports
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class CommandManager implements ApplicationContextAware {
private ApplicationContext applicationContext;
public Object process(Map commandState) {
// grab a new instance of the appropriate Command
Command command = createCommand();
// set the state on the (hopefully brand new) Command instance
command.setState(commandState);
return command.execute();
}
protected Command createCommand() {
// notice the Spring API dependency!
return this.applicationContext.getBean("command", Command.class);
}
public void setApplicationContext(
ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
Kotlin
// a class that uses a stateful Command-style class to perform some processing
package fiona.apple
// Spring-API imports
import org.springframework.context.ApplicationContext
import org.springframework.context.ApplicationContextAware
class CommandManager : ApplicationContextAware {
private lateinit var applicationContext: ApplicationContext
fun process(commandState: Map<, >): Any {
// grab a new instance of the appropriate Command
val command = createCommand()
// set the state on the (hopefully brand new) Command instance
command.state = commandState
return command.execute()
}
// notice the Spring API dependency!
protected fun createCommand() =
applicationContext.getBean("command", Command::class.java)
override fun setApplicationContext(applicationContext: ApplicationContext) {
this.applicationContext = applicationContext
}
}
The preceding is not desirable, because the business code is aware of and coupled to the Spring
Framework. Method Injection, a somewhat advanced feature of the Spring IoC container, lets you
handle this use case cleanly.
You can read more about the motivation for Method Injection in this blog entry.
Lookup Method Injection
Lookup method injection is the ability of the container to override methods on container-managed
beans and return the lookup result for another named bean in the container. The lookup typically
involves a prototype bean, as in the scenario described in the preceding section. The Spring
Framework implements this method injection by using bytecode generation from the CGLIB library
to dynamically generate a subclass that overrides the method.
• For this dynamic subclassing to work, the class that the Spring bean container
subclasses cannot be final, and the method to be overridden cannot be final,
either.
• Unit-testing a class that has an abstract method requires you to subclass the
class yourself and to supply a stub implementation of the abstract method.
• Concrete methods are also necessary for component scanning, which requires
concrete classes to pick up.
• A further key limitation is that lookup methods do not work with factory
methods and in particular not with @Bean methods in configuration classes,
since, in that case, the container is not in charge of creating the instance and
therefore cannot create a runtime-generated subclass on the fly.
In the case of the CommandManager class in the previous code snippet, the Spring container
dynamically overrides the implementation of the createCommand() method. The CommandManager class
does not have any Spring dependencies, as the reworked example shows:
Java
package fiona.apple;
// no more Spring imports!
public abstract class CommandManager {
public Object process(Object commandState) {
// grab a new instance of the appropriate Command interface
Command command = createCommand();
// set the state on the (hopefully brand new) Command instance
command.setState(commandState);
return command.execute();
}
// okay... but where is the implementation of this method?
protected abstract Command createCommand();
}
Kotlin
package fiona.apple
// no more Spring imports!
abstract class CommandManager {
fun process(commandState: Any): Any {
// grab a new instance of the appropriate Command interface
val command = createCommand()
// set the state on the (hopefully brand new) Command instance
command.state = commandState
return command.execute()
}
// okay... but where is the implementation of this method?
protected abstract fun createCommand(): Command
}
In the client class that contains the method to be injected (the CommandManager in this case), the
method to be injected requires a signature of the following form:
[abstract] <return-type> theMethodName(no-arguments);
If the method is abstract, the dynamically-generated subclass implements the method. Otherwise,
the dynamically-generated subclass overrides the concrete method defined in the original class.
Consider the following example:
<lookup-method name="createCommand" bean="myCommand"/>
The bean identified as commandManager calls its own createCommand() method whenever it needs a
new instance of the myCommand bean. You must be careful to deploy the myCommand bean as a prototype
if that is actually what is needed. If it is a singleton, the same instance of the myCommand bean is
returned each time.
Alternatively, within the annotation-based component model, you can declare a lookup method
through the @Lookup annotation, as the following example shows:
Java
public abstract class CommandManager {
public Object process(Object commandState) {
Command command = createCommand();
command.setState(commandState);
return command.execute();
}
@Lookup("myCommand")
protected abstract Command createCommand();
}
Kotlin
abstract class CommandManager {
fun process(commandState: Any): Any {
val command = createCommand()
command.state = commandState
return command.execute()
}
@Lookup("myCommand")
protected abstract fun createCommand(): Command
}
Or, more idiomatically, you can rely on the target bean getting resolved against the declared return
type of the lookup method:
Java
public abstract class CommandManager {
public Object process(Object commandState) {
Command command = createCommand();
command.setState(commandState);
return command.execute();
}
@Lookup
protected abstract Command createCommand();
}
Kotlin
abstract class CommandManager {
fun process(commandState: Any): Any {
val command = createCommand()
command.state = commandState
return command.execute()
}
@Lookup
protected abstract fun createCommand(): Command
}
Note that you should typically declare such annotated lookup methods with a concrete stub
implementation, in order for them to be compatible with Spring’s component scanning rules where
abstract classes get ignored by default. This limitation does not apply to explicitly registered or
explicitly imported bean classes.
Another way of accessing differently scoped target beans is an ObjectFactory/
Provider injection point. See Scoped Beans as Dependencies.
You may also find the ServiceLocatorFactoryBean (in the
org.springframework.beans.factory.config package) to be useful.
Arbitrary Method Replacement
A less useful form of method injection than lookup method injection is the ability to replace
arbitrary methods in a managed bean with another method implementation. You can safely skip
the rest of this section until you actually need this functionality.
With XML-based configuration metadata, you can use the replaced-method element to replace an
existing method implementation with another, for a deployed bean. Consider the following class,
which has a method called computeValue that we want to override:
Java
public class MyValueCalculator {
public String computeValue(String input) {
// some real code...
}
// some other methods...
}
Kotlin
class MyValueCalculator {
fun computeValue(input: String): String {
// some real code...
}
// some other methods...
}
A class that implements the org.springframework.beans.factory.support.MethodReplacer interface
provides the new method definition, as the following example shows:
Java
/
* meant to be used to override the existing computeValue(String)
* implementation in MyValueCalculator
*/
public class ReplacementComputeValue implements MethodReplacer {
public Object reimplement(Object o, Method m, Object[] args) throws Throwable {
// get the input value, work with it, and return a computed result
String input = (String) args[0];
...
return ...;
}
}
Kotlin
/
* meant to be used to override the existing computeValue(String)
* implementation in MyValueCalculator
*/
class ReplacementComputeValue : MethodReplacer {
override fun reimplement(obj: Any, method: Method, args: Array<out Any>): Any {
// get the input value, work with it, and return a computed result
val input = args[0] as String;
...
return ...;
}
}
The bean definition to deploy the original class and specify the method override would resemble
the following example:
<replaced-method name="computeValue" replacer="replacementComputeValue">
<arg-type>String</arg-type>
</replaced-method>
You can use one or more <arg-type/> elements within the <replaced-method/> element to indicate
the method signature of the method being overridden. The signature for the arguments is
necessary only if the method is overloaded and multiple variants exist within the class. For
convenience, the type string for an argument may be a substring of the fully qualified type name.
For example, the following all match java.lang.String:
java.lang.String
String
Str
Because the number of arguments is often enough to distinguish between each possible choice, this
shortcut can save a lot of typing, by letting you type only the shortest string that matches an
argument type.
2.1.5. Bean Scopes
When you create a bean definition, you create a recipe for creating actual instances of the class
defined by that bean definition. The idea that a bean definition is a recipe is important, because it
means that, as with a class, you can create many object instances from a single recipe.
You can control not only the various dependencies and configuration values that are to be plugged
into an object that is created from a particular bean definition but also control the scope of the
objects created from a particular bean definition. This approach is powerful and flexible, because
you can choose the scope of the objects you create through configuration instead of having to bake
in the scope of an object at the Java class level. Beans can be defined to be deployed in one of a
number of scopes. The Spring Framework supports six scopes, four of which are available only if
you use a web-aware ApplicationContext. You can also create a custom scope.
The following table describes the supported scopes:
Table 3. Bean scopes
Scope Description
singleton (Default) Scopes a single bean definition to a single object instance for each
Spring IoC container.
prototype Scopes a single bean definition to any number of object instances.
Scope Description
request Scopes a single bean definition to the lifecycle of a single HTTP request. That
is, each HTTP request has its own instance of a bean created off the back of a
single bean definition. Only valid in the context of a web-aware Spring
ApplicationContext.
session Scopes a single bean definition to the lifecycle of an HTTP Session. Only valid
in the context of a web-aware Spring ApplicationContext.
application Scopes a single bean definition to the lifecycle of a ServletContext. Only valid
in the context of a web-aware Spring ApplicationContext.
websocket Scopes a single bean definition to the lifecycle of a WebSocket. Only valid in the
context of a web-aware Spring ApplicationContext.
As of Spring 3.0, a thread scope is available but is not registered by default. For
more information, see the documentation for SimpleThreadScope. For instructions
on how to register this or any other custom scope, see Using a Custom Scope.
The Singleton Scope
Only one shared instance of a singleton bean is managed, and all requests for beans with an ID or
IDs that match that bean definition result in that one specific bean instance being returned by the
Spring container.
To put it another way, when you define a bean definition and it is scoped as a singleton, the Spring
IoC container creates exactly one instance of the object defined by that bean definition. This single
instance is stored in a cache of such singleton beans, and all subsequent requests and references
for that named bean return the cached object. The following image shows how the singleton scope
works:
Spring’s concept of a singleton bean differs from the singleton pattern as defined in the Gang of
Four (GoF) patterns book. The GoF singleton hard-codes the scope of an object such that one and
only one instance of a particular class is created per ClassLoader. The scope of the Spring singleton
is best described as being per-container and per-bean. This means that, if you define one bean for a
particular class in a single Spring container, the Spring container creates one and only one instance
of the class defined by that bean definition. The singleton scope is the default scope in Spring. To
define a bean as a singleton in XML, you can define a bean as shown in the following example:
The Prototype Scope
The non-singleton prototype scope of bean deployment results in the creation of a new bean
instance every time a request for that specific bean is made. That is, the bean is injected into
another bean or you request it through a getBean() method call on the container. As a rule, you
should use the prototype scope for all stateful beans and the singleton scope for stateless beans.
The following diagram illustrates the Spring prototype scope:
(A data access object (DAO) is not typically configured as a prototype, because a typical DAO does
not hold any conversational state. It was easier for us to reuse the core of the singleton diagram.)
The following example defines a bean as a prototype in XML:
In contrast to the other scopes, Spring does not manage the complete lifecycle of a prototype bean.
The container instantiates, configures, and otherwise assembles a prototype object and hands it to
the client, with no further record of that prototype instance. Thus, although initialization lifecycle
callback methods are called on all objects regardless of scope, in the case of prototypes, configured
destruction lifecycle callbacks are not called. The client code must clean up prototype-scoped
objects and release expensive resources that the prototype beans hold. To get the Spring container
to release resources held by prototype-scoped beans, try using a custom bean post-processor, which
holds a reference to beans that need to be cleaned up.
In some respects, the Spring container’s role in regard to a prototype-scoped bean is a replacement
for the Java new operator. All lifecycle management past that point must be handled by the client.
(For details on the lifecycle of a bean in the Spring container, see Lifecycle Callbacks.)
Singleton Beans with Prototype-bean Dependencies
When you use singleton-scoped beans with dependencies on prototype beans, be aware that
dependencies are resolved at instantiation time. Thus, if you dependency-inject a prototype-scoped
bean into a singleton-scoped bean, a new prototype bean is instantiated and then dependency-
injected into the singleton bean. The prototype instance is the sole instance that is ever supplied to
the singleton-scoped bean.
However, suppose you want the singleton-scoped bean to acquire a new instance of the prototype-
scoped bean repeatedly at runtime. You cannot dependency-inject a prototype-scoped bean into
your singleton bean, because that injection occurs only once, when the Spring container
instantiates the singleton bean and resolves and injects its dependencies. If you need a new
instance of a prototype bean at runtime more than once, see Method Injection.
Request, Session, Application, and WebSocket Scopes
The request, session, application, and websocket scopes are available only if you use a web-aware
Spring ApplicationContext implementation (such as XmlWebApplicationContext). If you use these
scopes with regular Spring IoC containers, such as the ClassPathXmlApplicationContext, an
IllegalStateException that complains about an unknown bean scope is thrown.
Initial Web Configuration
To support the scoping of beans at the request, session, application, and websocket levels (web-
scoped beans), some minor initial configuration is required before you define your beans. (This
initial setup is not required for the standard scopes: singleton and prototype.)
How you accomplish this initial setup depends on your particular Servlet environment.
If you access scoped beans within Spring Web MVC, in effect, within a request that is processed by
the Spring DispatcherServlet, no special setup is necessary. DispatcherServlet already exposes all
relevant state.
If you use a Servlet web container, with requests processed outside of Spring’s DispatcherServlet
(for example, when using JSF or Struts), you need to register the
org.springframework.web.context.request.RequestContextListener ServletRequestListener. This can
be done programmatically by using the WebApplicationInitializer interface. Alternatively, add the
following declaration to your web application’s web.xml file:
<web-app>
...
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
...
</web-app>
Alternatively, if there are issues with your listener setup, consider using Spring’s
RequestContextFilter. The filter mapping depends on the surrounding web application
configuration, so you have to change it as appropriate. The following listing shows the filter part of
a web application:
<web-app>
...
<filter>
<filter-name>requestContextFilter</filter-name>
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-
class>
</filter>
<filter-mapping>
<filter-name>requestContextFilter</filter-name>
/*
</filter-mapping>
...
</web-app>
DispatcherServlet, RequestContextListener, and RequestContextFilter all do exactly the same thing,
namely bind the HTTP request object to the Thread that is servicing that request. This makes beans
that are request- and session-scoped available further down the call chain.
Request scope
Consider the following XML configuration for a bean definition:
The Spring container creates a new instance of the LoginAction bean by using the loginAction bean
definition for each and every HTTP request. That is, the loginAction bean is scoped at the HTTP
request level. You can change the internal state of the instance that is created as much as you want,
because other instances created from the same loginAction bean definition do not see these
changes in state. They are particular to an individual request. When the request completes
processing, the bean that is scoped to the request is discarded.
When using annotation-driven components or Java configuration, the @RequestScope annotation can
be used to assign a component to the request scope. The following example shows how to do so:
Java
@RequestScope
@Component
public class LoginAction {
// ...
}
Kotlin
@RequestScope
@Component
class LoginAction {
// ...
}
Session Scope
Consider the following XML configuration for a bean definition:
The Spring container creates a new instance of the UserPreferences bean by using the
userPreferences bean definition for the lifetime of a single HTTP Session. In other words, the
userPreferences bean is effectively scoped at the HTTP Session level. As with request-scoped beans,
you can change the internal state of the instance that is created as much as you want, knowing that
other HTTP Session instances that are also using instances created from the same userPreferences
bean definition do not see these changes in state, because they are particular to an individual HTTP
Session. When the HTTP Session is eventually discarded, the bean that is scoped to that particular
HTTP Session is also discarded.
When using annotation-driven components or Java configuration, you can use the @SessionScope
annotation to assign a component to the session scope.
Java
@SessionScope
@Component
public class UserPreferences {
// ...
}
Kotlin
@SessionScope
@Component
class UserPreferences {
// ...
}
Application Scope
Consider the following XML configuration for a bean definition:
The Spring container creates a new instance of the AppPreferences bean by using the appPreferences
bean definition once for the entire web application. That is, the appPreferences bean is scoped at the
ServletContext level and stored as a regular ServletContext attribute. This is somewhat similar to a
Spring singleton bean but differs in two important ways: It is a singleton per ServletContext, not per
Spring ApplicationContext (for which there may be several in any given web application), and it is
actually exposed and therefore visible as a ServletContext attribute.
When using annotation-driven components or Java configuration, you can use the
@ApplicationScope annotation to assign a component to the application scope. The following
example shows how to do so:
Java
@ApplicationScope
@Component
public class AppPreferences {
// ...
}
Kotlin
@ApplicationScope
@Component
class AppPreferences {
// ...
}
WebSocket Scope
WebSocket scope is associated with the lifecycle of a WebSocket session and applies to STOMP over
WebSocket applications, see WebSocket scope for more details.
Scoped Beans as Dependencies
The Spring IoC container manages not only the instantiation of your objects (beans), but also the
wiring up of collaborators (or dependencies). If you want to inject (for example) an HTTP request-
scoped bean into another bean of a longer-lived scope, you may choose to inject an AOP proxy in
place of the scoped bean. That is, you need to inject a proxy object that exposes the same public
interface as the scoped object but that can also retrieve the real target object from the relevant
scope (such as an HTTP request) and delegate method calls onto the real object.
You may also use <aop:scoped-proxy/> between beans that are scoped as singleton,
with the reference then going through an intermediate proxy that is serializable
and therefore able to re-obtain the target singleton bean on deserialization.
When declaring <aop:scoped-proxy/> against a bean of scope prototype, every
method call on the shared proxy leads to the creation of a new target instance to
which the call is then being forwarded.
Also, scoped proxies are not the only way to access beans from shorter scopes in a
lifecycle-safe fashion. You may also declare your injection point (that is, the
constructor or setter argument or autowired field) as ObjectFactory<MyTargetBean>,
allowing for a getObject() call to retrieve the current instance on demand every
time it is needed — without holding on to the instance or storing it separately.
As an extended variant, you may declare ObjectProvider<MyTargetBean> which
delivers several additional access variants, including getIfAvailable and
getIfUnique.
The JSR-330 variant of this is called Provider and is used with a
Provider<MyTargetBean> declaration and a corresponding get() call for every
retrieval attempt. See here for more details on JSR-330 overall.
The configuration in the following example is only one line, but it is important to understand the
“why” as well as the “how” behind it:
<?xml version="1.0" encoding="UTF-8"?>
<aop:scoped-proxy/> ①
① The line that defines the proxy.
To create such a proxy, you insert a child <aop:scoped-proxy/> element into a scoped bean definition
(see Choosing the Type of Proxy to Create and XML Schema-based configuration). Why do
definitions of beans scoped at the request, session and custom-scope levels require the <aop:scoped-
proxy/> element? Consider the following singleton bean definition and contrast it with what you
need to define for the aforementioned scopes (note that the following userPreferences bean
definition as it stands is incomplete):
In the preceding example, the singleton bean (userManager) is injected with a reference to the HTTP
Session-scoped bean (userPreferences). The salient point here is that the userManager bean is a
singleton: it is instantiated exactly once per container, and its dependencies (in this case only one,
the userPreferences bean) are also injected only once. This means that the userManager bean
operates only on the exact same userPreferences object (that is, the one with which it was originally
injected).
This is not the behavior you want when injecting a shorter-lived scoped bean into a longer-lived
scoped bean (for example, injecting an HTTP Session-scoped collaborating bean as a dependency
into singleton bean). Rather, you need a single userManager object, and, for the lifetime of an HTTP
Session, you need a userPreferences object that is specific to the HTTP Session. Thus, the container
creates an object that exposes the exact same public interface as the UserPreferences class (ideally
an object that is a UserPreferences instance), which can fetch the real UserPreferences object from
the scoping mechanism (HTTP request, Session, and so forth). The container injects this proxy
object into the userManager bean, which is unaware that this UserPreferences reference is a proxy. In
this example, when a UserManager instance invokes a method on the dependency-injected
UserPreferences object, it is actually invoking a method on the proxy. The proxy then fetches the
real UserPreferences object from (in this case) the HTTP Session and delegates the method
invocation onto the retrieved real UserPreferences object.
Thus, you need the following (correct and complete) configuration when injecting request- and
session-scoped beans into collaborating objects, as the following example shows:
<aop:scoped-proxy/>
Choosing the Type of Proxy to Create
By default, when the Spring container creates a proxy for a bean that is marked up with the
<aop:scoped-proxy/> element, a CGLIB-based class proxy is created.
CGLIB proxies intercept only public method calls! Do not call non-public methods
on such a proxy. They are not delegated to the actual scoped target object.
Alternatively, you can configure the Spring container to create standard JDK interface-based
proxies for such scoped beans, by specifying false for the value of the proxy-target-class attribute
of the <aop:scoped-proxy/> element. Using JDK interface-based proxies means that you do not need
additional libraries in your application classpath to affect such proxying. However, it also means
that the class of the scoped bean must implement at least one interface and that all collaborators
into which the scoped bean is injected must reference the bean through one of its interfaces. The
following example shows a proxy based on an interface:
<aop:scoped-proxy proxy-target-class="false"/>
For more detailed information about choosing class-based or interface-based proxying, see
Proxying Mechanisms.
Custom Scopes
The bean scoping mechanism is extensible. You can define your own scopes or even redefine
existing scopes, although the latter is considered bad practice and you cannot override the built-in
singleton and prototype scopes.
Creating a Custom Scope
To integrate your custom scopes into the Spring container, you need to implement the
org.springframework.beans.factory.config.Scope interface, which is described in this section. For an
idea of how to implement your own scopes, see the Scope implementations that are supplied with
the Spring Framework itself and the Scope javadoc, which explains the methods you need to
implement in more detail.
The Scope interface has four methods to get objects from the scope, remove them from the scope,
and let them be destroyed.
The session scope implementation, for example, returns the session-scoped bean (if it does not
exist, the method returns a new instance of the bean, after having bound it to the session for future
reference). The following method returns the object from the underlying scope:
Java
Object get(String name, ObjectFactory<?> objectFactory)
Kotlin
fun get(name: String, objectFactory: ObjectFactory<*>): Any
The session scope implementation, for example, removes the session-scoped bean from the
underlying session. The object should be returned, but you can return null if the object with the
specified name is not found. The following method removes the object from the underlying scope:
Java
Object remove(String name)
Kotlin
fun remove(name: String): Any
The following method registers a callback that the scope should invoke when it is destroyed or
when the specified object in the scope is destroyed:
Java
void registerDestructionCallback(String name, Runnable destructionCallback)
Kotlin
fun registerDestructionCallback(name: String, destructionCallback: Runnable)
See the javadoc or a Spring scope implementation for more information on destruction callbacks.
The following method obtains the conversation identifier for the underlying scope:
Java
String getConversationId()
Kotlin
fun getConversationId(): String
This identifier is different for each scope. For a session scoped implementation, this identifier can
be the session identifier.
Using a Custom Scope
After you write and test one or more custom Scope implementations, you need to make the Spring
container aware of your new scopes. The following method is the central method to register a new
Scope with the Spring container:
Java
void registerScope(String scopeName, Scope scope);
Kotlin
fun registerScope(scopeName: String, scope: Scope)
This method is declared on the ConfigurableBeanFactory interface, which is available through the
BeanFactory property on most of the concrete ApplicationContext implementations that ship with
Spring.
The first argument to the registerScope(..) method is the unique name associated with a scope.
Examples of such names in the Spring container itself are singleton and prototype. The second
argument to the registerScope(..) method is an actual instance of the custom Scope
implementation that you wish to register and use.
Suppose that you write your custom Scope implementation, and then register it as shown in the
next example.
The next example uses SimpleThreadScope, which is included with Spring but is not
registered by default. The instructions would be the same for your own custom
Scope implementations.
Java
Scope threadScope = new SimpleThreadScope();
beanFactory.registerScope("thread", threadScope);
Kotlin
val threadScope = SimpleThreadScope()
beanFactory.registerScope("thread", threadScope)
You can then create bean definitions that adhere to the scoping rules of your custom Scope, as
follows:
With a custom Scope implementation, you are not limited to programmatic registration of the scope.
You can also do the Scope registration declaratively, by using the CustomScopeConfigurer class, as the
following example shows:
<?xml version="1.0" encoding="UTF-8"?>
<map>
<entry key="thread">
</entry>
</map>
<aop:scoped-proxy/>
When you place <aop:scoped-proxy/> within a declaration for a FactoryBean
implementation, it is the factory bean itself that is scoped, not the object returned
from getObject().
2.1.6. Customizing the Nature of a Bean
The Spring Framework provides a number of interfaces you can use to customize the nature of a
bean. This section groups them as follows:
• Lifecycle Callbacks
• ApplicationContextAware and BeanNameAware
• Other Aware Interfaces
Lifecycle Callbacks
To interact with the container’s management of the bean lifecycle, you can implement the Spring
InitializingBean and DisposableBean interfaces. The container calls afterPropertiesSet() for the
former and destroy() for the latter to let the bean perform certain actions upon initialization and
destruction of your beans.
The JSR-250 @PostConstruct and @PreDestroy annotations are generally considered
best practice for receiving lifecycle callbacks in a modern Spring application. Using
these annotations means that your beans are not coupled to Spring-specific
interfaces. For details, see Using @PostConstruct and @PreDestroy.
If you do not want to use the JSR-250 annotations but you still want to remove
coupling, consider init-method and destroy-method bean definition metadata.
Internally, the Spring Framework uses BeanPostProcessor implementations to process any callback
interfaces it can find and call the appropriate methods. If you need custom features or other
lifecycle behavior Spring does not by default offer, you can implement a BeanPostProcessor yourself.
For more information, see Container Extension Points.
In addition to the initialization and destruction callbacks, Spring-managed objects may also
implement the Lifecycle interface so that those objects can participate in the startup and shutdown
process, as driven by the container’s own lifecycle.
The lifecycle callback interfaces are described in this section.
Initialization Callbacks
The org.springframework.beans.factory.InitializingBean interface lets a bean perform
initialization work after the container has set all necessary properties on the bean. The
InitializingBean interface specifies a single method:
void afterPropertiesSet() throws Exception;
We recommend that you do not use the InitializingBean interface, because it unnecessarily couples
the code to Spring. Alternatively, we suggest using the @PostConstruct annotation or specifying a
POJO initialization method. In the case of XML-based configuration metadata, you can use the init-
method attribute to specify the name of the method that has a void no-argument signature. With
Java configuration, you can use the initMethod attribute of @Bean. See Receiving Lifecycle Callbacks.
Consider the following example:
Java
public class ExampleBean {
public void init() {
// do some initialization work
}
}
Kotlin
class ExampleBean {
fun init() {
// do some initialization work
}
}
The preceding example has almost exactly the same effect as the following example (which consists
of two listings):
Java
public class AnotherExampleBean implements InitializingBean {
@Override
public void afterPropertiesSet() {
// do some initialization work
}
}
Kotlin
class AnotherExampleBean : InitializingBean {
override fun afterPropertiesSet() {
// do some initialization work
}
}
However, the first of the two preceding examples does not couple the code to Spring.
Destruction Callbacks
Implementing the org.springframework.beans.factory.DisposableBean interface lets a bean get a
callback when the container that contains it is destroyed. The DisposableBean interface specifies a
single method:
void destroy() throws Exception;
We recommend that you do not use the DisposableBean callback interface, because it unnecessarily
couples the code to Spring. Alternatively, we suggest using the @PreDestroy annotation or specifying
a generic method that is supported by bean definitions. With XML-based configuration metadata,
you can use the destroy-method attribute on the . With Java configuration, you can use the
destroyMethod attribute of @Bean. See Receiving Lifecycle Callbacks. Consider the following
definition:
Java
public class ExampleBean {
public void cleanup() {
// do some destruction work (like releasing pooled connections)
}
}
Kotlin
class ExampleBean {
fun cleanup() {
// do some destruction work (like releasing pooled connections)
}
}
The preceding definition has almost exactly the same effect as the following definition:
Java
public class AnotherExampleBean implements DisposableBean {
@Override
public void destroy() {
// do some destruction work (like releasing pooled connections)
}
}
Kotlin
class AnotherExampleBean : DisposableBean {
override fun destroy() {
// do some destruction work (like releasing pooled connections)
}
}
However, the first of the two preceding definitions does not couple the code to Spring.
You can assign the destroy-method attribute of a element a special (inferred)
value, which instructs Spring to automatically detect a public close or shutdown
method on the specific bean class. (Any class that implements
java.lang.AutoCloseable or java.io.Closeable would therefore match.) You can
also set this special (inferred) value on the default-destroy-method attribute of a
element to apply this behavior to an entire set of beans (see Default
Initialization and Destroy Methods). Note that this is the default behavior with Java
configuration.
Default Initialization and Destroy Methods
When you write initialization and destroy method callbacks that do not use the Spring-specific
InitializingBean and DisposableBean callback interfaces, you typically write methods with names
such as init(), initialize(), dispose(), and so on. Ideally, the names of such lifecycle callback
methods are standardized across a project so that all developers use the same method names and
ensure consistency.
You can configure the Spring container to “look” for named initialization and destroy callback
method names on every bean. This means that you, as an application developer, can write your
application classes and use an initialization callback called init(), without having to configure an
init-method="init" attribute with each bean definition. The Spring IoC container calls that method
when the bean is created (and in accordance with the standard lifecycle callback contract described
previously). This feature also enforces a consistent naming convention for initialization and destroy
method callbacks.
Suppose that your initialization callback methods are named init() and your destroy callback
methods are named destroy(). Your class then resembles the class in the following example:
Java
public class DefaultBlogService implements BlogService {
private BlogDao blogDao;
public void setBlogDao(BlogDao blogDao) {
this.blogDao = blogDao;
}
// this is (unsurprisingly) the initialization callback method
public void init() {
if (this.blogDao == null) {
throw new IllegalStateException("The [blogDao] property must be set.");
}
}
}
Kotlin
class DefaultBlogService : BlogService {
private var blogDao: BlogDao? = null
// this is (unsurprisingly) the initialization callback method
fun init() {
if (blogDao == null) {
throw IllegalStateException("The [blogDao] property must be set.")
}
}
}
You could then use that class in a bean resembling the following:
The presence of the default-init-method attribute on the top-level element attribute causes
the Spring IoC container to recognize a method called init on the bean class as the initialization
method callback. When a bean is created and assembled, if the bean class has such a method, it is
invoked at the appropriate time.
You can configure destroy method callbacks similarly (in XML, that is) by using the default-
destroy-method attribute on the top-level element.
Where existing bean classes already have callback methods that are named at variance with the
convention, you can override the default by specifying (in XML, that is) the method name by using
the init-method and destroy-method attributes of the itself.
The Spring container guarantees that a configured initialization callback is called immediately after
a bean is supplied with all dependencies. Thus, the initialization callback is called on the raw bean
reference, which means that AOP interceptors and so forth are not yet applied to the bean. A target
bean is fully created first and then an AOP proxy (for example) with its interceptor chain is applied.
If the target bean and the proxy are defined separately, your code can even interact with the raw
target bean, bypassing the proxy. Hence, it would be inconsistent to apply the interceptors to the
init method, because doing so would couple the lifecycle of the target bean to its proxy or
interceptors and leave strange semantics when your code interacts directly with the raw target
bean.
Spring Ai Docs/Src/Main/Antora/Antora Playbook.Yml (spring-ai-docs/src/main/antora/antora-playbook.yml)
PACKAGES [email protected] @antora/atlas-extension:1.0.0-alpha.1 @antora/[email protected] @springio/[email protected] @asciidoctor/[email protected] @opendevise/[email protected]
# The purpose of this Antora playbook is to build the docs in the current branch.
antora:
extensions:
- '@antora/collector-extension'
# - require: '@springio/antora-extensions/root-component-extension'
- require: '@springio/antora-extensions'
root_component_name: 'ai'
site:
title: Spring AI Reference
url: https://docs.spring.io/spring-ai/reference
robots: allow
git:
ensure_git_suffix: false
content:
sources:
- url: ./../../../..
branches: HEAD
start_path: spring-ai-docs/src/main/antora
worktrees: true
asciidoc:
attributes:
page-related-doc-categories: ai,java,ml
page-pagination: ''
hide-uri-scheme: '@'
tabs-sync-option: '@'
chomp: 'all'
stem: 'asciimath'
extensions:
- '@asciidoctor/tabs'
- '@springio/asciidoctor-extensions'
- '@springio/asciidoctor-extensions/javadoc-extension'
- '@springio/asciidoctor-extensions/include-code-extension'
- '@djencks/asciidoctor-mathjax'
sourcemap: true
urls:
latest_version_segment_strategy: redirect:to
latest_version_segment: ''
redirect_facility: httpd
runtime:
log:
failure_level: warn
format: pretty
ui:
bundle:
url: https://github.com/spring-io/antora-ui-spring/releases/download/v0.4.17/ui-bundle.zip
snapshot: true
Spring Ai Docs/Src/Main/Antora/Antora.Yml (spring-ai-docs/src/main/antora/antora.yml)
name: ai
version: true
title: Spring AI
nav:
- modules/ROOT/nav.adoc
ext:
collector:
- run:
command: mvnw process-resources
local: true
scan:
dir: spring-ai-docs/target/classes/antora-resources
Spring Ai Docs/Src/Main/Antora/Resources/Antora Resources/Antora.Yml (spring-ai-docs/src/main/antora/resources/antora-resources/antora.yml)
version: ${antora-component.version}
prerelease: ${antora-component.prerelease}
Spring Ai Docs/Src/Main/Asciidoc/Mcp (spring-ai-docs/src/main/asciidoc/mcp.md)
Model Context Protocol (MCP) Server
The Spring AI MCP module provides integration with the Model Context Protocol, allowing you to expose your AI tools and resources through a standardized protocol. This module is particularly useful when you want to make your Spring AI tools and resources available to MCP-compatible clients.
Dependencies
To use the MCP server functionality, add the following dependency to your project:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server</artifactId>
<version>${spring-ai.version}</version>
</dependency>Configuration Properties
The MCP server can be configured using the following properties under the spring.ai.mcp.server prefix:
| Property | Default | Description |
|---|---|---|
enabled |
false | Enable/disable the MCP server |
| name | "mcp-server" | Name of the MCP server |
| version | "1.0.0" | Version of the MCP server |
| type | SYNC | Server type (SYNC or ASYNC) |
| resource-change-notification | true | Enable/disable resource change notifications |
| tool-change-notification | true | Enable/disable tool change notifications |
| prompt-change-notification | true | Enable/disable prompt change notifications |
| transport | STDIO | Transport type (STDIO, WEBMVC, or WEBFLUX) |
| sse-message-endpoint | "/mcp/message" | Server-Sent Events (SSE) message endpoint for web transports |
Server Types
The MCP server supports two operation modes:
1. Synchronous Mode (Default)
The synchronous mode is the default option, suitable for most use cases where tools and resources are accessed sequentially:
spring:
ai:
mcp:
server:
type: SYNC2. Asynchronous Mode
The asynchronous mode is designed for reactive applications and scenarios requiring non-blocking operations:
spring:
ai:
mcp:
server:
type: ASYNCTransport Options
The MCP server supports three transport types:
1. STDIO Transport (Default)
The Standard Input/Output transport is the default option, suitable for command-line tools and local development:
spring:
ai:
mcp:
server:
transport: STDIO2. WebMvc Transport
The WebMvc transport uses Spring MVC's Server-Sent Events (SSE) for communication:
spring:
ai:
mcp:
server:
transport: WEBMVC
sse-message-endpoint: /mcp/message # Optional, defaults to /mcp/messageRequired dependencies:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>mcp-spring-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>3. WebFlux Transport
The WebFlux transport uses Spring WebFlux's Server-Sent Events for reactive communication:
spring:
ai:
mcp:
server:
transport: WEBFLUX
sse-message-endpoint: /mcp/message # Optional, defaults to /mcp/messageRequired dependencies:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>mcp-spring-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>Core Features
The MCP server provides several core features:
Tools
- Extensible tool registration system supporting both sync and async execution
- Automatic tool discovery and registration through Spring's component scanning
- Change notification support for tool updates
Resources
- Static and dynamic resource management
- Optional change notifications for resource updates
- Support for both sync and async resource access
Prompts
- Configurable prompt templates
- Change notification support for template updates
- Integration with Spring AI's prompt system
Usage Example
Here's an example of configuring the MCP server with WebMvc transport and custom settings:
spring:
ai:
mcp:
server:
enabled: true
name: "My AI Tools Server"
version: "1.0.0"
type: SYNC
transport: WEBMVC
sse-message-endpoint: /ai/mcp/events
resource-change-notification: true
tool-change-notification: true
prompt-change-notification: falseAuto-configuration
The MCP server auto-configuration is provided through:
McpServerAutoConfiguration: Core server configuration supporting both sync and async modesMcpWebMvcServerAutoConfiguration: WebMvc transport configuration (activated when WebMvc dependencies are present)McpWebFluxServerAutoConfiguration: WebFlux transport configuration (activated when WebFlux dependencies are present)
The auto-configuration will automatically set up the appropriate server type and transport based on your configuration and available dependencies.
Implementing Tools and Resources
To expose your Spring AI tools and resources through the MCP server:
- Implement the
ToolCallbackinterface for your AI tools:
@Component
public class MyAiTool implements ToolCallback {
// Implementation
}- The auto-configuration will automatically discover and register your tools with the MCP server, converting them to either sync or async implementations based on your server type configuration.
Monitoring
The MCP server provides notifications for changes in:
- Tools (when tools are added or removed)
- Resources (when resources are updated)
- Prompts (when prompt templates change)
You can enable/disable these notifications using the configuration properties. The notification system works with both sync and async server types, providing consistent change tracking regardless of the chosen operation mode.
Spring Ai Integration Tests/Src/Test/Resources/Application.Yml (spring-ai-integration-tests/src/test/resources/application.yml)
spring:
main:
web-application-type: none
ai:
openai:
api-key: ${OPENAI_API_KEY}
chat:
options:
model: gpt-4o-mini
embedding:
options:
model: text-embedding-ada-002
retry:
max-attempts: 3
vectorstore:
pgvector:
initialize-schema: true
Spring Ai Integration Tests/Src/Test/Resources/Documents/Knowledge Base (spring-ai-integration-tests/src/test/resources/documents/knowledge-base.md)
Anacletus and Birba's Quest for the Loch of the Stars
Chapter 1: The Map and the Adventure
Once upon a time, in a cozy little cottage nestled at the edge of the Scottish Highlands, lived an owl named Anacletus and a curious cat named Birba. Anacletus was wise and careful, always reading maps and planning things thoroughly, while Birba was lively and adventurous, always ready to chase after the next interesting thing. Despite their differences, they were the best of friends and loved going on little adventures together.
Chapter 2: The Journey Begins
One sunny morning, Anacletus showed Birba an old, crinkled map he’d found in the attic. “Look, Birba,” he said, pointing with his feathery wing. “This map leads to the legendary Loch of the Stars. They say it shines brighter than any other lake at night.” Birba’s eyes sparkled with excitement. “Oh, we have to go there!” she meowed. So, they packed a small bag with snacks, a compass, and a flashlight, and off they went, eager to find the legendary loch.
Chapter 3: The Highland Adventure
Their journey began with a climb up the rolling hills covered in purple heather. Anacletus flapped his wings, soaring ahead to scout for any obstacles, while Birba trotted along below, her nose sniffing the air for interesting scents. Soon, they came across a bubbling brook. Anacletus carefully flew over it, but Birba hesitated. “Just a little jump!” Anacletus called out. With a deep breath, Birba leaped and landed safely on the other side. She purred proudly, and they continued on their way.
Chapter 4: The Highland Cows and the Hidden Path
As they ventured deeper into the Highlands, they stumbled upon a herd of curious Highland cows with long, shaggy hair. The cows mooed softly, and one of them named Fergus approached. “Where are you two headed?” Fergus asked. “We’re searching for the Loch of the Stars!” Anacletus replied. Fergus nodded knowingly and pointed his nose north. “Follow the path by the big stones, and it will lead you closer to the loch,” he said. Thanking Fergus, they set off again, Birba occasionally stopping to bat at the fluttering butterflies along the way.
Chapter 5: The Mysterious Forest and the Deer Family
The day wore on, and they soon found themselves in a mysterious forest. Tall, ancient pine trees surrounded them, casting long shadows. “Stay close, Birba,” Anacletus whispered, his wise eyes scanning for any sign of danger. But Birba had already darted after a flicker of light, thinking it was a firefly. Anacletus sighed and followed her until they came to a hidden glade where a family of deer grazed quietly. The smallest fawn looked up and gave them a curious nod before they moved along.
Chapter 6: The Loch of the Stars
After a while, the sun began to set, painting the sky in shades of pink and gold. Anacletus decided it was a good time to rest. They found a cozy hollow at the base of a tree, where they shared the snacks they’d packed. Birba munched on her fish treats while Anacletus nibbled on a biscuit. “Do you think we’ll find the Loch of the Stars?” Birba asked, her eyes twinkling. “I think so,” Anacletus replied with a wise smile. “We’re getting closer.”
Chapter 7: The Shimmering Loch
As night fell, they finally reached the top of a hill where they could see a shimmering light in the distance. “Look, Birba!” Anacletus hooted excitedly. There, nestled among the hills, was the Loch of the Stars, gleaming like a sky full of stars. The two friends hurried down to the water’s edge, marveling at how the loch sparkled under the moonlight, casting a gentle glow all around.
Chapter 8: The Magic of the Loch
Birba dipped a curious paw into the water, causing ripples that sent stars dancing across the surface. “It’s beautiful!” she gasped. Anacletus nodded, his heart filled with awe. They spent the night by the loch, watching the shimmering stars reflected in the water, feeling as though they were surrounded by magic.
Chapter 9: The Journey Home
When dawn broke, the shimmering loch returned to its quiet, glassy calm. With a satisfied yawn, Birba stretched and said, “That was the best adventure yet.” Anacletus agreed, feeling a warmth in his feathers as they turned back toward home, carrying memories of the Loch of the Stars in their hearts.
Chapter 10: The End of the Adventure
And as they made their way back to their cozy cottage, they already started dreaming of their next big adventure—because Anacletus and Birba knew that the Scottish Highlands held endless wonders for those who dared to explore.
Spring Ai Model/Src/Test/Resources/Text Source (spring-ai-model/src/test/resources/text_source.txt)
Spring Framework Documentation
Version 6.0.0
Chapter 1. Spring Framework Overview
Spring makes it easy to create Java enterprise applications. It provides everything you need to
embrace the Java language in an enterprise environment, with support for Groovy and Kotlin as
alternative languages on the JVM, and with the flexibility to create many kinds of architectures
depending on an application’s needs. As of Spring Framework 5.1, Spring requires JDK 8+ (Java SE
8+) and provides out-of-the-box support for JDK 11 LTS. Java SE 8 update 60 is suggested as the
minimum patch release for Java 8, but it is generally recommended to use a recent patch release.
Spring supports a wide range of application scenarios. In a large enterprise, applications often exist
for a long time and have to run on a JDK and application server whose upgrade cycle is beyond
developer control. Others may run as a single jar with the server embedded, possibly in a cloud
environment. Yet others may be standalone applications (such as batch or integration workloads)
that do not need a server.
Spring is open source. It has a large and active community that provides continuous feedback based
on a diverse range of real-world use cases. This has helped Spring to successfully evolve over a very
long time.
1.1. What We Mean by "Spring"
The term "Spring" means different things in different contexts. It can be used to refer to the Spring
Framework project itself, which is where it all started. Over time, other Spring projects have been
built on top of the Spring Framework. Most often, when people say "Spring", they mean the entire
family of projects. This reference documentation focuses on the foundation: the Spring Framework
itself.
The Spring Framework is divided into modules. Applications can choose which modules they need.
At the heart are the modules of the core container, including a configuration model and a
dependency injection mechanism. Beyond that, the Spring Framework provides foundational
support for different application architectures, including messaging, transactional data and
persistence, and web. It also includes the Servlet-based Spring MVC web framework and, in
parallel, the Spring WebFlux reactive web framework.
A note about modules: Spring’s framework jars allow for deployment to JDK 9’s module path
("Jigsaw"). For use in Jigsaw-enabled applications, the Spring Framework 5 jars come with
"Automatic-Module-Name" manifest entries which define stable language-level module names
("spring.core", "spring.context", etc.) independent from jar artifact names (the jars follow the same
naming pattern with "-" instead of ".", e.g. "spring-core" and "spring-context"). Of course, Spring’s
framework jars keep working fine on the classpath on both JDK 8 and 9+.
1.2. History of Spring and the Spring Framework
Spring came into being in 2003 as a response to the complexity of the early J2EE specifications.
While some consider Java EE and its modern-day successor Jakarta EE to be in competition with
Spring, they are in fact complementary. The Spring programming model does not embrace the
Jakarta EE platform specification; rather, it integrates with carefully selected individual
specifications from the traditional EE umbrella:
• Servlet API (JSR 340)
• WebSocket API (JSR 356)
• Concurrency Utilities (JSR 236)
• JSON Binding API (JSR 367)
• Bean Validation (JSR 303)
• JPA (JSR 338)
• JMS (JSR 914)
• as well as JTA/JCA setups for transaction coordination, if necessary.
The Spring Framework also supports the Dependency Injection (JSR 330) and Common Annotations
(JSR 250) specifications, which application developers may choose to use instead of the Spring-
specific mechanisms provided by the Spring Framework. Originally, those were based on common
javax packages.
As of Spring Framework 6.0, Spring has been upgraded to the Jakarta EE 9 level (e.g. Servlet 5.0+,
JPA 3.0+), based on the jakarta namespace instead of the traditional javax packages. With EE 9 as
the minimum and EE 10 supported already, Spring is prepared to provide out-of-the-box support
for the further evolution of the Jakarta EE APIs. Spring Framework 6.0 is fully compatible with
Tomcat 10.1, Jetty 11 and Undertow 2.3 as web servers, and also with Hibernate ORM 6.1.
Over time, the role of Java/Jakarta EE in application development has evolved. In the early days of
J2EE and Spring, applications were created to be deployed to an application server. Today, with the
help of Spring Boot, applications are created in a devops- and cloud-friendly way, with the Servlet
container embedded and trivial to change. As of Spring Framework 5, a WebFlux application does
not even use the Servlet API directly and can run on servers (such as Netty) that are not Servlet
containers.
Spring continues to innovate and to evolve. Beyond the Spring Framework, there are other projects,
such as Spring Boot, Spring Security, Spring Data, Spring Cloud, Spring Batch, among others. It’s
important to remember that each project has its own source code repository, issue tracker, and
release cadence. See spring.io/projects for the complete list of Spring projects.
1.3. Design Philosophy
When you learn about a framework, it’s important to know not only what it does but what
principles it follows. Here are the guiding principles of the Spring Framework:
• Provide choice at every level. Spring lets you defer design decisions as late as possible. For
example, you can switch persistence providers through configuration without changing your
code. The same is true for many other infrastructure concerns and integration with third-party
APIs.
• Accommodate diverse perspectives. Spring embraces flexibility and is not opinionated about
how things should be done. It supports a wide range of application needs with different
perspectives.
• Maintain strong backward compatibility. Spring’s evolution has been carefully managed to
force few breaking changes between versions. Spring supports a carefully chosen range of JDK
versions and third-party libraries to facilitate maintenance of applications and libraries that
depend on Spring.
• Care about API design. The Spring team puts a lot of thought and time into making APIs that are
intuitive and that hold up across many versions and many years.
• Set high standards for code quality. The Spring Framework puts a strong emphasis on
meaningful, current, and accurate javadoc. It is one of very few projects that can claim clean
code structure with no circular dependencies between packages.
1.4. Feedback and Contributions
For how-to questions or diagnosing or debugging issues, we suggest using Stack Overflow. Click
here for a list of the suggested tags to use on Stack Overflow. If you’re fairly certain that there is a
problem in the Spring Framework or would like to suggest a feature, please use the GitHub Issues.
If you have a solution in mind or a suggested fix, you can submit a pull request on Github.
However, please keep in mind that, for all but the most trivial issues, we expect a ticket to be filed
in the issue tracker, where discussions take place and leave a record for future reference.
For more details see the guidelines at the CONTRIBUTING, top-level project page.
1.5. Getting Started
If you are just getting started with Spring, you may want to begin using the Spring Framework by
creating a Spring Boot-based application. Spring Boot provides a quick (and opinionated) way to
create a production-ready Spring-based application. It is based on the Spring Framework, favors
convention over configuration, and is designed to get you up and running as quickly as possible.
You can use start.spring.io to generate a basic project or follow one of the "Getting Started" guides,
such as Getting Started Building a RESTful Web Service. As well as being easier to digest, these
guides are very task focused, and most of them are based on Spring Boot. They also cover other
projects from the Spring portfolio that you might want to consider when solving a particular
problem.
Chapter 2. Core Technologies
This part of the reference documentation covers all the technologies that are absolutely integral to
the Spring Framework.
Foremost amongst these is the Spring Framework’s Inversion of Control (IoC) container. A thorough
treatment of the Spring Framework’s IoC container is closely followed by comprehensive coverage
of Spring’s Aspect-Oriented Programming (AOP) technologies. The Spring Framework has its own
AOP framework, which is conceptually easy to understand and which successfully addresses the
80% sweet spot of AOP requirements in Java enterprise programming.
Coverage of Spring’s integration with AspectJ (currently the richest — in terms of features — and
certainly most mature AOP implementation in the Java enterprise space) is also provided.
AOT processing can be used to optimize your application ahead-of-time. It is typically used for
native image deployment using GraalVM.
2.1. The IoC Container
This chapter covers Spring’s Inversion of Control (IoC) container.
2.1.1. Introduction to the Spring IoC Container and Beans
This chapter covers the Spring Framework implementation of the Inversion of Control (IoC)
principle. IoC is also known as dependency injection (DI). It is a process whereby objects define
their dependencies (that is, the other objects they work with) only through constructor arguments,
arguments to a factory method, or properties that are set on the object instance after it is
constructed or returned from a factory method. The container then injects those dependencies
when it creates the bean. This process is fundamentally the inverse (hence the name, Inversion of
Control) of the bean itself controlling the instantiation or location of its dependencies by using
direct construction of classes or a mechanism such as the Service Locator pattern.
The org.springframework.beans and org.springframework.context packages are the basis for Spring
Framework’s IoC container. The BeanFactory interface provides an advanced configuration
mechanism capable of managing any type of object. ApplicationContext is a sub-interface of
BeanFactory. It adds:
• Easier integration with Spring’s AOP features
• Message resource handling (for use in internationalization)
• Event publication
• Application-layer specific contexts such as the WebApplicationContext for use in web
applications.
In short, the BeanFactory provides the configuration framework and basic functionality, and the
ApplicationContext adds more enterprise-specific functionality. The ApplicationContext is a
complete superset of the BeanFactory and is used exclusively in this chapter in descriptions of
Spring’s IoC container. For more information on using the BeanFactory instead of the
ApplicationContext, see the section covering the BeanFactory API.
In Spring, the objects that form the backbone of your application and that are managed by the
Spring IoC container are called beans. A bean is an object that is instantiated, assembled, and
managed by a Spring IoC container. Otherwise, a bean is simply one of many objects in your
application. Beans, and the dependencies among them, are reflected in the configuration metadata
used by a container.
2.1.2. Container Overview
The org.springframework.context.ApplicationContext interface represents the Spring IoC container
and is responsible for instantiating, configuring, and assembling the beans. The container gets its
instructions on what objects to instantiate, configure, and assemble by reading configuration
metadata. The configuration metadata is represented in XML, Java annotations, or Java code. It lets
you express the objects that compose your application and the rich interdependencies between
those objects.
Several implementations of the ApplicationContext interface are supplied with Spring. In stand-
alone applications, it is common to create an instance of ClassPathXmlApplicationContext or
FileSystemXmlApplicationContext. While XML has been the traditional format for defining
configuration metadata, you can instruct the container to use Java annotations or code as the
metadata format by providing a small amount of XML configuration to declaratively enable support
for these additional metadata formats.
In most application scenarios, explicit user code is not required to instantiate one or more
instances of a Spring IoC container. For example, in a web application scenario, a simple eight (or
so) lines of boilerplate web descriptor XML in the web.xml file of the application typically suffices
(see Convenient ApplicationContext Instantiation for Web Applications). If you use the Spring Tools
for Eclipse (an Eclipse-powered development environment), you can easily create this boilerplate
configuration with a few mouse clicks or keystrokes.
The following diagram shows a high-level view of how Spring works. Your application classes are
combined with configuration metadata so that, after the ApplicationContext is created and
initialized, you have a fully configured and executable system or application.
Figure 1. The Spring IoC container
Configuration Metadata
As the preceding diagram shows, the Spring IoC container consumes a form of configuration
metadata. This configuration metadata represents how you, as an application developer, tell the
Spring container to instantiate, configure, and assemble the objects in your application.
Configuration metadata is traditionally supplied in a simple and intuitive XML format, which is
what most of this chapter uses to convey key concepts and features of the Spring IoC container.
XML-based metadata is not the only allowed form of configuration metadata. The
Spring IoC container itself is totally decoupled from the format in which this
configuration metadata is actually written. These days, many developers choose
Java-based configuration for their Spring applications.
For information about using other forms of metadata with the Spring container, see:
• Annotation-based configuration: Spring 2.5 introduced support for annotation-based
configuration metadata.
• Java-based configuration: Starting with Spring 3.0, many features provided by the Spring
JavaConfig project became part of the core Spring Framework. Thus, you can define beans
external to your application classes by using Java rather than XML files. To use these new
features, see the @Configuration, @Bean, @Import, and @DependsOn annotations.
Spring configuration consists of at least one and typically more than one bean definition that the
container must manage. XML-based configuration metadata configures these beans as
elements inside a top-level element. Java configuration typically uses @Bean-annotated
methods within a @Configuration class.
These bean definitions correspond to the actual objects that make up your application. Typically,
you define service layer objects, data access objects (DAOs), presentation objects such as Struts
Action instances, infrastructure objects such as Hibernate SessionFactories, JMS Queues, and so
forth. Typically, one does not configure fine-grained domain objects in the container, because it is
usually the responsibility of DAOs and business logic to create and load domain objects. However,
you can use Spring’s integration with AspectJ to configure objects that have been created outside
the control of an IoC container. See Using AspectJ to dependency-inject domain objects with Spring.
The following example shows the basic structure of XML-based configuration metadata:
<?xml version="1.0" encoding="UTF-8"?>
① ②
① The id attribute is a string that identifies the individual bean definition.
② The class attribute defines the type of the bean and uses the fully qualified classname.
The value of the id attribute refers to collaborating objects. The XML for referring to collaborating
objects is not shown in this example. See Dependencies for more information.
Instantiating a Container
The location path or paths supplied to an ApplicationContext constructor are resource strings that
let the container load configuration metadata from a variety of external resources, such as the local
file system, the Java CLASSPATH, and so on.
Java
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml",
"daos.xml");
Kotlin
val context = ClassPathXmlApplicationContext("services.xml", "daos.xml")
After you learn about Spring’s IoC container, you may want to know more about
Spring’s Resource abstraction (as described in Resources), which provides a
convenient mechanism for reading an InputStream from locations defined in a
URI syntax. In particular, Resource paths are used to construct applications
contexts, as described in Application Contexts and Resource Paths.
The following example shows the service layer objects (services.xml) configuration file:
<?xml version="1.0" encoding="UTF-8"?>
The following example shows the data access objects daos.xml file:
<?xml version="1.0" encoding="UTF-8"?>
In the preceding example, the service layer consists of the PetStoreServiceImpl class and two data
access objects of the types JpaAccountDao and JpaItemDao (based on the JPA Object-Relational
Mapping standard). The property name element refers to the name of the JavaBean property, and the
ref element refers to the name of another bean definition. This linkage between id and ref
elements expresses the dependency between collaborating objects. For details of configuring an
object’s dependencies, see Dependencies.
Composing XML-based Configuration Metadata
It can be useful to have bean definitions span multiple XML files. Often, each individual XML
configuration file represents a logical layer or module in your architecture.
You can use the application context constructor to load bean definitions from all these XML
fragments. This constructor takes multiple Resource locations, as was shown in the previous section.
Alternatively, use one or more occurrences of the element to load bean definitions from
another file or files. The following example shows how to do so:
In the preceding example, external bean definitions are loaded from three files: services.xml,
messageSource.xml, and themeSource.xml. All location paths are relative to the definition file doing
the importing, so services.xml must be in the same directory or classpath location as the file doing
the importing, while messageSource.xml and themeSource.xml must be in a resources location below
the location of the importing file. As you can see, a leading slash is ignored. However, given that
these paths are relative, it is better form not to use the slash at all. The contents of the files being
imported, including the top level element, must be valid XML bean definitions, according
to the Spring Schema.
It is possible, but not recommended, to reference files in parent directories using a
relative "../" path. Doing so creates a dependency on a file that is outside the
current application. In particular, this reference is not recommended for
classpath: URLs (for example, classpath:../services.xml), where the runtime
resolution process chooses the “nearest” classpath root and then looks into its
parent directory. Classpath configuration changes may lead to the choice of a
different, incorrect directory.
You can always use fully qualified resource locations instead of relative paths: for
example, file:C:/config/services.xml or classpath:/config/services.xml.
However, be aware that you are coupling your application’s configuration to
specific absolute locations. It is generally preferable to keep an indirection for such
absolute locations — for example, through "${…}" placeholders that are resolved
against JVM system properties at runtime.
The namespace itself provides the import directive feature. Further configuration features beyond
plain bean definitions are available in a selection of XML namespaces provided by Spring — for
example, the context and util namespaces.
The Groovy Bean Definition DSL
As a further example for externalized configuration metadata, bean definitions can also be
expressed in Spring’s Groovy Bean Definition DSL, as known from the Grails framework. Typically,
such configuration live in a ".groovy" file with the structure shown in the following example:
beans {
dataSource(BasicDataSource) {
driverClassName = "org.hsqldb.jdbcDriver"
url = "jdbc:hsqldb:mem:grailsDB"
username = "sa"
password = ""
settings = [mynew:"setting"]
}
sessionFactory(SessionFactory) {
dataSource = dataSource
}
myService(MyService) {
nestedBean = { AnotherBean bean ->
dataSource = dataSource
}
}
}
This configuration style is largely equivalent to XML bean definitions and even supports Spring’s
XML configuration namespaces. It also allows for importing XML bean definition files through an
importBeans directive.
Using the Container
The ApplicationContext is the interface for an advanced factory capable of maintaining a registry of
different beans and their dependencies. By using the method T getBean(String name, Class<T>
requiredType), you can retrieve instances of your beans.
The ApplicationContext lets you read bean definitions and access them, as the following example
shows:
Java
// create and configure beans
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml",
"daos.xml");
// retrieve configured instance
PetStoreService service = context.getBean("petStore", PetStoreService.class);
// use configured instance
List<String> userList = service.getUsernameList();
Kotlin
import org.springframework.beans.factory.getBean
// create and configure beans
val context = ClassPathXmlApplicationContext("services.xml", "daos.xml")
// retrieve configured instance
val service = context.getBean("petStore")
// use configured instance
var userList = service.getUsernameList()
With Groovy configuration, bootstrapping looks very similar. It has a different context
implementation class which is Groovy-aware (but also understands XML bean definitions). The
following example shows Groovy configuration:
Java
ApplicationContext context = new GenericGroovyApplicationContext("services.groovy",
"daos.groovy");
Kotlin
val context = GenericGroovyApplicationContext("services.groovy", "daos.groovy")
The most flexible variant is GenericApplicationContext in combination with reader delegates — for
example, with XmlBeanDefinitionReader for XML files, as the following example shows:
Java
GenericApplicationContext context = new GenericApplicationContext();
new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml");
context.refresh();
Kotlin
val context = GenericApplicationContext()
XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml")
context.refresh()
You can also use the GroovyBeanDefinitionReader for Groovy files, as the following example shows:
Java
GenericApplicationContext context = new GenericApplicationContext();
new GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy",
"daos.groovy");
context.refresh();
Kotlin
val context = GenericApplicationContext()
GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy",
"daos.groovy")
context.refresh()
You can mix and match such reader delegates on the same ApplicationContext, reading bean
definitions from diverse configuration sources.
You can then use getBean to retrieve instances of your beans. The ApplicationContext interface has a
few other methods for retrieving beans, but, ideally, your application code should never use them.
Indeed, your application code should have no calls to the getBean() method at all and thus have no
dependency on Spring APIs at all. For example, Spring’s integration with web frameworks provides
dependency injection for various web framework components such as controllers and JSF-managed
beans, letting you declare a dependency on a specific bean through metadata (such as an
autowiring annotation).
2.1.3. Bean Overview
A Spring IoC container manages one or more beans. These beans are created with the configuration
metadata that you supply to the container (for example, in the form of XML definitions).
Within the container itself, these bean definitions are represented as BeanDefinition objects, which
contain (among other information) the following metadata:
• A package-qualified class name: typically, the actual implementation class of the bean being
defined.
• Bean behavioral configuration elements, which state how the bean should behave in the
container (scope, lifecycle callbacks, and so forth).
• References to other beans that are needed for the bean to do its work. These references are also
called collaborators or dependencies.
• Other configuration settings to set in the newly created object — for example, the size limit of
the pool or the number of connections to use in a bean that manages a connection pool.
This metadata translates to a set of properties that make up each bean definition. The following
table describes these properties:
Table 1. The bean definition
Property Explained in…
Class Instantiating Beans
Name Naming Beans
Scope Bean Scopes
Constructor arguments Dependency Injection
Properties Dependency Injection
Autowiring mode Autowiring Collaborators
Lazy initialization mode Lazy-initialized Beans
Initialization method Initialization Callbacks
Destruction method Destruction Callbacks
In addition to bean definitions that contain information on how to create a specific bean, the
ApplicationContext implementations also permit the registration of existing objects that are created
outside the container (by users). This is done by accessing the ApplicationContext’s BeanFactory
through the getBeanFactory() method, which returns the DefaultListableBeanFactory
implementation. DefaultListableBeanFactory supports this registration through the
registerSingleton(..) and registerBeanDefinition(..) methods. However, typical applications
work solely with beans defined through regular bean definition metadata.
Bean metadata and manually supplied singleton instances need to be registered as
early as possible, in order for the container to properly reason about them during
autowiring and other introspection steps. While overriding existing metadata and
existing singleton instances is supported to some degree, the registration of new
beans at runtime (concurrently with live access to the factory) is not officially
supported and may lead to concurrent access exceptions, inconsistent state in the
bean container, or both.
Naming Beans
Every bean has one or more identifiers. These identifiers must be unique within the container that
hosts the bean. A bean usually has only one identifier. However, if it requires more than one, the
extra ones can be considered aliases.
In XML-based configuration metadata, you use the id attribute, the name attribute, or both to specify
the bean identifiers. The id attribute lets you specify exactly one id. Conventionally, these names
are alphanumeric ('myBean', 'someService', etc.), but they can contain special characters as well. If
you want to introduce other aliases for the bean, you can also specify them in the name attribute,
separated by a comma (,), semicolon (;), or white space. As a historical note, in versions prior to
Spring 3.1, the id attribute was defined as an xsd:ID type, which constrained possible characters. As
of 3.1, it is defined as an xsd:string type. Note that bean id uniqueness is still enforced by the
container, though no longer by XML parsers.
You are not required to supply a name or an id for a bean. If you do not supply a name or id explicitly,
the container generates a unique name for that bean. However, if you want to refer to that bean by
name, through the use of the ref element or a Service Locator style lookup, you must provide a
name. Motivations for not supplying a name are related to using inner beans and autowiring
collaborators.
Bean Naming Conventions
The convention is to use the standard Java convention for instance field names when naming
beans. That is, bean names start with a lowercase letter and are camel-cased from there.
Examples of such names include accountManager, accountService, userDao, loginController, and
so forth.
Naming beans consistently makes your configuration easier to read and understand. Also, if
you use Spring AOP, it helps a lot when applying advice to a set of beans related by name.
With component scanning in the classpath, Spring generates bean names for
unnamed components, following the rules described earlier: essentially, taking the
simple class name and turning its initial character to lower-case. However, in the
(unusual) special case when there is more than one character and both the first
and second characters are upper case, the original casing gets preserved. These are
the same rules as defined by java.beans.Introspector.decapitalize (which Spring
uses here).
Aliasing a Bean outside the Bean Definition
In a bean definition itself, you can supply more than one name for the bean, by using a
combination of up to one name specified by the id attribute and any number of other names in the
name attribute. These names can be equivalent aliases to the same bean and are useful for some
situations, such as letting each component in an application refer to a common dependency by
using a bean name that is specific to that component itself.
Specifying all aliases where the bean is actually defined is not always adequate, however. It is
sometimes desirable to introduce an alias for a bean that is defined elsewhere. This is commonly
the case in large systems where configuration is split amongst each subsystem, with each
subsystem having its own set of object definitions. In XML-based configuration metadata, you can
use the <alias/> element to accomplish this. The following example shows how to do so:
<alias name="fromName" alias="toName"/>
In this case, a bean (in the same container) named fromName may also, after the use of this alias
definition, be referred to as toName.
For example, the configuration metadata for subsystem A may refer to a DataSource by the name of
subsystemA-dataSource. The configuration metadata for subsystem B may refer to a DataSource by
the name of subsystemB-dataSource. When composing the main application that uses both these
subsystems, the main application refers to the DataSource by the name of myApp-dataSource. To have
all three names refer to the same object, you can add the following alias definitions to the
configuration metadata:
<alias name="myApp-dataSource" alias="subsystemA-dataSource"/>
<alias name="myApp-dataSource" alias="subsystemB-dataSource"/>
Now each component and the main application can refer to the dataSource through a name that is
unique and guaranteed not to clash with any other definition (effectively creating a namespace),
yet they refer to the same bean.
Java-configuration
If you use Javaconfiguration, the @Bean annotation can be used to provide aliases. See Using
the @Bean Annotation for details.
Instantiating Beans
A bean definition is essentially a recipe for creating one or more objects. The container looks at the
recipe for a named bean when asked and uses the configuration metadata encapsulated by that
bean definition to create (or acquire) an actual object.
If you use XML-based configuration metadata, you specify the type (or class) of object that is to be
instantiated in the class attribute of the element. This class attribute (which, internally, is a
Class property on a BeanDefinition instance) is usually mandatory. (For exceptions, see
Instantiation by Using an Instance Factory Method and Bean Definition Inheritance.) You can use
the Class property in one of two ways:
• Typically, to specify the bean class to be constructed in the case where the container itself
directly creates the bean by calling its constructor reflectively, somewhat equivalent to Java
code with the new operator.
• To specify the actual class containing the static factory method that is invoked to create the
object, in the less common case where the container invokes a static factory method on a class
to create the bean. The object type returned from the invocation of the static factory method
may be the same class or another class entirely.
Nested class names
If you want to configure a bean definition for a nested class, you may use either the binary
name or the source name of the nested class.
For example, if you have a class called SomeThing in the com.example package, and this
SomeThing class has a static nested class called OtherThing, they can be separated by a dollar
sign ($) or a dot (.). So the value of the class attribute in a bean definition would be
com.example.SomeThing$OtherThing or com.example.SomeThing.OtherThing.
Instantiation with a Constructor
When you create a bean by the constructor approach, all normal classes are usable by and
compatible with Spring. That is, the class being developed does not need to implement any specific
interfaces or to be coded in a specific fashion. Simply specifying the bean class should suffice.
However, depending on what type of IoC you use for that specific bean, you may need a default
(empty) constructor.
The Spring IoC container can manage virtually any class you want it to manage. It is not limited to
managing true JavaBeans. Most Spring users prefer actual JavaBeans with only a default (no-
argument) constructor and appropriate setters and getters modeled after the properties in the
container. You can also have more exotic non-bean-style classes in your container. If, for example,
you need to use a legacy connection pool that absolutely does not adhere to the JavaBean
specification, Spring can manage it as well.
With XML-based configuration metadata you can specify your bean class as follows:
For details about the mechanism for supplying arguments to the constructor (if required) and
setting object instance properties after the object is constructed, see Injecting Dependencies.
Instantiation with a Static Factory Method
When defining a bean that you create with a static factory method, use the class attribute to specify
the class that contains the static factory method and an attribute named factory-method to specify
the name of the factory method itself. You should be able to call this method (with optional
arguments, as described later) and return a live object, which subsequently is treated as if it had
been created through a constructor. One use for such a bean definition is to call static factories in
legacy code.
The following bean definition specifies that the bean will be created by calling a factory method.
The definition does not specify the type (class) of the returned object, but rather the class
containing the factory method. In this example, the createInstance() method must be a static
method. The following example shows how to specify a factory method:
The following example shows a class that would work with the preceding bean definition:
Java
public class ClientService {
private static ClientService clientService = new ClientService();
private ClientService() {}
public static ClientService createInstance() {
return clientService;
}
}
Kotlin
class ClientService private constructor() {
companion object {
private val clientService = ClientService()
@JvmStatic
fun createInstance() = clientService
}
}
For details about the mechanism for supplying (optional) arguments to the factory method and
setting object instance properties after the object is returned from the factory, see Dependencies
and Configuration in Detail.
Instantiation by Using an Instance Factory Method
Similar to instantiation through a static factory method, instantiation with an instance factory
method invokes a non-static method of an existing bean from the container to create a new bean.
To use this mechanism, leave the class attribute empty and, in the factory-bean attribute, specify
the name of a bean in the current (or parent or ancestor) container that contains the instance
method that is to be invoked to create the object. Set the name of the factory method itself with the
factory-method attribute. The following example shows how to configure such a bean:
The following example shows the corresponding class:
Java
public class DefaultServiceLocator {
private static ClientService clientService = new ClientServiceImpl();
public ClientService createClientServiceInstance() {
return clientService;
}
}
Kotlin
class DefaultServiceLocator {
companion object {
private val clientService = ClientServiceImpl()
}
fun createClientServiceInstance(): ClientService {
return clientService
}
}
One factory class can also hold more than one factory method, as the following example shows:
The following example shows the corresponding class:
Java
public class DefaultServiceLocator {
private static ClientService clientService = new ClientServiceImpl();
private static AccountService accountService = new AccountServiceImpl();
public ClientService createClientServiceInstance() {
return clientService;
}
public AccountService createAccountServiceInstance() {
return accountService;
}
}
Kotlin
class DefaultServiceLocator {
companion object {
private val clientService = ClientServiceImpl()
private val accountService = AccountServiceImpl()
}
fun createClientServiceInstance(): ClientService {
return clientService
}
fun createAccountServiceInstance(): AccountService {
return accountService
}
}
This approach shows that the factory bean itself can be managed and configured through
dependency injection (DI). See Dependencies and Configuration in Detail.
In Spring documentation, "factory bean" refers to a bean that is configured in the
Spring container and that creates objects through an instance or static factory
method. By contrast, FactoryBean (notice the capitalization) refers to a Spring-
specific FactoryBean implementation class.
Determining a Bean’s Runtime Type
The runtime type of a specific bean is non-trivial to determine. A specified class in the bean
metadata definition is just an initial class reference, potentially combined with a declared factory
method or being a FactoryBean class which may lead to a different runtime type of the bean, or not
being set at all in case of an instance-level factory method (which is resolved via the specified
factory-bean name instead). Additionally, AOP proxying may wrap a bean instance with an
interface-based proxy with limited exposure of the target bean’s actual type (just its implemented
interfaces).
The recommended way to find out about the actual runtime type of a particular bean is a
BeanFactory.getType call for the specified bean name. This takes all of the above cases into account
and returns the type of object that a BeanFactory.getBean call is going to return for the same bean
name.
2.1.4. Dependencies
A typical enterprise application does not consist of a single object (or bean in the Spring parlance).
Even the simplest application has a few objects that work together to present what the end-user
sees as a coherent application. This next section explains how you go from defining a number of
bean definitions that stand alone to a fully realized application where objects collaborate to achieve
a goal.
Dependency Injection
Dependency injection (DI) is a process whereby objects define their dependencies (that is, the other
objects with which they work) only through constructor arguments, arguments to a factory method,
or properties that are set on the object instance after it is constructed or returned from a factory
method. The container then injects those dependencies when it creates the bean. This process is
fundamentally the inverse (hence the name, Inversion of Control) of the bean itself controlling the
instantiation or location of its dependencies on its own by using direct construction of classes or the
Service Locator pattern.
Code is cleaner with the DI principle, and decoupling is more effective when objects are provided
with their dependencies. The object does not look up its dependencies and does not know the
location or class of the dependencies. As a result, your classes become easier to test, particularly
when the dependencies are on interfaces or abstract base classes, which allow for stub or mock
implementations to be used in unit tests.
DI exists in two major variants: Constructor-based dependency injection and Setter-based
dependency injection.
Constructor-based Dependency Injection
Constructor-based DI is accomplished by the container invoking a constructor with a number of
arguments, each representing a dependency. Calling a static factory method with specific
arguments to construct the bean is nearly equivalent, and this discussion treats arguments to a
constructor and to a static factory method similarly. The following example shows a class that can
only be dependency-injected with constructor injection:
Java
public class SimpleMovieLister {
// the SimpleMovieLister has a dependency on a MovieFinder
private final MovieFinder movieFinder;
// a constructor so that the Spring container can inject a MovieFinder
public SimpleMovieLister(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// business logic that actually uses the injected MovieFinder is omitted...
}
Kotlin
// a constructor so that the Spring container can inject a MovieFinder
class SimpleMovieLister(private val movieFinder: MovieFinder) {
// business logic that actually uses the injected MovieFinder is omitted...
}
Notice that there is nothing special about this class. It is a POJO that has no dependencies on
container specific interfaces, base classes, or annotations.
Constructor Argument Resolution
Constructor argument resolution matching occurs by using the argument’s type. If no potential
ambiguity exists in the constructor arguments of a bean definition, the order in which the
constructor arguments are defined in a bean definition is the order in which those arguments are
supplied to the appropriate constructor when the bean is being instantiated. Consider the following
class:
Java
package x.y;
public class ThingOne {
public ThingOne(ThingTwo thingTwo, ThingThree thingThree) {
// ...
}
}
Kotlin
package x.y
class ThingOne(thingTwo: ThingTwo, thingThree: ThingThree)
Assuming that the ThingTwo and ThingThree classes are not related by inheritance, no potential
ambiguity exists. Thus, the following configuration works fine, and you do not need to specify the
constructor argument indexes or types explicitly in the <constructor-arg/> element.
<constructor-arg ref="beanTwo"/>
<constructor-arg ref="beanThree"/>
When another bean is referenced, the type is known, and matching can occur (as was the case with
the preceding example). When a simple type is used, such as <value>true</value>, Spring cannot
determine the type of the value, and so cannot match by type without help. Consider the following
class:
Java
package examples;
public class ExampleBean {
// Number of years to calculate the Ultimate Answer
private final int years;
// The Answer to Life, the Universe, and Everything
private final String ultimateAnswer;
public ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
}
}
Kotlin
package examples
class ExampleBean(
private val years: Int, // Number of years to calculate the Ultimate Answer
private val ultimateAnswer: String // The Answer to Life, the Universe, and
Everything
)
Constructor argument type matching
In the preceding scenario, the container can use type matching with simple types if you explicitly
specify the type of the constructor argument by using the type attribute, as the following example
shows:
<constructor-arg type="int" value="7500000"/>
<constructor-arg type="java.lang.String" value="42"/>
Constructor argument index
You can use the index attribute to specify explicitly the index of constructor arguments, as the
following example shows:
<constructor-arg index="0" value="7500000"/>
<constructor-arg index="1" value="42"/>
In addition to resolving the ambiguity of multiple simple values, specifying an index resolves
ambiguity where a constructor has two arguments of the same type.
The index is 0-based.
Constructor argument name
You can also use the constructor parameter name for value disambiguation, as the following
example shows:
<constructor-arg name="years" value="7500000"/>
<constructor-arg name="ultimateAnswer" value="42"/>
Keep in mind that, to make this work out of the box, your code must be compiled with the debug
flag enabled so that Spring can look up the parameter name from the constructor. If you cannot or
do not want to compile your code with the debug flag, you can use the @ConstructorProperties JDK
annotation to explicitly name your constructor arguments. The sample class would then have to
look as follows:
Java
package examples;
public class ExampleBean {
// Fields omitted
@ConstructorProperties({"years", "ultimateAnswer"})
public ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
}
}
Kotlin
package examples
class ExampleBean
@ConstructorProperties("years", "ultimateAnswer")
constructor(val years: Int, val ultimateAnswer: String)
Setter-based Dependency Injection
Setter-based DI is accomplished by the container calling setter methods on your beans after
invoking a no-argument constructor or a no-argument static factory method to instantiate your
bean.
The following example shows a class that can only be dependency-injected by using pure setter
injection. This class is conventional Java. It is a POJO that has no dependencies on container specific
interfaces, base classes, or annotations.
Java
public class SimpleMovieLister {
// the SimpleMovieLister has a dependency on the MovieFinder
private MovieFinder movieFinder;
// a setter method so that the Spring container can inject a MovieFinder
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// business logic that actually uses the injected MovieFinder is omitted...
}
Kotlin
class SimpleMovieLister {
// a late-initialized property so that the Spring container can inject a
MovieFinder
lateinit var movieFinder: MovieFinder
// business logic that actually uses the injected MovieFinder is omitted...
}
The ApplicationContext supports constructor-based and setter-based DI for the beans it manages. It
also supports setter-based DI after some dependencies have already been injected through the
constructor approach. You configure the dependencies in the form of a BeanDefinition, which you
use in conjunction with PropertyEditor instances to convert properties from one format to another.
However, most Spring users do not work with these classes directly (that is, programmatically) but
rather with XML bean definitions, annotated components (that is, classes annotated with @Component,
@Controller, and so forth), or @Bean methods in Java-based @Configuration classes. These sources are
then converted internally into instances of BeanDefinition and used to load an entire Spring IoC
container instance.
Constructor-based or setter-based DI?
Since you can mix constructor-based and setter-based DI, it is a good rule of thumb to use
constructors for mandatory dependencies and setter methods or configuration methods for
optional dependencies. Note that use of the @Autowired annotation on a setter method can
be used to make the property be a required dependency; however, constructor injection with
programmatic validation of arguments is preferable.
The Spring team generally advocates constructor injection, as it lets you implement
application components as immutable objects and ensures that required dependencies are
not null. Furthermore, constructor-injected components are always returned to the client
(calling) code in a fully initialized state. As a side note, a large number of constructor
arguments is a bad code smell, implying that the class likely has too many responsibilities and
should be refactored to better address proper separation of concerns.
Setter injection should primarily only be used for optional dependencies that can be assigned
reasonable default values within the class. Otherwise, not-null checks must be performed
everywhere the code uses the dependency. One benefit of setter injection is that setter
methods make objects of that class amenable to reconfiguration or re-injection later.
Management through JMX MBeans is therefore a compelling use case for setter injection.
Use the DI style that makes the most sense for a particular class. Sometimes, when dealing
with third-party classes for which you do not have the source, the choice is made for you. For
example, if a third-party class does not expose any setter methods, then constructor injection
may be the only available form of DI.
Dependency Resolution Process
The container performs bean dependency resolution as follows:
• The ApplicationContext is created and initialized with configuration metadata that describes all
the beans. Configuration metadata can be specified by XML, Java code, or annotations.
• For each bean, its dependencies are expressed in the form of properties, constructor arguments,
or arguments to the static-factory method (if you use that instead of a normal constructor).
These dependencies are provided to the bean, when the bean is actually created.
• Each property or constructor argument is an actual definition of the value to set, or a reference
to another bean in the container.
• Each property or constructor argument that is a value is converted from its specified format to
the actual type of that property or constructor argument. By default, Spring can convert a value
supplied in string format to all built-in types, such as int, long, String, boolean, and so forth.
The Spring container validates the configuration of each bean as the container is created. However,
the bean properties themselves are not set until the bean is actually created. Beans that are
singleton-scoped and set to be pre-instantiated (the default) are created when the container is
created. Scopes are defined in Bean Scopes. Otherwise, the bean is created only when it is
requested. Creation of a bean potentially causes a graph of beans to be created, as the bean’s
dependencies and its dependencies' dependencies (and so on) are created and assigned. Note that
resolution mismatches among those dependencies may show up late — that is, on first creation of
the affected bean.
Circular dependencies
If you use predominantly constructor injection, it is possible to create an unresolvable
circular dependency scenario.
For example: Class A requires an instance of class B through constructor injection, and class B
requires an instance of class A through constructor injection. If you configure beans for
classes A and B to be injected into each other, the Spring IoC container detects this circular
reference at runtime, and throws a BeanCurrentlyInCreationException.
One possible solution is to edit the source code of some classes to be configured by setters
rather than constructors. Alternatively, avoid constructor injection and use setter injection
only. In other words, although it is not recommended, you can configure circular
dependencies with setter injection.
Unlike the typical case (with no circular dependencies), a circular dependency between bean
A and bean B forces one of the beans to be injected into the other prior to being fully
initialized itself (a classic chicken-and-egg scenario).
You can generally trust Spring to do the right thing. It detects configuration problems, such as
references to non-existent beans and circular dependencies, at container load-time. Spring sets
properties and resolves dependencies as late as possible, when the bean is actually created. This
means that a Spring container that has loaded correctly can later generate an exception when you
request an object if there is a problem creating that object or one of its dependencies — for
example, the bean throws an exception as a result of a missing or invalid property. This potentially
delayed visibility of some configuration issues is why ApplicationContext implementations by
default pre-instantiate singleton beans. At the cost of some upfront time and memory to create
these beans before they are actually needed, you discover configuration issues when the
ApplicationContext is created, not later. You can still override this default behavior so that singleton
beans initialize lazily, rather than being eagerly pre-instantiated.
If no circular dependencies exist, when one or more collaborating beans are being injected into a
dependent bean, each collaborating bean is totally configured prior to being injected into the
dependent bean. This means that, if bean A has a dependency on bean B, the Spring IoC container
completely configures bean B prior to invoking the setter method on bean A. In other words, the
bean is instantiated (if it is not a pre-instantiated singleton), its dependencies are set, and the
relevant lifecycle methods (such as a configured init method or the InitializingBean callback
method) are invoked.
Examples of Dependency Injection
The following example uses XML-based configuration metadata for setter-based DI. A small part of
a Spring XML configuration file specifies some bean definitions as follows:
<ref bean="anotherExampleBean"/>
The following example shows the corresponding ExampleBean class:
Java
public class ExampleBean {
private AnotherBean beanOne;
private YetAnotherBean beanTwo;
private int i;
public void setBeanOne(AnotherBean beanOne) {
this.beanOne = beanOne;
}
public void setBeanTwo(YetAnotherBean beanTwo) {
this.beanTwo = beanTwo;
}
public void setIntegerProperty(int i) {
this.i = i;
}
}
Kotlin
class ExampleBean {
lateinit var beanOne: AnotherBean
lateinit var beanTwo: YetAnotherBean
var i: Int = 0
}
In the preceding example, setters are declared to match against the properties specified in the XML
file. The following example uses constructor-based DI:
<constructor-arg>
<ref bean="anotherExampleBean"/>
</constructor-arg>
<constructor-arg ref="yetAnotherBean"/>
<constructor-arg type="int" value="1"/>
The following example shows the corresponding ExampleBean class:
Java
public class ExampleBean {
private AnotherBean beanOne;
private YetAnotherBean beanTwo;
private int i;
public ExampleBean(
AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
this.beanOne = anotherBean;
this.beanTwo = yetAnotherBean;
this.i = i;
}
}
Kotlin
class ExampleBean(
private val beanOne: AnotherBean,
private val beanTwo: YetAnotherBean,
private val i: Int)
The constructor arguments specified in the bean definition are used as arguments to the
constructor of the ExampleBean.
Now consider a variant of this example, where, instead of using a constructor, Spring is told to call
a static factory method to return an instance of the object:
<constructor-arg ref="anotherExampleBean"/>
<constructor-arg ref="yetAnotherBean"/>
<constructor-arg value="1"/>
The following example shows the corresponding ExampleBean class:
Java
public class ExampleBean {
// a private constructor
private ExampleBean(...) {
...
}
// a static factory method; the arguments to this method can be
// considered the dependencies of the bean that is returned,
// regardless of how those arguments are actually used.
public static ExampleBean createInstance (
AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
ExampleBean eb = new ExampleBean (...);
// some other operations...
return eb;
}
}
Kotlin
class ExampleBean private constructor() {
companion object {
// a static factory method; the arguments to this method can be
// considered the dependencies of the bean that is returned,
// regardless of how those arguments are actually used.
@JvmStatic
fun createInstance(anotherBean: AnotherBean, yetAnotherBean: YetAnotherBean,
i: Int): ExampleBean {
val eb = ExampleBean (...)
// some other operations...
return eb
}
}
}
Arguments to the static factory method are supplied by <constructor-arg/> elements, exactly the
same as if a constructor had actually been used. The type of the class being returned by the factory
method does not have to be of the same type as the class that contains the static factory method
(although, in this example, it is). An instance (non-static) factory method can be used in an
essentially identical fashion (aside from the use of the factory-bean attribute instead of the class
attribute), so we do not discuss those details here.
Dependencies and Configuration in Detail
As mentioned in the previous section, you can define bean properties and constructor arguments as
references to other managed beans (collaborators) or as values defined inline. Spring’s XML-based
configuration metadata supports sub-element types within its and <constructor-arg/>
elements for this purpose.
Straight Values (Primitives, Strings, and so on)
The value attribute of the element specifies a property or constructor argument as a
human-readable string representation. Spring’s conversion service is used to convert these values
from a String to the actual type of the property or argument. The following example shows various
values being set:
The following example uses the p-namespace for even more succinct XML configuration:
The preceding XML is more succinct. However, typos are discovered at runtime rather than design
time, unless you use an IDE (such as IntelliJ IDEA or the Spring Tools for Eclipse) that supports
automatic property completion when you create bean definitions. Such IDE assistance is highly
recommended.
You can also configure a java.util.Properties instance, as follows:
<value>
jdbc.driver.className=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mydb
</value>
The Spring container converts the text inside the <value/> element into a java.util.Properties
instance by using the JavaBeans PropertyEditor mechanism. This is a nice shortcut, and is one of a
few places where the Spring team do favor the use of the nested <value/> element over the value
attribute style.
The idref element
The idref element is simply an error-proof way to pass the id (a string value - not a reference) of
another bean in the container to a <constructor-arg/> or element. The following
example shows how to use it:
The preceding bean definition snippet is exactly equivalent (at runtime) to the following snippet:
The first form is preferable to the second, because using the idref tag lets the container validate at
deployment time that the referenced, named bean actually exists. In the second variation, no
validation is performed on the value that is passed to the targetName property of the client bean.
Typos are only discovered (with most likely fatal results) when the client bean is actually
instantiated. If the client bean is a prototype bean, this typo and the resulting exception may only
be discovered long after the container is deployed.
The local attribute on the idref element is no longer supported in the 4.0 beans
XSD, since it does not provide value over a regular bean reference any more.
Change your existing idref local references to idref bean when upgrading to the
4.0 schema.
A common place (at least in versions earlier than Spring 2.0) where the element brings
value is in the configuration of AOP interceptors in a ProxyFactoryBean bean definition. Using
elements when you specify the interceptor names prevents you from misspelling an
interceptor ID.
References to Other Beans (Collaborators)
The ref element is the final element inside a <constructor-arg/> or definition element.
Here, you set the value of the specified property of a bean to be a reference to another bean (a
collaborator) managed by the container. The referenced bean is a dependency of the bean whose
property is to be set, and it is initialized on demand as needed before the property is set. (If the
collaborator is a singleton bean, it may already be initialized by the container.) All references are
ultimately a reference to another object. Scoping and validation depend on whether you specify the
ID or name of the other object through the bean or parent attribute.
Specifying the target bean through the bean attribute of the <ref/> tag is the most general form and
allows creation of a reference to any bean in the same container or parent container, regardless of
whether it is in the same XML file. The value of the bean attribute may be the same as the id
attribute of the target bean or be the same as one of the values in the name attribute of the target
bean. The following example shows how to use a ref element:
<ref bean="someBean"/>
Specifying the target bean through the parent attribute creates a reference to a bean that is in a
parent container of the current container. The value of the parent attribute may be the same as
either the id attribute of the target bean or one of the values in the name attribute of the target bean.
The target bean must be in a parent container of the current one. You should use this bean
reference variant mainly when you have a hierarchy of containers and you want to wrap an
existing bean in a parent container with a proxy that has the same name as the parent bean. The
following pair of listings shows how to use the parent attribute:
<ref parent="accountService"/>
The local attribute on the ref element is no longer supported in the 4.0 beans XSD,
since it does not provide value over a regular bean reference any more. Change
your existing ref local references to ref bean when upgrading to the 4.0 schema.
Inner Beans
A element inside the or <constructor-arg/> elements defines an inner bean, as
the following example shows:
An inner bean definition does not require a defined ID or name. If specified, the container does not
use such a value as an identifier. The container also ignores the scope flag on creation, because
inner beans are always anonymous and are always created with the outer bean. It is not possible to
access inner beans independently or to inject them into collaborating beans other than into the
enclosing bean.
As a corner case, it is possible to receive destruction callbacks from a custom scope — for example,
for a request-scoped inner bean contained within a singleton bean. The creation of the inner bean
instance is tied to its containing bean, but destruction callbacks let it participate in the request
scope’s lifecycle. This is not a common scenario. Inner beans typically simply share their containing
bean’s scope.
Collections
The <list/>, <set/>, <map/>, and elements set the properties and arguments of the Java
Collection types List, Set, Map, and Properties, respectively. The following example shows how to
use them:
[email protected]
[email protected]
[email protected]
<list>
<value>a list element followed by a reference</value>
<ref bean="myDataSource" />
</list>
<map>
<entry key="an entry" value="just some string"/>
<entry key="a ref" value-ref="myDataSource"/>
</map>
<set>
<value>just some string</value>
<ref bean="myDataSource" />
</set>
The value of a map key or value, or a set value, can also be any of the following elements:
bean | ref | idref | list | set | map | props | value | null
Collection Merging
The Spring container also supports merging collections. An application developer can define a
parent <list/>, <map/>, <set/> or element and have child <list/>, <map/>, <set/> or
elements inherit and override values from the parent collection. That is, the child collection’s
values are the result of merging the elements of the parent and child collections, with the child’s
collection elements overriding values specified in the parent collection.
This section on merging discusses the parent-child bean mechanism. Readers unfamiliar with
parent and child bean definitions may wish to read the relevant section before continuing.
The following example demonstrates collection merging:
[email protected]
[email protected]
[email protected]
[email protected]
Notice the use of the merge=true attribute on the element of the adminEmails property of the
child bean definition. When the child bean is resolved and instantiated by the container, the
resulting instance has an adminEmails Properties collection that contains the result of merging the
child’s adminEmails collection with the parent’s adminEmails collection. The following listing shows
the result:
[email protected]
[email protected]
[email protected]
The child Properties collection’s value set inherits all property elements from the parent ,
and the child’s value for the support value overrides the value in the parent collection.
This merging behavior applies similarly to the <list/>, <map/>, and <set/> collection types. In the
specific case of the <list/> element, the semantics associated with the List collection type (that is,
the notion of an ordered collection of values) is maintained. The parent’s values precede all of the
child list’s values. In the case of the Map, Set, and Properties collection types, no ordering exists.
Hence, no ordering semantics are in effect for the collection types that underlie the associated Map,
Set, and Properties implementation types that the container uses internally.
Limitations of Collection Merging
You cannot merge different collection types (such as a Map and a List). If you do attempt to do so, an
appropriate Exception is thrown. The merge attribute must be specified on the lower, inherited, child
definition. Specifying the merge attribute on a parent collection definition is redundant and does not
result in the desired merging.
Strongly-typed collection
Thanks to Java’s support for generic types, you can use strongly typed collections. That is, it is
possible to declare a Collection type such that it can only contain (for example) String elements. If
you use Spring to dependency-inject a strongly-typed Collection into a bean, you can take
advantage of Spring’s type-conversion support such that the elements of your strongly-typed
Collection instances are converted to the appropriate type prior to being added to the Collection.
The following Java class and bean definition show how to do so:
Java
public class SomeClass {
private Map<String, Float> accounts;
public void setAccounts(Map<String, Float> accounts) {
this.accounts = accounts;
}
}
Kotlin
class SomeClass {
lateinit var accounts: Map<String, Float>
}
<map>
<entry key="one" value="9.99"/>
<entry key="two" value="2.75"/>
<entry key="six" value="3.99"/>
</map>
When the accounts property of the something bean is prepared for injection, the generics
information about the element type of the strongly-typed Map<String, Float> is available by
reflection. Thus, Spring’s type conversion infrastructure recognizes the various value elements as
being of type Float, and the string values (9.99, 2.75, and 3.99) are converted into an actual Float
type.
Null and Empty String Values
Spring treats empty arguments for properties and the like as empty Strings. The following XML-
based configuration metadata snippet sets the email property to the empty String value ("").
The preceding example is equivalent to the following Java code:
Java
exampleBean.setEmail("");
Kotlin
exampleBean.email = ""
The <null/> element handles null values. The following listing shows an example:
<null/>
The preceding configuration is equivalent to the following Java code:
Java
exampleBean.setEmail(null);
Kotlin
exampleBean.email = null
XML Shortcut with the p-namespace
The p-namespace lets you use the bean element’s attributes (instead of nested elements)
to describe your property values collaborating beans, or both.
Spring supports extensible configuration formats with namespaces, which are based on an XML
Schema definition. The beans configuration format discussed in this chapter is defined in an XML
Schema document. However, the p-namespace is not defined in an XSD file and exists only in the
core of Spring.
The following example shows two XML snippets (the first uses standard XML format and the
second uses the p-namespace) that resolve to the same result:
The example shows an attribute in the p-namespace called email in the bean definition. This tells
Spring to include a property declaration. As previously mentioned, the p-namespace does not have
a schema definition, so you can set the name of the attribute to the property name.
This next example includes two more bean definitions that both have a reference to another bean:
This example includes not only a property value using the p-namespace but also uses a special
format to declare property references. Whereas the first bean definition uses to create a reference from bean john to bean jane, the second bean
definition uses p:spouse-ref="jane" as an attribute to do the exact same thing. In this case, spouse is
the property name, whereas the -ref part indicates that this is not a straight value but rather a
reference to another bean.
The p-namespace is not as flexible as the standard XML format. For example, the
format for declaring property references clashes with properties that end in Ref,
whereas the standard XML format does not. We recommend that you choose your
approach carefully and communicate this to your team members to avoid
producing XML documents that use all three approaches at the same time.
XML Shortcut with the c-namespace
Similar to the XML Shortcut with the p-namespace, the c-namespace, introduced in Spring 3.1,
allows inlined attributes for configuring the constructor arguments rather then nested constructor-
arg elements.
The following example uses the c: namespace to do the same thing as the from Constructor-based
Dependency Injection:
<constructor-arg name="thingTwo" ref="beanTwo"/>
<constructor-arg name="thingThree" ref="beanThree"/>
<constructor-arg name="email" value="[email protected]"/>
The c: namespace uses the same conventions as the p: one (a trailing -ref for bean references) for
setting the constructor arguments by their names. Similarly, it needs to be declared in the XML file
even though it is not defined in an XSD schema (it exists inside the Spring core).
For the rare cases where the constructor argument names are not available (usually if the bytecode
was compiled without debugging information), you can use fallback to the argument indexes, as
follows:
Due to the XML grammar, the index notation requires the presence of the leading
_, as XML attribute names cannot start with a number (even though some IDEs
allow it). A corresponding index notation is also available for <constructor-arg>
elements but not commonly used since the plain order of declaration is usually
sufficient there.
In practice, the constructor resolution mechanism is quite efficient in matching arguments, so
unless you really need to, we recommend using the name notation throughout your configuration.
Compound Property Names
You can use compound or nested property names when you set bean properties, as long as all
components of the path except the final property name are not null. Consider the following bean
definition:
The something bean has a fred property, which has a bob property, which has a sammy property, and
that final sammy property is being set to a value of 123. In order for this to work, the fred property of
something and the bob property of fred must not be null after the bean is constructed. Otherwise, a
NullPointerException is thrown.
Using depends-on
If a bean is a dependency of another bean, that usually means that one bean is set as a property of
another. Typically you accomplish this with the <ref/> element in XML-based configuration
metadata. However, sometimes dependencies between beans are less direct. An example is when a
static initializer in a class needs to be triggered, such as for database driver registration. The
depends-on attribute can explicitly force one or more beans to be initialized before the bean using
this element is initialized. The following example uses the depends-on attribute to express a
dependency on a single bean:
To express a dependency on multiple beans, supply a list of bean names as the value of the depends-
on attribute (commas, whitespace, and semicolons are valid delimiters):
The depends-on attribute can specify both an initialization-time dependency and, in
the case of singleton beans only, a corresponding destruction-time dependency.
Dependent beans that define a depends-on relationship with a given bean are
destroyed first, prior to the given bean itself being destroyed. Thus, depends-on can
also control shutdown order.
Lazy-initialized Beans
By default, ApplicationContext implementations eagerly create and configure all singleton beans as
part of the initialization process. Generally, this pre-instantiation is desirable, because errors in the
configuration or surrounding environment are discovered immediately, as opposed to hours or
even days later. When this behavior is not desirable, you can prevent pre-instantiation of a
singleton bean by marking the bean definition as being lazy-initialized. A lazy-initialized bean tells
the IoC container to create a bean instance when it is first requested, rather than at startup.
In XML, this behavior is controlled by the lazy-init attribute on the element, as the
following example shows:
When the preceding configuration is consumed by an ApplicationContext, the lazy bean is not
eagerly pre-instantiated when the ApplicationContext starts, whereas the not.lazy bean is eagerly
pre-instantiated.
However, when a lazy-initialized bean is a dependency of a singleton bean that is not lazy-
initialized, the ApplicationContext creates the lazy-initialized bean at startup, because it must
satisfy the singleton’s dependencies. The lazy-initialized bean is injected into a singleton bean
elsewhere that is not lazy-initialized.
You can also control lazy-initialization at the container level by using the default-lazy-init
attribute on the element, as the following example shows:
Autowiring Collaborators
The Spring container can autowire relationships between collaborating beans. You can let Spring
resolve collaborators (other beans) automatically for your bean by inspecting the contents of the
ApplicationContext. Autowiring has the following advantages:
• Autowiring can significantly reduce the need to specify properties or constructor arguments.
(Other mechanisms such as a bean template discussed elsewhere in this chapter are also
valuable in this regard.)
• Autowiring can update a configuration as your objects evolve. For example, if you need to add a
dependency to a class, that dependency can be satisfied automatically without you needing to
modify the configuration. Thus autowiring can be especially useful during development,
without negating the option of switching to explicit wiring when the code base becomes more
stable.
When using XML-based configuration metadata (see Dependency Injection), you can specify the
autowire mode for a bean definition with the autowire attribute of the element. The
autowiring functionality has four modes. You specify autowiring per bean and can thus choose
which ones to autowire. The following table describes the four autowiring modes:
Table 2. Autowiring modes
Mode Explanation
no (Default) No autowiring. Bean references must be defined by ref elements.
Changing the default setting is not recommended for larger deployments,
because specifying collaborators explicitly gives greater control and clarity. To
some extent, it documents the structure of a system.
byName Autowiring by property name. Spring looks for a bean with the same name as
the property that needs to be autowired. For example, if a bean definition is
set to autowire by name and it contains a master property (that is, it has a
setMaster(..) method), Spring looks for a bean definition named master and
uses it to set the property.
byType Lets a property be autowired if exactly one bean of the property type exists in
the container. If more than one exists, a fatal exception is thrown, which
indicates that you may not use byType autowiring for that bean. If there are no
matching beans, nothing happens (the property is not set).
constructor Analogous to byType but applies to constructor arguments. If there is not
exactly one bean of the constructor argument type in the container, a fatal
error is raised.
With byType or constructor autowiring mode, you can wire arrays and typed collections. In such
cases, all autowire candidates within the container that match the expected type are provided to
satisfy the dependency. You can autowire strongly-typed Map instances if the expected key type is
String. An autowired Map instance’s values consist of all bean instances that match the expected
type, and the Map instance’s keys contain the corresponding bean names.
Limitations and Disadvantages of Autowiring
Autowiring works best when it is used consistently across a project. If autowiring is not used in
general, it might be confusing to developers to use it to wire only one or two bean definitions.
Consider the limitations and disadvantages of autowiring:
• Explicit dependencies in property and constructor-arg settings always override autowiring. You
cannot autowire simple properties such as primitives, Strings, and Classes (and arrays of such
simple properties). This limitation is by-design.
• Autowiring is less exact than explicit wiring. Although, as noted in the earlier table, Spring is
careful to avoid guessing in case of ambiguity that might have unexpected results. The
relationships between your Spring-managed objects are no longer documented explicitly.
• Wiring information may not be available to tools that may generate documentation from a
Spring container.
• Multiple bean definitions within the container may match the type specified by the setter
method or constructor argument to be autowired. For arrays, collections, or Map instances, this is
not necessarily a problem. However, for dependencies that expect a single value, this ambiguity
is not arbitrarily resolved. If no unique bean definition is available, an exception is thrown.
In the latter scenario, you have several options:
• Abandon autowiring in favor of explicit wiring.
• Avoid autowiring for a bean definition by setting its autowire-candidate attributes to false, as
described in the next section.
• Designate a single bean definition as the primary candidate by setting the primary attribute of its
element to true.
• Implement the more fine-grained control available with annotation-based configuration, as
described in Annotation-based Container Configuration.
Excluding a Bean from Autowiring
On a per-bean basis, you can exclude a bean from autowiring. In Spring’s XML format, set the
autowire-candidate attribute of the element to false. The container makes that specific bean
definition unavailable to the autowiring infrastructure (including annotation style configurations
such as @Autowired).
The autowire-candidate attribute is designed to only affect type-based autowiring.
It does not affect explicit references by name, which get resolved even if the
specified bean is not marked as an autowire candidate. As a consequence,
autowiring by name nevertheless injects a bean if the name matches.
You can also limit autowire candidates based on pattern-matching against bean names. The top-
level element accepts one or more patterns within its default-autowire-candidates
attribute. For example, to limit autowire candidate status to any bean whose name ends with
Repository, provide a value of *Repository. To provide multiple patterns, define them in a comma-
separated list. An explicit value of true or false for a bean definition’s autowire-candidate attribute
always takes precedence. For such beans, the pattern matching rules do not apply.
These techniques are useful for beans that you never want to be injected into other beans by
autowiring. It does not mean that an excluded bean cannot itself be configured by using
autowiring. Rather, the bean itself is not a candidate for autowiring other beans.
Method Injection
In most application scenarios, most beans in the container are singletons. When a singleton bean
needs to collaborate with another singleton bean or a non-singleton bean needs to collaborate with
another non-singleton bean, you typically handle the dependency by defining one bean as a
property of the other. A problem arises when the bean lifecycles are different. Suppose singleton
bean A needs to use non-singleton (prototype) bean B, perhaps on each method invocation on A.
The container creates the singleton bean A only once, and thus only gets one opportunity to set the
properties. The container cannot provide bean A with a new instance of bean B every time one is
needed.
A solution is to forego some inversion of control. You can make bean A aware of the container by
implementing the ApplicationContextAware interface, and by making a getBean("B") call to the
container ask for (a typically new) bean B instance every time bean A needs it. The following
example shows this approach:
Java
// a class that uses a stateful Command-style class to perform some processing
package fiona.apple;
// Spring-API imports
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class CommandManager implements ApplicationContextAware {
private ApplicationContext applicationContext;
public Object process(Map commandState) {
// grab a new instance of the appropriate Command
Command command = createCommand();
// set the state on the (hopefully brand new) Command instance
command.setState(commandState);
return command.execute();
}
protected Command createCommand() {
// notice the Spring API dependency!
return this.applicationContext.getBean("command", Command.class);
}
public void setApplicationContext(
ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
Kotlin
// a class that uses a stateful Command-style class to perform some processing
package fiona.apple
// Spring-API imports
import org.springframework.context.ApplicationContext
import org.springframework.context.ApplicationContextAware
class CommandManager : ApplicationContextAware {
private lateinit var applicationContext: ApplicationContext
fun process(commandState: Map<, >): Any {
// grab a new instance of the appropriate Command
val command = createCommand()
// set the state on the (hopefully brand new) Command instance
command.state = commandState
return command.execute()
}
// notice the Spring API dependency!
protected fun createCommand() =
applicationContext.getBean("command", Command::class.java)
override fun setApplicationContext(applicationContext: ApplicationContext) {
this.applicationContext = applicationContext
}
}
The preceding is not desirable, because the business code is aware of and coupled to the Spring
Framework. Method Injection, a somewhat advanced feature of the Spring IoC container, lets you
handle this use case cleanly.
You can read more about the motivation for Method Injection in this blog entry.
Lookup Method Injection
Lookup method injection is the ability of the container to override methods on container-managed
beans and return the lookup result for another named bean in the container. The lookup typically
involves a prototype bean, as in the scenario described in the preceding section. The Spring
Framework implements this method injection by using bytecode generation from the CGLIB library
to dynamically generate a subclass that overrides the method.
• For this dynamic subclassing to work, the class that the Spring bean container
subclasses cannot be final, and the method to be overridden cannot be final,
either.
• Unit-testing a class that has an abstract method requires you to subclass the
class yourself and to supply a stub implementation of the abstract method.
• Concrete methods are also necessary for component scanning, which requires
concrete classes to pick up.
• A further key limitation is that lookup methods do not work with factory
methods and in particular not with @Bean methods in configuration classes,
since, in that case, the container is not in charge of creating the instance and
therefore cannot create a runtime-generated subclass on the fly.
In the case of the CommandManager class in the previous code snippet, the Spring container
dynamically overrides the implementation of the createCommand() method. The CommandManager class
does not have any Spring dependencies, as the reworked example shows:
Java
package fiona.apple;
// no more Spring imports!
public abstract class CommandManager {
public Object process(Object commandState) {
// grab a new instance of the appropriate Command interface
Command command = createCommand();
// set the state on the (hopefully brand new) Command instance
command.setState(commandState);
return command.execute();
}
// okay... but where is the implementation of this method?
protected abstract Command createCommand();
}
Kotlin
package fiona.apple
// no more Spring imports!
abstract class CommandManager {
fun process(commandState: Any): Any {
// grab a new instance of the appropriate Command interface
val command = createCommand()
// set the state on the (hopefully brand new) Command instance
command.state = commandState
return command.execute()
}
// okay... but where is the implementation of this method?
protected abstract fun createCommand(): Command
}
In the client class that contains the method to be injected (the CommandManager in this case), the
method to be injected requires a signature of the following form:
[abstract] <return-type> theMethodName(no-arguments);
If the method is abstract, the dynamically-generated subclass implements the method. Otherwise,
the dynamically-generated subclass overrides the concrete method defined in the original class.
Consider the following example:
<lookup-method name="createCommand" bean="myCommand"/>
The bean identified as commandManager calls its own createCommand() method whenever it needs a
new instance of the myCommand bean. You must be careful to deploy the myCommand bean as a prototype
if that is actually what is needed. If it is a singleton, the same instance of the myCommand bean is
returned each time.
Alternatively, within the annotation-based component model, you can declare a lookup method
through the @Lookup annotation, as the following example shows:
Java
public abstract class CommandManager {
public Object process(Object commandState) {
Command command = createCommand();
command.setState(commandState);
return command.execute();
}
@Lookup("myCommand")
protected abstract Command createCommand();
}
Kotlin
abstract class CommandManager {
fun process(commandState: Any): Any {
val command = createCommand()
command.state = commandState
return command.execute()
}
@Lookup("myCommand")
protected abstract fun createCommand(): Command
}
Or, more idiomatically, you can rely on the target bean getting resolved against the declared return
type of the lookup method:
Java
public abstract class CommandManager {
public Object process(Object commandState) {
Command command = createCommand();
command.setState(commandState);
return command.execute();
}
@Lookup
protected abstract Command createCommand();
}
Kotlin
abstract class CommandManager {
fun process(commandState: Any): Any {
val command = createCommand()
command.state = commandState
return command.execute()
}
@Lookup
protected abstract fun createCommand(): Command
}
Note that you should typically declare such annotated lookup methods with a concrete stub
implementation, in order for them to be compatible with Spring’s component scanning rules where
abstract classes get ignored by default. This limitation does not apply to explicitly registered or
explicitly imported bean classes.
Another way of accessing differently scoped target beans is an ObjectFactory/
Provider injection point. See Scoped Beans as Dependencies.
You may also find the ServiceLocatorFactoryBean (in the
org.springframework.beans.factory.config package) to be useful.
Arbitrary Method Replacement
A less useful form of method injection than lookup method injection is the ability to replace
arbitrary methods in a managed bean with another method implementation. You can safely skip
the rest of this section until you actually need this functionality.
With XML-based configuration metadata, you can use the replaced-method element to replace an
existing method implementation with another, for a deployed bean. Consider the following class,
which has a method called computeValue that we want to override:
Java
public class MyValueCalculator {
public String computeValue(String input) {
// some real code...
}
// some other methods...
}
Kotlin
class MyValueCalculator {
fun computeValue(input: String): String {
// some real code...
}
// some other methods...
}
A class that implements the org.springframework.beans.factory.support.MethodReplacer interface
provides the new method definition, as the following example shows:
Java
/
* meant to be used to override the existing computeValue(String)
* implementation in MyValueCalculator
*/
public class ReplacementComputeValue implements MethodReplacer {
public Object reimplement(Object o, Method m, Object[] args) throws Throwable {
// get the input value, work with it, and return a computed result
String input = (String) args[0];
...
return ...;
}
}
Kotlin
/
* meant to be used to override the existing computeValue(String)
* implementation in MyValueCalculator
*/
class ReplacementComputeValue : MethodReplacer {
override fun reimplement(obj: Any, method: Method, args: Array<out Any>): Any {
// get the input value, work with it, and return a computed result
val input = args[0] as String;
...
return ...;
}
}
The bean definition to deploy the original class and specify the method override would resemble
the following example:
<replaced-method name="computeValue" replacer="replacementComputeValue">
<arg-type>String</arg-type>
</replaced-method>
You can use one or more <arg-type/> elements within the <replaced-method/> element to indicate
the method signature of the method being overridden. The signature for the arguments is
necessary only if the method is overloaded and multiple variants exist within the class. For
convenience, the type string for an argument may be a substring of the fully qualified type name.
For example, the following all match java.lang.String:
java.lang.String
String
Str
Because the number of arguments is often enough to distinguish between each possible choice, this
shortcut can save a lot of typing, by letting you type only the shortest string that matches an
argument type.
2.1.5. Bean Scopes
When you create a bean definition, you create a recipe for creating actual instances of the class
defined by that bean definition. The idea that a bean definition is a recipe is important, because it
means that, as with a class, you can create many object instances from a single recipe.
You can control not only the various dependencies and configuration values that are to be plugged
into an object that is created from a particular bean definition but also control the scope of the
objects created from a particular bean definition. This approach is powerful and flexible, because
you can choose the scope of the objects you create through configuration instead of having to bake
in the scope of an object at the Java class level. Beans can be defined to be deployed in one of a
number of scopes. The Spring Framework supports six scopes, four of which are available only if
you use a web-aware ApplicationContext. You can also create a custom scope.
The following table describes the supported scopes:
Table 3. Bean scopes
Scope Description
singleton (Default) Scopes a single bean definition to a single object instance for each
Spring IoC container.
prototype Scopes a single bean definition to any number of object instances.
Scope Description
request Scopes a single bean definition to the lifecycle of a single HTTP request. That
is, each HTTP request has its own instance of a bean created off the back of a
single bean definition. Only valid in the context of a web-aware Spring
ApplicationContext.
session Scopes a single bean definition to the lifecycle of an HTTP Session. Only valid
in the context of a web-aware Spring ApplicationContext.
application Scopes a single bean definition to the lifecycle of a ServletContext. Only valid
in the context of a web-aware Spring ApplicationContext.
websocket Scopes a single bean definition to the lifecycle of a WebSocket. Only valid in the
context of a web-aware Spring ApplicationContext.
As of Spring 3.0, a thread scope is available but is not registered by default. For
more information, see the documentation for SimpleThreadScope. For instructions
on how to register this or any other custom scope, see Using a Custom Scope.
The Singleton Scope
Only one shared instance of a singleton bean is managed, and all requests for beans with an ID or
IDs that match that bean definition result in that one specific bean instance being returned by the
Spring container.
To put it another way, when you define a bean definition and it is scoped as a singleton, the Spring
IoC container creates exactly one instance of the object defined by that bean definition. This single
instance is stored in a cache of such singleton beans, and all subsequent requests and references
for that named bean return the cached object. The following image shows how the singleton scope
works:
Spring’s concept of a singleton bean differs from the singleton pattern as defined in the Gang of
Four (GoF) patterns book. The GoF singleton hard-codes the scope of an object such that one and
only one instance of a particular class is created per ClassLoader. The scope of the Spring singleton
is best described as being per-container and per-bean. This means that, if you define one bean for a
particular class in a single Spring container, the Spring container creates one and only one instance
of the class defined by that bean definition. The singleton scope is the default scope in Spring. To
define a bean as a singleton in XML, you can define a bean as shown in the following example:
The Prototype Scope
The non-singleton prototype scope of bean deployment results in the creation of a new bean
instance every time a request for that specific bean is made. That is, the bean is injected into
another bean or you request it through a getBean() method call on the container. As a rule, you
should use the prototype scope for all stateful beans and the singleton scope for stateless beans.
The following diagram illustrates the Spring prototype scope:
(A data access object (DAO) is not typically configured as a prototype, because a typical DAO does
not hold any conversational state. It was easier for us to reuse the core of the singleton diagram.)
The following example defines a bean as a prototype in XML:
In contrast to the other scopes, Spring does not manage the complete lifecycle of a prototype bean.
The container instantiates, configures, and otherwise assembles a prototype object and hands it to
the client, with no further record of that prototype instance. Thus, although initialization lifecycle
callback methods are called on all objects regardless of scope, in the case of prototypes, configured
destruction lifecycle callbacks are not called. The client code must clean up prototype-scoped
objects and release expensive resources that the prototype beans hold. To get the Spring container
to release resources held by prototype-scoped beans, try using a custom bean post-processor, which
holds a reference to beans that need to be cleaned up.
In some respects, the Spring container’s role in regard to a prototype-scoped bean is a replacement
for the Java new operator. All lifecycle management past that point must be handled by the client.
(For details on the lifecycle of a bean in the Spring container, see Lifecycle Callbacks.)
Singleton Beans with Prototype-bean Dependencies
When you use singleton-scoped beans with dependencies on prototype beans, be aware that
dependencies are resolved at instantiation time. Thus, if you dependency-inject a prototype-scoped
bean into a singleton-scoped bean, a new prototype bean is instantiated and then dependency-
injected into the singleton bean. The prototype instance is the sole instance that is ever supplied to
the singleton-scoped bean.
However, suppose you want the singleton-scoped bean to acquire a new instance of the prototype-
scoped bean repeatedly at runtime. You cannot dependency-inject a prototype-scoped bean into
your singleton bean, because that injection occurs only once, when the Spring container
instantiates the singleton bean and resolves and injects its dependencies. If you need a new
instance of a prototype bean at runtime more than once, see Method Injection.
Request, Session, Application, and WebSocket Scopes
The request, session, application, and websocket scopes are available only if you use a web-aware
Spring ApplicationContext implementation (such as XmlWebApplicationContext). If you use these
scopes with regular Spring IoC containers, such as the ClassPathXmlApplicationContext, an
IllegalStateException that complains about an unknown bean scope is thrown.
Initial Web Configuration
To support the scoping of beans at the request, session, application, and websocket levels (web-
scoped beans), some minor initial configuration is required before you define your beans. (This
initial setup is not required for the standard scopes: singleton and prototype.)
How you accomplish this initial setup depends on your particular Servlet environment.
If you access scoped beans within Spring Web MVC, in effect, within a request that is processed by
the Spring DispatcherServlet, no special setup is necessary. DispatcherServlet already exposes all
relevant state.
If you use a Servlet web container, with requests processed outside of Spring’s DispatcherServlet
(for example, when using JSF or Struts), you need to register the
org.springframework.web.context.request.RequestContextListener ServletRequestListener. This can
be done programmatically by using the WebApplicationInitializer interface. Alternatively, add the
following declaration to your web application’s web.xml file:
<web-app>
...
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
...
</web-app>
Alternatively, if there are issues with your listener setup, consider using Spring’s
RequestContextFilter. The filter mapping depends on the surrounding web application
configuration, so you have to change it as appropriate. The following listing shows the filter part of
a web application:
<web-app>
...
<filter>
<filter-name>requestContextFilter</filter-name>
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-
class>
</filter>
<filter-mapping>
<filter-name>requestContextFilter</filter-name>
/*
</filter-mapping>
...
</web-app>
DispatcherServlet, RequestContextListener, and RequestContextFilter all do exactly the same thing,
namely bind the HTTP request object to the Thread that is servicing that request. This makes beans
that are request- and session-scoped available further down the call chain.
Request scope
Consider the following XML configuration for a bean definition:
The Spring container creates a new instance of the LoginAction bean by using the loginAction bean
definition for each and every HTTP request. That is, the loginAction bean is scoped at the HTTP
request level. You can change the internal state of the instance that is created as much as you want,
because other instances created from the same loginAction bean definition do not see these
changes in state. They are particular to an individual request. When the request completes
processing, the bean that is scoped to the request is discarded.
When using annotation-driven components or Java configuration, the @RequestScope annotation can
be used to assign a component to the request scope. The following example shows how to do so:
Java
@RequestScope
@Component
public class LoginAction {
// ...
}
Kotlin
@RequestScope
@Component
class LoginAction {
// ...
}
Session Scope
Consider the following XML configuration for a bean definition:
The Spring container creates a new instance of the UserPreferences bean by using the
userPreferences bean definition for the lifetime of a single HTTP Session. In other words, the
userPreferences bean is effectively scoped at the HTTP Session level. As with request-scoped beans,
you can change the internal state of the instance that is created as much as you want, knowing that
other HTTP Session instances that are also using instances created from the same userPreferences
bean definition do not see these changes in state, because they are particular to an individual HTTP
Session. When the HTTP Session is eventually discarded, the bean that is scoped to that particular
HTTP Session is also discarded.
When using annotation-driven components or Java configuration, you can use the @SessionScope
annotation to assign a component to the session scope.
Java
@SessionScope
@Component
public class UserPreferences {
// ...
}
Kotlin
@SessionScope
@Component
class UserPreferences {
// ...
}
Application Scope
Consider the following XML configuration for a bean definition:
The Spring container creates a new instance of the AppPreferences bean by using the appPreferences
bean definition once for the entire web application. That is, the appPreferences bean is scoped at the
ServletContext level and stored as a regular ServletContext attribute. This is somewhat similar to a
Spring singleton bean but differs in two important ways: It is a singleton per ServletContext, not per
Spring ApplicationContext (for which there may be several in any given web application), and it is
actually exposed and therefore visible as a ServletContext attribute.
When using annotation-driven components or Java configuration, you can use the
@ApplicationScope annotation to assign a component to the application scope. The following
example shows how to do so:
Java
@ApplicationScope
@Component
public class AppPreferences {
// ...
}
Kotlin
@ApplicationScope
@Component
class AppPreferences {
// ...
}
WebSocket Scope
WebSocket scope is associated with the lifecycle of a WebSocket session and applies to STOMP over
WebSocket applications, see WebSocket scope for more details.
Scoped Beans as Dependencies
The Spring IoC container manages not only the instantiation of your objects (beans), but also the
wiring up of collaborators (or dependencies). If you want to inject (for example) an HTTP request-
scoped bean into another bean of a longer-lived scope, you may choose to inject an AOP proxy in
place of the scoped bean. That is, you need to inject a proxy object that exposes the same public
interface as the scoped object but that can also retrieve the real target object from the relevant
scope (such as an HTTP request) and delegate method calls onto the real object.
You may also use <aop:scoped-proxy/> between beans that are scoped as singleton,
with the reference then going through an intermediate proxy that is serializable
and therefore able to re-obtain the target singleton bean on deserialization.
When declaring <aop:scoped-proxy/> against a bean of scope prototype, every
method call on the shared proxy leads to the creation of a new target instance to
which the call is then being forwarded.
Also, scoped proxies are not the only way to access beans from shorter scopes in a
lifecycle-safe fashion. You may also declare your injection point (that is, the
constructor or setter argument or autowired field) as ObjectFactory<MyTargetBean>,
allowing for a getObject() call to retrieve the current instance on demand every
time it is needed — without holding on to the instance or storing it separately.
As an extended variant, you may declare ObjectProvider<MyTargetBean> which
delivers several additional access variants, including getIfAvailable and
getIfUnique.
The JSR-330 variant of this is called Provider and is used with a
Provider<MyTargetBean> declaration and a corresponding get() call for every
retrieval attempt. See here for more details on JSR-330 overall.
The configuration in the following example is only one line, but it is important to understand the
“why” as well as the “how” behind it:
<?xml version="1.0" encoding="UTF-8"?>
<aop:scoped-proxy/> ①
① The line that defines the proxy.
To create such a proxy, you insert a child <aop:scoped-proxy/> element into a scoped bean definition
(see Choosing the Type of Proxy to Create and XML Schema-based configuration). Why do
definitions of beans scoped at the request, session and custom-scope levels require the <aop:scoped-
proxy/> element? Consider the following singleton bean definition and contrast it with what you
need to define for the aforementioned scopes (note that the following userPreferences bean
definition as it stands is incomplete):
In the preceding example, the singleton bean (userManager) is injected with a reference to the HTTP
Session-scoped bean (userPreferences). The salient point here is that the userManager bean is a
singleton: it is instantiated exactly once per container, and its dependencies (in this case only one,
the userPreferences bean) are also injected only once. This means that the userManager bean
operates only on the exact same userPreferences object (that is, the one with which it was originally
injected).
This is not the behavior you want when injecting a shorter-lived scoped bean into a longer-lived
scoped bean (for example, injecting an HTTP Session-scoped collaborating bean as a dependency
into singleton bean). Rather, you need a single userManager object, and, for the lifetime of an HTTP
Session, you need a userPreferences object that is specific to the HTTP Session. Thus, the container
creates an object that exposes the exact same public interface as the UserPreferences class (ideally
an object that is a UserPreferences instance), which can fetch the real UserPreferences object from
the scoping mechanism (HTTP request, Session, and so forth). The container injects this proxy
object into the userManager bean, which is unaware that this UserPreferences reference is a proxy. In
this example, when a UserManager instance invokes a method on the dependency-injected
UserPreferences object, it is actually invoking a method on the proxy. The proxy then fetches the
real UserPreferences object from (in this case) the HTTP Session and delegates the method
invocation onto the retrieved real UserPreferences object.
Thus, you need the following (correct and complete) configuration when injecting request- and
session-scoped beans into collaborating objects, as the following example shows:
<aop:scoped-proxy/>
Choosing the Type of Proxy to Create
By default, when the Spring container creates a proxy for a bean that is marked up with the
<aop:scoped-proxy/> element, a CGLIB-based class proxy is created.
CGLIB proxies intercept only public method calls! Do not call non-public methods
on such a proxy. They are not delegated to the actual scoped target object.
Alternatively, you can configure the Spring container to create standard JDK interface-based
proxies for such scoped beans, by specifying false for the value of the proxy-target-class attribute
of the <aop:scoped-proxy/> element. Using JDK interface-based proxies means that you do not need
additional libraries in your application classpath to affect such proxying. However, it also means
that the class of the scoped bean must implement at least one interface and that all collaborators
into which the scoped bean is injected must reference the bean through one of its interfaces. The
following example shows a proxy based on an interface:
<aop:scoped-proxy proxy-target-class="false"/>
For more detailed information about choosing class-based or interface-based proxying, see
Proxying Mechanisms.
Custom Scopes
The bean scoping mechanism is extensible. You can define your own scopes or even redefine
existing scopes, although the latter is considered bad practice and you cannot override the built-in
singleton and prototype scopes.
Creating a Custom Scope
To integrate your custom scopes into the Spring container, you need to implement the
org.springframework.beans.factory.config.Scope interface, which is described in this section. For an
idea of how to implement your own scopes, see the Scope implementations that are supplied with
the Spring Framework itself and the Scope javadoc, which explains the methods you need to
implement in more detail.
The Scope interface has four methods to get objects from the scope, remove them from the scope,
and let them be destroyed.
The session scope implementation, for example, returns the session-scoped bean (if it does not
exist, the method returns a new instance of the bean, after having bound it to the session for future
reference). The following method returns the object from the underlying scope:
Java
Object get(String name, ObjectFactory<?> objectFactory)
Kotlin
fun get(name: String, objectFactory: ObjectFactory<*>): Any
The session scope implementation, for example, removes the session-scoped bean from the
underlying session. The object should be returned, but you can return null if the object with the
specified name is not found. The following method removes the object from the underlying scope:
Java
Object remove(String name)
Kotlin
fun remove(name: String): Any
The following method registers a callback that the scope should invoke when it is destroyed or
when the specified object in the scope is destroyed:
Java
void registerDestructionCallback(String name, Runnable destructionCallback)
Kotlin
fun registerDestructionCallback(name: String, destructionCallback: Runnable)
See the javadoc or a Spring scope implementation for more information on destruction callbacks.
The following method obtains the conversation identifier for the underlying scope:
Java
String getConversationId()
Kotlin
fun getConversationId(): String
This identifier is different for each scope. For a session scoped implementation, this identifier can
be the session identifier.
Using a Custom Scope
After you write and test one or more custom Scope implementations, you need to make the Spring
container aware of your new scopes. The following method is the central method to register a new
Scope with the Spring container:
Java
void registerScope(String scopeName, Scope scope);
Kotlin
fun registerScope(scopeName: String, scope: Scope)
This method is declared on the ConfigurableBeanFactory interface, which is available through the
BeanFactory property on most of the concrete ApplicationContext implementations that ship with
Spring.
The first argument to the registerScope(..) method is the unique name associated with a scope.
Examples of such names in the Spring container itself are singleton and prototype. The second
argument to the registerScope(..) method is an actual instance of the custom Scope
implementation that you wish to register and use.
Suppose that you write your custom Scope implementation, and then register it as shown in the
next example.
The next example uses SimpleThreadScope, which is included with Spring but is not
registered by default. The instructions would be the same for your own custom
Scope implementations.
Java
Scope threadScope = new SimpleThreadScope();
beanFactory.registerScope("thread", threadScope);
Kotlin
val threadScope = SimpleThreadScope()
beanFactory.registerScope("thread", threadScope)
You can then create bean definitions that adhere to the scoping rules of your custom Scope, as
follows:
With a custom Scope implementation, you are not limited to programmatic registration of the scope.
You can also do the Scope registration declaratively, by using the CustomScopeConfigurer class, as the
following example shows:
<?xml version="1.0" encoding="UTF-8"?>
<map>
<entry key="thread">
</entry>
</map>
<aop:scoped-proxy/>
When you place <aop:scoped-proxy/> within a declaration for a FactoryBean
implementation, it is the factory bean itself that is scoped, not the object returned
from getObject().
2.1.6. Customizing the Nature of a Bean
The Spring Framework provides a number of interfaces you can use to customize the nature of a
bean. This section groups them as follows:
• Lifecycle Callbacks
• ApplicationContextAware and BeanNameAware
• Other Aware Interfaces
Lifecycle Callbacks
To interact with the container’s management of the bean lifecycle, you can implement the Spring
InitializingBean and DisposableBean interfaces. The container calls afterPropertiesSet() for the
former and destroy() for the latter to let the bean perform certain actions upon initialization and
destruction of your beans.
The JSR-250 @PostConstruct and @PreDestroy annotations are generally considered
best practice for receiving lifecycle callbacks in a modern Spring application. Using
these annotations means that your beans are not coupled to Spring-specific
interfaces. For details, see Using @PostConstruct and @PreDestroy.
If you do not want to use the JSR-250 annotations but you still want to remove
coupling, consider init-method and destroy-method bean definition metadata.
Internally, the Spring Framework uses BeanPostProcessor implementations to process any callback
interfaces it can find and call the appropriate methods. If you need custom features or other
lifecycle behavior Spring does not by default offer, you can implement a BeanPostProcessor yourself.
For more information, see Container Extension Points.
In addition to the initialization and destruction callbacks, Spring-managed objects may also
implement the Lifecycle interface so that those objects can participate in the startup and shutdown
process, as driven by the container’s own lifecycle.
The lifecycle callback interfaces are described in this section.
Initialization Callbacks
The org.springframework.beans.factory.InitializingBean interface lets a bean perform
initialization work after the container has set all necessary properties on the bean. The
InitializingBean interface specifies a single method:
void afterPropertiesSet() throws Exception;
We recommend that you do not use the InitializingBean interface, because it unnecessarily couples
the code to Spring. Alternatively, we suggest using the @PostConstruct annotation or specifying a
POJO initialization method. In the case of XML-based configuration metadata, you can use the init-
method attribute to specify the name of the method that has a void no-argument signature. With
Java configuration, you can use the initMethod attribute of @Bean. See Receiving Lifecycle Callbacks.
Consider the following example:
Java
public class ExampleBean {
public void init() {
// do some initialization work
}
}
Kotlin
class ExampleBean {
fun init() {
// do some initialization work
}
}
The preceding example has almost exactly the same effect as the following example (which consists
of two listings):
Java
public class AnotherExampleBean implements InitializingBean {
@Override
public void afterPropertiesSet() {
// do some initialization work
}
}
Kotlin
class AnotherExampleBean : InitializingBean {
override fun afterPropertiesSet() {
// do some initialization work
}
}
However, the first of the two preceding examples does not couple the code to Spring.
Destruction Callbacks
Implementing the org.springframework.beans.factory.DisposableBean interface lets a bean get a
callback when the container that contains it is destroyed. The DisposableBean interface specifies a
single method:
void destroy() throws Exception;
We recommend that you do not use the DisposableBean callback interface, because it unnecessarily
couples the code to Spring. Alternatively, we suggest using the @PreDestroy annotation or specifying
a generic method that is supported by bean definitions. With XML-based configuration metadata,
you can use the destroy-method attribute on the . With Java configuration, you can use the
destroyMethod attribute of @Bean. See Receiving Lifecycle Callbacks. Consider the following
definition:
Java
public class ExampleBean {
public void cleanup() {
// do some destruction work (like releasing pooled connections)
}
}
Kotlin
class ExampleBean {
fun cleanup() {
// do some destruction work (like releasing pooled connections)
}
}
The preceding definition has almost exactly the same effect as the following definition:
Java
public class AnotherExampleBean implements DisposableBean {
@Override
public void destroy() {
// do some destruction work (like releasing pooled connections)
}
}
Kotlin
class AnotherExampleBean : DisposableBean {
override fun destroy() {
// do some destruction work (like releasing pooled connections)
}
}
However, the first of the two preceding definitions does not couple the code to Spring.
You can assign the destroy-method attribute of a element a special (inferred)
value, which instructs Spring to automatically detect a public close or shutdown
method on the specific bean class. (Any class that implements
java.lang.AutoCloseable or java.io.Closeable would therefore match.) You can
also set this special (inferred) value on the default-destroy-method attribute of a
element to apply this behavior to an entire set of beans (see Default
Initialization and Destroy Methods). Note that this is the default behavior with Java
configuration.
Default Initialization and Destroy Methods
When you write initialization and destroy method callbacks that do not use the Spring-specific
InitializingBean and DisposableBean callback interfaces, you typically write methods with names
such as init(), initialize(), dispose(), and so on. Ideally, the names of such lifecycle callback
methods are standardized across a project so that all developers use the same method names and
ensure consistency.
You can configure the Spring container to “look” for named initialization and destroy callback
method names on every bean. This means that you, as an application developer, can write your
application classes and use an initialization callback called init(), without having to configure an
init-method="init" attribute with each bean definition. The Spring IoC container calls that method
when the bean is created (and in accordance with the standard lifecycle callback contract described
previously). This feature also enforces a consistent naming convention for initialization and destroy
method callbacks.
Suppose that your initialization callback methods are named init() and your destroy callback
methods are named destroy(). Your class then resembles the class in the following example:
Java
public class DefaultBlogService implements BlogService {
private BlogDao blogDao;
public void setBlogDao(BlogDao blogDao) {
this.blogDao = blogDao;
}
// this is (unsurprisingly) the initialization callback method
public void init() {
if (this.blogDao == null) {
throw new IllegalStateException("The [blogDao] property must be set.");
}
}
}
Kotlin
class DefaultBlogService : BlogService {
private var blogDao: BlogDao? = null
// this is (unsurprisingly) the initialization callback method
fun init() {
if (blogDao == null) {
throw IllegalStateException("The [blogDao] property must be set.")
}
}
}
You could then use that class in a bean resembling the following:
The presence of the default-init-method attribute on the top-level element attribute causes
the Spring IoC container to recognize a method called init on the bean class as the initialization
method callback. When a bean is created and assembled, if the bean class has such a method, it is
invoked at the appropriate time.
You can configure destroy method callbacks similarly (in XML, that is) by using the default-
destroy-method attribute on the top-level element.
Where existing bean classes already have callback methods that are named at variance with the
convention, you can override the default by specifying (in XML, that is) the method name by using
the init-method and destroy-method attributes of the itself.
The Spring container guarantees that a configured initialization callback is called immediately after
a bean is supplied with all dependencies. Thus, the initialization callback is called on the raw bean
reference, which means that AOP interceptors and so forth are not yet applied to the bean. A target
bean is fully created first and then an AOP proxy (for example) with its interceptor chain is applied.
If the target bean and the proxy are defined separately, your code can even interact with the raw
target bean, bypassing the proxy. Hence, it would be inconsistent to apply the interceptors to the
init method, because doing so would couple the lifecycle of the target bean to its proxy or
interceptors and leave strange semantics when your code interacts directly with the raw target
bean.
Spring Ai Spring Boot Docker Compose/Src/Test/Resources/Org/Springframework/Ai/Docker/Compose/Service/Connection/Chroma/Chroma Compose.Yaml (spring-ai-spring-boot-docker-compose/src/test/resources/org/springframework/ai/docker/compose/service/connection/chroma/chroma-compose.yaml)
services:
chroma:
image: '{imageName}'
ports:
- '8000'
Spring Ai Spring Boot Docker Compose/Src/Test/Resources/Org/Springframework/Ai/Docker/Compose/Service/Connection/Chroma/Chroma With Token Compose.Yaml (spring-ai-spring-boot-docker-compose/src/test/resources/org/springframework/ai/docker/compose/service/connection/chroma/chroma-with-token-compose.yaml)
services:
chroma:
image: '{imageName}'
ports:
- '8000'
environment:
- CHROMA_SERVER_AUTHN_CREDENTIALS=secret
- CHROMA_SERVER_AUTHN_PROVIDER=chromadb.auth.token_authn.TokenAuthenticationServerProvider
Spring Ai Spring Boot Docker Compose/Src/Test/Resources/Org/Springframework/Ai/Docker/Compose/Service/Connection/Docker/Docker Agents Gateway Compose.Yaml (spring-ai-spring-boot-docker-compose/src/test/resources/org/springframework/ai/docker/compose/service/connection/docker/docker-agents-gateway-compose.yaml)
services:
mcp-gateway:
image: '{imageName}'
ports:
- 8811
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
command:
- --transport=sse
Spring Ai Spring Boot Docker Compose/Src/Test/Resources/Org/Springframework/Ai/Docker/Compose/Service/Connection/Milvus/Milvus Compose.Yaml (spring-ai-spring-boot-docker-compose/src/test/resources/org/springframework/ai/docker/compose/service/connection/milvus/milvus-compose.yaml)
services:
milvus:
image: '{imageName}'
command: milvus run standalone
ports:
- '9091'
- '19530'
environment:
- COMMON_STORAGETYPE=local
- DEPLOY_MODE=STANDALONE
- ETCD_USE_EMBED=true
- ETCD_DATA_DIR=/var/lib/milvus/etcd
- ETCD_CONFIG_PATH=/milvus/configs/embedEtcd.yaml
configs:
- source: embedEtcd
target: /milvus/configs/embedEtcd.yaml
configs:
embedEtcd:
content: |
listen-client-urls: http://0.0.0.0:2379
advertise-client-urls: http://0.0.0.0:2379
Spring Ai Spring Boot Docker Compose/Src/Test/Resources/Org/Springframework/Ai/Docker/Compose/Service/Connection/Mongo/Mongo Compose.Yaml (spring-ai-spring-boot-docker-compose/src/test/resources/org/springframework/ai/docker/compose/service/connection/mongo/mongo-compose.yaml)
services:
mongo:
image: '{imageName}'
ports:
- '27017'
Spring Ai Spring Boot Docker Compose/Src/Test/Resources/Org/Springframework/Ai/Docker/Compose/Service/Connection/Ollama/Ollama Compose.Yaml (spring-ai-spring-boot-docker-compose/src/test/resources/org/springframework/ai/docker/compose/service/connection/ollama/ollama-compose.yaml)
services:
ollama:
image: '{imageName}'
ports:
- '11434'
Spring Ai Spring Boot Docker Compose/Src/Test/Resources/Org/Springframework/Ai/Docker/Compose/Service/Connection/Opensearch/Localstack Compose.Yaml (spring-ai-spring-boot-docker-compose/src/test/resources/org/springframework/ai/docker/compose/service/connection/opensearch/localstack-compose.yaml)
services:
localstack:
image: '{imageName}'
ports:
- '4566'
Spring Ai Spring Boot Docker Compose/Src/Test/Resources/Org/Springframework/Ai/Docker/Compose/Service/Connection/Opensearch/Opensearch Compose.Yaml (spring-ai-spring-boot-docker-compose/src/test/resources/org/springframework/ai/docker/compose/service/connection/opensearch/opensearch-compose.yaml)
services:
opensearch:
image: '{imageName}'
ports:
- '9200'
environment:
- OPENSEARCH_INITIAL_ADMIN_PASSWORD=D3v3l0p-ment
- discovery.type=single-node
Spring Ai Spring Boot Docker Compose/Src/Test/Resources/Org/Springframework/Ai/Docker/Compose/Service/Connection/Qdrant/Qdrant Compose.Yaml (spring-ai-spring-boot-docker-compose/src/test/resources/org/springframework/ai/docker/compose/service/connection/qdrant/qdrant-compose.yaml)
services:
qdrant:
image: '{imageName}'
ports:
- '6334'
environment:
- QDRANT__SERVICE__API_KEY=springai
Spring Ai Spring Boot Docker Compose/Src/Test/Resources/Org/Springframework/Ai/Docker/Compose/Service/Connection/Typesense/Typesense Compose.Yaml (spring-ai-spring-boot-docker-compose/src/test/resources/org/springframework/ai/docker/compose/service/connection/typesense/typesense-compose.yaml)
services:
typesense:
image: '{imageName}'
ports:
- '8108'
command: '--data-dir /tmp --enable-cors'
environment:
- TYPESENSE_API_KEY=secret
Spring Ai Spring Boot Docker Compose/Src/Test/Resources/Org/Springframework/Ai/Docker/Compose/Service/Connection/Weaviate/Weaviate Compose.Yaml (spring-ai-spring-boot-docker-compose/src/test/resources/org/springframework/ai/docker/compose/service/connection/weaviate/weaviate-compose.yaml)
services:
weaviate:
image: '{imageName}'
ports:
- '8080'
environment:
- AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED=true
- PERSISTENCE_DATA_PATH=/var/lib/weaviate
Spring Ai Test/README (spring-ai-test/README.md)
Spring AI Test
The Spring AI Test module provides utilities and base classes for testing AI applications built with Spring AI.
Features
- BasicEvaluationTest: A base test class for evaluating question-answer quality using AI models
- Vector Store Testing: Utilities for testing vector store implementations
- Audio Testing: Utilities for testing audio-related functionality
BasicEvaluationTest
The BasicEvaluationTest class provides a framework for evaluating the quality and relevance of AI-generated answers to questions.
Usage
Extend the BasicEvaluationTest class in your test classes:
@SpringBootTest
public class MyAiEvaluationTest extends BasicEvaluationTest {
@Test
public void testQuestionAnswerAccuracy() {
String question = "What is the capital of France?";
String answer = "The capital of France is Paris.";
// Evaluate if the answer is accurate and related to the question
evaluateQuestionAndAnswer(question, answer, true);
}
}Configuration
The test requires:
- A
ChatModelbean (typically OpenAI) - Evaluation prompt templates located in
classpath:/prompts/spring/test/evaluation/
Evaluation Types
- Fact-based evaluation: Use
factBased = truefor questions requiring factual accuracy - General evaluation: Use
factBased = falsefor more subjective questions
The evaluation process:
- Checks if the answer is related to the question
- Evaluates the accuracy/appropriateness of the answer
- Fails the test with detailed feedback if the answer is inadequate
Spring Ai Test/Src/Main/Resources/Test/Data/Great.Depression (spring-ai-test/src/main/resources/test/data/great.depression.txt)
The Great Depression (1929–1939) was an economic shock that affected most countries across the world. It was a period of economic depression that became evident after a major fall in stock prices in the United States.[1] The economic contagion began around September 1929 and led to the Wall Street stock market crash of October 24 (Black Thursday). It was the longest, deepest, and most widespread depression of the 20th century.[2]
Between 1929 and 1932, worldwide gross domestic product (GDP) fell by an estimated 15%. By comparison, worldwide GDP fell by less than 1% from 2008 to 2009 during the Great Recession.[3] Some economies started to recover by the mid-1930s. However, in many countries,[specify] the negative effects of the Great Depression lasted until the beginning of World War II. Devastating effects were seen in both rich and poor countries with falling personal income, prices, tax revenues, and profits. International trade fell by more than 50%, unemployment in the U.S. rose to 23% and in some countries rose as high as 33%.[4]
Cities around the world were hit hard, especially those dependent on heavy industry. Construction was virtually halted in many countries. Farming communities and rural areas suffered as crop prices fell by about 60%.[5][6][7] Faced with plummeting demand and few job alternatives, areas dependent on primary sector industries suffered the most.[8]
Economic historians usually consider the catalyst of the Great Depression to be the sudden devastating collapse of U.S. stock market prices, starting on October 24, 1929. However, some dispute this conclusion, seeing the stock crash less than a cause of the Depression and more as a symptom of the rising nervousness of investors partly due to gradual price declines caused by falling sales of consumer goods (as a result of overproduction because of new production techniques, falling exports and income inequality, among other factors) that had already been underway as part of a gradual Depression
Spring Ai Test/Src/Main/Resources/Test/Data/Spring.Ai (spring-ai-test/src/main/resources/test/data/spring.ai.txt)
The Spring AI project aims to streamline the development of applications that incorporate artificial intelligence functionality without unnecessary complexity.
The project draws inspiration from notable Python projects, such as LangChain and LlamaIndex, but Spring AI is not a direct port of those projects. The project was founded with the belief that the next wave of Generative AI applications will not be only for Python developers but will be ubiquitous across many programming languages.
At its core, Spring AI provides abstractions that serve as the foundation for developing AI applications. These abstractions have multiple implementations, enabling easy component swapping with minimal code changes. For example, Spring AI introduces the ChatModel interface with implementations for OpenAI and Azure OpenAI.
In addition to these core abstractions, Spring AI aims to provide higher-level functionalities to address common use cases such as “Q&A over your documentation” or “Chat with your documentation.” As the complexity of the use cases increases, the Spring AI project will integrate with other projects in the Spring Ecosystem, such as Spring Integration, Spring Batch, and Spring Data.
To simplify setup, Spring Boot starters are available to help set up essential dependencies and classes. There is also a collection of sample applications to help you explore the project’s features. Lastly, the new Spring CLI project also enables you to get started quickly by using the spring boot new AI command for new projects or spring boot add AI for adding AI capabilities to your existing application.
Spring Ai Test/Src/Main/Resources/Test/Data/Time.Shelter (spring-ai-test/src/main/resources/test/data/time.shelter.txt)
Somewhere in the Andes, they believe in this very day that the future is behind you. It comes up from behind your back, surprising and unforeseeable, while the past is always before your eyes, that which has already happened. When they talk about the past, the people of the Aymara tribe point in front of them. You walk forward facing the past, and you turn back toward the future.
― Georgi Gospodinov, Time Shelter
Spring Ai Tool Search Tool/Src/Main/Resources/DEFAULT SYSTEM PROMPT SUFFIX (spring-ai-tool-search-tool/src/main/resources/DEFAULT_SYSTEM_PROMPT_SUFFIX.md)
You have access to a special tool called toolSearchTool that allows you to discover relevant tools on-demand. When you need to perform an action but don't see an appropriate tool in your current context, use toolSearchTool to search for it.
Spring Ai Tool Search Tool/Src/Main/Resources/DEFAULT SYSTEM PROMPT SUFFIX LARGE (spring-ai-tool-search-tool/src/main/resources/DEFAULT_SYSTEM_PROMPT_SUFFIX_LARGE.md)
You are an AI assistant with access to a large library of tools. However, not all tools are loaded into your context initially to conserve context window space and improve accuracy.
Tool Discovery Process
You have access to a special tool called toolSearchTool that allows you to discover relevant tools on-demand. When you need to perform an action but don't see an appropriate tool in your current context, use toolSearchTool to search for it.
How tool search works:
- When you receive a request that may require tools not currently visible to you, call
toolSearchToolwith a search query describing what capability you need - The search will return references to matching tools (typically 3-5 most relevant)
- These tool references will be automatically expanded into full tool definitions that you can then use
- Select the most appropriate discovered tool and invoke it with the required parameters
When to use tool search:
- When you need a capability not provided by your currently available tools
- When the user's request implies operations (database queries, API calls, file operations, etc.) that require specific tools
- When you're unsure which tool to use for a complex task - search can help you discover the right one
Search query best practices:
- Use descriptive keywords related to the functionality you need
- Include domain-specific terms (e.g., "github pull request", "slack message", "database query")
- You can search by functionality ("send notification"), by service ("jira"), or by action type ("create ticket")
Available tool categories in this system:
[PLACEHOLDER: List your tool categories here, e.g., "Slack messaging, GitHub operations, database queries, file management, calendar scheduling"]
Remember: After discovering tools via search, you must still invoke them using the standard tool calling mechanism. The search only makes tools visible to you - it doesn't execute them.
Spring Ai Vector Store/Src/Main/Resources/META INF/Additional Spring Configuration Metadata.Json (spring-ai-vector-store/src/main/resources/META-INF/additional-spring-configuration-metadata.json)
{
"groups": [],
"properties": [
{
"name": "spring.ai.vectorstore.type",
"type": "java.lang.String",
"description": "Vector store type. Requires a vector store."
}
],
"hints": [],
"ignored": {
"properties": []
}
}
Src/Checkstyle/Checkstyle Header (src/checkstyle/checkstyle-header.txt)
^\Q/*\E$
^\Q * Copyright 2023-present the original author or authors.\E$
^\Q *\E$
^\Q * Licensed under the Apache License, Version 2.0 (the "License");\E$
^\Q * you may not use this file except in compliance with the License.\E$
^\Q * You may obtain a copy of the License at\E$
^\Q *\E$
^\Q * https://www.apache.org/licenses/LICENSE-2.0\E$
^\Q *\E$
^\Q * Unless required by applicable law or agreed to in writing, software\E$
^\Q * distributed under the License is distributed on an "AS IS" BASIS,\E$
^\Q * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\E$
^\Q * See the License for the specific language governing permissions and\E$
^\Q * limitations under the License.\E$
^\Q */\E$
^$
^.*$
Src/Ecosystem Ci/README (src/ecosystem-ci/README.md)
Ecosystem CI Dashboard
This directory contains the configuration for the Spring AI Ecosystem CI Dashboard, which monitors the CI health of key ecosystem dependencies.
Overview
The dashboard workflow runs daily and:
- Queries CI status for each monitored repository
- Updates the Wiki Dashboard with current status
- Posts alerts to Issue #5334 when dependencies fail for extended periods
Subscribing to Alerts
To receive notifications when ecosystem dependencies fail CI:
- Go to Issue #5334
- Click Subscribe in the right sidebar
- You'll receive GitHub notifications when alerts are posted
Alert Policy
| Condition | Action |
|---|---|
| Dependency fails (day 1) |
Dashboard updated, no alert |
| Dependency fails for 2+ days | Alert comment posted (triggers notification) |
| Dependency recovers | Dashboard updated, no alert |
The alert_after_days setting in ci-alert-config.json controls the threshold (default: 2 days).
Adding or Removing Dependencies
Edit ci-alert-config.json:
{
"dependencies": [
{ "owner": "org-name", "repo": "repo-name" },
...
]
}Each dependency must have:
owner: GitHub organization or userrepo: Repository name
The workflow monitors the branch specified by tracked_branch (default: main).
Configuration Reference
| Field | Description | Default |
|---|---|---|
issue_number |
GitHub issue for dashboard and alerts | 5334 |
| tracked_branch | Branch to monitor for each repo | main |
| alert_after_days | Days of failure before alerting | 2 |
| heartbeat_days | Minimum days between repeat alerts | 1 |
Manual Trigger
To run the dashboard manually:
- Go to Actions > Ecosystem CI Dashboard
- Click Run workflow
- Select the
mainbranch and click Run workflow
Files
ci-alert-config.json- Dashboard configuration../../.github/workflows/dependency-ci-dashboard.yml- GitHub Actions workflow
Src/Ecosystem Ci/Ci Alert Config.Json (src/ecosystem-ci/ci-alert-config.json)
{
"issue_number": 5334,
"tracked_branch": "main",
"alert_after_days": 2,
"heartbeat_days": 1,
"dependencies": [
{ "owner": "modelcontextprotocol", "repo": "java-sdk" },
{ "owner": "spring-projects", "repo": "spring-ai-examples" },
{ "owner": "spring-projects", "repo": "spring-ai-integration-tests" },
{ "owner": "spring-ai-community", "repo": "spring-ai-tool-search-tool" },
{ "owner": "spring-ai-community", "repo": "spring-ai-agent-utils" },
{ "owner": "spring-ai-community", "repo": "mcp-security" },
{ "owner": "spring-ai-community", "repo": "mcp-annotations" }
]
}
Src/Prompts/Update To M7 (src/prompts/update-to-m7.txt)
Please perform the following three tasks in my project:
Important: File Access Instructions
- For all file reading operations, use the view tool to view file contents. e.g. cat on linux/mac
- For multi-module projects, you'll need to examine multiple pom.xml or build.gradle files
- Examples:
cat pom.xml # For Maven root project
cat module/pom.xml # For Maven modules
cat build.gradle # For Gradle
cat module/build.gradle # For Gradle modules
cat build.gradle.kts # For Kotlin DSL
Task 1: Update Spring AI BOM Version to 1.0.0-M7
For Maven (pom.xml):
- Replace <version>1.0.0-M6</version> or older versions with <version>1.0.0-M7</version> within the spring-ai-bom dependency
- Use the exact whitespace/indentation from the original file
For Gradle (build.gradle or build.gradle.kts):
- Update implementation platform("org.springframework.ai:spring-ai-bom:1.0.0-M6") or older versions to:
implementation platform("org.springframework.ai:spring-ai-bom:1.0.0-M7")
Task 2: Ensure All Required Repositories Exist
For Maven (pom.xml):
- Verify these three repositories exist in pom.xml file:
<repository>
spring-milestones
<name>Spring Milestones</name>
https://repo.spring.io/milestone
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
- Add any missing repositories to the <repositories> section
- Use the existing indentation style from the pom.xml file
For Gradle:
- Add any missing repositories with proper formatting:
repositories {
mavenCentral()
maven {
url = uri("https://repo.spring.io/milestone")
mavenContent {
releasesOnly()
}
}
}
Task 3: Update Spring AI Artifact IDs
Apply this pattern for all Spring AI starters:
- Model starters: spring-ai-{model}-spring-boot-starter → spring-ai-starter-model-{model}
- Vector Store starters: spring-ai-{store}-store-spring-boot-starter → spring-ai-starter-vector-store-{store}
- MCP starters: spring-ai-mcp-{type}-spring-boot-starter → spring-ai-starter-mcp-{type}
For Maven (pom.xml) - Examples:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
For Gradle - Examples:
// BEFORE
implementation 'org.springframework.ai:spring-ai-openai-spring-boot-starter'
implementation 'org.springframework.ai:spring-ai-redis-store-spring-boot-starter'
// AFTER
implementation 'org.springframework.ai:spring-ai-starter-model-openai'
implementation 'org.springframework.ai:spring-ai-starter-vector-store-redis'
CRITICAL - Do NOT make these changes:
1. Do NOT change any XML tags such as:
- Do NOT change <name> to <n> (leave all <name> tags exactly as they are)
- Do NOT modify any other XML elements like <description>, , etc.
2. Do NOT attempt to fix XML formatting:
- Do NOT add or remove whitespace except where specifically instructed
- Do NOT add or remove newlines
- Do NOT reformat XML indentation
3. Make ONLY the three specific changes described above:
- Update spring-ai-bom version to 1.0.0-M7
- Add missing repositories from the list above
- Update Spring AI artifactIds using the specified patterns
For all replacements, maintain the exact indentation and whitespace from the original file.
Src/Prompts/Update To Snapshot (src/prompts/update-to-snapshot.txt)
Please perform the following three tasks in my project:
Important: File Access Instructions
- For all file reading operations, use the view tool to view file contents. e.g. cat on linux/mac
- For multi-module projects, you'll need to examine multiple pom.xml or build.gradle files
- Examples:
cat pom.xml # For Maven root project
cat module/pom.xml # For Maven modules
cat build.gradle # For Gradle
cat module/build.gradle # For Gradle modules
cat build.gradle.kts # For Kotlin DSL
Task 1: Update Spring AI BOM Version to 1.0.0-SNAPSHOT
For Maven (pom.xml):
- Replace <version>1.0.0-M5</version> with <version>1.0.0-SNAPSHOT</version> within the spring-ai-bom dependency
- Use the exact whitespace/indentation from the original file
For Gradle (build.gradle or build.gradle.kts):
- Update implementation platform("org.springframework.ai:spring-ai-bom:1.0.0-M5") to:
implementation platform("org.springframework.ai:spring-ai-bom:1.0.0-SNAPSHOT")
Task 2: Ensure All Required Repositories Exist
For Maven (pom.xml):
- Verify these three repositories exist in pom.xml file:
<repository>
spring-milestones
<name>Spring Milestones</name>
https://repo.spring.io/milestone
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
spring-snapshots
<name>Spring Snapshots</name>
https://repo.spring.io/snapshot
<releases>
<enabled>false</enabled>
</releases>
</repository>
<repository>
central-portal-snapshots
<name>Central Portal Snapshots</name>
https://central.sonatype.com/repository/maven-snapshots/
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
- Add any missing repositories to the <repositories> section
- Use the existing indentation style from the pom.xml file
For Gradle:
- Add any missing repositories with proper formatting:
repositories {
mavenCentral()
maven {
url = uri("https://repo.spring.io/milestone")
mavenContent {
releasesOnly()
}
}
maven {
url = uri("https://repo.spring.io/snapshot")
mavenContent {
snapshotsOnly()
}
}
maven {
url = uri("https://central.sonatype.com/repository/maven-snapshots/")
mavenContent {
snapshotsOnly()
}
}
}
Task 3: Update Spring AI Artifact IDs
Apply this pattern for all Spring AI starters:
- Model starters: spring-ai-{model}-spring-boot-starter → spring-ai-starter-model-{model}
- Vector Store starters: spring-ai-{store}-store-spring-boot-starter → spring-ai-starter-vector-store-{store}
- MCP starters: spring-ai-mcp-{type}-spring-boot-starter → spring-ai-starter-mcp-{type}
For Maven (pom.xml) - Examples:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
For Gradle - Examples:
// BEFORE
implementation 'org.springframework.ai:spring-ai-openai-spring-boot-starter'
implementation 'org.springframework.ai:spring-ai-redis-store-spring-boot-starter'
// AFTER
implementation 'org.springframework.ai:spring-ai-starter-model-openai'
implementation 'org.springframework.ai:spring-ai-starter-vector-store-redis'
CRITICAL - Do NOT make these changes:
1. Do NOT change any XML tags such as:
- Do NOT change <name> to <n> (leave all <name> tags exactly as they are)
- Do NOT modify any other XML elements like <description>, , etc.
2. Do NOT attempt to fix XML formatting:
- Do NOT add or remove whitespace except where specifically instructed
- Do NOT add or remove newlines
- Do NOT reformat XML indentation
3. Make ONLY the three specific changes described above:
- Update spring-ai-bom version to 1.0.0-SNAPSHOT
- Add missing repositories from the list above
- Update Spring AI artifactIds using the specified patterns
For all replacements, maintain the exact indentation and whitespace from the original file.
Src/Rewrite/Migrate To 2 0 0 M3.Yaml (src/rewrite/migrate-to-2-0-0-M3.yaml)
type: specs.openrewrite.org/v1beta/recipe
name: org.springframework.ai.migration.MigrateToSpringAI200M3
displayName: Migrate to Spring AI 2.0.0-M3
Umbrella recipe that applies all breaking-change migrations required for
Spring AI 2.0.0-M3. Run this recipe to perform all changes in one step.
Included migrations:
- M3MigrateMcpAnnotations: org.springaicommunity:mcp-annotations → spring-ai-mcp-annotations
- M3MigrateMcpSpringTransports: io.modelcontextprotocol.sdk mcp-spring-webflux/webmvc → org.springframework.ai
- M3MigrateMcpClientCustomizer: McpAsyncClientCustomizer / McpSyncClientCustomizer → McpClientCustomizer
tags:
- spring-ai
- mcp
- migration
recipeList:
- org.springframework.ai.migration.M3MigrateMcpAnnotations
- org.springframework.ai.migration.M3MigrateMcpSpringTransports
- org.springframework.ai.migration.M3MigrateMcpClientCustomizer
type: specs.openrewrite.org/v1beta/recipe
name: org.springframework.ai.migration.M3MigrateMcpAnnotations
displayName: Migrate MCP annotations from springaicommunity to Spring AI
Migrates all MCP annotation, method-callback, provider, and context classes from the
removed org.springaicommunity:mcp-annotations library to their new locations
inside org.springframework.ai:spring-ai-mcp-annotations.
Package changes:
org.springaicommunity.mcp.annotation. → org.springframework.ai.mcp.annotation.
org.springaicommunity.mcp.method. → org.springframework.ai.mcp.annotation.method.
org.springaicommunity.mcp.provider. → org.springframework.ai.mcp.annotation.provider.
org.springaicommunity.mcp.context. → org.springframework.ai.mcp.annotation.context.
tags:
- spring-ai
- mcp
- migration
recipeList:
# -------------------------------------------------------------------------
# Maven: remove the old external dependency (classes are now in spring-ai)
# -------------------------------------------------------------------------
- org.openrewrite.maven.RemoveDependency:
groupId: org.springaicommunity
artifactId: mcp-annotations
# -------------------------------------------------------------------------
# Java: text-based package renamings (no classpath resolution needed).
# Sub-packages (method, provider, context) must come before the parent
# annotation package to avoid double-rewriting already-replaced strings.
# -------------------------------------------------------------------------
- org.openrewrite.text.FindAndReplace:
find: "org.springaicommunity.mcp.method."
replace: "org.springframework.ai.mcp.annotation.method."
filePattern: "/*.java"
- org.openrewrite.text.FindAndReplace:
find: "org.springaicommunity.mcp.provider."
replace: "org.springframework.ai.mcp.annotation.provider."
filePattern: "/*.java"
- org.openrewrite.text.FindAndReplace:
find: "org.springaicommunity.mcp.context."
replace: "org.springframework.ai.mcp.annotation.context."
filePattern: "/*.java"
- org.openrewrite.text.FindAndReplace:
find: "org.springaicommunity.mcp.annotation."
replace: "org.springframework.ai.mcp.annotation."
filePattern: "/*.java"
type: specs.openrewrite.org/v1beta/recipe
name: org.springframework.ai.migration.M3MigrateMcpSpringTransports
displayName: Migrate MCP Spring transport modules from MCP Java SDK to Spring AI
Migrates the mcp-spring-webflux and mcp-spring-webmvc transport modules
from the MCP Java SDK (io.modelcontextprotocol.sdk) to Spring AI
(org.springframework.ai).
Maven dependency group ID changes:
io.modelcontextprotocol.sdk:mcp-spring-webflux → org.springframework.ai:mcp-spring-webflux
io.modelcontextprotocol.sdk:mcp-spring-webmvc → org.springframework.ai:mcp-spring-webmvc
Java package changes (server transports):
io.modelcontextprotocol.server.transport.WebFluxSseServerTransportProvider → org.springframework.ai.mcp.server.webflux.transport
io.modelcontextprotocol.server.transport.WebFluxStreamableServerTransportProvider → org.springframework.ai.mcp.server.webflux.transport
io.modelcontextprotocol.server.transport.WebFluxStatelessServerTransport → org.springframework.ai.mcp.server.webflux.transport
io.modelcontextprotocol.server.transport.WebMvcSseServerTransportProvider → org.springframework.ai.mcp.server.webmvc.transport
io.modelcontextprotocol.server.transport.WebMvcStreamableServerTransportProvider → org.springframework.ai.mcp.server.webmvc.transport
io.modelcontextprotocol.server.transport.WebMvcStatelessServerTransport → org.springframework.ai.mcp.server.webmvc.transport
Java package changes (client transports):
io.modelcontextprotocol.client.transport.WebFluxSseClientTransport → org.springframework.ai.mcp.client.webflux.transport
io.modelcontextprotocol.client.transport.WebClientStreamableHttpTransport → org.springframework.ai.mcp.client.webflux.transport
tags:
- spring-ai
- mcp
- migration
recipeList:
# -------------------------------------------------------------------------
# Maven: change group ID for the WebFlux transport.
# Text-based regex replacement is used instead of
# org.openrewrite.maven.ChangeDependencyGroupIdAndArtifactId because that
# recipe requires Maven to fully resolve the POM model first — which fails
# when the dependency declares no <version> (version managed via BOM/parent).
# The \s+ capture group preserves whatever whitespace/indentation the file uses.
# -------------------------------------------------------------------------
- org.openrewrite.text.FindAndReplace:
find: "<groupId>io\\.modelcontextprotocol\\.sdk</groupId>(\\s+)<artifactId>mcp-spring-webflux</artifactId>"
replace: "<groupId>org.springframework.ai</groupId>$1<artifactId>mcp-spring-webflux</artifactId>"
regex: true
filePattern: "/pom.xml"
# -------------------------------------------------------------------------
# Maven: change group ID for the WebMvc transport (same rationale as above).
# -------------------------------------------------------------------------
- org.openrewrite.text.FindAndReplace:
find: "<groupId>io\\.modelcontextprotocol\\.sdk</groupId>(\\s+)<artifactId>mcp-spring-webmvc</artifactId>"
replace: "<groupId>org.springframework.ai</groupId>$1<artifactId>mcp-spring-webmvc</artifactId>"
regex: true
filePattern: "/pom.xml"
# -------------------------------------------------------------------------
# Java: server transport classes (WebFlux)
# FindAndReplace is used instead of ChangeType because the old artifacts are
# no longer on the classpath, making AST-based type resolution impossible.
# -------------------------------------------------------------------------
- org.openrewrite.text.FindAndReplace:
find: "io.modelcontextprotocol.server.transport.WebFluxSseServerTransportProvider"
replace: "org.springframework.ai.mcp.server.webflux.transport.WebFluxSseServerTransportProvider"
filePattern: "/*.java"
- org.openrewrite.text.FindAndReplace:
find: "io.modelcontextprotocol.server.transport.WebFluxStreamableServerTransportProvider"
replace: "org.springframework.ai.mcp.server.webflux.transport.WebFluxStreamableServerTransportProvider"
filePattern: "/*.java"
- org.openrewrite.text.FindAndReplace:
find: "io.modelcontextprotocol.server.transport.WebFluxStatelessServerTransport"
replace: "org.springframework.ai.mcp.server.webflux.transport.WebFluxStatelessServerTransport"
filePattern: "/*.java"
# -------------------------------------------------------------------------
# Java: server transport classes (WebMvc)
# -------------------------------------------------------------------------
- org.openrewrite.text.FindAndReplace:
find: "io.modelcontextprotocol.server.transport.WebMvcSseServerTransportProvider"
replace: "org.springframework.ai.mcp.server.webmvc.transport.WebMvcSseServerTransportProvider"
filePattern: "/*.java"
- org.openrewrite.text.FindAndReplace:
find: "io.modelcontextprotocol.server.transport.WebMvcStreamableServerTransportProvider"
replace: "org.springframework.ai.mcp.server.webmvc.transport.WebMvcStreamableServerTransportProvider"
filePattern: "/*.java"
- org.openrewrite.text.FindAndReplace:
find: "io.modelcontextprotocol.server.transport.WebMvcStatelessServerTransport"
replace: "org.springframework.ai.mcp.server.webmvc.transport.WebMvcStatelessServerTransport"
filePattern: "/*.java"
# -------------------------------------------------------------------------
# Java: client transport classes (WebFlux)
# -------------------------------------------------------------------------
- org.openrewrite.text.FindAndReplace:
find: "io.modelcontextprotocol.client.transport.WebFluxSseClientTransport"
replace: "org.springframework.ai.mcp.client.webflux.transport.WebFluxSseClientTransport"
filePattern: "/*.java"
- org.openrewrite.text.FindAndReplace:
find: "io.modelcontextprotocol.client.transport.WebClientStreamableHttpTransport"
replace: "org.springframework.ai.mcp.client.webflux.transport.WebClientStreamableHttpTransport"
filePattern: "/*.java"
# -------------------------------------------------------------------------
# Java: McpJsonMapper.createDefault() → McpJsonDefaults.getMapper()
# The factory method moved from McpJsonMapper to McpJsonDefaults.
# Replace the call first, then the import so the import line is also updated.
# -------------------------------------------------------------------------
- org.openrewrite.text.FindAndReplace:
find: "McpJsonMapper.createDefault()"
replace: "McpJsonDefaults.getMapper()"
filePattern: "/*.java"
# Always add the McpJsonDefaults import alongside McpJsonMapper.
# If McpJsonMapper is no longer used after the call-site replacement above,
# it will surface as an unused-import warning for manual cleanup.
- org.openrewrite.text.FindAndReplace:
find: "import io.modelcontextprotocol.json.McpJsonMapper;"
replace: "import io.modelcontextprotocol.json.McpJsonDefaults;\nimport io.modelcontextprotocol.json.McpJsonMapper;"
filePattern: "/*.java"
type: specs.openrewrite.org/v1beta/recipe
name: org.springframework.ai.migration.M3MigrateMcpClientCustomizer
displayName: Migrate McpAsyncClientCustomizer and McpSyncClientCustomizer to McpClientCustomizer
Replaces the removed McpAsyncClientCustomizer and McpSyncClientCustomizer interfaces
with the new generic McpClientCustomizer interface introduced in Spring AI 2.0.0-M3.
Changes applied:
- Import org.springframework.ai.mcp.customizer.McpAsyncClientCustomizer
→ org.springframework.ai.mcp.customizer.McpClientCustomizer
+ adds import io.modelcontextprotocol.client.McpClient;
- Import org.springframework.ai.mcp.customizer.McpSyncClientCustomizer
→ org.springframework.ai.mcp.customizer.McpClientCustomizer
+ adds import io.modelcontextprotocol.client.McpClient;
- Simple-name usage McpAsyncClientCustomizer → McpClientCustomizer<McpClient.AsyncSpec>
- Simple-name usage McpSyncClientCustomizer → McpClientCustomizer<McpClient.SyncSpec>
NOTE: McpSyncHttpClientRequestCustomizer and McpAsyncHttpClientRequestCustomizer
(from io.modelcontextprotocol.client.transport.customizer) are no longer applied by
the auto-configurations. Migrate them manually to
McpClientCustomizer<HttpClientSseClientTransport.Builder> or
McpClientCustomizer<HttpClientStreamableHttpTransport.Builder> as appropriate.
tags:
- spring-ai
- mcp
- migration
recipeList:
# -------------------------------------------------------------------------
# Step 1 — rewrite the fully-qualified import for McpAsyncClientCustomizer.
# The McpClient import is added at the same time because the new parameterised
# type McpClientCustomizer<McpClient.AsyncSpec> requires it at the call-site.
# -------------------------------------------------------------------------
- org.openrewrite.text.FindAndReplace:
find: "import org.springframework.ai.mcp.customizer.McpAsyncClientCustomizer;"
replace: "import io.modelcontextprotocol.client.McpClient;\nimport org.springframework.ai.mcp.customizer.McpClientCustomizer;"
filePattern: "/*.java"
# -------------------------------------------------------------------------
# Step 2 — rewrite the fully-qualified import for McpSyncClientCustomizer.
# -------------------------------------------------------------------------
- org.openrewrite.text.FindAndReplace:
find: "import org.springframework.ai.mcp.customizer.McpSyncClientCustomizer;"
replace: "import io.modelcontextprotocol.client.McpClient;\nimport org.springframework.ai.mcp.customizer.McpClientCustomizer;"
filePattern: "/*.java"
# -------------------------------------------------------------------------
# Step 3 — replace simple-name occurrences of McpAsyncClientCustomizer
# (return types, implements clauses, parameter types, variable declarations).
# Must run AFTER the import replacement so the import line is not touched
# again (it no longer contains "McpAsyncClientCustomizer" at this point).
# -------------------------------------------------------------------------
- org.openrewrite.text.FindAndReplace:
find: "McpAsyncClientCustomizer"
replace: "McpClientCustomizer<McpClient.AsyncSpec>"
filePattern: "/*.java"
# -------------------------------------------------------------------------
# Step 4 — replace simple-name occurrences of McpSyncClientCustomizer.
# -------------------------------------------------------------------------
- org.openrewrite.text.FindAndReplace:
find: "McpSyncClientCustomizer"
replace: "McpClientCustomizer<McpClient.SyncSpec>"
filePattern: "/*.java"
Vector Stores/Spring Ai Azure Store/README (vector-stores/spring-ai-azure-store/README.md)
Azure AI Search Vector Store Documentation
Vector Stores/Spring Ai Cassandra Store/README (vector-stores/spring-ai-cassandra-store/README.md)
Apache Cassandra Vector Store Documentation
Vector Stores/Spring Ai Chroma Store/README (vector-stores/spring-ai-chroma-store/README.md)
Chroma Vector Store Documentation
Vector Stores/Spring Ai Coherence Store/README (vector-stores/spring-ai-coherence-store/README.md)
Oracle Coherence Vector Search Documentation
Vector Stores/Spring Ai Couchbase Store/README (vector-stores/spring-ai-couchbase-store/README.md)
Couchbase Vector Store Documentation
Vector Stores/Spring Ai Gemfire Store/README (vector-stores/spring-ai-gemfire-store/README.md)
GemFire Vector Store Documentation
Vector Stores/Spring Ai Mariadb Store/README (vector-stores/spring-ai-mariadb-store/README.md)
MariaDB Vector Store Documentation
Vector Stores/Spring Ai Milvus Store/README (vector-stores/spring-ai-milvus-store/README.md)
Milvus Vector Store Documentation
Vector Stores/Spring Ai Neo4j Store/README (vector-stores/spring-ai-neo4j-store/README.md)
Neo4j Vector Store Documentation
Vector Stores/Spring Ai Oracle Store/README (vector-stores/spring-ai-oracle-store/README.md)
Oracle AI Vector Search Documentation
Vector Stores/Spring Ai Pgvector Store/README (vector-stores/spring-ai-pgvector-store/README.md)
PGvector Vector Store Documentation
Vector Stores/Spring Ai Pinecone Store/README (vector-stores/spring-ai-pinecone-store/README.md)
Pinecone Vector Store Documentation
Vector Stores/Spring Ai Qdrant Store/README (vector-stores/spring-ai-qdrant-store/README.md)
Qdrant Vector Store
Run locally
Accessing the Web UI
First, run the Docker container:
docker run -p 6333:6333 -p 6334:6334 \
-v $(pwd)/qdrant_storage:/qdrant/storage:z \
qdrant/qdrantSecurity: Adding API Key to Qdrant Container
To enhance security, you can add an API key to your Qdrant container using the environment variable.
-e QDRANT__SERVICE__API_KEY=<your_generated_api_key_here>This ensures that only authorized users with the correct API key can access the Qdrant service.
The GUI is available at http://localhost:6333/dashboard
Qdrant references
- https://qdrant.tech/documentation/interfaces/
- https://github.com/qdrant/java-client
Vector Stores/Spring Ai Redis Semantic Cache/README (vector-stores/spring-ai-redis-semantic-cache/README.md)
Redis Semantic Cache for Spring AI
This module provides a Redis-based implementation of semantic caching for Spring AI.
Overview
Semantic caching allows storing and retrieving chat responses based on the semantic similarity of user queries.
This implementation uses Redis vector search capabilities to efficiently find similar queries and return cached responses.
Features
- Store chat responses with their associated queries in Redis
- Retrieve responses based on semantic similarity
- Support for time-based expiration of cached entries
- Includes a ChatClient advisor for automatic caching
- Built on Redis vector search technology
Requirements
- Redis Stack with Redis Query Engine and RedisJSON modules
- Java 17 or later
- Spring AI core dependencies
- An embedding model for vector generation
Usage
Maven Configuration
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-redis-semantic-cache</artifactId>
</dependency>For Spring Boot applications, you can use the starter:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-vector-store-redis-semantic-cache</artifactId>
</dependency>Basic Usage
// Create Redis client
RedisClient jedisClient = RedisClient.builder().hostAndPort("localhost", 6379).build();
// Create the embedding model
EmbeddingModel embeddingModel = new OpenAiEmbeddingModel(apiKey);
// Create the semantic cache
SemanticCache semanticCache = DefaultSemanticCache.builder()
.jedisClient(jedisClient)
.embeddingModel(embeddingModel)
.similarityThreshold(0.85) // Optional: adjust similarity threshold (0-1)
.build();
// Create the cache advisor
SemanticCacheAdvisor cacheAdvisor = SemanticCacheAdvisor.builder()
.cache(semanticCache)
.build();
// Use with ChatClient
ChatResponse response = ChatClient.builder(chatModel)
.build()
.prompt("What is the capital of France?")
.advisors(cacheAdvisor) // Add the advisor
.call()
.chatResponse();Direct Cache Usage
You can also use the cache directly:
// Store a response
semanticCache.set("What is the capital of France?", parisResponse);
// Store with expiration
semanticCache.set("What's the weather today?", weatherResponse, Duration.ofHours(1));
// Retrieve a semantically similar response
Optional<ChatResponse> response = semanticCache.get("Tell me the capital city of France");
// Clear the cache
semanticCache.clear();Configuration Options
The DefaultSemanticCache can be configured with the following options:
jedisClient- The Redis clientvectorStore- Optional existing vector store to useembeddingModel- The embedding model for vector generationsimilarityThreshold- Threshold for determining similarity (0-1)indexName- The name of the Redis search indexprefix- Key prefix for Redis documents
Spring Boot Integration
When using Spring Boot and the Redis Semantic Cache starter, the components will be automatically configured.
You can customize behavior using properties in application.properties or application.yml:
spring:
ai:
vectorstore:
redis:
semantic-cache:
host: localhost
port: 6379
similarity-threshold: 0.85
index-name: semantic-cacheVector Stores/Spring Ai Redis Store/README (vector-stores/spring-ai-redis-store/README.md)
Spring AI Redis Vector Store
A Redis-based vector store implementation for Spring AI using Redis Stack with Redis Query Engine and RedisJSON.
Documentation
For comprehensive documentation, see
the Redis Vector Store Documentation.
Features
- Vector similarity search using KNN
- Range-based vector search with radius threshold
- Text-based search on TEXT fields
- Support for multiple distance metrics (COSINE, L2, IP)
- Multiple text scoring algorithms (BM25, TFIDF, etc.)
- HNSW and FLAT vector indexing algorithms
- Configurable metadata fields (TEXT, TAG, NUMERIC)
- Filter expressions for advanced filtering
- Batch processing support
Usage
KNN Search
The standard similarity search returns the k-nearest neighbors:
// Create Redis client
RedisClient jedisClient = RedisClient.builder().hostAndPort("localhost", 6379).build();
// Create the vector store
RedisVectorStore vectorStore = RedisVectorStore.builder(jedisClient, embeddingModel)
.indexName("my-index")
.vectorAlgorithm(Algorithm.HNSW)
.distanceMetric(DistanceMetric.COSINE)
.build();
// Add documents
vectorStore.add(List.of(
new Document("content1", Map.of("category", "AI")),
new Document("content2", Map.of("category", "DB"))
));
// Search with KNN
List<Document> results = vectorStore.similaritySearch(
SearchRequest.builder()
.query("AI and machine learning")
.topK(5)
.similarityThreshold(0.7)
.filterExpression("category == 'AI'")
.build()
);Text Search
The text search capability allows you to find documents based on keywords and phrases in TEXT fields:
// Search for documents containing specific text
List<Document> textResults = vectorStore.searchByText(
"machine learning", // search query
"content", // field to search (must be TEXT type)
10, // limit
"category == 'AI'" // optional filter expression
);Text search supports:
- Single word searches
- Phrase searches with exact matching when
inOrderis true - Term-based searches with OR semantics when
inOrderis false - Stopword filtering to ignore common words
- Multiple text scoring algorithms (BM25, TFIDF, DISMAX, etc.)
Configure text search behavior at construction time:
RedisClient jedisClient = RedisClient.builder().hostAndPort("localhost", 6379).build();
RedisVectorStore vectorStore = RedisVectorStore.builder(jedisClient, embeddingModel)
.textScorer(TextScorer.TFIDF) // Text scoring algorithm
.inOrder(true) // Match terms in order
.stopwords(Set.of("is", "a", "the", "and")) // Ignore common words
.metadataFields(MetadataField.text("description")) // Define TEXT fields
.build();Range Search
The range search returns all documents within a specified radius:
// Search with radius
List<Document> rangeResults = vectorStore.searchByRange(
"AI and machine learning", // query
0.8, // radius (similarity threshold)
"category == 'AI'" // optional filter expression
);You can also set a default range threshold at construction time:
RedisClient jedisClient = RedisClient.builder().hostAndPort("localhost", 6379).build();
RedisVectorStore vectorStore = RedisVectorStore.builder(jedisClient, embeddingModel)
.defaultRangeThreshold(0.8) // Set default threshold
.build();
// Use default threshold
List<Document> results = vectorStore.searchByRange("query");Configuration Options
The Redis Vector Store supports multiple configuration options:
RedisClient jedisClient = RedisClient.builder().hostAndPort("localhost", 6379).build();
RedisVectorStore vectorStore = RedisVectorStore.builder(jedisClient, embeddingModel)
.indexName("custom-index") // Redis index name
.prefix("custom-prefix") // Redis key prefix
.contentFieldName("content") // Field for document content
.embeddingFieldName("embedding") // Field for vector embeddings
.vectorAlgorithm(Algorithm.HNSW) // Vector algorithm (HNSW or FLAT)
.distanceMetric(DistanceMetric.COSINE) // Distance metric
.hnswM(32) // HNSW parameter for connections
.hnswEfConstruction(100) // HNSW parameter for index building
.hnswEfRuntime(50) // HNSW parameter for search
.defaultRangeThreshold(0.8) // Default radius for range searches
.textScorer(TextScorer.BM25) // Text scoring algorithm
.inOrder(true) // Match terms in order
.stopwords(Set.of("the", "and")) // Stopwords to ignore
.metadataFields( // Metadata field definitions
MetadataField.tag("category"),
MetadataField.numeric("year"),
MetadataField.text("description")
)
.initializeSchema(true) // Auto-create index schema
.build();Distance Metrics
The Redis Vector Store supports three distance metrics:
- COSINE: Cosine similarity (default)
- L2: Euclidean distance
- IP: Inner Product
Each metric is automatically normalized to a 0-1 similarity score, where 1 is most similar.
Text Scoring Algorithms
For text search, several scoring algorithms are supported:
- BM25: Modern version of TF-IDF with term saturation (default)
- TFIDF: Classic term frequency-inverse document frequency
- BM25STD: Standardized BM25
- DISMAX: Disjunction max
- DOCSCORE: Document score
Scores are normalized to a 0-1 range for consistency with vector similarity scores.
Vector Stores/Spring Ai Weaviate Store/README (vector-stores/spring-ai-weaviate-store/README.md)
Weaviate Vector Store Documentation
Vector Stores/Spring Ai Weaviate Store/Src/Test/Resources/Docker Compose.Yml (vector-stores/spring-ai-weaviate-store/src/test/resources/docker-compose.yml)
version: '3.4'
services:
weaviate:
command:
- --host
- 0.0.0.0
- --port
- '8080'
- --scheme
- http
image: semitechnologies/weaviate:1.31.22
ports:
- "8080:8080"
restart: on-failure:0
environment:
QUERY_DEFAULTS_LIMIT: 25
AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: 'true'
PERSISTENCE_DATA_PATH: '/var/lib/weaviate'
DEFAULT_VECTORIZER_MODULE: 'none'
CLUSTER_HOSTNAME: 'node1'
.Github/PULL REQUEST TEMPLATE (.github/PULL_REQUEST_TEMPLATE.md)
Thank you for taking time to contribute this pull request!
You might have already read the [contributor guide][1], but as a reminder, please make sure to:
- Add a Signed-off-by line to each commit (
git commit -s) per the DCO - Rebase your changes on the latest
mainbranch and squash your commits - Add/Update unit tests as needed
- Run a build and make sure all tests pass prior to submission
For more details, please check the [contributor guide][1].
Thank you upfront!
[1]: https://github.com/spring-projects/spring-ai/blob/main/CONTRIBUTING.adoc
.Github/Release Files Spec.Json (.github/release-files-spec.json)
{
"files": [
{
"aql": {
"items.find": {
"$and": [
{
"@build.name": "${buildname}",
"@build.number": "${buildnumber}",
"path": {"$match": "org*"}
},
{
"$or": [
{
"name": {"$match": "*.pom"}
},
{
"name": {"$match": "*.jar"}
}
]
}
]
}
},
"target": "nexus/"
}
]
}
.Github/Workflow Generator.Yml (.github/workflow-generator.yml)
workflow:
generator:
project:
java:
versions:
primary: 17
workflows:
release-train:
build:
env:
COMMERCIAL_ARTIFACTORY_USERNAME: secrets.COMMERCIAL_ARTIFACTORY_USERNAME
COMMERCIAL_ARTIFACTORY_PASSWORD: secrets.COMMERCIAL_ARTIFACTORY_PASSWORD
COMMERCIAL_RELEASE_REPO_URL: vars.COMMERCIAL_RELEASE_REPO_URL
test:
env:
COMMERCIAL_ARTIFACTORY_USERNAME: secrets.COMMERCIAL_ARTIFACTORY_USERNAME
COMMERCIAL_ARTIFACTORY_PASSWORD: secrets.COMMERCIAL_ARTIFACTORY_PASSWORD
COMMERCIAL_RELEASE_REPO_URL: vars.COMMERCIAL_RELEASE_REPO_URL
.Github/Actions/Create Github Release/Action.Yml (.github/actions/create-github-release/action.yml)
name: Create GitHub Release
inputs:
commercial:
required: true
draft:
required: false
default: 'false'
latest:
required: false
default: 'false'
milestone:
required: true
pre-release:
required: false
default: 'false'
token:
required: true
runs:
using: composite
steps:
- name: Generate Changelog
uses: spring-io/github-changelog-generator@f7d7a87a3e7c627ecb8c26cf086c38ac5a939721 #v0.0.14
with:
config-file: ${{ inputs.commercial == 'true' && '.github/actions/create-github-release/changelog-generator-commercial.yml' || '.github/actions/create-github-release/changelog-generator-oss.yml' }}
milestone: ${{ inputs.milestone }}
token: ${{ inputs.token }}
- name: Create GitHub Release
shell: bash
env:
GITHUB_TOKEN: ${{ inputs.token }}
TAG: ${{ format('v{0}', inputs.milestone) }}
run: gh release create "$TAG" --title "$TAG" --verify-tag --notes-file changelog.md ${{ inputs.pre-release == 'true' && '--prerelease' || format('--latest={0}', inputs.latest) }} ${{ inputs.draft == 'true' && '--draft' || '' }}
.Github/Actions/Create Github Release/Changelog Generator Commercial.Yml (.github/actions/create-github-release/changelog-generator-commercial.yml)
changelog:
issues:
generate_links: false
contributors:
exclude:
names:
- "tzolov"
- "sdeleuze"
- "ilayaperumalg"
- "ericbottard"
- "sobychacko"
- "dimitarproynov"
.Github/Actions/Create Github Release/Changelog Generator Oss.Yml (.github/actions/create-github-release/changelog-generator-oss.yml)
changelog:
issues:
generate_links: true
contributors:
exclude:
names:
- "tzolov"
- "sdeleuze"
- "ilayaperumalg"
- "ericbottard"
- "sobychacko"
- "dimitarproynov"
.Github/Actions/Do Autoconfigure Test/Action.Yml (.github/actions/do-autoconfigure-test/action.yml)
name: "Run Spring AI Autoconfigure Integration Tests"
inputs:
spring-ai-branch:
required: true
default: "main"
maven-properties:
required: false
default: ""
spring-boot-version:
required: false
default: ""
runs:
using: "composite"
steps:
- name: Check environment
uses: actions/github-script@v7
with:
script: |
const env = ${{ toJson(env) }}
const emptyEnvEntries = Object.entries(env).filter(e => e[1].length === 0)
emptyEnvEntries.length > 0 &&
core.setFailed('Missing value for environment variable(s): ' + emptyEnvEntries.map(e => e[0]).join(', '));
- name: Run Spring AI Retry Autoconfigure test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/common/spring-ai-autoconfigure-retry \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Chat Observation test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/models/chat/observation/spring-ai-autoconfigure-model-chat-observation \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Embedding Observation test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/models/embedding/observation/spring-ai-autoconfigure-model-embedding-observation \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Image Observation test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/models/image/observation/spring-ai-autoconfigure-model-image-observation \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Chat Client test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/models/chat/client/spring-ai-autoconfigure-model-chat-client \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Neo4j Chat memory repository test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-neo4j \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Cassandra Chat memory repository test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-cassandra \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure JDBC Chat memory repository test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-jdbc \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure MongoDB Chat memory repository test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/models/chat/memory/repository/spring-ai-autoconfigure-model-chat-memory-repository-mongodb \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Redis Chat memory test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/models/chat/memory/spring-ai-autoconfigure-model-chat-memory-redis \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Tooling test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/models/tool/spring-ai-autoconfigure-model-tool \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Anthropic Model test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/models/spring-ai-autoconfigure-model-anthropic \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure DeepSeek test
if: ${{ inputs.spring-ai-branch == 'main' }}
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/models/spring-ai-autoconfigure-model-deepseek \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure ElevenLabs test
if: ${{ inputs.spring-ai-branch == 'main' }}
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/models/spring-ai-autoconfigure-model-elevenlabs \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Google GenAI test
if: ${{ inputs.spring-ai-branch == 'main' }}
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/models/spring-ai-autoconfigure-model-google-genai \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Azure OpenAI test
if: ${{ inputs.spring-ai-branch == '1.0.x' || inputs.spring-ai-branch == '1.1.x' }}
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/models/spring-ai-autoconfigure-model-azure-openai \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Bedrock AI test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/models/spring-ai-autoconfigure-model-bedrock-ai \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Huggingface test
if: ${{ inputs.spring-ai-branch == '1.1.x' || inputs.spring-ai-branch == '1.0.x' }}
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/models/spring-ai-autoconfigure-model-huggingface \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Minimax test
if: ${{ inputs.spring-ai-branch == '1.0.x' || inputs.spring-ai-branch == '1.1.x' }}
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/models/spring-ai-autoconfigure-model-minimax \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Mistral AI test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/models/spring-ai-autoconfigure-model-mistral-ai \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure OCI GenAI test
if: ${{ inputs.spring-ai-branch == '1.1.x' || inputs.spring-ai-branch == '1.0.x' }}
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/models/spring-ai-autoconfigure-model-oci-genai \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Ollama test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/models/spring-ai-autoconfigure-model-ollama \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure OpenAI test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/models/spring-ai-autoconfigure-model-openai \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure PostgresML Embedding test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/models/spring-ai-autoconfigure-model-postgresml-embedding \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Stability AI test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/models/spring-ai-autoconfigure-model-stability-ai \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Transformers test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/models/spring-ai-autoconfigure-model-transformers \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Vertex AI test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/models/spring-ai-autoconfigure-model-vertex-ai \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure ZhipuAI test
if: ${{ inputs.spring-ai-branch == '1.1.x' || inputs.spring-ai-branch == '1.0.x' }}
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/models/spring-ai-autoconfigure-model-zhipuai \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Azure vector store test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-azure \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Azure Cosmos DB test
if: ${{ inputs.spring-ai-branch == '1.1.x' || inputs.spring-ai-branch == '1.0.x' }}
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-azure-cosmos-db \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Cassandra Vector Store test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-cassandra \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Chroma Vector Store test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-chroma \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Couchbase Vector Store test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-couchbase \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure ElasticSearch Vector Store test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-elasticsearch \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure GemFire Vector Store test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-gemfire \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Mariadb Vector Store test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mariadb \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Milvus Vector Store test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-milvus \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure MongoDB Atlas Vector Store test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mongodb-atlas \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Neo4j Vector Store test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-neo4j \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Vector Store Observation test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-observation \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Opensearch Vector Store test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-opensearch \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Oracle Vector Store test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-oracle \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Pgvector test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-pgvector \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Pinecone Vector Store test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-pinecone \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Qdrant Vector Store test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-qdrant \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Redis Vector Store test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-redis \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Redis Semantic Cache Vector Store test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-redis-semantic-cache \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Typesense Vector Store test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-typesense \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure Weaviate Vector Store test
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-weaviate \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure MCP Client test
if: ${{ inputs.spring-ai-branch == '1.0.x' }}
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/mcp/spring-ai-autoconfigure-mcp-client \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure MCP common Client test
if: ${{ inputs.spring-ai-branch == 'main' }}
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/mcp/spring-ai-autoconfigure-mcp-client-common \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure MCP HTTP Client test
if: ${{ inputs.spring-ai-branch == 'main' }}
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/mcp/spring-ai-autoconfigure-mcp-client-httpclient \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure MCP Webflux Client test
if: ${{ inputs.spring-ai-branch == 'main' }}
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/mcp/spring-ai-autoconfigure-mcp-client-webflux \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure MCP Server test
if: ${{ inputs.spring-ai-branch == '1.0.x' }}
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/mcp/spring-ai-autoconfigure-mcp-server \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure MCP common Server test
if: ${{ inputs.spring-ai-branch == 'main' }}
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure MCP Webflux Server test
if: ${{ inputs.spring-ai-branch == 'main' }}
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
- name: Run Spring AI Autoconfigure MCP WebMVC Server test
if: ${{ inputs.spring-ai-branch == 'main' }}
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webmvc \
-Pintegration-tests ${{ inputs.maven-properties }} ${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} -Dfailsafe.rerunFailingTestsCount=2 verify
.Github/Actions/Do Integration Test/Action.Yml (.github/actions/do-integration-test/action.yml)
name: "Run Spring AI Integration Test"
inputs:
model-name:
required: true
maven-properties:
required: false
default: ""
spring-boot-version:
required: false
default: ""
runs:
using: "composite"
steps:
- name: Check environment
uses: actions/github-script@v7
with:
script: |
const env = ${{ toJson(env) }}
const emptyEnvEntries = Object.entries(env).filter(e => e[1].length === 0)
emptyEnvEntries.length > 0 &&
core.setFailed('Missing value for environment variable(s): ' + emptyEnvEntries.map(e => e[0]).join(', '));
- name: Run ${{ inputs.model-name }} model tests
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl models/spring-ai-${{ inputs.model-name }} \
-Pintegration-tests \
${{ inputs.maven-properties }} \
${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} \
-Dfailsafe.rerunFailingTestsCount=2 \
verify
.Github/Actions/Do Multi Module Test/Action.Yml (.github/actions/do-multi-module-test/action.yml)
name: "Run Spring AI Multi-Module Integration Tests"
inputs:
modules:
required: true
maven-properties:
required: false
default: ""
spring-boot-version:
required: false
default: ""
runs:
using: "composite"
steps:
- name: Check environment
uses: actions/github-script@v7
with:
script: |
const env = ${{ toJson(env) }}
const emptyEnvEntries = Object.entries(env).filter(e => e[1].length === 0)
emptyEnvEntries.length > 0 &&
core.setFailed('Missing value for environment variable(s): ' + emptyEnvEntries.map(e => e[0]).join(', '));
- name: Run integration tests
shell: bash
run: |
echo 'Running with maven properties:' ${{ inputs.maven-properties }}
./mvnw --batch-mode -ntp --no-snapshot-updates \
-pl ${{ inputs.modules }} \
-Pintegration-tests \
${{ inputs.maven-properties }} \
${{ inputs.spring-boot-version != '' && format('-Dspring-boot.version={0}', inputs.spring-boot-version) || '' }} \
-Dfailsafe.rerunFailingTestsCount=2 \
verify
.Github/Actions/Release Train Build/Action.Yml (.github/actions/release-train-build/action.yml)
name: Build Release
runs:
using: composite
steps:
- name: Build Release
shell: bash
run: ./mvnw --batch-mode -ntp -PreleaseTrain --settings release-train-settings.xml -DaltDeploymentRepository="release-train::file://$(pwd)/deployment-repository" -Dmaven.test.skip deploy
.Github/Actions/Release Train Test/Action.Yml (.github/actions/release-train-test/action.yml)
name: Test Release
runs:
using: composite
steps:
- name: Test Release
shell: bash
run: ./mvnw --batch-mode -ntp -PreleaseTrain --settings release-train-settings.xml test
.Github/ISSUE TEMPLATE/Bug Report (.github/ISSUE_TEMPLATE/bug_report.md)
name: Bug report
about: Create a bug report to help us improve the project
title: ''
labels: 'type: bug, status: waiting-for-triage'
assignees: ''
Please do a quick search on GitHub issues first, there might be already a duplicate issue for the one you are about to create.
If the bug is trivial, just go ahead and create the issue. Otherwise, please take a few moments and fill in the following sections:
Bug description
A clear and concise description of what the bug is about.
Environment
Please provide as many details as possible: Spring AI version, Java version, which vector store you use if any, etc
Steps to reproduce
Steps to reproduce the issue.
Expected behavior
A clear and concise description of what you expected to happen.
Minimal Complete Reproducible example
Please provide a failing test or a minimal complete verifiable example that reproduces the issue.
Bug reports that are reproducible will take priority in resolution over reports that are not reproducible.
.Github/ISSUE TEMPLATE/Config.Yml (.github/ISSUE_TEMPLATE/config.yml)
blank_issues_enabled: false
contact_links:
- name: Questions and Community Support
url: https://stackoverflow.com/questions/tagged/spring-ai
about: Please ask and answer questions on StackOverflow with the spring-ai tag
.Github/ISSUE TEMPLATE/Feature Request (.github/ISSUE_TEMPLATE/feature_request.md)
name: Feature request
about: Suggest an idea for this project
title: ''
labels: 'status: waiting-for-triage, type: feature'
assignees: ''
Please do a quick search on GitHub issues first, the feature you are about to request might have already been requested.
Expected Behavior
Current Behavior
Context
.Github/ISSUE TEMPLATE/Miscellaneous (.github/ISSUE_TEMPLATE/miscellaneous.md)
name: Miscellaneous
about: Suggest an improvement for this project
title: ''
labels: 'status: waiting-for-triage'
assignees: ''
For anything other than bug reports and feature requests (performance, refactoring, etc),
just go ahead and file the issue. Please provide as many details as possible.
If you have a question or a support request, please open a new discussion on GitHub Discussions
or ask a question on StackOverflow.
Please do not create issues on the Issue Tracker for questions or support requests.
We would like to keep the issue tracker exclusively for bug reports and feature requests.
.Github/Workflows/Auto Cherry Pick.Yml (.github/workflows/auto-cherry-pick.yml)
name: Auto Cherry-Pick
on:
push:
branches:
- main
- '*.x'
jobs:
cherry-pick-commit:
uses: spring-io/spring-github-workflows/.github/workflows/spring-cherry-pick.yml@v5
secrets:
GH_ACTIONS_REPO_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
.Github/Workflows/Backport Issue.Yml (.github/workflows/backport-issue.yml)
name: Backport Bot
on:
issues:
types: [labeled]
pull_request:
types: [labeled]
push:
branches:
- '[0-9]+.[0-9]+.x'
- 'main'
jobs:
backport-issue:
permissions:
contents: read
issues: write
pull-requests: write
runs-on: ubuntu-latest
steps:
- name: Create Backport Issue
uses: spring-io/[email protected]
with:
token: ${{ secrets.GITHUB_TOKEN }}
.Github/Workflows/Build And Deploy Snapshot.Yml (.github/workflows/build-and-deploy-snapshot.yml)
name: Build and Deploy Snapshot
on:
push:
branches:
- 'main'
- '[0-9].[0-9].x'
- '[0-9].[0-9].x-internal'
schedule:
- cron: '30 11 1-5' # 12:30 PM CET / 6:30 AM
workflow_dispatch:
concurrency:
group: ${{ github.workflow_ref }}
cancel-in-progress: true
jobs:
build-all:
name: Build all modules
if: ${{ github.repository_owner == 'spring-projects' }}
runs-on: ${{ vars.COMMERCIAL && vars.UBUNTU_SMALL || 'ubuntu-latest' }}
steps:
- name: Checkout source code
uses: actions/checkout@v6
- name: Set up JDK
uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'liberica'
cache: 'maven'
- name: Setup Maven Build-Cache (~/.m2/build-cache)
if: ${{ github.event_name != 'schedule' }}
uses: actions/cache@v5
with:
path: ~/.m2/build-cache
# See pr-check.yml for an explanation of the key format
key: build-cache-${{ runner.os }}-${{ hashFiles('/pom.xml') }}-${{ github.run_id }}
restore-keys: |
build-cache-${{ runner.os }}-${{ hashFiles('/pom.xml') }}-
build-cache-${{ runner.os }}-
- name: Build all modules with unit tests
env:
COMMERCIAL_ARTIFACTORY_USERNAME: "${{ secrets.COMMERCIAL_ARTIFACTORY_USERNAME }}"
COMMERCIAL_ARTIFACTORY_PASSWORD: "${{ secrets.COMMERCIAL_ARTIFACTORY_PASSWORD }}"
COMMERCIAL_SNAPSHOT_REPO_URL: "${{ vars.COMMERCIAL_SNAPSHOT_REPO_URL }}"
COMMERCIAL_RELEASE_REPO_URL: "${{ vars.COMMERCIAL_RELEASE_REPO_URL }}"
run: |
./mvnw ${{ vars.COMMERCIAL && '-s commercial-settings.xml -Pcommercial' || '' }} --batch-mode -ntp --update-snapshots clean install
- name: Upload Spring-AI Built Artifacts
uses: actions/upload-artifact@v6
with:
name: build-artifacts
path: ~/.m2/repository/org/springframework/ai
retention-days: 1 # Intent is to share only with downstream jobs in this workflow
- name: Purge Spring AI Built Artifacts # We don't want the setup-java m2 cache to capture our products, only our deps
run: rm -fr ~/.m2/repository/org/springframework/ai
test-ollama:
name: Test Ollama
if: ${{ github.repository_owner == 'spring-projects' }}
runs-on: ${{ vars.COMMERCIAL && vars.UBUNTU_SMALL || 'ubuntu-latest' }}
needs: build-all
services:
ollama:
image: ollama/ollama:latest
ports:
- 11434:11434
env:
OLLAMA_WITH_REUSE: true
OLLAMA_AUTOCONF_TESTS_ENABLED: "true"
steps:
- name: Checkout source code
uses: actions/checkout@v6
- name: Set up JDK
uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'liberica'
cache: 'maven'
- name: Setup Maven Build-Cache (~/.m2/build-cache)
uses: actions/cache@v5
if: ${{ github.event_name != 'schedule' }}
with:
path: ~/.m2/build-cache
key: build-cache-${{ runner.os }}-ollama-${{ hashFiles('/pom.xml') }}-${{ github.run_id }}
restore-keys: |
build-cache-${{ runner.os }}-ollama-${{ hashFiles('/pom.xml') }}-
build-cache-${{ runner.os }}-
- name: Download Spring-AI Built Artifacts
uses: actions/download-artifact@v7
with:
name: build-artifacts
path: ~/.m2/repository/org/springframework/ai
- name: Configure Testcontainers
run: echo "testcontainers.reuse.enable=true" > $HOME/.testcontainers.properties
- name: Test Ollama modules
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
COMMERCIAL_ARTIFACTORY_USERNAME: "${{ secrets.COMMERCIAL_ARTIFACTORY_USERNAME }}"
COMMERCIAL_ARTIFACTORY_PASSWORD: "${{ secrets.COMMERCIAL_ARTIFACTORY_PASSWORD }}"
COMMERCIAL_SNAPSHOT_REPO_URL: "${{ vars.COMMERCIAL_SNAPSHOT_REPO_URL }}"
COMMERCIAL_RELEASE_REPO_URL: "${{ vars.COMMERCIAL_RELEASE_REPO_URL }}"
run: |
./mvnw ${{ vars.COMMERCIAL && '-s commercial-settings.xml -Pcommercial' || '' }} --batch-mode -ntp --no-snapshot-updates \
-pl models/spring-ai-ollama,auto-configurations/models/spring-ai-autoconfigure-model-ollama \
-Pci-fast-integration-tests \
-Dfailsafe.rerunFailingTestsCount=3 \
verify
test-openai:
name: Test OpenAI
if: ${{ github.repository_owner == 'spring-projects' }}
runs-on: ${{ vars.COMMERCIAL && vars.UBUNTU_SMALL || 'ubuntu-latest' }}
needs: build-all
steps:
- name: Checkout source code
uses: actions/checkout@v6
- name: Set up JDK
uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'liberica'
cache: 'maven'
- name: Setup Maven Build-Cache (~/.m2/build-cache)
uses: actions/cache@v5
with:
path: ~/.m2/build-cache
key: build-cache-${{ runner.os }}-openai-${{ hashFiles('/pom.xml') }}-${{ github.run_id }}
restore-keys: |
build-cache-${{ runner.os }}-openai-${{ hashFiles('/pom.xml') }}-
build-cache-${{ runner.os }}-
- name: Download Spring-AI Built Artifacts
uses: actions/download-artifact@v7
with:
name: build-artifacts
path: ~/.m2/repository/org/springframework/ai
- name: Configure Testcontainers
run: echo "testcontainers.reuse.enable=true" > $HOME/.testcontainers.properties
- name: Test OpenAI modules
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
COMMERCIAL_ARTIFACTORY_USERNAME: "${{ secrets.COMMERCIAL_ARTIFACTORY_USERNAME }}"
COMMERCIAL_ARTIFACTORY_PASSWORD: "${{ secrets.COMMERCIAL_ARTIFACTORY_PASSWORD }}"
COMMERCIAL_SNAPSHOT_REPO_URL: "${{ vars.COMMERCIAL_SNAPSHOT_REPO_URL }}"
COMMERCIAL_RELEASE_REPO_URL: "${{ vars.COMMERCIAL_RELEASE_REPO_URL }}"
run: |
./mvnw ${{ vars.COMMERCIAL && '-s commercial-settings.xml -Pcommercial' || '' }} --batch-mode -ntp --no-snapshot-updates \
-pl models/spring-ai-openai,auto-configurations/models/spring-ai-autoconfigure-model-openai \
-Pci-fast-integration-tests \
-Dfailsafe.rerunFailingTestsCount=3 \
verify
test-remaining:
name: Test Remaining (MCP, Google GenAI, Vertex AI Embedding, Chroma, PgVector)
if: ${{ github.repository_owner == 'spring-projects' }}
runs-on: ${{ vars.COMMERCIAL && vars.UBUNTU_SMALL || 'ubuntu-latest' }}
needs: build-all
steps:
- name: Checkout source code
uses: actions/checkout@v6
- name: Set up JDK
uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'liberica'
cache: 'maven'
- name: Setup Maven Build-Cache (~/.m2/build-cache)
uses: actions/cache@v5
with:
path: ~/.m2/build-cache
key: build-cache-${{ runner.os }}-other-${{ hashFiles('/pom.xml') }}-${{ github.run_id }}
restore-keys: |
build-cache-${{ runner.os }}-other-${{ hashFiles('/pom.xml') }}-
build-cache-${{ runner.os }}-
- name: Download Spring-AI Built Artifacts
uses: actions/download-artifact@v7
with:
name: build-artifacts
path: ~/.m2/repository/org/springframework/ai
- name: Configure Testcontainers
run: echo "testcontainers.reuse.enable=true" > $HOME/.testcontainers.properties
- name: Test remaining modules
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
COMMERCIAL_ARTIFACTORY_USERNAME: "${{ secrets.COMMERCIAL_ARTIFACTORY_USERNAME }}"
COMMERCIAL_ARTIFACTORY_PASSWORD: "${{ secrets.COMMERCIAL_ARTIFACTORY_PASSWORD }}"
COMMERCIAL_SNAPSHOT_REPO_URL: "${{ vars.COMMERCIAL_SNAPSHOT_REPO_URL }}"
COMMERCIAL_RELEASE_REPO_URL: "${{ vars.COMMERCIAL_RELEASE_REPO_URL }}"
run: |
./mvnw ${{ vars.COMMERCIAL && '-s commercial-settings.xml -Pcommercial' || '' }} --batch-mode -ntp --no-snapshot-updates \
-pl models/spring-ai-google-genai, \
-pl auto-configurations/models/spring-ai-autoconfigure-model-google-genai, \
${{ vars.COMMERCIAL && '-pl models/spring-ai-vertex-ai-embedding,' || '-pl mcp/mcp-annotations,' }} \
-pl mcp/common, \
-pl mcp/transport/mcp-spring-webflux, \
-pl mcp/transport/mcp-spring-webmvc, \
-pl auto-configurations/mcp/spring-ai-autoconfigure-mcp-client-common, \
-pl auto-configurations/mcp/spring-ai-autoconfigure-mcp-client-httpclient, \
-pl auto-configurations/mcp/spring-ai-autoconfigure-mcp-client-webflux, \
-pl auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common, \
-pl auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webmvc, \
-pl auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux, \
-pl vector-stores/spring-ai-chroma-store, \
-pl vector-stores/spring-ai-pgvector-store, \
-pl spring-ai-integration-tests \
-Pci-fast-integration-tests \
-Dfailsafe.rerunFailingTestsCount=3 \
verify
deploy-artifactory:
name: Deploy to Artifactory
if: ${{ github.repository_owner == 'spring-projects' && github.event_name != 'schedule' }}
runs-on: ${{ vars.COMMERCIAL && vars.UBUNTU_SMALL || 'ubuntu-latest' }}
needs: [build-all, test-ollama, test-openai, test-remaining]
steps:
- name: Checkout source code
uses: actions/checkout@v6
- name: Set up JDK
uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'liberica'
cache: 'maven'
- name: Setup Maven Build-Cache (~/.m2/build-cache)
uses: actions/cache@v5
with:
path: ~/.m2/build-cache
key: build-cache-${{ runner.os }}-${{ hashFiles('/pom.xml') }}-${{ github.run_id }}
restore-keys: |
build-cache-${{ runner.os }}-${{ hashFiles('/pom.xml') }}-
build-cache-${{ runner.os }}-
- name: Deploy to Artifactory
env:
ARTIFACTORY_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }}
ARTIFACTORY_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }}
COMMERCIAL_ARTIFACTORY_USERNAME: "${{ secrets.COMMERCIAL_ARTIFACTORY_USERNAME }}"
COMMERCIAL_ARTIFACTORY_PASSWORD: "${{ secrets.COMMERCIAL_ARTIFACTORY_PASSWORD }}"
COMMERCIAL_SNAPSHOT_REPO_URL: "${{ vars.COMMERCIAL_SNAPSHOT_REPO_URL }}"
COMMERCIAL_RELEASE_REPO_URL: "${{ vars.COMMERCIAL_RELEASE_REPO_URL }}"
run: |
./mvnw ${{ vars.COMMERCIAL && '-s commercial-settings.xml -Pcommercial' || '-s settings.xml' }} --batch-mode -ntp -Dmaven.test.skip \
${{ vars.COMMERCIAL && format('-DaltSnapshotDeploymentRepository=spring-enterprise-snapshot::{0}', vars.COMMERCIAL_SNAPSHOT_REPO_URL) || '' }} \
deploy
.Github/Workflows/Dependency Ci Dashboard.Yml (.github/workflows/dependency-ci-dashboard.yml)
name: Ecosystem CI Dashboard
on:
schedule:
- cron: '15 6 *' # 06:15 UTC daily
workflow_dispatch:
permissions:
issues: write
contents: write
jobs:
update-dashboard:
name: Update Ecosystem CI Dashboard
runs-on: ubuntu-latest
if: ${{ github.repository == 'spring-projects/spring-ai' }}
steps:
- name: Checkout source code
uses: actions/checkout@v6
- name: Load configuration
id: config
run: |
CONFIG=$(cat src/ecosystem-ci/ci-alert-config.json)
echo "issue_number=$(echo "$CONFIG" | jq -r '.issue_number')" >> $GITHUB_OUTPUT
echo "tracked_branch=$(echo "$CONFIG" | jq -r '.tracked_branch')" >> $GITHUB_OUTPUT
echo "alert_after_days=$(echo "$CONFIG" | jq -r '.alert_after_days')" >> $GITHUB_OUTPUT
echo "heartbeat_days=$(echo "$CONFIG" | jq -r '.heartbeat_days')" >> $GITHUB_OUTPUT
echo "dependencies<<EOF" >> $GITHUB_OUTPUT
echo "$CONFIG" | jq -c '.dependencies' >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Query CI status for all dependencies
id: query-status
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DEPENDENCIES: ${{ steps.config.outputs.dependencies }}
TRACKED_BRANCH: ${{ steps.config.outputs.tracked_branch }}
run: |
RESULTS="[]"
for row in $(echo "$DEPENDENCIES" | jq -r '.[] | @base64'); do
_jq() {
echo ${row} | base64 --decode | jq -r ${1}
}
OWNER=$(_jq '.owner')
REPO=$(_jq '.repo')
echo "Querying status for $OWNER/$REPO..."
# Query workflow runs for the branch (most reliable for GitHub Actions)
RUNS_RESPONSE=$(curl -s -H "Authorization: token $GH_TOKEN" \
-H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/$OWNER/$REPO/actions/runs?branch=$TRACKED_BRANCH&per_page=10")
# Find the most recent completed workflow run
LATEST_RUN=$(echo "$RUNS_RESPONSE" | jq '[.workflow_runs[] | select(.status == "completed")] | .[0]')
if [ "$LATEST_RUN" != "null" ] && [ -n "$LATEST_RUN" ]; then
CONCLUSION=$(echo "$LATEST_RUN" | jq -r '.conclusion // "unknown"')
COMMIT_SHA=$(echo "$LATEST_RUN" | jq -r '.head_sha // "unknown"' | head -c 7)
COMMIT_DATE=$(echo "$LATEST_RUN" | jq -r '.created_at // ""')
# Map conclusion to state
case "$CONCLUSION" in
"success") STATE="success" ;;
"failure"|"timed_out"|"cancelled") STATE="failure" ;;
*) STATE="unknown" ;;
esac
else
# Check if there are any in-progress runs
IN_PROGRESS=$(echo "$RUNS_RESPONSE" | jq '[.workflow_runs[] | select(.status == "in_progress" or .status == "queued")] | length')
if [ "$IN_PROGRESS" -gt 0 ]; then
STATE="pending"
# Get commit from in-progress run
COMMIT_SHA=$(echo "$RUNS_RESPONSE" | jq -r '.workflow_runs[0].head_sha // "unknown"' | head -c 7)
COMMIT_DATE=$(echo "$RUNS_RESPONSE" | jq -r '.workflow_runs[0].created_at // ""')
else
STATE="unknown"
# Fall back to HEAD commit info
COMMIT_RESPONSE=$(curl -s -H "Authorization: token $GH_TOKEN" \
-H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/$OWNER/$REPO/commits/$TRACKED_BRANCH")
COMMIT_SHA=$(echo "$COMMIT_RESPONSE" | jq -r '.sha // "unknown"' | head -c 7)
COMMIT_DATE=$(echo "$COMMIT_RESPONSE" | jq -r '.commit.committer.date // ""')
fi
fi
RESULT=$(jq -n \
--arg owner "$OWNER" \
--arg repo "$REPO" \
--arg state "$STATE" \
--arg sha "$COMMIT_SHA" \
--arg date "$COMMIT_DATE" \
'{owner: $owner, repo: $repo, state: $state, sha: $sha, commit_date: $date}')
RESULTS=$(echo "$RESULTS" | jq --argjson result "$RESULT" '. + [$result]')
done
echo "results<<EOF" >> $GITHUB_OUTPUT
echo "$RESULTS" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Update dashboard and check alerts
uses: actions/github-script@v7
env:
RESULTS: ${{ steps.query-status.outputs.results }}
ISSUE_NUMBER: ${{ steps.config.outputs.issue_number }}
ALERT_AFTER_DAYS: ${{ steps.config.outputs.alert_after_days }}
HEARTBEAT_DAYS: ${{ steps.config.outputs.heartbeat_days }}
TRACKED_BRANCH: ${{ steps.config.outputs.tracked_branch }}
with:
script: |
const results = JSON.parse(process.env.RESULTS);
const issueNumber = parseInt(process.env.ISSUE_NUMBER);
const alertAfterDays = parseInt(process.env.ALERT_AFTER_DAYS);
const heartbeatDays = parseInt(process.env.HEARTBEAT_DAYS);
const trackedBranch = process.env.TRACKED_BRANCH;
const now = new Date();
const timestamp = now.toISOString();
// Status emoji mapping
const statusEmoji = {
'success': ':white_check_mark:',
'failure': ':x:',
'pending': ':yellow_circle:',
'unknown': ':grey_question:'
};
// Find dashboard comment (contains hidden state marker)
const STATE_MARKER = '';
const comments = await github.paginate(github.rest.issues.listComments, {
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber
});
let dashboardComment = comments.find(c => c.body.includes(DASHBOARD_MARKER));
// Parse previous state from comment
let previousState = {};
if (dashboardComment) {
const stateMatch = dashboardComment.body.match(//s);
if (stateMatch) {
try {
previousState = JSON.parse(stateMatch[1]);
} catch (e) {
console.log('Failed to parse previous state:', e);
}
}
}
// Update state with current results
const newState = {};
const alertsNeeded = [];
for (const result of results) {
const key = ${result.owner}/${result.repo};
const prevEntry = previousState[key] || {};
if (result.state === 'failure') {
// Track when it first failed
const failedSince = prevEntry.failedSince || timestamp;
const failedDays = Math.floor((now - new Date(failedSince)) / (1000 60 60 * 24));
const lastAlerted = prevEntry.lastAlerted;
newState[key] = {
state: result.state,
failedSince: failedSince,
failedDays: failedDays,
lastAlerted: lastAlerted
};
// Check if we need to alert
if (failedDays >= alertAfterDays) {
// Only alert if we haven't alerted in the last heartbeat period
const shouldAlert = !lastAlerted ||
(now - new Date(lastAlerted)) >= (heartbeatDays 24 60 60 1000);
if (shouldAlert) {
alertsNeeded.push({
owner: result.owner,
repo: result.repo,
failedDays: failedDays,
sha: result.sha
});
newState[key].lastAlerted = timestamp;
}
}
} else {
// Not failing - clear failure tracking
newState[key] = {
state: result.state
};
}
}
// Build dashboard table
let dashboardTable = | Repository | Status | Branch | Latest Commit | Last Run |\n;
dashboardTable += |------------|--------|--------|---------------|----------|\n;
for (const result of results) {
const key = ${result.owner}/${result.repo};
const emoji = statusEmoji[result.state] || statusEmoji['unknown'];
const stateEntry = newState[key];
let statusText = emoji;
if (result.state === 'failure' && stateEntry.failedDays > 0) {
statusText += (${stateEntry.failedDays}d);
}
const repoLink = ${result.owner}/${result.repo};
const commitLink = result.sha !== 'unknown'
? \${result.sha}\
: 'N/A';
const actionsLink = ${trackedBranch};
// Format date as YYYY-MM-DD
const lastRun = result.commit_date
? new Date(result.commit_date).toISOString().split('T')[0]
: 'N/A';
dashboardTable += | ${repoLink} | ${statusText} | ${actionsLink} | ${commitLink} | ${lastRun} |\n;
}
// Build dashboard comment body
const stateJson = JSON.stringify(newState);
const dashboardBody = `${DASHBOARD_MARKER}
## Ecosystem CI Dashboard
Last updated: ${timestamp}
${dashboardTable}
### Legend
- :white_check_mark: All checks passing
- :x: CI failing (days in parentheses)
- :yellow_circle: Checks in progress
- :grey_question: Status unknown
### Alert Policy
- Alerts are posted when a dependency has been failing for ${alertAfterDays}+ days
- Subscribe to this issue to receive CI failure notifications
${STATE_MARKER}${stateJson}-->
`.split('\n').map(line => line.trim()).join('\n');
// Update or create dashboard comment
if (dashboardComment) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: dashboardComment.id,
body: dashboardBody
});
console.log('Updated dashboard comment');
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
body: dashboardBody
});
console.log('Created dashboard comment');
}
// Post alert comments if needed
for (const alert of alertsNeeded) {
const alertBody = `:rotating_light: CI Alert: ${alert.owner}/${alert.repo} has been failing for ${alert.failedDays} days
- Branch: ${trackedBranch}
- Latest commit: \${alert.sha}\
- CI Status: View Actions
Please investigate and fix the CI failure.`;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
body: alertBody
});
console.log(Posted alert for ${alert.owner}/${alert.repo});
}
// Set outputs for wiki update
core.setOutput('dashboard_table', dashboardTable);
core.setOutput('timestamp', timestamp);
core.setOutput('alert_after_days', alertAfterDays);
- name: Update Wiki Dashboard
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
RESULTS: ${{ steps.query-status.outputs.results }}
TRACKED_BRANCH: ${{ steps.config.outputs.tracked_branch }}
ALERT_AFTER_DAYS: ${{ steps.config.outputs.alert_after_days }}
run: |
# Configure git
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
# Clone wiki repo
WIKI_DIR=$(mktemp -d)
git clone "https://x-access-token:${GH_TOKEN}@github.com/${{ github.repository }}.wiki.git" "$WIKI_DIR"
# Generate wiki page content
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
# Status emoji mapping for wiki (GitHub wiki renders these)
cat > "$WIKI_DIR/Ecosystem-CI-Dashboard.md" << 'WIKI_HEADER'
# Ecosystem CI Dashboard
This dashboard monitors the CI health of Spring AI ecosystem dependencies.
WIKI_HEADER
echo "Last updated: $TIMESTAMP" >> "$WIKI_DIR/Ecosystem-CI-Dashboard.md"
echo "" >> "$WIKI_DIR/Ecosystem-CI-Dashboard.md"
# Build table
echo "| Repository | Status | Branch | Latest Commit | Last Run |" >> "$WIKI_DIR/Ecosystem-CI-Dashboard.md"
echo "|------------|--------|--------|---------------|----------|" >> "$WIKI_DIR/Ecosystem-CI-Dashboard.md"
echo "$RESULTS" | jq -r '.[] | @base64' | while read row; do
OWNER=$(echo "$row" | base64 --decode | jq -r '.owner')
REPO=$(echo "$row" | base64 --decode | jq -r '.repo')
STATE=$(echo "$row" | base64 --decode | jq -r '.state')
SHA=$(echo "$row" | base64 --decode | jq -r '.sha')
COMMIT_DATE=$(echo "$row" | base64 --decode | jq -r '.commit_date')
case "$STATE" in
"success") EMOJI=":white_check_mark:" ;;
"failure") EMOJI=":x:" ;;
"pending") EMOJI=":yellow_circle:" ;;
*) EMOJI=":grey_question:" ;;
esac
REPO_LINK="$OWNER/$REPO"
COMMIT_LINK="\$SHA\"
ACTIONS_LINK="$TRACKED_BRANCH"
# Format date as YYYY-MM-DD
if [ -n "$COMMIT_DATE" ] && [ "$COMMIT_DATE" != "null" ]; then
LAST_RUN=$(echo "$COMMIT_DATE" | cut -d'T' -f1)
else
LAST_RUN="N/A"
fi
echo "| $REPO_LINK | $EMOJI | $ACTIONS_LINK | $COMMIT_LINK | $LAST_RUN |" >> "$WIKI_DIR/Ecosystem-CI-Dashboard.md"
done
cat >> "$WIKI_DIR/Ecosystem-CI-Dashboard.md" << WIKI_FOOTER
## Legend
- :white_check_mark: All checks passing
- :x: CI failing
- :yellow_circle: Checks in progress
- :grey_question: Status unknown
## Alert Policy
Alerts are posted to Issue #${{ steps.config.outputs.issue_number }} when a dependency has been failing for ${ALERT_AFTER_DAYS}+ days.
Subscribe to that issue to receive CI failure notifications.
## Monitored Repositories
The following repositories are monitored as part of the Spring AI ecosystem:
WIKI_FOOTER
echo "$RESULTS" | jq -r '.[] | "- \(.owner)/\(.repo)/\(.repo))"' >> "$WIKI_DIR/Ecosystem-CI-Dashboard.md"
cat >> "$WIKI_DIR/Ecosystem-CI-Dashboard.md" << 'WIKI_END'
---
This page is automatically updated by the Ecosystem CI Dashboard workflow.
WIKI_END
# Commit and push wiki changes
cd "$WIKI_DIR"
git add Ecosystem-CI-Dashboard.md
if git diff --staged --quiet; then
echo "No changes to wiki"
else
git commit -m "Update Ecosystem CI Dashboard - $TIMESTAMP"
git push
echo "Wiki updated successfully"
fi
.Github/Workflows/Deploy Docs.Yml (.github/workflows/deploy-docs.yml)
name: Deploy Docs
run-name: ${{ github.event_name == 'workflow_dispatch' && 'Deploy Docs (Build)' || 'Deploy Docs (Dispatcher)' }}
on:
workflow_dispatch:
permissions:
actions: write
jobs:
build:
runs-on: ${{ vars.COMMERCIAL && vars.UBUNTU_SMALL || 'ubuntu-latest' }}
if: ${{ github.repository_owner == 'spring-projects' }}
steps:
- name: Dispatch (full build)
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh workflow run deploy-docs.yml -r docs-build --repo ${{ github.repository }}
.Github/Workflows/Deploy Javadoc.Yml (.github/workflows/deploy-javadoc.yml)
name: Deploy Javadoc
on:
push:
tags:
- 'v*'
workflow_dispatch:
permissions:
contents: read
jobs:
deploy-javadoc:
name: Deploy Javadoc
if: ${{ github.repository_owner == 'spring-projects' }}
runs-on: ${{ vars.COMMERCIAL && vars.UBUNTU_SMALL || 'ubuntu-latest' }}
steps:
- name: Check Out
uses: actions/checkout@v4
- name: Set Up Java
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'liberica'
- name: Generate Javadoc (commercial)
if: ${{ vars.COMMERCIAL }}
shell: bash
env:
COMMERCIAL_RELEASE_REPO_URL: ${{ vars.COMMERCIAL_RELEASE_REPO_URL }}
COMMERCIAL_ARTIFACTORY_PASSWORD: ${{ secrets.COMMERCIAL_ARTIFACTORY_PASSWORD }}
COMMERCIAL_ARTIFACTORY_USERNAME: ${{ secrets.COMMERCIAL_ARTIFACTORY_USERNAME }}
COMMERCIAL_SNAPSHOT_REPO_URL: ${{ vars.COMMERCIAL_SNAPSHOT_REPO_URL }}
USW1_USERNAME: ${{ secrets.COMMERCIAL_ARTIFACTORY_RO_USERNAME }}
USW1_PASSWORD: ${{ secrets.COMMERCIAL_ARTIFACTORY_RO_PASSWORD }}
run: ./mvnw -s commercial-settings.xml --batch-mode -ntp javadoc:aggregate-jar
- name: Generate Javadoc (OSS)
if: ${{ !vars.COMMERCIAL }}
run: ./mvnw --batch-mode -ntp javadoc:aggregate-jar
- name: Capture project version
run: echo PROJECT_VERSION=$(./mvnw ${{ vars.COMMERCIAL && '-s commercial-settings.xml' || '' }} help:evaluate -Dexpression=project.version --quiet -DforceStdout) >> $GITHUB_ENV
- name: Extract Javadoc
if: ${{ vars.COMMERCIAL }}
run: |
mkdir -p target/javadoc-site/${PROJECT_VERSION}/api
unzip target/spring-ai-parent-${PROJECT_VERSION}-javadoc.jar -d target/javadoc-site/${PROJECT_VERSION}/api
- name: Authenticate to GCP
if: ${{ vars.COMMERCIAL }}
uses: google-github-actions/[email protected]
with:
credentials_json: ${{ secrets.COMMERCIAL_DOCS_GCP_BUCKET_JSON }}
- name: Upload Javadoc to GCP (commercial)
if: ${{ vars.COMMERCIAL }}
uses: google-github-actions/[email protected]
with:
path: target/javadoc-site
destination: ${{ secrets.COMMERCIAL_DOCS_HOST }}/spring-ai/docs/
parent: false
- name: Setup SSH key (OSS)
if: ${{ !vars.COMMERCIAL }}
run: |
mkdir "$HOME/.ssh"
echo "${{ secrets.DOCS_SSH_KEY }}" > "$HOME/.ssh/key"
chmod 600 "$HOME/.ssh/key"
echo "${{ secrets.DOCS_SSH_HOST_KEY }}" > "$HOME/.ssh/known_hosts"
- name: Deploy Javadoc via SSH (OSS)
if: ${{ !vars.COMMERCIAL }}
run: |
ssh -i $HOME/.ssh/key ${{ secrets.DOCS_USERNAME }}@${{ secrets.DOCS_HOST }} "cd ${{ secrets.DOCS_PATH }} && rm -fr $PROJECT_VERSION && mkdir -p $PROJECT_VERSION"
scp -i $HOME/.ssh/key target/spring-ai-parent-${PROJECT_VERSION}-javadoc.jar ${{ secrets.DOCS_USERNAME }}@${{ secrets.DOCS_HOST }}:${{ secrets.DOCS_PATH }}/$PROJECT_VERSION
ssh -i $HOME/.ssh/key ${{ secrets.DOCS_USERNAME }}@${{ secrets.DOCS_HOST }} "cd ${{ secrets.DOCS_PATH }}/${PROJECT_VERSION} && unzip spring-ai-parent-${PROJECT_VERSION}-javadoc.jar -d api && rm spring-ai-parent-${PROJECT_VERSION}-javadoc.jar"
.Github/Workflows/Github Release.Yml (.github/workflows/github-release.yml)
name: GitHub Release
run-name: "GitHub Release (${{ inputs.version }})"
on:
workflow_dispatch:
inputs:
version:
required: true
latest:
type: boolean
required: false
default: false
draft:
type: boolean
required: false
default: false
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ inputs.version }}
jobs:
create-github-release:
name: Create GitHub Release
runs-on: ubuntu-latest
steps:
- name: Check Out Code
uses: actions/checkout@v6
- name: Create GitHub Release
uses: ./.github/actions/create-github-release
with:
commercial: ${{ vars.COMMERCIAL }}
draft: ${{ inputs.draft }}
latest: ${{ inputs.latest }}
milestone: ${{ inputs.version }}
pre-release: ${{ contains(inputs.version, '-') }}
token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
.Github/Workflows/Mcp Integration Tests.Yml (.github/workflows/mcp-integration-tests.yml)
name: MCP Integration Tests
on:
pull_request:
push:
branches:
- 'main'
- '[0-9].[0-9].x'
workflow_dispatch:
inputs:
runner:
required: false
default: ''
type: string
jobs:
mcp-it:
name: MCP integration tests
runs-on: ${{ inputs.runner != '' && inputs.runner || (vars.COMMERCIAL && vars.UBUNTU_SMALL || 'ubuntu-latest') }}
steps:
- name: Checkout source code
uses: actions/checkout@v6
- name: Set up JDK
uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'liberica'
cache: 'maven'
- name: Setup Maven Build-Cache (~/.m2/build-cache)
if: ${{ false }} # Disable until test flakiness has been resolved
uses: actions/cache@v4
with:
path: ~/.m2/build-cache
# See pr-check.yml for an explanation of the key format
key: build-cache-${{ runner.os }}-mcp-${{ hashFiles('/pom.xml') }}-${{ github.run_id }}
restore-keys: |
build-cache-${{ runner.os }}-mcp-${{ hashFiles('/pom.xml') }}-
build-cache-${{ runner.os }}-
- name: Build with Maven and run integration tests
run: |
./mvnw --batch-mode -ntp verify -Pintegration-tests -am -pl "mcp/transport/mcp-spring-webflux,mcp/transport/mcp-spring-webmvc"
.Github/Workflows/Pr Check.Yml (.github/workflows/pr-check.yml)
name: PR Check
on:
pull_request:
jobs:
build:
name: Build branch
runs-on: ubuntu-latest
if: ${{ github.repository_owner == 'spring-projects' }}
steps:
- name: Checkout source code
uses: actions/checkout@v6
- name: Set up JDK
uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'liberica'
cache: 'maven'
- name: Setup Maven Build-Cache (~/.m2/build-cache)
uses: actions/cache@v5
with:
path: ~/.m2/build-cache
# See https://github.com/actions/cache/blob/main/tips-and-workarounds.md#update-a-cache
# We need to incrementally save the contents of the build-cache directory, even if there was a hit prior to the build
# Cached restored from restore-keys are restored using the latest one first, so this is a good compromise
key: build-cache-${{ runner.os }}-${{ hashFiles('/pom.xml') }}-${{ github.run_id }}
restore-keys: |
build-cache-${{ runner.os }}-${{ hashFiles('/pom.xml') }}-
build-cache-${{ runner.os }}-
- name: Run tests
run: |
./mvnw -ntp -B -U package
.Github/Workflows/Release Train Build.Yml (.github/workflows/release-train-build.yml)
This file was auto-generated by github-actions-workflow-generator 0.0.6. Do not edit.
To update it, modify .github/workflow-generator.yml as needed and re-run the generator.
name: "Release Train – Build"
run-name: "${{ inputs.callback-ref }} – Build"
"on":
workflow_dispatch:
inputs:
callback:
required: true
type: "string"
callback-ref:
required: true
type: "string"
release-train-maven-repository-url:
required: true
type: "string"
permissions:
contents: "read"
concurrency:
group: "${{ github.workflow }}-${{ github.ref }}"
jobs:
build-release:
name: "Build Release"
runs-on: ${{ vars.UBUNTU_SMALL || 'ubuntu-latest' }}
steps:
- name: "Prevent Re-runs"
id: "prevent-re-runs"
run: |-
if [ "$GITHUB_RUN_ATTEMPT" -gt 1 ]; then
echo "Re-runs are prohibited. Use the 'Release Train – Retry' workflow to retry build failures"
exit 1
fi
- name: "Set up Java"
id: "set-up-java"
uses: "actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95" # v5.6.0
with:
distribution: "liberica"
java-version: "17"
- name: "Check Out Code"
id: "check-out-code"
uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0
- name: "Build Release"
id: "build-release"
uses: "./.github/actions/release-train-build"
env:
COMMERCIAL_ARTIFACTORY_PASSWORD: "${{ secrets.COMMERCIAL_ARTIFACTORY_PASSWORD }}"
COMMERCIAL_ARTIFACTORY_USERNAME: "${{ secrets.COMMERCIAL_ARTIFACTORY_USERNAME }}"
COMMERCIAL_RELEASE_REPO_URL: "${{ vars.COMMERCIAL_RELEASE_REPO_URL }}"
RELEASE_TRAIN_MAVEN_REPOSITORY_PASSWORD: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_MAVEN_REPOSITORY_PASSWORD }}"
RELEASE_TRAIN_MAVEN_REPOSITORY_URL: "${{ inputs.release-train-maven-repository-url }}"
RELEASE_TRAIN_MAVEN_REPOSITORY_USERNAME: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_MAVEN_REPOSITORY_USERNAME }}"
- name: "Upload Deployment Repository"
id: "upload-deployment-repository"
uses: "actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a" # v7.0.1
with:
name: "deployment-repository"
path: "deployment-repository/"
- name: "Upload Deployment Spec"
id: "upload-deployment-spec"
uses: "actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a" # v7.0.1
with:
archive: "false"
if-no-files-found: "ignore"
name: "deployment-spec"
path: ".github/actions/release-train-build/deployment-spec.yml"
- name: "Save Build System Caches"
id: "save-build-system-caches"
uses: "actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9" # v6.1.0
with:
key: "release-train-${{ inputs.callback-ref }}-${{ github.ref_name }}"
path: "~/.m2/repository"
- name: "Send Callback"
id: "send-callback"
if: "${{ !cancelled() }}"
env:
GH_TOKEN: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_GITHUB_TOKEN }}"
run: |-
gh workflow run callback \
--repo ${{ inputs.callback }} \
--ref ${{ inputs.callback-ref }} \
--field commit-hash=${{ steps.check-out-code.outputs.commit }} \
--field deployment-repository-artifact-identifier=${{ steps.upload-deployment-repository.outputs.artifact-id }} \
--field deployment-spec-artifact-identifier=${{ steps.upload-deployment-spec.outputs.artifact-id }} \
--field release-branch=${{ github.ref_name }} \
--field release-repository=${{ github.repository }} \
--field result=${{ job.status == 'success' && 'built' || 'build-failed' }} \
--field workflow-run-url=${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
.Github/Workflows/Release Train Join.Yml (.github/workflows/release-train-join.yml)
This file was auto-generated by github-actions-workflow-generator 0.0.6. Do not edit.
To update it, modify .github/workflow-generator.yml as needed and re-run the generator.
name: "Release Train – Join"
run-name: "${{ inputs.release-train }} – Join"
"on":
workflow_dispatch:
inputs:
deployment-destination:
options:
- "Maven Central"
- "Spring Enterprise"
required: true
type: "choice"
release-train:
required: true
type: "string"
release-train-repository:
default: "spring-io/release-train"
required: true
type: "string"
permissions:
contents: "none"
jobs:
join-release-train:
name: "Join Release Train"
runs-on: "ubuntu-latest"
steps:
- name: "Join Release Train"
id: "join-release-train"
env:
GH_TOKEN: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_GITHUB_TOKEN }}"
run: |-
run_url=$(
gh workflow run join \
--repo ${{ inputs.release-train-repository }} \
--ref ${{ inputs.release-train }} \
--field commit-hash=${{ github.sha }} \
--field deployment-destination=${{ inputs.deployment-destination == 'Maven Central' && 'maven-central' || 'spring-enterprise' }} \
--field release-branch=${{ github.ref_name }} \
--field release-repository=${{ github.repository }}
)
echo "Dispatched workflow run. Waiting for $run_url to complete."
run_id=${run_url##*/}
watch_exit_code=0
gh run watch $run_id --repo ${{ inputs.release-train-repository }} --exit-status --interval=3 > /dev/null 2>&1 || watch_exit_code=$?
if [[ $watch_exit_code -eq 0 ]]; then
echo "Workflow run succeeded."
else
echo "Workflow run failed."
fi
exit $watch_exit_code
.Github/Workflows/Release Train Leave.Yml (.github/workflows/release-train-leave.yml)
This file was auto-generated by github-actions-workflow-generator 0.0.6. Do not edit.
To update it, modify .github/workflow-generator.yml as needed and re-run the generator.
name: "Release Train – Leave"
run-name: "${{ inputs.release-train }} – Leave"
"on":
workflow_dispatch:
inputs:
release-train:
required: true
type: "string"
release-train-repository:
default: "spring-io/release-train"
required: true
type: "string"
permissions:
contents: "none"
jobs:
leave:
name: "Leave"
runs-on: "ubuntu-latest"
steps:
- name: "Leave"
id: "leave"
env:
GH_TOKEN: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_GITHUB_TOKEN }}"
run: |-
run_url=$(
gh workflow run leave \
--repo ${{ inputs.release-train-repository }} \
--ref ${{ inputs.release-train }} \
--field release-branch=${{ github.ref_name }} \
--field release-repository=${{ github.repository }}
)
echo "Dispatched workflow run. Waiting for $run_url to complete."
run_id=${run_url##*/}
watch_exit_code=0
gh run watch $run_id --repo ${{ inputs.release-train-repository }} --exit-status --interval=3 > /dev/null 2>&1 || watch_exit_code=$?
if [[ $watch_exit_code -eq 0 ]]; then
echo "Workflow run succeeded."
else
echo "Workflow run failed."
fi
exit $watch_exit_code
.Github/Workflows/Release Train Ready.Yml (.github/workflows/release-train-ready.yml)
This file was auto-generated by github-actions-workflow-generator 0.0.6. Do not edit.
To update it, modify .github/workflow-generator.yml as needed and re-run the generator.
name: "Release Train – Ready"
run-name: "${{ inputs.release-train }} – Ready"
"on":
workflow_dispatch:
inputs:
release-train:
required: true
type: "string"
release-train-repository:
default: "spring-io/release-train"
required: true
type: "string"
permissions:
contents: "none"
jobs:
ready:
name: "Ready"
runs-on: "ubuntu-latest"
steps:
- name: "Ready"
id: "ready"
env:
GH_TOKEN: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_GITHUB_TOKEN }}"
run: |-
run_url=$(
gh workflow run ready \
--repo ${{ inputs.release-train-repository }} \
--ref ${{ inputs.release-train }} \
--field commit-hash=${{ github.sha }} \
--field release-branch=${{ github.ref_name }} \
--field release-repository=${{ github.repository }}
)
echo "Dispatched workflow run. Waiting for $run_url to complete."
run_id=${run_url##*/}
watch_exit_code=0
gh run watch $run_id --repo ${{ inputs.release-train-repository }} --exit-status --interval=3 > /dev/null 2>&1 || watch_exit_code=$?
if [[ $watch_exit_code -eq 0 ]]; then
echo "Workflow run succeeded."
else
echo "Workflow run failed."
fi
exit $watch_exit_code
.Github/Workflows/Release Train Retry.Yml (.github/workflows/release-train-retry.yml)
This file was auto-generated by github-actions-workflow-generator 0.0.6. Do not edit.
To update it, modify .github/workflow-generator.yml as needed and re-run the generator.
name: "Release Train – Retry"
run-name: "${{ inputs.release-train }} – Retry"
"on":
workflow_dispatch:
inputs:
release-train:
required: true
type: "string"
release-train-repository:
default: "spring-io/release-train"
required: true
type: "string"
permissions:
contents: "none"
jobs:
trigger-retry:
name: "Trigger Retry"
runs-on: "ubuntu-latest"
steps:
- name: "Trigger Retry"
id: "trigger-retry"
env:
GH_TOKEN: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_GITHUB_TOKEN }}"
run: |-
gh workflow run retry \
--repo ${{ inputs.release-train-repository }} \
--ref ${{ inputs.release-train }} \
--field release-branch=${{ github.ref_name }} \
--field release-repository=${{ github.repository }}
.Github/Workflows/Release Train Test.Yml (.github/workflows/release-train-test.yml)
This file was auto-generated by github-actions-workflow-generator 0.0.6. Do not edit.
To update it, modify .github/workflow-generator.yml as needed and re-run the generator.
name: "Release Train – Test"
run-name: "${{ inputs.callback-ref }} – Test"
"on":
workflow_dispatch:
inputs:
callback:
required: true
type: "string"
callback-ref:
required: true
type: "string"
release-train-maven-repository-url:
required: true
type: "string"
permissions:
contents: "read"
concurrency:
group: "${{ github.workflow }}-${{ github.ref }}"
jobs:
test-release:
name: "Test Release"
runs-on: ${{ vars.UBUNTU_SMALL || 'ubuntu-latest' }}
steps:
- name: "Prevent Re-runs"
id: "prevent-re-runs"
run: |-
if [ "$GITHUB_RUN_ATTEMPT" -gt 1 ]; then
echo "Re-runs are prohibited. Use the 'Release Train – Retry' workflow to retry test failures"
exit 1
fi
- name: "Set up Java"
id: "set-up-java"
uses: "actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95" # v5.6.0
with:
distribution: "liberica"
java-version: "17"
- name: "Check Out Code"
id: "check-out-code"
uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0
- name: "Restore Build System Caches"
id: "restore-build-system-caches"
uses: "actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9" # v6.1.0
with:
key: "release-train-${{ inputs.callback-ref }}-${{ github.ref_name }}"
path: "~/.m2/repository"
- name: "Test Release"
id: "test-release"
uses: "./.github/actions/release-train-test"
env:
COMMERCIAL_ARTIFACTORY_PASSWORD: "${{ secrets.COMMERCIAL_ARTIFACTORY_PASSWORD }}"
COMMERCIAL_ARTIFACTORY_USERNAME: "${{ secrets.COMMERCIAL_ARTIFACTORY_USERNAME }}"
COMMERCIAL_RELEASE_REPO_URL: "${{ vars.COMMERCIAL_RELEASE_REPO_URL }}"
RELEASE_TRAIN_MAVEN_REPOSITORY_PASSWORD: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_MAVEN_REPOSITORY_PASSWORD }}"
RELEASE_TRAIN_MAVEN_REPOSITORY_URL: "${{ inputs.release-train-maven-repository-url }}"
RELEASE_TRAIN_MAVEN_REPOSITORY_USERNAME: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_MAVEN_REPOSITORY_USERNAME }}"
- name: "Send Callback"
id: "send-callback"
if: "${{ !cancelled() }}"
env:
GH_TOKEN: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_GITHUB_TOKEN }}"
run: |-
gh workflow run callback \
--repo ${{ inputs.callback }} \
--ref ${{ inputs.callback-ref }} \
--field commit-hash=${{ steps.check-out-code.outputs.commit }} \
--field release-branch=${{ github.ref_name }} \
--field release-repository=${{ github.repository }} \
--field result=${{ job.status == 'success' && 'tested' || 'test-failed' }} \
--field workflow-run-url=${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
- name: "Upload Build System Reports"
id: "upload-build-system-reports"
if: "${{ failure() }}"
uses: "actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a" # v7.0.1
with:
name: "build-system-reports"
path: |-
/target/surefire-reports
/target/failsafe-reports
.Github/Workflows/Spring Ai Dependency Updates.Yml (.github/workflows/spring-ai-dependency-updates.yml)
name: Dependency Updates
on:
schedule:
- cron: '0 7 1' # 07:00 UTC every Monday
workflow_dispatch:
jobs:
dependency-updates:
name: List dependency updates
runs-on: ubuntu-latest
if: ${{ github.repository_owner == 'spring-projects' }}
steps:
- name: Checkout source code
uses: actions/checkout@v6
- name: Set up JDK
uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'liberica'
cache: 'maven'
- name: Check for dependency updates
run: |
./mvnw --batch-mode -ntp \
versions:display-dependency-updates \
-DprocessDependencyManagementTransitive=false \
-DallowSnapshots=false \
-Dversions.outputFile=$(pwd)/dependency-updates.txt \
-Dversions.logOutput=false
- name: Publish job summary
run: |
# Parse the versions-maven-plugin output into artifact|current|latest rows.
# Lines come in two formats:
# single-line: " groupId:artifact ..... current -> latest"
# wrapped: " groupId:artifact ..." (artifact too long)
# " current -> latest"
awk '
/->/ {
split($0, parts, " -> ")
latest = parts[2]
gsub(/^[ \t]+|[ \t\r\n]+$/, "", latest)
n = split(parts[1], words, " ")
current = words[n]
if (pending != "") {
print pending "|" current "|" latest
pending = ""
} else {
artifact = words[1]
if (index(artifact, ":") > 0) print artifact "|" current "|" latest
}
next
}
/^\s+[a-z].:.\.\.\.$/ {
split($0, words, " ")
pending = words[1]
next
}
{ pending = "" }
' dependency-updates.txt \
| grep -v '^org\.springframework\.ai:' \
| grep -v '|\${project\.version}|' \
| grep -v '|\${.*}|' \
| grep -v '^ch\.qos\.logback:' \
| grep -v '^co\.elastic\.clients:' \
| grep -v '^com\.couchbase\.client:' \
| grep -v '^com\.fasterxml\.jackson\.' \
| grep -v '^com\.google\.code\.gson:' \
| grep -v '^com\.microsoft\.onnxruntime:' \
| grep -v '^com\.zaxxer:HikariCP' \
| grep -v '^io\.grpc:' \
| grep -v '^io\.rest-assured:json-path' \
| grep -v '^io\.rest-assured:rest-assured\b' \
| grep -v '^jakarta\.servlet:' \
| grep -v '^jakarta\.validation:' \
| grep -v '^net\.bytebuddy:' \
| grep -v '^org\.apache\.httpcomponents\.client5:httpclient5' \
| grep -v '^org\.apache\.tomcat\.embed:' \
| grep -v '^org\.assertj:' \
| grep -v '^org\.hsqldb:' \
| grep -v '^org\.jetbrains\.kotlin:' \
| grep -v '^org\.junit\.jupiter:' \
| grep -v '^org\.mariadb\.jdbc:' \
| grep -v '^org\.neo4j\.driver:neo4j-java-driver' \
| grep -v '^org\.postgresql:' \
| grep -v '^org\.skyscreamer:' \
| grep -v '^redis\.clients:' \
| grep -v '^tools\.jackson\.' \
| sort -u \
> filtered-updates.txt
echo "## Dependency Updates Available" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "> Versions already managed by imported BOMs (Spring Boot, DJL, MCP, REST Assured) are excluded from the report." >> $GITHUB_STEP_SUMMARY
echo "> All updates require manual verification and integration testing before adoption." >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ ! -s filtered-updates.txt ]; then
echo "All dependencies are up to date." >> $GITHUB_STEP_SUMMARY
else
echo "| Dependency | Current | Latest |" >> $GITHUB_STEP_SUMMARY
echo "|-----------|---------|--------|" >> $GITHUB_STEP_SUMMARY
while IFS='|' read -r artifact current latest; do
echo "| \$artifact\ | $current | $latest |" >> $GITHUB_STEP_SUMMARY
done < filtered-updates.txt
fi
- name: Upload full dependency update report
if: always()
uses: actions/upload-artifact@v6
with:
name: dependency-updates-report
path: dependency-updates.txt
retention-days: 1
.Github/Workflows/Spring Ai Integration Tests.Yml (.github/workflows/spring-ai-integration-tests.yml)
name: Spring AI Integration Tests
run-name: Spring AI Integration Tests
on:
workflow_dispatch:
inputs:
test_suites:
required: false
default: ''
type: string
exclude_test_suites:
required: false
default: ''
type: string
springBootVersion:
required: false
default: ''
type: string
runner:
required: false
default: ''
type: string
schedule:
- cron: '0 4 1,3,5' # Mon, Wed, Fri at 4 AM UTC
jobs:
build-all:
name: Build all modules
if: ${{ github.repository_owner == 'spring-projects' }}
runs-on: ${{ inputs.runner != '' && inputs.runner || (vars.COMMERCIAL && vars.UBUNTU_SMALL || 'ubuntu-latest') }}
steps:
- name: Checkout source code
uses: actions/checkout@v6
- name: Set up JDK
uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'liberica'
cache: 'maven'
- name: Build all modules
env:
COMMERCIAL_ARTIFACTORY_USERNAME: "${{ secrets.COMMERCIAL_ARTIFACTORY_USERNAME }}"
COMMERCIAL_ARTIFACTORY_PASSWORD: "${{ secrets.COMMERCIAL_ARTIFACTORY_PASSWORD }}"
COMMERCIAL_SNAPSHOT_REPO_URL: "${{ vars.COMMERCIAL_SNAPSHOT_REPO_URL }}"
COMMERCIAL_RELEASE_REPO_URL: "${{ vars.COMMERCIAL_RELEASE_REPO_URL }}"
run: |
./mvnw ${{ vars.COMMERCIAL && '-s commercial-settings.xml -Pcommercial' || '' }} --batch-mode -ntp --update-snapshots clean install -DskipTests \
${{ inputs.springBootVersion != '' && format('-Dspring-boot.version={0}', inputs.springBootVersion) || '' }}
- name: Upload Spring AI built artifacts
uses: actions/upload-artifact@v6
with:
name: build-artifacts
path: ~/.m2/repository/org/springframework/ai
retention-days: 1
- name: Purge Spring AI built artifacts
run: rm -fr ~/.m2/repository/org/springframework/ai
test-ollama:
needs: build-all
if: ${{ (github.event_name == 'schedule' || inputs.test_suites == '' || contains(inputs.test_suites, 'ollama')) && !contains(inputs.exclude_test_suites || '', 'ollama') }}
runs-on: ${{ inputs.runner != '' && inputs.runner || (vars.COMMERCIAL && vars.UBUNTU_MEDIUM || 'ubuntu-latest') }}
services:
ollama:
image: ollama/ollama:latest
ports:
- 11434:11434
env:
OLLAMA_WITH_REUSE: true
steps:
- name: Checkout source code
uses: actions/checkout@v6
- name: Set up JDK
uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'liberica'
cache: 'maven'
- name: Download Spring AI built artifacts
uses: actions/download-artifact@v7
with:
name: build-artifacts
path: ~/.m2/repository/org/springframework/ai
- name: Configure Testcontainers
run: |
mkdir -p $HOME
echo "testcontainers.reuse.enable = true" >> $HOME/.testcontainers.properties
- name: Integration Test
uses: ./.github/actions/do-integration-test
with:
model-name: ollama
maven-properties: "-Dskip.model.ollama=false"
spring-boot-version: ${{ inputs.springBootVersion }}
test-anthropic:
needs: build-all
if: ${{ (github.event_name == 'schedule' || inputs.test_suites == '' || contains(inputs.test_suites, 'anthropic')) && !contains(inputs.exclude_test_suites || '', 'anthropic') }}
runs-on: ${{ inputs.runner != '' && inputs.runner || (vars.COMMERCIAL && vars.UBUNTU_SMALL || 'ubuntu-latest') }}
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
steps:
- name: Check secret
id: secret_check
if: ${{ env.ANTHROPIC_API_KEY != '' }}
run: echo "Secret exists"
- name: Checkout source code
if: steps.secret_check.conclusion == 'success'
uses: actions/checkout@v6
- name: Set up JDK
if: steps.secret_check.conclusion == 'success'
uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'liberica'
cache: 'maven'
- name: Download Spring AI built artifacts
if: steps.secret_check.conclusion == 'success'
uses: actions/download-artifact@v7
with:
name: build-artifacts
path: ~/.m2/repository/org/springframework/ai
- name: Integration Test
if: steps.secret_check.conclusion == 'success'
uses: ./.github/actions/do-integration-test
with:
model-name: anthropic
spring-boot-version: ${{ inputs.springBootVersion }}
test-azure-openai:
needs: build-all
if: ${{ (github.event_name == 'schedule' || inputs.test_suites == '' || contains(inputs.test_suites, 'azure-openai')) && !contains(inputs.exclude_test_suites || '', 'azure-openai') }}
runs-on: ${{ inputs.runner != '' && inputs.runner || (vars.COMMERCIAL && vars.UBUNTU_SMALL || 'ubuntu-latest') }}
env:
AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }}
AZURE_OPENAI_ENDPOINT: ${{ secrets.AZURE_OPENAI_ENDPOINT }}
AZURE_OPENAI_TRANSCRIPTION_API_KEY: ${{ secrets.AZURE_OPENAI_TRANSCRIPTION_API_KEY }}
AZURE_OPENAI_TRANSCRIPTION_ENDPOINT: ${{ secrets.AZURE_OPENAI_TRANSCRIPTION_ENDPOINT }}
AZURE_OPENAI_IMAGE_API_KEY: ${{ secrets.AZURE_OPENAI_IMAGE_API_KEY }}
AZURE_OPENAI_IMAGE_ENDPOINT: ${{ secrets.AZURE_OPENAI_IMAGE_ENDPOINT }}
steps:
- name: Check secrets
id: secret_check
if: ${{ env.AZURE_OPENAI_API_KEY != '' && env.AZURE_OPENAI_ENDPOINT != '' && env.AZURE_OPENAI_TRANSCRIPTION_API_KEY != '' && env.AZURE_OPENAI_TRANSCRIPTION_ENDPOINT != '' && env.AZURE_OPENAI_IMAGE_API_KEY != '' && env.AZURE_OPENAI_IMAGE_ENDPOINT != '' }}
run: echo "Secrets exist"
- name: Checkout source code
if: steps.secret_check.conclusion == 'success'
uses: actions/checkout@v6
- name: Set up JDK
if: steps.secret_check.conclusion == 'success'
uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'liberica'
cache: 'maven'
- name: Download Spring AI built artifacts
if: steps.secret_check.conclusion == 'success'
uses: actions/download-artifact@v7
with:
name: build-artifacts
path: ~/.m2/repository/org/springframework/ai
- name: Integration Test
if: steps.secret_check.conclusion == 'success'
uses: ./.github/actions/do-integration-test
with:
model-name: azure-openai
spring-boot-version: ${{ inputs.springBootVersion }}
test-mistral-ai:
needs: build-all
if: ${{ (github.event_name == 'schedule' || inputs.test_suites == '' || contains(inputs.test_suites, 'mistral-ai')) && !contains(inputs.exclude_test_suites || '', 'mistral-ai') }}
runs-on: ${{ inputs.runner != '' && inputs.runner || (vars.COMMERCIAL && vars.UBUNTU_SMALL || 'ubuntu-latest') }}
env:
MISTRAL_AI_API_KEY: ${{ secrets.MISTRAL_AI_API_KEY }}
steps:
- name: Check secrets
id: secret_check
if: ${{ env.MISTRAL_AI_API_KEY != '' }}
run: echo "Secrets exist"
- name: Checkout source code
uses: actions/checkout@v6
- name: Set up JDK
uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'liberica'
cache: 'maven'
- name: Download Spring AI built artifacts
uses: actions/download-artifact@v7
with:
name: build-artifacts
path: ~/.m2/repository/org/springframework/ai
- name: Integration Test
uses: ./.github/actions/do-integration-test
with:
model-name: mistral-ai
spring-boot-version: ${{ inputs.springBootVersion }}
test-elevenlabs:
needs: build-all
if: ${{ (github.event_name == 'schedule' || inputs.test_suites == '' || contains(inputs.test_suites, 'elevenlabs')) && !contains(inputs.exclude_test_suites || '', 'elevenlabs') }}
runs-on: ${{ inputs.runner != '' && inputs.runner || (vars.COMMERCIAL && vars.UBUNTU_SMALL || 'ubuntu-latest') }}
env:
ELEVEN_LABS_API_KEY: ${{ secrets.ELEVEN_LABS_API_KEY }}
steps:
- name: Check secrets
id: secret_check
if: ${{ env.ELEVEN_LABS_API_KEY != '' }}
run: echo "Secrets exist"
- name: Checkout source code
uses: actions/checkout@v6
- name: Set up JDK
uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'liberica'
cache: 'maven'
- name: Download Spring AI built artifacts
uses: actions/download-artifact@v7
with:
name: build-artifacts
path: ~/.m2/repository/org/springframework/ai
- name: Integration Test
uses: ./.github/actions/do-integration-test
with:
model-name: elevenlabs
spring-boot-version: ${{ inputs.springBootVersion }}
test-bedrock:
needs: build-all
if: ${{ (github.event_name == 'schedule' || inputs.test_suites == '' || contains(inputs.test_suites, 'bedrock')) && !contains(inputs.exclude_test_suites || '', 'bedrock') }}
runs-on: ${{ inputs.runner != '' && inputs.runner || (vars.COMMERCIAL && vars.UBUNTU_SMALL || 'ubuntu-latest') }}
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
steps:
- name: Check secrets
id: secret_check
if: ${{ env.AWS_ACCESS_KEY_ID != '' && env.AWS_SECRET_ACCESS_KEY != '' }}
run: echo "Secrets exist"
- name: Checkout source code
if: steps.secret_check.conclusion == 'success'
uses: actions/checkout@v6
- name: Set up JDK
if: steps.secret_check.conclusion == 'success'
uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'liberica'
cache: 'maven'
- name: Download Spring AI built artifacts
if: steps.secret_check.conclusion == 'success'
uses: actions/download-artifact@v7
with:
name: build-artifacts
path: ~/.m2/repository/org/springframework/ai
- name: Integration Test
if: steps.secret_check.conclusion == 'success'
uses: ./.github/actions/do-multi-module-test
with:
modules: models/spring-ai-bedrock,models/spring-ai-bedrock-converse
spring-boot-version: ${{ inputs.springBootVersion }}
test-deepseek:
needs: build-all
if: ${{ (github.event_name == 'schedule' || inputs.test_suites == '' || contains(inputs.test_suites, 'deepseek')) && !contains(inputs.exclude_test_suites || '', 'deepseek') }}
runs-on: ${{ inputs.runner != '' && inputs.runner || (vars.COMMERCIAL && vars.UBUNTU_SMALL || 'ubuntu-latest') }}
env:
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
steps:
- name: Check secret
id: secret_check
if: ${{ env.DEEPSEEK_API_KEY != '' }}
run: echo "Secret exists"
- name: Checkout source code
if: steps.secret_check.conclusion == 'success'
uses: actions/checkout@v6
- name: Set up JDK
if: steps.secret_check.conclusion == 'success'
uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'liberica'
cache: 'maven'
- name: Download Spring AI built artifacts
if: steps.secret_check.conclusion == 'success'
uses: actions/download-artifact@v7
with:
name: build-artifacts
path: ~/.m2/repository/org/springframework/ai
- name: Integration Test
if: steps.secret_check.conclusion == 'success'
uses: ./.github/actions/do-integration-test
with:
model-name: deepseek
spring-boot-version: ${{ inputs.springBootVersion }}
test-google-genai:
needs: build-all
if: ${{ (github.event_name == 'schedule' || inputs.test_suites == '' || contains(inputs.test_suites, 'google-genai')) && !contains(inputs.exclude_test_suites || '', 'google-genai') }}
runs-on: ${{ inputs.runner != '' && inputs.runner || (vars.COMMERCIAL && vars.UBUNTU_SMALL || 'ubuntu-latest') }}
env:
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
steps:
- name: Check secret
id: secret_check
if: ${{ env.GOOGLE_API_KEY != '' }}
run: echo "Secret exists"
- name: Checkout source code
if: steps.secret_check.conclusion == 'success'
uses: actions/checkout@v6
- name: Set up JDK
if: steps.secret_check.conclusion == 'success'
uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'liberica'
cache: 'maven'
- name: Download Spring AI built artifacts
if: steps.secret_check.conclusion == 'success'
uses: actions/download-artifact@v7
with:
name: build-artifacts
path: ~/.m2/repository/org/springframework/ai
- name: Integration Test
if: steps.secret_check.conclusion == 'success'
uses: ./.github/actions/do-integration-test
with:
model-name: google-genai
spring-boot-version: ${{ inputs.springBootVersion }}
test-vectorstores:
needs: build-all
if: ${{ (github.event_name == 'schedule' || inputs.test_suites == '' || contains(inputs.test_suites, 'vectorstores')) && !contains(inputs.exclude_test_suites || '', 'vectorstores') }}
runs-on: ${{ inputs.runner != '' && inputs.runner || (vars.COMMERCIAL && vars.UBUNTU_MEDIUM || 'ubuntu-latest') }}
services:
ollama:
image: ollama/ollama:latest
ports:
- 11434:11434
env:
DOCKER_QUIET: 1 # Suppresses Docker CLI progress output
TESTCONTAINERS_QUIET: true # Additional quieting for testcontainers
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
MISTRAL_AI_API_KEY: ${{ secrets.MISTRAL_AI_API_KEY }}
OLLAMA_TESTS_ENABLED: true
steps:
- name: Check secrets
id: secret_check
if: ${{ env.OPENAI_API_KEY != '' && env.MISTRAL_AI_API_KEY != '' }}
run: echo "Secrets exist"
- name: Checkout source code
uses: actions/checkout@v6
- name: Set up JDK
uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'liberica'
cache: 'maven'
- name: Download Spring AI built artifacts
uses: actions/download-artifact@v7
with:
name: build-artifacts
path: ~/.m2/repository/org/springframework/ai
- name: Configure Testcontainers
run: |
mkdir -p $HOME
echo "testcontainers.reuse.enable = true" >> $HOME/.testcontainers.properties
- name: Integration Test
uses: ./.github/actions/do-multi-module-test
with:
modules: vector-stores/spring-ai-azure-store,vector-stores/spring-ai-bedrock-knowledgebase-store,vector-stores/spring-ai-cassandra-store,vector-stores/spring-ai-chroma-store,vector-stores/spring-ai-coherence-store,vector-stores/spring-ai-couchbase-store,vector-stores/spring-ai-elasticsearch-store,vector-stores/spring-ai-gemfire-store,vector-stores/spring-ai-mariadb-store,vector-stores/spring-ai-milvus-store,vector-stores/spring-ai-mongodb-atlas-store,vector-stores/spring-ai-neo4j-store,vector-stores/spring-ai-opensearch-store,vector-stores/spring-ai-oracle-store,vector-stores/spring-ai-pgvector-store,vector-stores/spring-ai-pinecone-store,vector-stores/spring-ai-qdrant-store,vector-stores/spring-ai-redis-semantic-cache,vector-stores/spring-ai-redis-store,${{ vars.COMMERCIAL && 'vector-stores/spring-ai-s3-vector-store,' || '' }}vector-stores/spring-ai-typesense-store,vector-stores/spring-ai-weaviate-store
spring-boot-version: ${{ inputs.springBootVersion }}
test-autoconfigure:
needs: build-all
if: ${{ (github.event_name == 'schedule' || inputs.test_suites == '' || contains(inputs.test_suites, 'autoconfigure')) && !contains(inputs.exclude_test_suites || '', 'autoconfigure') }}
runs-on: ${{ inputs.runner != '' && inputs.runner || (vars.COMMERCIAL && vars.UBUNTU_MEDIUM || 'ubuntu-latest') }}
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }}
AZURE_OPENAI_ENDPOINT: ${{ secrets.AZURE_OPENAI_ENDPOINT }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
steps:
- name: Checkout source code
uses: actions/checkout@v6
- name: Set up JDK
uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'liberica'
cache: 'maven'
- name: Download Spring AI built artifacts
uses: actions/download-artifact@v7
with:
name: build-artifacts
path: ~/.m2/repository/org/springframework/ai
- name: Autoconfigure Test
uses: ./.github/actions/do-autoconfigure-test
with:
spring-ai-branch: ${{ github.ref_name }}
spring-boot-version: ${{ inputs.springBootVersion }}
test-spring-ai-integration:
needs: build-all
if: ${{ (github.event_name == 'schedule' || inputs.test_suites == '' || contains(inputs.test_suites, 'spring-ai-integration')) && !contains(inputs.exclude_test_suites || '', 'spring-ai-integration') }}
runs-on: ${{ inputs.runner != '' && inputs.runner || (vars.COMMERCIAL && vars.UBUNTU_SMALL || 'ubuntu-latest') }}
env:
DOCKER_QUIET: 1 # Suppresses Docker CLI progress output
TESTCONTAINERS_QUIET: true # Additional quieting for testcontainers
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
steps:
- name: Check secrets
id: secret_check
if: ${{ env.OPENAI_API_KEY != '' }}
run: echo "Secrets exist"
- name: Checkout source code
uses: actions/checkout@v6
- name: Set up JDK
uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'liberica'
cache: 'maven'
- name: Download Spring AI built artifacts
uses: actions/download-artifact@v7
with:
name: build-artifacts
path: ~/.m2/repository/org/springframework/ai
- name: Configure Testcontainers
run: |
mkdir -p $HOME
echo "testcontainers.reuse.enable = true" >> $HOME/.testcontainers.properties
- name: Integration Test
uses: ./.github/actions/do-multi-module-test
with:
modules: spring-ai-integration-tests
spring-boot-version: ${{ inputs.springBootVersion }}
test-docker-compose:
needs: build-all
if: ${{ (github.event_name == 'schedule' || inputs.test_suites == '' || contains(inputs.test_suites, 'docker-compose')) && !contains(inputs.exclude_test_suites || '', 'docker-compose') }}
runs-on: ${{ inputs.runner != '' && inputs.runner || (vars.COMMERCIAL && vars.UBUNTU_SMALL || 'ubuntu-latest') }}
env:
DOCKER_QUIET: 1 # Suppresses Docker CLI progress output
TESTCONTAINERS_QUIET: true # Additional quieting for testcontainers
steps:
- name: Checkout source code
uses: actions/checkout@v6
- name: Set up JDK
uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'liberica'
cache: 'maven'
- name: Download Spring AI built artifacts
uses: actions/download-artifact@v7
with:
name: build-artifacts
path: ~/.m2/repository/org/springframework/ai
- name: Configure Testcontainers
run: |
mkdir -p $HOME
echo "testcontainers.reuse.enable = true" >> $HOME/.testcontainers.properties
- name: Integration Test
uses: ./.github/actions/do-multi-module-test
with:
modules: spring-ai-spring-boot-docker-compose
spring-boot-version: ${{ inputs.springBootVersion }}
test-testcontainers:
needs: build-all
if: ${{ (github.event_name == 'schedule' || inputs.test_suites == '' || contains(inputs.test_suites, 'testcontainers')) && !contains(inputs.exclude_test_suites || '', 'testcontainers') }}
runs-on: ${{ inputs.runner != '' && inputs.runner || (vars.COMMERCIAL && vars.UBUNTU_MEDIUM || 'ubuntu24-2-8-OSS') }}
env:
DOCKER_QUIET: 1 # Suppresses Docker CLI progress output
TESTCONTAINERS_QUIET: true # Additional quieting for testcontainers
steps:
- name: Checkout source code
uses: actions/checkout@v6
- name: Set up JDK
uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'liberica'
cache: 'maven'
- name: Download Spring AI built artifacts
uses: actions/download-artifact@v7
with:
name: build-artifacts
path: ~/.m2/repository/org/springframework/ai
- name: Configure Testcontainers
run: |
mkdir -p $HOME
echo "testcontainers.reuse.enable = true" >> $HOME/.testcontainers.properties
- name: Integration Test
uses: ./.github/actions/do-multi-module-test
with:
modules: spring-ai-spring-boot-testcontainers
spring-boot-version: ${{ inputs.springBootVersion }}