Adding new TLP as per INFRA-5163



git-svn-id: https://svn.apache.org/repos/asf/directmemory/tags/directmemory-0.1-incubating@1375467 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..96f31a1
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,8 @@
+target
+*.iml
+.idea
+.classpath
+.project
+.settings
+.DS_Store
+out
diff --git a/DISCLAIMER b/DISCLAIMER
new file mode 100644
index 0000000..33d4abd
--- /dev/null
+++ b/DISCLAIMER
@@ -0,0 +1,10 @@
+Apache DirectMemory is an effort undergoing incubation at the Apache Software
+Foundation (ASF), sponsored by the Apache Incubator PMC. 
+
+Incubation is required of all newly accepted projects until a further review 
+indicates that the infrastructure, communications, and decision making process 
+have stabilized in a manner consistent with other successful ASF projects. 
+
+While incubation status is not necessarily a reflection of the completeness 
+or stability of the code, it does indicate that the project has yet to be 
+fully endorsed by the ASF.
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..66de955
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,247 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://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
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+APPENDIX II:  Licenses for Incorporated Works.
+
+------
+jQuery, Jquery tmpl, jQuery JSON Plugin
+
+Copyright (c) 2011 John Resig, http://jquery.com/
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+------
+Bootstrap
+
+Copyright 2012 Twitter, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..19f0ba0
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,11 @@
+Apache DirectMemory
+Copyright 2001-2012 The Apache Software Foundation
+
+This product includes software developed by
+The Apache Software Foundation (http://www.apache.org/).
+
+This product includes software (bootstrap) developed by
+Twitter (http://twitter.github.com/bootstrap/).
+
+This product includes software (jquery) developed by
+Jquery (http://jquery.org/).
diff --git a/README b/README
new file mode 100644
index 0000000..7099295
--- /dev/null
+++ b/README
@@ -0,0 +1,13 @@
+Apache DirectMemory is a multi layered cache implementation featuring off-heap memory storage (a-la BigMemory)
+to enable caching of java objects without degrading jvm performance.
+Its main purpose is to act as a second level cache (after a heap based one)
+to collect large amounts of data without filling up the java heap and thus avoiding long garbage collection cycles.
+Included in the box is a small set of utility classes to easily handle off-heap memory buffers.
+
+------------
+Build
+------------
+You need Apache Maven to build the project. Just use: mvn clean install (you will have jars installed locally in your
+local Maven repository.
+
+NOTE: the buildnumber maven plugin which add a maven property with the current svn revision has been configured to work with svn 1.7
diff --git a/directmemory-cache/bench.bat b/directmemory-cache/bench.bat
new file mode 100644
index 0000000..77fa9fd
--- /dev/null
+++ b/directmemory-cache/bench.bat
@@ -0,0 +1,15 @@
+rem Licensed to the Apache Software Foundation (ASF) under one or more

+rem contributor license agreements.  See the NOTICE file distributed with

+rem this work for additional information regarding copyright ownership.

+rem The ASF licenses this file to You under the Apache License, Version 2.0

+rem (the "License"); you may not use this file except in compliance with

+rem the License.  You may obtain a copy of the License at

+rem

+rem     http://www.apache.org/licenses/LICENSE-2.0

+rem

+rem Unless required by applicable law or agreed to in writing, software

+rem distributed under the License is distributed on an "AS IS" BASIS,

+rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+rem See the License for the specific language governing permissions and

+rem limitations under the License.

+mvn test -Dtest=SerializerTest -Djub.customkey=%1 -Djub.consumers=CONSOLE,XML,H2 -Djub.db.file=data/benchmarks/database -Djub.xml.file=data/benchmarks/benchmarks.xml -Djub.charts.dir=data/benchmarks/graphs

diff --git a/directmemory-cache/bench.sh b/directmemory-cache/bench.sh
new file mode 100644
index 0000000..6abc326
--- /dev/null
+++ b/directmemory-cache/bench.sh
@@ -0,0 +1,16 @@
+#!/bin/bash

+# Licensed to the Apache Software Foundation (ASF) under one or more

+# contributor license agreements.  See the NOTICE file distributed with

+# this work for additional information regarding copyright ownership.

+# The ASF licenses this file to You under the Apache License, Version 2.0

+# (the "License"); you may not use this file except in compliance with

+# the License.  You may obtain a copy of the License at

+#

+#     http://www.apache.org/licenses/LICENSE-2.0

+#

+# Unless required by applicable law or agreed to in writing, software

+# distributed under the License is distributed on an "AS IS" BASIS,

+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+# See the License for the specific language governing permissions and

+# limitations under the License.

+mvn test -Djub.customkey=$1 -Dtest=MicroBenchmarks -Djub.consumers=CONSOLE,XML,H2 -Djub.db.file=target/benchmarks/database -Djub.xml.file=target/logs/benchmarks.xml -Djub.charts.dir=target/data/benchmarks/graphs

diff --git a/directmemory-cache/pom.xml b/directmemory-cache/pom.xml
new file mode 100644
index 0000000..42529d3
--- /dev/null
+++ b/directmemory-cache/pom.xml
@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.directmemory</groupId>
+    <artifactId>directmemory</artifactId>
+    <version>0.1-incubating</version>
+    <relativePath>../</relativePath>
+  </parent>
+
+  <artifactId>directmemory-cache</artifactId>
+  <name>Apache DirectMemory :: Cache</name>
+  <packaging>bundle</packaging>
+  <description>DirectMemory Cache is a multi layered cache implementation featuring off-heap memory management (a-la
+    BigMemory) to enable efficient handling of a large number of java objects without affecting jvm garbage collection
+    performance
+  </description>
+
+  <properties>
+    <osgi.import>
+      !org.apache.directmemory*,
+      com.google.common.collect;version="[9.0,11)",
+      com.google.common.base;version="[9.0,11)",
+      org.aspectj*;version="[1.6,2)",
+      org.slf4j*
+    </osgi.import>
+    <osgi.export>org.apache.directmemory*;version="${project.version}</osgi.export>
+  </properties>
+
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-clean-plugin</artifactId>
+        <configuration>
+          <filesets>
+            <fileset>
+              <directory>logs</directory>
+              <followSymlinks>false</followSymlinks>
+            </fileset>
+          </filesets>
+        </configuration>
+      </plugin>
+
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>aspectj-maven-plugin</artifactId>
+        <version>1.4</version>
+        <configuration>
+          <source>${maven.compile.source}</source>
+          <target>${maven.compile.target}</target>
+          <complianceLevel>${java.version}</complianceLevel>
+        </configuration>
+        <executions>
+          <execution>
+            <goals>
+              <goal>compile</goal>
+              <!-- use this goal to weave all your main classes -->
+              <goal>test-compile</goal>
+              <!-- use this goal to weave all your test classes -->
+            </goals>
+          </execution>
+        </executions>
+        <dependencies>
+          <dependency>
+            <groupId>org.aspectj</groupId>
+            <artifactId>aspectjtools</artifactId>
+            <version>${aspectj.version}</version>
+          </dependency>
+        </dependencies>
+      </plugin>
+
+    </plugins>
+  </build>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.aspectj</groupId>
+      <artifactId>aspectjrt</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.carrotsearch</groupId>
+      <artifactId>junit-benchmarks</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>ch.qos.logback</groupId>
+      <artifactId>logback-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>ch.qos.logback</groupId>
+      <artifactId>logback-classic</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+</project>
diff --git a/directmemory-cache/src/main/aspect/org/apache/directmemory/monitoring/Performance.aj b/directmemory-cache/src/main/aspect/org/apache/directmemory/monitoring/Performance.aj
new file mode 100644
index 0000000..110ec78
--- /dev/null
+++ b/directmemory-cache/src/main/aspect/org/apache/directmemory/monitoring/Performance.aj
@@ -0,0 +1,196 @@
+package org.apache.directmemory.monitoring;

+

+/*

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ *

+ *  http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+

+import static java.lang.String.format;

+

+import org.apache.directmemory.cache.Cache;

+import org.apache.directmemory.measures.Monitor;

+import org.apache.directmemory.measures.MonitorService;

+import org.apache.directmemory.memory.Pointer;

+import org.slf4j.Logger;

+import org.slf4j.LoggerFactory;

+

+public aspect Performance

+{

+

+    public static final String cache_prefix = "cache";

+

+    public static final String cache_putByteArray = cache_prefix + ".putByteArray";

+

+    public static final String cache_retrieveByteArray = cache_prefix + ".retrieveByteArray";

+

+    public static final String cache_getPointer = cache_prefix + ".getPointer";

+

+    public static final String cache_putObject = cache_prefix + ".put";

+

+    public static final String cache_retrieveObject = cache_prefix + ".get";

+

+    public static final String cache_collectLFU = cache_prefix + ".collectLFU";

+

+    public static final String cache_collectExpired = cache_prefix + ".collectExpired";

+

+    public static final String cache_serialize = cache_prefix + ".serializer.serialize";

+

+    public static final String cache_deserialize = cache_prefix + ".serializer.deserialize";

+

+    private static Logger logger = LoggerFactory.getLogger( Cache.class );

+

+    pointcut putByteArrayPointcut( String key, byte[] payload ):

+            execution(Pointer org.apache.directmemory.cache.Cache.putByteArray(java.lang.String, byte[])) &&

+                    args(key, payload);

+

+    pointcut putObjectPointcut( String key, Object object, int expiresIn ):

+            execution(Pointer org.apache.directmemory.cache.Cache.put(java.lang.String, java.lang.Object, int)) &&

+                    args(key, object, expiresIn);

+

+    pointcut retrieveByteArrayPointcut( String key ):

+            execution(byte[] org.apache.directmemory.cache.Cache.retrieveByteArray(java.lang.String)) &&

+                    args(key);

+

+    pointcut retrieveObjectPointcut( String key ):

+            execution(java.lang.Object org.apache.directmemory.cache.Cache.retrieve(java.lang.String)) &&

+                    args(key);

+

+    pointcut getPointcut( String key ):

+            execution(Pointer org.apache.directmemory.cache.Cache.getPointer(java.lang.String)) &&

+                    args(key);

+

+    pointcut collectLFUPointcut():

+            execution(void org.apache.directmemory.cache.Cache.collectLFU());

+

+    pointcut collectExpiredPointcut():

+            execution(void org.apache.directmemory.cache.Cache.collectExpired());

+

+    pointcut serializePointcut( Object obj, @SuppressWarnings( "rawtypes" ) Class clazz ):

+            execution(byte[] org.apache.directmemory.serialization.ProtoStuffSerializerV1.serialize(java.lang.Object, java.lang.Class)) &&

+                    args(obj, clazz);

+

+    pointcut deserializePointcut( byte[] source, @SuppressWarnings( "rawtypes" ) Class clazz ):

+            execution(java.lang.Object org.apache.directmemory.serialization.ProtoStuffSerializerV1.deserialize(byte[], java.lang.Class)) &&

+                    args(source, clazz);

+

+    Pointer around( String key, byte[] payload ): putByteArrayPointcut(key, payload) {

+        MonitorService mon = Monitor.get( cache_putByteArray );

+        final long startedAt = mon.start();

+        Pointer entry = proceed( key, payload );

+        if ( logger.isDebugEnabled() )

+        {

+            logger.debug( format( "put: [%s] %d bytes", key, payload.length ) );

+        }

+        mon.stop( startedAt );

+        return entry;

+    }

+

+    Pointer around( String key, Object object, int expiresIn ): putObjectPointcut(key, object, expiresIn) {

+        MonitorService mon = Monitor.get( cache_putObject );

+        final long startedAt = mon.start();

+        Pointer entry = proceed( key, object, expiresIn );

+        if ( logger.isDebugEnabled() )

+        {

+            logger.debug( format( "put object: [%s]", key ) );

+        }

+        mon.stop( startedAt );

+        return entry;

+    }

+

+    byte[] around( String key ): retrieveByteArrayPointcut(key) {

+        MonitorService mon = Monitor.get( cache_retrieveByteArray );

+        final long startedAt = mon.start();

+        byte[] payload = proceed( key );

+        if ( logger.isDebugEnabled() )

+        {

+            logger.debug( format( "retrieve: [%s]", key ) );

+        }

+        mon.stop( startedAt );

+        return payload;

+    }

+

+    Object around( String key ): retrieveObjectPointcut(key) {

+        MonitorService mon = Monitor.get( cache_retrieveObject );

+        final long startedAt = mon.start();

+        Object payload = proceed( key );

+        if ( logger.isDebugEnabled() )

+        {

+            logger.debug( format( "retrieve object: [%s]", key ) );

+        }

+        mon.stop( startedAt );

+        return payload;

+    }

+

+    Pointer around( String key ): getPointcut(key) {

+        MonitorService mon = Monitor.get( cache_getPointer );

+        final long startedAt = mon.start();

+        Pointer pointer = proceed( key );

+        if ( logger.isDebugEnabled() )

+        {

+            logger.debug( format( "get: [%s]", key ) );

+        }

+        mon.stop( startedAt );

+        return pointer;

+    }

+

+    void around(): collectLFUPointcut() {

+        MonitorService mon = Monitor.get( cache_collectLFU );

+        final long startedAt = mon.start();

+        proceed();

+        if ( logger.isDebugEnabled() )

+        {

+            logger.debug( "collect LFU" );

+        }

+        mon.stop( startedAt );

+    }

+

+    void around(): collectExpiredPointcut() {

+        MonitorService mon = Monitor.get( cache_collectExpired );

+        final long startedAt = mon.start();

+        proceed();

+        if ( logger.isDebugEnabled() )

+        {

+            logger.debug( "collect expired" );

+        }

+        mon.stop( startedAt );

+    }

+

+    byte[] around( Object obj, @SuppressWarnings( "rawtypes" ) Class clazz ): serializePointcut(obj, clazz) {

+        MonitorService mon = Monitor.get( cache_serialize );

+        final long startedAt = mon.start();

+        byte[] payload = proceed( obj, clazz );

+        if ( logger.isDebugEnabled() )

+        {

+            logger.debug( format( "serialize: [%s]", clazz.getSimpleName() ) );

+        }

+        mon.stop( startedAt );

+        return payload;

+    }

+

+    Object around( byte[] source, @SuppressWarnings( "rawtypes" ) Class clazz ): deserializePointcut(source, clazz) {

+        MonitorService mon = Monitor.get( cache_deserialize );

+        final long startedAt = mon.start();

+        Object obj = proceed( source, clazz );

+        if ( logger.isDebugEnabled() )

+        {

+            logger.debug( format( "deserialize: [%s]", clazz.getSimpleName() ) );

+        }

+        mon.stop( startedAt );

+        return obj;

+    }

+

+}

diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/DirectMemory.java b/directmemory-cache/src/main/java/org/apache/directmemory/DirectMemory.java
new file mode 100644
index 0000000..f6c91df
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/DirectMemory.java
@@ -0,0 +1,180 @@
+package org.apache.directmemory;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.lang.String.format;
+import static org.apache.directmemory.measures.In.seconds;
+import static org.apache.directmemory.serialization.SerializerFactory.createNewSerializer;
+
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.directmemory.cache.CacheService;
+import org.apache.directmemory.cache.CacheServiceImpl;
+import org.apache.directmemory.measures.Ram;
+import org.apache.directmemory.memory.MemoryManagerService;
+import org.apache.directmemory.memory.MemoryManagerServiceImpl;
+import org.apache.directmemory.memory.Pointer;
+import org.apache.directmemory.serialization.Serializer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.MapMaker;
+
+public final class DirectMemory<K, V>
+{
+
+    public static final int DEFAULT_CONCURRENCY_LEVEL = 4;
+
+    public static final int DEFAULT_INITIAL_CAPACITY = 100000;
+
+    public static final int DEFAULT_DISPOSAL_TIME = 10; // seconds
+
+    private final Logger logger = LoggerFactory.getLogger( getClass() );
+
+    private int numberOfBuffers;
+
+    private int size;
+
+    private int initialCapacity = DEFAULT_INITIAL_CAPACITY;
+
+    private int concurrencyLevel = DEFAULT_CONCURRENCY_LEVEL;
+
+    private long disposalTime = seconds( DEFAULT_DISPOSAL_TIME );
+
+    private ConcurrentMap<K, Pointer<V>> map;
+
+    private Serializer serializer;
+
+    private MemoryManagerService<V> memoryManager;
+
+    public DirectMemory()
+    {
+        // does nothing
+    }
+
+    public DirectMemory( DirectMemory<K, V> prototype )
+    {
+        checkArgument( prototype != null, "Impossible to create a DirectMemory instance from a null prototype" );
+
+        numberOfBuffers = prototype.numberOfBuffers;
+        size = prototype.size;
+        initialCapacity = prototype.initialCapacity;
+        concurrencyLevel = prototype.concurrencyLevel;
+        disposalTime = prototype.disposalTime;
+
+        map = prototype.map;
+        serializer = prototype.serializer;
+        memoryManager = prototype.memoryManager;
+    }
+
+    public DirectMemory<K, V> setNumberOfBuffers( int numberOfBuffers )
+    {
+        checkArgument( numberOfBuffers > 0, "Impossible to create a CacheService with a number of buffers lesser than 1" );
+        this.numberOfBuffers = numberOfBuffers;
+        return this;
+    }
+
+    public DirectMemory<K, V> setSize( int size )
+    {
+        checkArgument( size > 0, "Impossible to create a CacheService with a size lesser than 1" );
+        this.size = size;
+        return this;
+    }
+
+    public DirectMemory<K, V> setInitialCapacity( int initialCapacity )
+    {
+        checkArgument( initialCapacity > 0, "Impossible to create a CacheService with an initialCapacity lesser than 1" );
+        this.initialCapacity = initialCapacity;
+        return this;
+    }
+
+    public DirectMemory<K, V> setConcurrencyLevel( int concurrencyLevel )
+    {
+        checkArgument( concurrencyLevel > 0, "Impossible to create a CacheService with a concurrencyLevel lesser than 1" );
+        this.concurrencyLevel = concurrencyLevel;
+        return this;
+    }
+
+    public DirectMemory<K, V> setDisposalTime( long disposalTime )
+    {
+        checkArgument( disposalTime > 0, "Impossible to create a CacheService with a disposalTime lesser than 1" );
+        this.disposalTime = disposalTime;
+        return this;
+    }
+
+    public DirectMemory<K, V> setMap( ConcurrentMap<K, Pointer<V>> map )
+    {
+        checkArgument( map != null, "Impossible to create a CacheService with a null map" );
+        this.map = map;
+        return this;
+    }
+
+    public DirectMemory<K, V> setSerializer( Serializer serializer )
+    {
+        checkArgument( serializer != null, "Impossible to create a CacheService with a null serializer" );
+        this.serializer = serializer;
+        return this;
+    }
+
+    public DirectMemory<K, V> setMemoryManager( MemoryManagerService<V> memoryManager )
+    {
+        checkArgument( memoryManager != null, "Impossible to create a CacheService with a null memoryManager" );
+        this.memoryManager = memoryManager;
+        return this;
+    }
+
+    public CacheService<K, V> newCacheService()
+    {
+        if ( map == null )
+        {
+            map = new MapMaker().concurrencyLevel( concurrencyLevel ).initialCapacity( initialCapacity ).makeMap();
+        }
+        if ( memoryManager == null )
+        {
+            memoryManager = new MemoryManagerServiceImpl<V>();
+        }
+        if ( serializer == null )
+        {
+            serializer = createNewSerializer();
+        }
+
+        logger.info( "******************************** initializing *******************************" );
+        logger.info( "         ____  _                 __  __  ___" );
+        logger.info( "        / __ \\(_)________  _____/ /_/  |/  /___  ____ ___  ____  _______  __" );
+        logger.info( "       / / / / // ___/ _ \\/ ___/ __/ /|_/ // _ \\/ __ `__ \\/ __ \\/ ___/ / / /" );
+        logger.info( "      / /_/ / // /  /  __/ /__/ /_/ /  / //  __/ / / / / / /_/ / /  / /_/ / " );
+        logger.info( "     /_____/_//_/   \\___/\\___/\\__/_/  /_/ \\___/_/ /_/ /_/\\____/_/   \\__, /" );
+        logger.info( "                                                                   /____/   " );
+        logger.info( "********************************************************************************" );
+
+        memoryManager.init( numberOfBuffers, size );
+
+        logger.info( "initialized" );
+        logger.info( format( "number of buffer(s): \t%1d  with %2s each", numberOfBuffers, Ram.inMb( size ) ) );
+        logger.info( format( "initial capacity: \t%1d", initialCapacity ) );
+        logger.info( format( "concurrency level: \t%1d", concurrencyLevel ) );
+
+        CacheService<K, V> cacheService = new CacheServiceImpl<K, V>( map, memoryManager, serializer );
+        cacheService.scheduleDisposalEvery( disposalTime );
+        return cacheService;
+    }
+
+}
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/cache/Cache.java b/directmemory-cache/src/main/java/org/apache/directmemory/cache/Cache.java
new file mode 100644
index 0000000..f097238
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/cache/Cache.java
@@ -0,0 +1,154 @@
+package org.apache.directmemory.cache;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+import org.apache.directmemory.DirectMemory;
+import org.apache.directmemory.memory.MemoryManagerService;
+import org.apache.directmemory.memory.Pointer;
+import org.apache.directmemory.serialization.Serializer;
+
+public class Cache
+{
+
+    private static final DirectMemory<String, Object> builder = new DirectMemory<String, Object>();
+
+    private static CacheService<String, Object> cacheService = builder.newCacheService();
+
+    // olamy chicken and eggs isssue
+    // private static CacheService cacheService = new CacheServiceImpl( getMemoryManager());
+
+    private Cache()
+    {
+        // not instantiable
+    }
+
+    public static void scheduleDisposalEvery( long l )
+    {
+        // store to builder
+        builder.setDisposalTime( l );
+
+        cacheService.scheduleDisposalEvery( l );
+    }
+
+    public static void init( int numberOfBuffers, int size, int initialCapacity, int concurrencyLevel )
+    {
+        cacheService =
+            builder.setNumberOfBuffers( numberOfBuffers ).setInitialCapacity( initialCapacity ).setConcurrencyLevel(
+                concurrencyLevel ).setSize( size ).newCacheService();
+    }
+
+    public static void init( int numberOfBuffers, int size )
+    {
+        init( numberOfBuffers, size, DirectMemory.DEFAULT_INITIAL_CAPACITY, DirectMemory.DEFAULT_CONCURRENCY_LEVEL );
+    }
+
+    public static Pointer<Object> putByteArray( String key, byte[] payload, int expiresIn )
+    {
+        return cacheService.putByteArray( key, payload, expiresIn );
+    }
+
+    public static Pointer<Object> putByteArray( String key, byte[] payload )
+    {
+        return cacheService.putByteArray( key, payload );
+    }
+
+    public static Pointer<Object> put( String key, Object object )
+    {
+        return cacheService.put( key, object );
+    }
+
+    public static Pointer<Object> put( String key, Object object, int expiresIn )
+    {
+        return cacheService.put( key, object, expiresIn );
+    }
+
+    public static byte[] retrieveByteArray( String key )
+    {
+        return cacheService.retrieveByteArray( key );
+    }
+
+    public static Object retrieve( String key )
+    {
+        return cacheService.retrieve( key );
+    }
+
+    public static Pointer<Object> getPointer( String key )
+    {
+        return cacheService.getPointer( key );
+    }
+
+    public static void free( String key )
+    {
+        cacheService.free( key );
+    }
+
+    public static void free( Pointer<Object> pointer )
+    {
+        cacheService.free( pointer );
+    }
+
+    public static void collectExpired()
+    {
+        cacheService.collectExpired();
+    }
+
+    public static void collectLFU()
+    {
+        cacheService.collectLFU();
+    }
+
+    public static void collectAll()
+    {
+        cacheService.collectAll();
+    }
+
+
+    public static void clear()
+    {
+        cacheService.clear();
+    }
+
+    public static long entries()
+    {
+        return cacheService.entries();
+    }
+
+    public static void dump()
+    {
+        cacheService.dump();
+    }
+
+    public static Serializer getSerializer()
+    {
+        return cacheService.getSerializer();
+    }
+
+    public static MemoryManagerService<Object> getMemoryManager()
+    {
+        return cacheService.getMemoryManager();
+    }
+
+    public static Pointer<Object> allocate( String key, int size )
+    {
+        return cacheService.allocate( key, Object.class, size );
+    }
+
+}
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/cache/CacheService.java b/directmemory-cache/src/main/java/org/apache/directmemory/cache/CacheService.java
new file mode 100644
index 0000000..bd96a71
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/cache/CacheService.java
@@ -0,0 +1,93 @@
+package org.apache.directmemory.cache;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+import org.apache.directmemory.memory.MemoryManagerService;
+import org.apache.directmemory.memory.Pointer;
+import org.apache.directmemory.serialization.Serializer;
+
+import java.util.concurrent.ConcurrentMap;
+
+public interface CacheService<K, V>
+{
+
+    void scheduleDisposalEvery( long l );
+
+    /**
+     *
+     * @param key
+     * @param payload
+     * @param expiresIn in ms
+     * @return
+     */
+    Pointer<V> putByteArray( K key, byte[] payload, int expiresIn );
+
+    Pointer<V> putByteArray( K key, byte[] payload );
+
+    Pointer<V> put( K key, V value );
+
+    /**
+     *
+     * @param key
+     * @param value
+     * @param expiresIn in ms
+     * @return
+     */
+    Pointer<V> put( K key, V value, int expiresIn );
+
+    byte[] retrieveByteArray( K key );
+
+    V retrieve( K key );
+
+    Pointer<V> getPointer( K key );
+
+    void free( K key );
+
+    void free( Pointer<V> pointer );
+
+    void collectExpired();
+
+    void collectLFU();
+
+    void collectAll();
+
+
+    void clear();
+
+    long entries();
+
+    void dump();
+
+    ConcurrentMap<K, Pointer<V>> getMap();
+
+    void setMap( ConcurrentMap<K, Pointer<V>> map );
+
+    Serializer getSerializer();
+
+    MemoryManagerService<V> getMemoryManager();
+
+    void setMemoryManager( MemoryManagerService<V> memoryManager );
+
+    void setSerializer( Serializer serializer );
+
+    <T extends V> Pointer<V> allocate( K key, Class<T> type, int size );
+
+}
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/cache/CacheServiceImpl.java b/directmemory-cache/src/main/java/org/apache/directmemory/cache/CacheServiceImpl.java
new file mode 100644
index 0000000..946f26c
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/cache/CacheServiceImpl.java
@@ -0,0 +1,357 @@
+package org.apache.directmemory.cache;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.directmemory.measures.Ram;
+import org.apache.directmemory.memory.MemoryManagerService;
+import org.apache.directmemory.memory.Pointer;
+import org.apache.directmemory.serialization.Serializer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.ConcurrentMap;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.lang.String.format;
+
+public class CacheServiceImpl<K, V>
+    implements CacheService<K, V>
+{
+
+    private static Logger logger = LoggerFactory.getLogger( CacheServiceImpl.class );
+
+    private ConcurrentMap<K, Pointer<V>> map;
+
+    private Serializer serializer;
+
+    private MemoryManagerService<V> memoryManager;
+
+    private final Timer timer = new Timer();
+
+    /**
+     * Constructor
+     */
+    public CacheServiceImpl( ConcurrentMap<K, Pointer<V>> map, MemoryManagerService<V> memoryManager,
+                             Serializer serializer )
+    {
+        checkArgument( map != null, "Impossible to initialize the CacheService with a null map" );
+        checkArgument( memoryManager != null, "Impossible to initialize the CacheService with a null memoryManager" );
+        checkArgument( serializer != null, "Impossible to initialize the CacheService with a null serializer" );
+
+        this.map = map;
+        this.memoryManager = memoryManager;
+        this.serializer = serializer;
+    }
+
+    @Override
+    public void scheduleDisposalEvery( long l )
+    {
+        timer.schedule( new TimerTask()
+        {
+            public void run()
+            {
+                logger.info( "begin scheduled disposal" );
+
+                collectExpired();
+                collectLFU();
+
+                logger.info( "scheduled disposal complete" );
+            }
+        }, l, l );
+
+        logger.info( "disposal scheduled every {} milliseconds", l );
+    }
+
+    @Override
+    public Pointer<V> putByteArray( K key, byte[] payload )
+    {
+        return store( key, payload, 0 );
+    }
+
+    @Override
+    public Pointer<V> putByteArray( K key, byte[] payload, int expiresIn )
+    {
+        return store( key, payload, expiresIn );
+    }
+
+    @Override
+    public Pointer<V> put( K key, V value )
+    {
+        return put( key, value, 0 );
+    }
+
+    @Override
+    public Pointer<V> put( K key, V value, int expiresIn )
+    {
+        try
+        {
+            byte[] payload = serializer.serialize( value );
+            Pointer<V> ptr = store( key, payload, expiresIn );
+            if ( ptr != null )
+            {
+                @SuppressWarnings( "unchecked" ) // type driven by the compiler
+                    Class<? extends V> clazz = (Class<? extends V>) value.getClass();
+
+                ptr.setClazz( clazz );
+            }
+            return ptr;
+        }
+        catch ( IOException e )
+        {
+
+            if ( logger.isDebugEnabled() )
+            {
+                logger.debug( "IOException put object in cache:{}", e.getMessage(), e );
+            }
+            else
+            {
+                logger.error( "IOException put object in cache:{}", e.getMessage() );
+            }
+            return null;
+        }
+    }
+
+    private Pointer<V> store( K key, byte[] payload, int expiresIn )
+    {
+        Pointer<V> pointer = map.get( key );
+        if ( pointer != null )
+        {
+            return memoryManager.update( pointer, payload );
+        }
+        else
+        {
+            pointer = memoryManager.store( payload, expiresIn );
+            if ( pointer != null )
+            {
+                map.put( key, pointer );
+            }
+            return pointer;
+        }
+    }
+
+    @Override
+    public byte[] retrieveByteArray( K key )
+    {
+        Pointer<V> ptr = getPointer( key );
+        if ( ptr == null )
+        {
+            return null;
+        }
+        if ( ptr.isExpired() || ptr.isFree() )
+        {
+            map.remove( key );
+            if ( !ptr.isFree() )
+            {
+                memoryManager.free( ptr );
+            }
+            return null;
+        }
+        else
+        {
+            return memoryManager.retrieve( ptr );
+        }
+    }
+
+    @Override
+    public V retrieve( K key )
+    {
+        Pointer<V> ptr = getPointer( key );
+        if ( ptr == null )
+        {
+            return null;
+        }
+        if ( ptr.isExpired() || ptr.isFree() )
+        {
+            map.remove( key );
+            if ( !ptr.isFree() )
+            {
+                memoryManager.free( ptr );
+            }
+            return null;
+        }
+        else
+        {
+            try
+            {
+                return serializer.deserialize( memoryManager.retrieve( ptr ), ptr.getClazz() );
+            }
+            catch ( EOFException e )
+            {
+                logger.error( e.getMessage() );
+            }
+            catch ( IOException e )
+            {
+                logger.error( e.getMessage() );
+            }
+            catch ( ClassNotFoundException e )
+            {
+                logger.error( e.getMessage() );
+            }
+            catch ( InstantiationException e )
+            {
+                logger.error( e.getMessage() );
+            }
+            catch ( IllegalAccessException e )
+            {
+                logger.error( e.getMessage() );
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public Pointer<V> getPointer( K key )
+    {
+        return map.get( key );
+    }
+
+    @Override
+    public void free( K key )
+    {
+        Pointer<V> p = map.remove( key );
+        if ( p != null )
+        {
+            memoryManager.free( p );
+        }
+    }
+
+    @Override
+    public void free( Pointer<V> pointer )
+    {
+        memoryManager.free( pointer );
+    }
+
+    @Override
+    public void collectExpired()
+    {
+        memoryManager.collectExpired();
+        // still have to look for orphan (storing references to freed pointers) map entries
+    }
+
+    @Override
+    public void collectLFU()
+    {
+        memoryManager.collectLFU();
+        // can possibly clear one whole buffer if it's too fragmented - investigate
+    }
+
+    @Override
+    public void collectAll()
+    {
+        Thread thread = new Thread()
+        {
+            public void run()
+            {
+                logger.info( "begin disposal" );
+                collectExpired();
+                collectLFU();
+                logger.info( "disposal complete" );
+            }
+        };
+        thread.start();
+    }
+
+
+    @Override
+    public void clear()
+    {
+        map.clear();
+        memoryManager.clear();
+        logger.info( "Cache cleared" );
+    }
+
+    @Override
+    public long entries()
+    {
+        return map.size();
+    }
+
+    public void dump( MemoryManagerService<V> mms )
+    {
+        logger.info( format( "off-heap - allocated: \t%1s", Ram.inMb( mms.capacity() ) ) );
+        logger.info( format( "off-heap - used:      \t%1s", Ram.inMb( mms.used() ) ) );
+        logger.info( format( "heap  - max: \t%1s", Ram.inMb( Runtime.getRuntime().maxMemory() ) ) );
+        logger.info( format( "heap     - allocated: \t%1s", Ram.inMb( Runtime.getRuntime().totalMemory() ) ) );
+        logger.info( format( "heap     - free : \t%1s", Ram.inMb( Runtime.getRuntime().freeMemory() ) ) );
+        logger.info( "************************************************" );
+    }
+
+    @Override
+    public void dump()
+    {
+        if ( !logger.isInfoEnabled() )
+        {
+            return;
+        }
+
+        logger.info( "*** DirectMemory statistics ********************" );
+
+        dump( memoryManager );
+    }
+
+    @Override
+    public ConcurrentMap<K, Pointer<V>> getMap()
+    {
+        return map;
+    }
+
+    @Override
+    public void setMap( ConcurrentMap<K, Pointer<V>> map )
+    {
+        this.map = map;
+    }
+
+    @Override
+    public Serializer getSerializer()
+    {
+        return serializer;
+    }
+
+    @Override
+    public void setSerializer( Serializer serializer )
+    {
+        this.serializer = serializer;
+    }
+
+    @Override
+    public MemoryManagerService<V> getMemoryManager()
+    {
+        return memoryManager;
+    }
+
+    @Override
+    public void setMemoryManager( MemoryManagerService<V> memoryManager )
+    {
+        this.memoryManager = memoryManager;
+    }
+
+    @Override
+    public <T extends V> Pointer<V> allocate( K key, Class<T> type, int size )
+    {
+        Pointer<V> ptr = memoryManager.allocate( type, size, -1, -1 );
+        map.put( key, ptr );
+        ptr.setClazz( type );
+        return ptr;
+    }
+}
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/cache/package-info.java b/directmemory-cache/src/main/java/org/apache/directmemory/cache/package-info.java
new file mode 100644
index 0000000..0fcdf8a
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/cache/package-info.java
@@ -0,0 +1,23 @@
+/**
+ * Apache DirectMemory cache APIs.
+ */
+package org.apache.directmemory.cache;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/measures/Every.java b/directmemory-cache/src/main/java/org/apache/directmemory/measures/Every.java
new file mode 100644
index 0000000..a94dcd8
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/measures/Every.java
@@ -0,0 +1,31 @@
+package org.apache.directmemory.measures;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+public class Every
+    extends In
+{
+
+    public Every( double measure )
+    {
+        super( measure );
+    }
+
+}
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/measures/Expires.java b/directmemory-cache/src/main/java/org/apache/directmemory/measures/Expires.java
new file mode 100644
index 0000000..84f5773
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/measures/Expires.java
@@ -0,0 +1,40 @@
+package org.apache.directmemory.measures;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+public class Expires
+    extends In
+{
+
+    public Expires( double measure )
+    {
+        super( measure );
+    }
+
+    public static In in( double measure )
+    {
+        return new In( measure );
+    }
+
+    public static long never()
+    {
+        return -1L;
+    }
+}
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/measures/For.java b/directmemory-cache/src/main/java/org/apache/directmemory/measures/For.java
new file mode 100644
index 0000000..0474015
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/measures/For.java
@@ -0,0 +1,31 @@
+package org.apache.directmemory.measures;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+public class For
+    extends In
+{
+
+    public For( double measure )
+    {
+        super( measure );
+    }
+
+}
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/measures/Heap.java b/directmemory-cache/src/main/java/org/apache/directmemory/measures/Heap.java
new file mode 100644
index 0000000..c6285f5
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/measures/Heap.java
@@ -0,0 +1,26 @@
+package org.apache.directmemory.measures;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+public class Heap
+    extends Sizing
+{
+
+}
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/measures/In.java b/directmemory-cache/src/main/java/org/apache/directmemory/measures/In.java
new file mode 100644
index 0000000..c26cb06
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/measures/In.java
@@ -0,0 +1,92 @@
+package org.apache.directmemory.measures;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+public class In
+{
+
+    private static final int MILLISECONDS_IN_SECOND = 1000;
+
+    private static final int SECONDS_IN_MINUTE_OR_MINUTES_IN_HOUR = 60;
+
+    private static final int HOUR_IN_DAY = 24;
+
+    private double measure;
+
+    public In( double measure )
+    {
+        this.measure = measure;
+    }
+
+    public long seconds()
+    {
+        return seconds( measure );
+    }
+
+    public long minutes()
+    {
+        return minutes( measure );
+    }
+
+    public long hours()
+    {
+        return hours( measure );
+    }
+
+    public long days()
+    {
+        return days( measure );
+    }
+
+    public static long seconds( double seconds )
+    {
+        return (long) seconds * MILLISECONDS_IN_SECOND;
+    }
+
+    public static long minutes( double minutes )
+    {
+        return seconds( minutes * SECONDS_IN_MINUTE_OR_MINUTES_IN_HOUR );
+    }
+
+    public static long hours( double hours )
+    {
+        return minutes( hours * SECONDS_IN_MINUTE_OR_MINUTES_IN_HOUR );
+    }
+
+    public static long days( double days )
+    {
+        return hours( days * HOUR_IN_DAY );
+    }
+
+    public static In just( double measure )
+    {
+        return new In( measure );
+    }
+
+    public static In exactly( double measure )
+    {
+        return new In( measure );
+    }
+
+    public static In only( double measure )
+    {
+        return new In( measure );
+    }
+}
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/measures/Memory.java b/directmemory-cache/src/main/java/org/apache/directmemory/measures/Memory.java
new file mode 100644
index 0000000..860d029
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/measures/Memory.java
@@ -0,0 +1,26 @@
+package org.apache.directmemory.measures;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+public class Memory
+    extends Sizing
+{
+
+}
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/measures/Monitor.java b/directmemory-cache/src/main/java/org/apache/directmemory/measures/Monitor.java
new file mode 100644
index 0000000..5aa65ff
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/measures/Monitor.java
@@ -0,0 +1,118 @@
+package org.apache.directmemory.measures;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import static java.lang.String.format;
+
+import java.text.DecimalFormat;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Monitor
+{
+
+    private static final Logger LOG = LoggerFactory.getLogger( Monitor.class );
+
+    //TODO: MONITORS looks like a good candidate to become a private field
+    public static final Map<String, MonitorService> MONITORS = new HashMap<String, MonitorService>();
+
+    private MonitorService monitorService;
+
+    public static MonitorService get( String key )
+    {
+        MonitorService mon = MONITORS.get( key );
+        if ( mon == null )
+        {
+            mon = new MonitorServiceImpl( key );
+            MONITORS.put( key, mon );
+        }
+        return mon;
+    }
+
+    public Monitor( String name )
+    {
+        this.monitorService = new MonitorServiceImpl( name );
+        MONITORS.put( name, monitorService );
+    }
+
+    public long start()
+    {
+        return System.nanoTime();
+    }
+
+    public long stop( long begunAt )
+    {
+        monitorService.getHits().incrementAndGet();
+        final long lastAccessed = System.nanoTime();
+        final long elapsed = lastAccessed - begunAt;
+        monitorService.addToTotalTime( elapsed );
+        if ( elapsed > monitorService.getMax() && monitorService.getHits().get() > 0 )
+        {
+            monitorService.setMax( elapsed );
+        }
+        if ( elapsed < monitorService.getMin() && monitorService.getHits().get() > 0 )
+        {
+            monitorService.setMin( elapsed );
+        }
+        return elapsed;
+    }
+
+    public long hits()
+    {
+        return monitorService.getHits().get();
+    }
+
+    public long totalTime()
+    {
+        return monitorService.totalTime();
+    }
+
+    public long average()
+    {
+        return monitorService.getHits().get() > 0 ? monitorService.getTotalTime() / monitorService.getHits().get() : 0;
+    }
+
+    public String toString()
+    {
+        return format( "%1$s hits: %2$d, avg: %3$s ms, tot: %4$s seconds", monitorService.getName(),
+                       monitorService.getHits().get(),
+                       new DecimalFormat( "####.###" ).format( (double) average() / 1000000 ),
+                       new DecimalFormat( "####.###" ).format( (double) monitorService.getTotalTime() / 1000000000 ) );
+    }
+
+    public static void dump( String prefix )
+    {
+        for ( MonitorService monitor : MONITORS.values() )
+        {
+            if ( monitor.getName().startsWith( prefix ) )
+            {
+                LOG.info( monitor.toString() );
+            }
+        }
+    }
+
+    public static void dump()
+    {
+        dump( "" );
+    }
+}
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/measures/MonitorService.java b/directmemory-cache/src/main/java/org/apache/directmemory/measures/MonitorService.java
new file mode 100644
index 0000000..44a677a
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/measures/MonitorService.java
@@ -0,0 +1,58 @@
+package org.apache.directmemory.measures;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+import java.util.concurrent.atomic.AtomicLong;
+
+public interface MonitorService
+{
+
+    long start();
+
+    long stop( long begunAt );
+
+    long hits();
+
+    long totalTime();
+
+    long average();
+
+    void dump( String prefix );
+
+    void dump();
+
+    AtomicLong getHits();
+
+    long getTotalTime();
+
+    void addToTotalTime( long time );
+
+    long getMin();
+
+    void setMin( long min );
+
+    long getMax();
+
+    void setMax( long max );
+
+    String getName();
+
+}
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/measures/MonitorServiceImpl.java b/directmemory-cache/src/main/java/org/apache/directmemory/measures/MonitorServiceImpl.java
new file mode 100644
index 0000000..f2cc6d1
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/measures/MonitorServiceImpl.java
@@ -0,0 +1,158 @@
+package org.apache.directmemory.measures;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import static java.lang.String.format;
+
+import java.text.DecimalFormat;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MonitorServiceImpl
+    implements MonitorService
+{
+
+    private AtomicLong hits = new AtomicLong( 0 );
+
+    private long totalTime = 0;
+
+    private long min = -1;
+
+    private long max = -1;
+
+    public String name;
+
+    private static final Logger LOG = LoggerFactory.getLogger( MonitorServiceImpl.class );
+
+    //TODO: MONITORS looks like a good candidate to become a private field
+    public static final Map<String, MonitorServiceImpl> MONITORS = new HashMap<String, MonitorServiceImpl>();
+
+    public MonitorServiceImpl( String name )
+    {
+        this.name = name;
+    }
+
+    public long start()
+    {
+        return System.nanoTime();
+    }
+
+    public long stop( long begunAt )
+    {
+        hits.incrementAndGet();
+        final long lastAccessed = System.nanoTime();
+        final long elapsed = lastAccessed - begunAt;
+        totalTime += elapsed;
+        if ( elapsed > max && hits.get() > 0 )
+        {
+            max = elapsed;
+        }
+        if ( elapsed < min && hits.get() > 0 )
+        {
+            min = elapsed;
+        }
+        return elapsed;
+    }
+
+    public long hits()
+    {
+        return hits.get();
+    }
+
+    public long totalTime()
+    {
+        return totalTime;
+    }
+
+    public long average()
+    {
+        return hits.get() > 0 ? totalTime / hits.get() : 0;
+    }
+
+    public String toString()
+    {
+        return format( "%1$s hits: %2$d, avg: %3$s ms, tot: %4$s seconds", name, hits.get(),
+                       new DecimalFormat( "####.###" ).format( (double) average() / 1000000 ),
+                       new DecimalFormat( "####.###" ).format( (double) totalTime / 1000000000 ) );
+    }
+
+    public void dump( String prefix )
+    {
+        for ( MonitorServiceImpl monitor : MonitorServiceImpl.MONITORS.values() )
+        {
+            if ( monitor.name.startsWith( prefix ) )
+            {
+                LOG.info( monitor.toString() );
+            }
+        }
+    }
+
+    public void dump()
+    {
+        dump( "" );
+    }
+
+    public String getName()
+    {
+        return name;
+    }
+
+    public AtomicLong getHits()
+    {
+        return hits;
+    }
+
+    public long getTotalTime()
+    {
+        return totalTime;
+    }
+
+    @Override
+    public void addToTotalTime( long time )
+    {
+        totalTime += time;
+    }
+
+    public long getMin()
+    {
+        return min;
+    }
+
+    public void setMin( long min )
+    {
+        this.min = min;
+    }
+
+    public long getMax()
+    {
+        return max;
+    }
+
+    public void setMax( long max )
+    {
+        this.max = max;
+    }
+
+
+}
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/measures/Ram.java b/directmemory-cache/src/main/java/org/apache/directmemory/measures/Ram.java
new file mode 100644
index 0000000..2a9786e
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/measures/Ram.java
@@ -0,0 +1,26 @@
+package org.apache.directmemory.measures;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+public class Ram
+    extends Sizing
+{
+
+}
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/measures/Sizing.java b/directmemory-cache/src/main/java/org/apache/directmemory/measures/Sizing.java
new file mode 100644
index 0000000..980a545
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/measures/Sizing.java
@@ -0,0 +1,64 @@
+package org.apache.directmemory.measures;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import static java.lang.String.format;
+
+public class Sizing
+{
+
+    private static final int KILOBYTE_UNIT = 1024;
+
+    public static int Gb( double giga )
+    {
+        return (int) giga * KILOBYTE_UNIT * KILOBYTE_UNIT * KILOBYTE_UNIT;
+    }
+
+    public static int Mb( double mega )
+    {
+        return (int) mega * KILOBYTE_UNIT * KILOBYTE_UNIT;
+    }
+
+    public static int Kb( double kilo )
+    {
+        return (int) kilo * KILOBYTE_UNIT;
+    }
+
+    public static int unlimited()
+    {
+        return -1;
+    }
+
+    public static String inKb( long bytes )
+    {
+        return format( "%(,.1fKb", (double) bytes / KILOBYTE_UNIT );
+    }
+
+    public static String inMb( long bytes )
+    {
+        return format( "%(,.1fMb", (double) bytes / KILOBYTE_UNIT / KILOBYTE_UNIT );
+    }
+
+    public static String inGb( long bytes )
+    {
+        return format( "%(,.1fGb", (double) bytes / KILOBYTE_UNIT / KILOBYTE_UNIT / KILOBYTE_UNIT );
+    }
+
+}
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/measures/Space.java b/directmemory-cache/src/main/java/org/apache/directmemory/measures/Space.java
new file mode 100644
index 0000000..3e8e633
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/measures/Space.java
@@ -0,0 +1,26 @@
+package org.apache.directmemory.measures;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+public class Space
+    extends Sizing
+{
+
+}
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/measures/package-info.java b/directmemory-cache/src/main/java/org/apache/directmemory/measures/package-info.java
new file mode 100644
index 0000000..003f77c
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/measures/package-info.java
@@ -0,0 +1,23 @@
+/**
+ * Fluent APIs for manipulate unit measures, such as time and space memory.
+ */
+package org.apache.directmemory.measures;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/memory/AllocationPolicy.java b/directmemory-cache/src/main/java/org/apache/directmemory/memory/AllocationPolicy.java
new file mode 100644
index 0000000..3b98043
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/memory/AllocationPolicy.java
@@ -0,0 +1,59 @@
+package org.apache.directmemory.memory;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.util.List;
+
+import org.apache.directmemory.memory.allocator.ByteBufferAllocator;
+
+/**
+ * Interface describing the buffer allocation policy.
+ * The implementations will be initialized by setting the list of buffers {@link #init(List)},
+ * and every allocation will call {@link #getActiveBuffer(OffHeapMemoryBuffer, int)},
+ * passing the previously (possibly null) buffer that failed to allocate and the number of the current allocation
+ *
+ * @author bperroud
+ *
+ */
+public interface AllocationPolicy
+{
+
+    /**
+     * Initialization function.
+     *
+     * @param buffers
+     */
+    void init( List<ByteBufferAllocator> allocators );
+
+    /**
+     * Returns the {@link ByteBufferAllocator} to use to allocate.
+     *
+     * @param previousAllocator : the previously used {@link ByteBufferAllocator}, or null if it's the first allocation
+     * @param allocationNumber : the number of time the allocation has already failed.
+     * @return the {@link ByteBufferAllocator} to use, or null if allocation has failed.
+     */
+    ByteBufferAllocator getActiveAllocator( ByteBufferAllocator previousAllocator, int allocationNumber );
+
+    /**
+     * Reset internal state
+     */
+    void reset();
+
+}
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/memory/MemoryManager.java b/directmemory-cache/src/main/java/org/apache/directmemory/memory/MemoryManager.java
new file mode 100644
index 0000000..90a30ef
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/memory/MemoryManager.java
@@ -0,0 +1,90 @@
+package org.apache.directmemory.memory;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+public class MemoryManager
+{
+    private static MemoryManagerService<Object> memoryManager = new MemoryManagerServiceImpl<Object>();
+
+    private MemoryManager()
+    {
+        //static class
+    }
+
+    public static void init( int numberOfBuffers, int size )
+    {
+        memoryManager.init( numberOfBuffers, size );
+    }
+
+    public static Pointer<Object> store( byte[] payload, int expiresIn )
+    {
+        return memoryManager.store( payload, expiresIn );
+    }
+
+    public static Pointer<Object> store( byte[] payload )
+    {
+        return store( payload, 0 );
+    }
+
+    public static Pointer<Object> update( Pointer<Object> pointer, byte[] payload )
+    {
+        return memoryManager.update( pointer, payload );
+    }
+
+    public static byte[] retrieve( Pointer<Object> pointer )
+    {
+        return memoryManager.retrieve( pointer );
+    }
+
+    public static void free( Pointer<Object> pointer )
+    {
+        memoryManager.free( pointer );
+    }
+
+    public static void clear()
+    {
+        memoryManager.clear();
+    }
+
+    public static long capacity()
+    {
+        return memoryManager.capacity();
+    }
+
+    public static long collectExpired()
+    {
+        return memoryManager.collectExpired();
+    }
+
+    public static void collectLFU()
+    {
+        memoryManager.collectLFU();
+    }
+
+    public static MemoryManagerService<Object> getMemoryManager()
+    {
+        return memoryManager;
+    }
+
+    public static Pointer<Object> allocate( int size )
+    {
+        return memoryManager.allocate( Object.class, size, -1, -1 ); //add a version with expiration
+    }
+}
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/memory/MemoryManagerService.java b/directmemory-cache/src/main/java/org/apache/directmemory/memory/MemoryManagerService.java
new file mode 100644
index 0000000..2b17db5
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/memory/MemoryManagerService.java
@@ -0,0 +1,88 @@
+package org.apache.directmemory.memory;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+public interface MemoryManagerService<V>
+{
+
+    /**
+     * Initialize the internal structure. Need to be called before the service
+     * can be used.
+     *
+     * @param numberOfBuffers
+     *            : number of internal bucket
+     * @param size
+     *            : size in B of internal buckets
+     */
+    void init( int numberOfBuffers, int size );
+
+    /**
+     * Store function family. Store the given payload at a certain offset in a MemoryBuffer, returning the pointer to the value.
+     *
+     * @param payload : the data to store
+     * @return the pointer to the value, or null if not enough space has been found.
+     */
+    Pointer<V> store( byte[] payload, int expiresIn );
+
+    /**
+     * Same function as {@link #store(byte[])}, but add an relative expiration delta in milliseconds
+     *
+     * @param payload : the data to store
+     * @param expiresIn : relative amount of milliseconds the data will expire
+     * @return the pointer to the value, or null if not enough space has been found.
+     */
+    Pointer<V> store( byte[] payload );
+
+    /**
+     * Same function as {@link #store(byte[])}, but add an absolute expiration date
+     * @param payload : the data to store
+     * @param expires : the absolute date the data will expire
+     * @return the pointer to the value, or null if not enough space has been found.
+     */
+    //public Pointer store(byte[] payload, Date expires);
+
+    /**
+     *
+     *
+     * Update value of a {@link Pointer
+     * @param pointer
+     * @param payload
+     * @return
+     * @throw BufferOverflowException if the size of the payload id bigger than the pointer capacity
+     */
+    Pointer<V> update( Pointer<V> pointer, byte[] payload );
+
+    byte[] retrieve( Pointer<V> pointer );
+
+    void free( Pointer<V> pointer );
+
+    void clear();
+
+    long capacity();
+
+    long used();
+
+    long collectExpired();
+
+    void collectLFU();
+
+    <T extends V> Pointer<V> allocate( Class<T> type, int size, long expiresIn, long expires );
+
+}
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/memory/MemoryManagerServiceImpl.java b/directmemory-cache/src/main/java/org/apache/directmemory/memory/MemoryManagerServiceImpl.java
new file mode 100644
index 0000000..1a90290
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/memory/MemoryManagerServiceImpl.java
@@ -0,0 +1,387 @@
+package org.apache.directmemory.memory;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import com.google.common.base.Predicate;
+import org.apache.directmemory.measures.Ram;
+import org.apache.directmemory.memory.allocator.ByteBufferAllocator;
+import org.apache.directmemory.memory.allocator.MergingByteBufferAllocatorImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+
+import static com.google.common.collect.Iterables.filter;
+import static com.google.common.collect.Iterables.limit;
+import static com.google.common.collect.Ordering.from;
+import static java.lang.String.format;
+
+public class MemoryManagerServiceImpl<V>
+    implements MemoryManagerService<V>
+{
+
+    protected static final long NEVER_EXPIRES = 0L;
+
+    protected static Logger logger = LoggerFactory.getLogger( MemoryManager.class );
+
+    private List<ByteBufferAllocator> allocators;
+
+    private final Set<Pointer<V>> pointers = Collections.newSetFromMap( new ConcurrentHashMap<Pointer<V>, Boolean>() );
+
+    private final boolean returnNullWhenFull;
+
+    protected final AtomicLong used = new AtomicLong( 0L );
+
+    protected final AllocationPolicy allocationPolicy;
+
+    public MemoryManagerServiceImpl()
+    {
+        this( true );
+    }
+
+    public MemoryManagerServiceImpl( final boolean returnNullWhenFull )
+    {
+        this( new RoundRobinAllocationPolicy(), returnNullWhenFull );
+    }
+
+    public MemoryManagerServiceImpl( final AllocationPolicy allocationPolicy, final boolean returnNullWhenFull )
+    {
+        this.allocationPolicy = allocationPolicy;
+        this.returnNullWhenFull = returnNullWhenFull;
+    }
+
+    @Override
+    public void init( int numberOfBuffers, int size )
+    {
+
+        allocators = new ArrayList<ByteBufferAllocator>( numberOfBuffers );
+
+        for ( int i = 0; i < numberOfBuffers; i++ )
+        {
+            final ByteBufferAllocator allocator = instanciateByteBufferAllocator( i, size );
+            allocators.add( allocator );
+        }
+
+        allocationPolicy.init( allocators );
+
+        logger.info( format( "MemoryManager initialized - %d buffers, %s each", numberOfBuffers, Ram.inMb( size ) ) );
+    }
+
+
+    protected ByteBufferAllocator instanciateByteBufferAllocator( final int allocatorNumber, final int size )
+    {
+        final MergingByteBufferAllocatorImpl allocator = new MergingByteBufferAllocatorImpl( allocatorNumber, size );
+
+        // Hack to ensure the pointers are always split to keep backward compatibility.
+        allocator.setMinSizeThreshold( 0 );
+        allocator.setSizeRatioThreshold( 1.0 );
+
+        return allocator;
+    }
+
+    protected ByteBufferAllocator getAllocator( int allocatorIndex )
+    {
+        return allocators.get( allocatorIndex );
+    }
+
+    protected ByteBufferAllocator getCurrentAllocator()
+    {
+        return allocationPolicy.getActiveAllocator( null, 0 );
+    }
+
+    @Override
+    public Pointer<V> store( byte[] payload, int expiresIn )
+    {
+        Pointer<V> p = null;
+        ByteBufferAllocator allocator = null;
+        int allocationNumber = 0;
+        do
+        {
+            allocationNumber++;
+            allocator = allocationPolicy.getActiveAllocator( allocator, allocationNumber );
+            if ( allocator == null )
+            {
+                if ( returnsNullWhenFull() )
+                {
+                    return null;
+                }
+                else
+                {
+                    throw new BufferOverflowException();
+                }
+            }
+            final ByteBuffer buffer = allocator.allocate( payload.length );
+
+            if ( buffer == null )
+            {
+                continue;
+            }
+
+            p = instanciatePointer( buffer, allocator.getNumber(), expiresIn, NEVER_EXPIRES );
+
+            buffer.rewind();
+            buffer.put( payload );
+
+            used.addAndGet( payload.length );
+
+        }
+        while ( p == null );
+        return p;
+    }
+
+    @Override
+    public Pointer<V> store( byte[] payload )
+    {
+        return store( payload, 0 );
+    }
+
+    @Override
+    public Pointer<V> update( Pointer<V> pointer, byte[] payload )
+    {
+        free( pointer );
+        return store( payload );
+    }
+
+    @Override
+    public byte[] retrieve( final Pointer<V> pointer )
+    {
+        // check if pointer has not been freed before
+        if ( !pointers.contains( pointer ) )
+        {
+            return null;
+        }
+
+        pointer.hit();
+
+        final ByteBuffer buf = pointer.getDirectBuffer().asReadOnlyBuffer();
+        buf.rewind();
+
+        final byte[] swp = new byte[buf.limit()];
+        buf.get( swp );
+        return swp;
+    }
+
+    @Override
+    public void free( final Pointer<V> pointer )
+    {
+        if ( !pointers.remove( pointer ) )
+        {
+            // pointers has been already freed.
+            //throw new IllegalArgumentException( "This pointer " + pointer + " has already been freed" );
+            return;
+        }
+
+        getAllocator( pointer.getBufferNumber() ).free( pointer.getDirectBuffer() );
+
+        used.addAndGet( -pointer.getCapacity() );
+
+        pointer.setFree( true );
+    }
+
+    @Override
+    public void clear()
+    {
+        for ( Pointer<V> pointer : pointers )
+        {
+            pointer.setFree( true );
+        }
+        pointers.clear();
+        for ( ByteBufferAllocator allocator : allocators )
+        {
+            allocator.clear();
+        }
+        allocationPolicy.reset();
+    }
+
+    @Override
+    public long capacity()
+    {
+        long totalCapacity = 0;
+        for ( ByteBufferAllocator allocator : allocators )
+        {
+            totalCapacity += allocator.getCapacity();
+        }
+        return totalCapacity;
+    }
+
+    @Override
+    public long used()
+    {
+        return used.get();
+    }
+
+    private final Predicate<Pointer<V>> relative = new Predicate<Pointer<V>>()
+    {
+
+        @Override
+        public boolean apply( Pointer<V> input )
+        {
+            return !input.isFree() && input.isExpired();
+        }
+
+    };
+
+    private final Predicate<Pointer<V>> absolute = new Predicate<Pointer<V>>()
+    {
+
+        @Override
+        public boolean apply( Pointer<V> input )
+        {
+            return !input.isFree() && input.isExpired();
+        }
+
+    };
+
+    @Override
+    public long collectExpired()
+    {
+        int limit = 50;
+        return free( limit( filter( pointers, relative ), limit ) ) + free(
+            limit( filter( pointers, absolute ), limit ) );
+
+    }
+
+    @Override
+    public void collectLFU()
+    {
+
+        int limit = pointers.size() / 10;
+
+        Iterable<Pointer<V>> result = from( new Comparator<Pointer<V>>()
+        {
+
+            public int compare( Pointer<V> o1, Pointer<V> o2 )
+            {
+                float f1 = o1.getFrequency();
+                float f2 = o2.getFrequency();
+
+                return Float.compare( f1, f2 );
+            }
+
+        } ).sortedCopy( limit( filter( pointers, new Predicate<Pointer<V>>()
+        {
+
+            @Override
+            public boolean apply( Pointer<V> input )
+            {
+                return !input.isFree();
+            }
+
+        } ), limit ) );
+
+        free( result );
+
+    }
+
+    protected long free( Iterable<Pointer<V>> pointers )
+    {
+        long howMuch = 0;
+        for ( Pointer<V> expired : pointers )
+        {
+            howMuch += expired.getCapacity();
+            free( expired );
+        }
+        return howMuch;
+    }
+
+
+    protected List<ByteBufferAllocator> getAllocators()
+    {
+        return allocators;
+    }
+
+    @Deprecated
+    @Override
+    public <T extends V> Pointer<V> allocate( final Class<T> type, final int size, final long expiresIn,
+                                              final long expires )
+    {
+
+        Pointer<V> p = null;
+        ByteBufferAllocator allocator = null;
+        int allocationNumber = 0;
+        do
+        {
+            allocationNumber++;
+            allocator = allocationPolicy.getActiveAllocator( allocator, allocationNumber );
+            if ( allocator == null )
+            {
+                if ( returnsNullWhenFull() )
+                {
+                    return null;
+                }
+                else
+                {
+                    throw new BufferOverflowException();
+                }
+            }
+
+            final ByteBuffer buffer = allocator.allocate( size );
+
+            if ( buffer == null )
+            {
+                continue;
+            }
+
+            p = instanciatePointer( buffer, allocator.getNumber(), expiresIn, NEVER_EXPIRES );
+
+            used.addAndGet( size );
+        }
+        while ( p == null );
+
+        p.setClazz( type );
+
+        return p;
+    }
+
+    protected Pointer<V> instanciatePointer( final ByteBuffer buffer, final int allocatorIndex, final long expiresIn,
+                                             final long expires )
+    {
+
+        Pointer<V> p = new PointerImpl<V>();
+
+        p.setDirectBuffer( buffer );
+        p.setExpiration( expires, expiresIn );
+        p.setBufferNumber( allocatorIndex );
+        p.setFree( false );
+        p.createdNow();
+
+        pointers.add( p );
+
+        return p;
+    }
+
+    protected boolean returnsNullWhenFull()
+    {
+        return returnNullWhenFull;
+    }
+
+    public Set<Pointer<V>> getPointers()
+    {
+        return Collections.unmodifiableSet( pointers );
+    }
+}
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/memory/Pointer.java b/directmemory-cache/src/main/java/org/apache/directmemory/memory/Pointer.java
new file mode 100644
index 0000000..8b18f2b
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/memory/Pointer.java
@@ -0,0 +1,67 @@
+package org.apache.directmemory.memory;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.nio.ByteBuffer;
+
+public interface Pointer<T>
+{
+
+    byte[] content();
+
+    boolean isFree();
+
+    void setFree( boolean free );
+
+    boolean isExpired();
+
+    float getFrequency();
+
+    int getCapacity();
+
+    void reset();
+
+    int getBufferNumber();
+
+    void setBufferNumber( int bufferNumber );
+
+    int getStart();
+
+    void setStart( int start );
+
+    int getEnd();
+
+    void setEnd( int end );
+
+    void hit();
+
+    Class<? extends T> getClazz();
+
+    void setClazz( Class<? extends T> clazz );
+
+    ByteBuffer getDirectBuffer();
+
+    void setDirectBuffer( ByteBuffer directBuffer );
+
+    void createdNow();
+
+    void setExpiration( long expires, long expiresIn );
+
+}
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/memory/PointerImpl.java b/directmemory-cache/src/main/java/org/apache/directmemory/memory/PointerImpl.java
new file mode 100644
index 0000000..d94e02b
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/memory/PointerImpl.java
@@ -0,0 +1,199 @@
+package org.apache.directmemory.memory;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import static java.lang.System.currentTimeMillis;
+import static java.lang.String.format;
+
+import java.nio.ByteBuffer;
+
+public class PointerImpl<T>
+    implements Pointer<T>
+{
+    public int start;
+
+    public int end;
+
+    public long created;
+
+    public long expires;
+
+    public long expiresIn;
+
+    public long hits;
+
+    public boolean free;
+
+    public long lastHit;
+
+    public int bufferNumber;
+
+    public Class<? extends T> clazz;
+
+    public ByteBuffer directBuffer = null;
+
+    public PointerImpl()
+    {
+    }
+
+    public PointerImpl( int start, int end )
+    {
+        this.start = start;
+        this.end = end;
+    }
+
+    @Override
+    public byte[] content()
+    {
+        return null;
+    }
+
+    @Override
+    public float getFrequency()
+    {
+        return (float) ( currentTimeMillis() - created ) / hits;
+    }
+
+    @Override
+    public int getCapacity()
+    {
+        return directBuffer == null ? end - start + 1 : directBuffer.limit();
+    }
+
+    @Override
+    public String toString()
+    {
+        return format( "%s[%s, %s] %s free", getClass().getSimpleName(), start, end, ( free ? "" : "not" ) );
+    }
+
+    @Override
+    public void reset()
+    {
+        free = true;
+        created = 0;
+        lastHit = 0;
+        hits = 0;
+        expiresIn = 0;
+        clazz = null;
+        directBuffer = null;
+    }
+
+    @Override
+    public boolean isFree()
+    {
+        return free;
+    }
+
+    @Override
+    public boolean isExpired()
+    {
+        if ( expires > 0 || expiresIn > 0 )
+        {
+            return ( expiresIn + created < currentTimeMillis() );
+        }
+        return false;
+    }
+
+    @Override
+    public int getBufferNumber()
+    {
+        return bufferNumber;
+    }
+
+    @Override
+    public int getStart()
+    {
+        return start;
+    }
+
+    @Override
+    public int getEnd()
+    {
+        return end;
+    }
+
+    @Override
+    public void setStart( int start )
+    {
+        this.start = start;
+    }
+
+    @Override
+    public void hit()
+    {
+        lastHit = System.currentTimeMillis();
+        hits++;
+    }
+
+    @Override
+    public Class<? extends T> getClazz()
+    {
+        return clazz;
+    }
+
+    @Override
+    public ByteBuffer getDirectBuffer()
+    {
+        return directBuffer;
+    }
+
+    @Override
+    public void setFree( boolean free )
+    {
+        this.free = free;
+    }
+
+    @Override
+    public void setEnd( int end )
+    {
+        this.end = end;
+    }
+
+    @Override
+    public void setClazz( Class<? extends T> clazz )
+    {
+        this.clazz = clazz;
+    }
+
+    @Override
+    public void setDirectBuffer( ByteBuffer directBuffer )
+    {
+        this.directBuffer = directBuffer;
+    }
+
+    @Override
+    public void createdNow()
+    {
+        created = System.currentTimeMillis();
+    }
+
+    @Override
+    public void setBufferNumber( int bufferNumber )
+    {
+        this.bufferNumber = bufferNumber;
+    }
+
+    @Override
+    public void setExpiration( long expires, long expiresIn )
+    {
+        this.expires = expires;
+        this.expiresIn = expiresIn;
+    }
+}
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/memory/RoundRobinAllocationPolicy.java b/directmemory-cache/src/main/java/org/apache/directmemory/memory/RoundRobinAllocationPolicy.java
new file mode 100644
index 0000000..80cf397
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/memory/RoundRobinAllocationPolicy.java
@@ -0,0 +1,107 @@
+package org.apache.directmemory.memory;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.directmemory.memory.allocator.ByteBufferAllocator;
+
+/**
+ * Round Robin allocation policy. An internal counter is incremented (modulo the size of the buffer), so each calls to
+ * {@link #getActiveBuffer(OffHeapMemoryBuffer, int)} will increment the counter and return the buffer at the index of
+ * the counter.
+ *
+ * @author bperroud
+ */
+public class RoundRobinAllocationPolicy
+    implements AllocationPolicy
+{
+
+    // Increment the counter and get the value. Need to start at -1 to have 0'index at first call.
+    private static final int BUFFERS_INDEX_INITIAL_VALUE = -1;
+
+    // All the buffers to allocate
+    private List<ByteBufferAllocator> allocators;
+
+    // Cyclic counter
+    private AtomicInteger buffersIndexCounter = new AtomicInteger( BUFFERS_INDEX_INITIAL_VALUE );
+
+    // Default max number of allocations before returning null buffer.
+    private static final int DEFAULT_MAX_ALLOCATIONS = 2;
+
+    // Current max number of allocations
+    private int maxAllocations = DEFAULT_MAX_ALLOCATIONS;
+
+    public void setMaxAllocations( final int maxAllocations )
+    {
+        this.maxAllocations = maxAllocations;
+    }
+
+    @Override
+    public void init( final List<ByteBufferAllocator> allocators )
+    {
+        this.allocators = allocators;
+    }
+
+    @Override
+    public ByteBufferAllocator getActiveAllocator( final ByteBufferAllocator previousAllocator, final int allocationNumber )
+    {
+        // If current allocation is more than the limit, return a null buffer.
+        if ( allocationNumber > maxAllocations )
+        {
+            return null;
+        }
+
+        // Thread safely increment and get the next buffer's index
+        int i = incrementAndGetBufferIndex();
+
+        final ByteBufferAllocator allocator = allocators.get( i );
+
+        return allocator;
+    }
+
+    @Override
+    public void reset()
+    {
+        // Reinitialize the counter to it's initial value
+        buffersIndexCounter.set( BUFFERS_INDEX_INITIAL_VALUE );
+    }
+
+    /**
+     * Optimistic (lock free) cyclic (modulo size of the buffer) increment of the counter
+     *
+     * @return next index
+     */
+    private int incrementAndGetBufferIndex()
+    {
+        int newIndex = 0;
+        boolean updateOk = false;
+        do
+        {
+            int currentIndex = buffersIndexCounter.get();
+            newIndex = ( currentIndex + 1 ) % allocators.size();
+            updateOk = buffersIndexCounter.compareAndSet( currentIndex, newIndex );
+        }
+        while ( !updateOk );
+        return newIndex;
+    }
+
+}
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/memory/allocator/AbstractByteBufferAllocator.java b/directmemory-cache/src/main/java/org/apache/directmemory/memory/allocator/AbstractByteBufferAllocator.java
new file mode 100644
index 0000000..be6c328
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/memory/allocator/AbstractByteBufferAllocator.java
@@ -0,0 +1,70 @@
+package org.apache.directmemory.memory.allocator;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.nio.ByteBuffer;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+
+public abstract class AbstractByteBufferAllocator
+    implements ByteBufferAllocator
+{
+
+    protected final Logger logger = LoggerFactory.getLogger( this.getClass() );
+
+    private final int number;
+
+    private final AtomicBoolean closed = new AtomicBoolean( false );
+
+    AbstractByteBufferAllocator( final int number )
+    {
+        this.number = number;
+    }
+
+    @Override
+    public int getNumber()
+    {
+        return number;
+    }
+
+    protected final Logger getLogger()
+    {
+        return logger;
+    }
+
+    protected final boolean isClosed()
+    {
+        return closed.get();
+    }
+
+    protected final void setClosed( final boolean closed )
+    {
+        this.closed.set( closed );
+    }
+
+    protected static Integer getHash( final ByteBuffer buffer )
+    {
+        return Integer.valueOf( System.identityHashCode( buffer ) );
+    }
+
+}
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/memory/allocator/ByteBufferAllocator.java b/directmemory-cache/src/main/java/org/apache/directmemory/memory/allocator/ByteBufferAllocator.java
new file mode 100644
index 0000000..b959c9a
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/memory/allocator/ByteBufferAllocator.java
@@ -0,0 +1,63 @@
+package org.apache.directmemory.memory.allocator;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.Closeable;
+import java.nio.ByteBuffer;
+
+/**
+ * Interface defining interaction with {@link ByteBuffer}
+ * 
+ * @since 0.6
+ */
+public interface ByteBufferAllocator
+    extends Closeable
+{
+    
+    /**
+     * Returns the given {@link ByteBuffer} making it available for a future usage. Returning twice a {@link ByteBuffer} won't throw an exception. 
+     * @param buffer : the {@link ByteBuffer} to return
+     */
+    void free( final ByteBuffer buffer );
+    
+    /**
+     * Allocates and returns a {@link ByteBuffer} with {@link ByteBuffer#limit()} set to the given size.
+     * When the allocation fails, it returns either null or throws an {@link BufferOverflowException}, depending on the implementation. 
+     * @param size : the size in byte to allocate
+     * @return a {@link ByteBuffer} of the given size, or either return null or throw an {@link BufferOverflowException} when the allocation fails.
+     */
+    ByteBuffer allocate( final int size );
+    
+    /**
+     * Clear all allocated {@link ByteBuffer}, resulting in a empty and ready to deserve {@link ByteBufferAllocator}
+     */
+    void clear();
+    
+    /**
+     * @return the internal total size that can be allocated 
+     */
+    int getCapacity();
+    
+    /**
+     * @return the internal identifier of the {@link ByteBufferAllocator}
+     */
+    int getNumber();
+    
+}
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/memory/allocator/DirectByteBufferUtils.java b/directmemory-cache/src/main/java/org/apache/directmemory/memory/allocator/DirectByteBufferUtils.java
new file mode 100644
index 0000000..6932c0c
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/memory/allocator/DirectByteBufferUtils.java
@@ -0,0 +1,61 @@
+package org.apache.directmemory.memory.allocator;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.nio.ByteBuffer;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+/**
+ * Utility class around direct {@link ByteBuffer} 
+ *
+ */
+public class DirectByteBufferUtils
+{
+
+    /**
+     * Clear and release the internal content of a direct {@link ByteBuffer}.
+     * Clearing manually the content avoid waiting till the GC do his job.
+     * @param buffer : the buffer to clear
+     * @throws IllegalArgumentException
+     * @throws IllegalAccessException
+     * @throws InvocationTargetException
+     * @throws SecurityException
+     * @throws NoSuchMethodException
+     */
+    public static void destroyDirectByteBuffer( final ByteBuffer buffer )
+        throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, SecurityException,
+        NoSuchMethodException
+    {
+
+        checkArgument( buffer.isDirect(), "toBeDestroyed isn't direct!" );
+
+        Method cleanerMethod = buffer.getClass().getMethod( "cleaner" );
+        cleanerMethod.setAccessible( true );
+        Object cleaner = cleanerMethod.invoke( buffer );
+        Method cleanMethod = cleaner.getClass().getMethod( "clean" );
+        cleanMethod.setAccessible( true );
+        cleanMethod.invoke( cleaner );
+
+    }
+    
+}
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/memory/allocator/FixedSizeByteBufferAllocatorImpl.java b/directmemory-cache/src/main/java/org/apache/directmemory/memory/allocator/FixedSizeByteBufferAllocatorImpl.java
new file mode 100644
index 0000000..bfe9e35
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/memory/allocator/FixedSizeByteBufferAllocatorImpl.java
@@ -0,0 +1,221 @@
+package org.apache.directmemory.memory.allocator;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+
+/**
+ * {@link ByteBufferAllocator} implementation that instantiate {@link ByteBuffer}s of fixed size, called slices.
+ *
+ * @since 0.6
+ */
+public class FixedSizeByteBufferAllocatorImpl
+    extends AbstractByteBufferAllocator
+{
+
+    // Collection that keeps track of the parent buffers (segments) where slices are allocated
+    private final List<ByteBuffer> segmentsBuffers;
+
+    // Collection that owns all slices that can be used.
+    private final Queue<ByteBuffer> freeBuffers = new ConcurrentLinkedQueue<ByteBuffer>();
+
+    // Size of each slices dividing each segments of the slab
+    private final int sliceSize;
+
+    // Total size of the current slab
+    private int totalSize;
+
+    // Tells if it returns null or throw an BufferOverflowException when the requested size is bigger than the size of the slices
+    private boolean returnNullWhenOversizingSliceSize = true;
+
+    // Tells if it returns null when no buffers are available
+    private boolean returnNullWhenNoBufferAvailable = true;
+
+    // Collection that keeps track of borrowed buffers
+    private final Map<Integer, ByteBuffer> usedSliceBuffers = new ConcurrentHashMap<Integer, ByteBuffer>();
+
+
+    /**
+     * Constructor.
+     *
+     * @param number           : internal identifier of the allocator
+     * @param totalSize        : the internal buffer
+     * @param sliceSize        : arbitrary number of the buffer.
+     * @param numberOfSegments : number of parent {@link ByteBuffer} to allocate.
+     */
+    public FixedSizeByteBufferAllocatorImpl( final int number, final int totalSize, final int sliceSize,
+                                             final int numberOfSegments )
+    {
+        super( number );
+
+        this.totalSize = totalSize;
+        this.sliceSize = sliceSize;
+
+        this.segmentsBuffers = new ArrayList<ByteBuffer>( numberOfSegments );
+
+        init( numberOfSegments );
+
+    }
+
+    protected void init( final int numberOfSegments )
+    {
+        checkArgument( numberOfSegments > 0 );
+
+        // Compute the size of each segments
+        int segmentSize = totalSize / numberOfSegments;
+        // size is rounded down to a multiple of the slice size
+        segmentSize -= segmentSize % sliceSize;
+
+        for ( int i = 0; i < numberOfSegments; i++ )
+        {
+            final ByteBuffer segment = ByteBuffer.allocateDirect( segmentSize );
+            segmentsBuffers.add( segment );
+
+            for ( int j = 0; j < segment.capacity(); j += sliceSize )
+            {
+                segment.clear();
+                segment.position( j );
+                segment.limit( j + sliceSize );
+                final ByteBuffer slice = segment.slice();
+                freeBuffers.add( slice );
+            }
+        }
+    }
+
+
+    protected ByteBuffer findFreeBuffer( int capacity )
+    {
+        // ensure the requested size is not bigger than the slices' size
+        if ( capacity > sliceSize )
+        {
+            if ( returnNullWhenOversizingSliceSize )
+            {
+                return null;
+            }
+            else
+            {
+                throw new BufferOverflowException();
+            }
+        }
+        // TODO : Add capacity to wait till a given timeout for a freed buffer
+        return freeBuffers.poll();
+    }
+
+    @Override
+    public void free( final ByteBuffer byteBuffer )
+    {
+
+        checkState( !isClosed() );
+
+        if ( usedSliceBuffers.remove( getHash( byteBuffer ) ) == null )
+        {
+            return;
+        }
+
+        // Ensure the buffer belongs to this slab
+        checkArgument( byteBuffer.capacity() == sliceSize );
+
+        freeBuffers.offer( byteBuffer );
+
+    }
+
+    @Override
+    public ByteBuffer allocate( int size )
+    {
+
+        checkState( !isClosed() );
+
+        ByteBuffer allocatedByteBuffer = findFreeBuffer( size );
+
+        if ( allocatedByteBuffer == null )
+        {
+            if ( returnNullWhenNoBufferAvailable )
+            {
+                return null;
+            }
+            else
+            {
+                throw new BufferOverflowException();
+            }
+        }
+
+        // Reset buffer's state
+        allocatedByteBuffer.clear();
+        allocatedByteBuffer.limit( size );
+
+        usedSliceBuffers.put( getHash( allocatedByteBuffer ), allocatedByteBuffer );
+
+        return allocatedByteBuffer;
+
+    }
+
+    public int getSliceSize()
+    {
+        return sliceSize;
+    }
+
+    @Override
+    public void clear()
+    {
+        for ( final Map.Entry<Integer, ByteBuffer> entry : usedSliceBuffers.entrySet() )
+        {
+            freeBuffers.offer( entry.getValue() );
+        }
+        usedSliceBuffers.clear();
+    }
+
+    @Override
+    public int getCapacity()
+    {
+        return totalSize;
+    }
+
+    @Override
+    public void close()
+    {
+        checkState( !isClosed() );
+
+        setClosed( true );
+
+        clear();
+
+        for ( final ByteBuffer buffer : segmentsBuffers )
+        {
+            try
+            {
+                DirectByteBufferUtils.destroyDirectByteBuffer( buffer );
+            }
+            catch ( Exception e )
+            {
+                getLogger().warn( "Exception thrown while closing the allocator", e );
+            }
+        }
+    }
+}
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/memory/allocator/MergingByteBufferAllocatorImpl.java b/directmemory-cache/src/main/java/org/apache/directmemory/memory/allocator/MergingByteBufferAllocatorImpl.java
new file mode 100644
index 0000000..0dc905e
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/memory/allocator/MergingByteBufferAllocatorImpl.java
@@ -0,0 +1,431 @@
+package org.apache.directmemory.memory.allocator;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.IOException;
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.NavigableMap;
+import java.util.SortedMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentSkipListMap;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * {@link ByteBufferAllocator} implementation with {@link ByteBuffer} merging capabilities.
+ * <p/>
+ * {@link ByteBuffer}s are wrapped into an {@link LinkedByteBuffer}, and when a {@link ByteBuffer} is freed,
+ * lookup is done to the neighbor to check if they are also free, in which case they are merged.
+ * <p/>
+ * {@link #setMinSizeThreshold(int)} gives the minimum buffer's size under which no splitting is done.
+ * {@link #setSizeRatioThreshold(double)} gives the size ratio (requested allocation / free buffer's size} under which no splitting is done
+ * <p/>
+ * The free {@link ByteBuffer} are held into a {@link NavigableMap} with keys defining the size's range : 0 -> first key (included), first key -> second key (included), ...
+ * Instead of keeping a list of {@link ByteBuffer}s sorted by capacity, {@link ByteBuffer}s in the same size's range are held in the same collection.
+ * The size's range are computed by {@link #generateFreeSizesRange(Integer)} and can be overridden.
+ *
+ * @since 0.6
+ */
+public class MergingByteBufferAllocatorImpl
+    extends AbstractByteBufferAllocator
+{
+
+    private static final double DEFAULT_SIZE_RATIO_THRESHOLD = 0.9;
+
+    private static final int DEFAULT_MIN_SIZE_THRESHOLD = 128;
+
+    // List of free pointers, with several lists of different size
+    private final NavigableMap<Integer, Collection<LinkedByteBuffer>> freePointers =
+        new ConcurrentSkipListMap<Integer, Collection<LinkedByteBuffer>>();
+
+    // Set of used pointers. The key is #getHash(ByteBuffer).
+    private final Map<Integer, LinkedByteBuffer> usedPointers = new ConcurrentHashMap<Integer, LinkedByteBuffer>();
+
+    // Lock used instead of synchronized block to guarantee consistency when manipulating list of pointers.
+    private final Lock linkedStructureManipulationLock = new ReentrantLock();
+
+    // The initial buffer, from which all the others are sliced
+    private final ByteBuffer parentBuffer;
+
+    // Allowed size ratio (requested size / buffer's size) of the returned buffer before splitting
+    private double sizeRatioThreshold = DEFAULT_SIZE_RATIO_THRESHOLD;
+
+    // Min size of the returned buffer before splitting
+    private int minSizeThreshold = DEFAULT_MIN_SIZE_THRESHOLD;
+
+    // Tells if null is returned or an BufferOverflowException is thrown when the buffer is full
+    private boolean returnNullWhenBufferIsFull = true;
+
+    /**
+     * Constructor.
+     *
+     * @param number    : the internal buffer identifier
+     * @param totalSize : total size of the parent buffer.
+     */
+    public MergingByteBufferAllocatorImpl( final int number, final int totalSize )
+    {
+        super( number );
+
+        parentBuffer = ByteBuffer.allocateDirect( totalSize );
+        init();
+    }
+
+    /**
+     * Initialization function. Create an initial free {@link Pointer} mapping the whole buffer.
+     */
+    protected void init()
+    {
+        Integer totalSize = Integer.valueOf( parentBuffer.capacity() );
+
+        for ( Integer i : generateFreeSizesRange( totalSize ) )
+        {
+            freePointers.put( Integer.valueOf( i ), new LinkedHashSet<LinkedByteBuffer>() );
+        }
+
+        initFirstBuffer();
+
+    }
+
+    /**
+     * Create the first {@link LinkedByteBuffer}
+     */
+    private void initFirstBuffer()
+    {
+        parentBuffer.clear();
+        final ByteBuffer initialBuffer = parentBuffer.slice();
+        final LinkedByteBuffer initialLinkedBuffer = new LinkedByteBuffer( 0, initialBuffer, null, null );
+
+        insertLinkedBuffer( initialLinkedBuffer );
+    }
+
+
+    /**
+     * Generate free sizes' range. Sizes' range are used to try to allocate the best matching {@ByteBuffer}
+     * regarding the requested size. Instead of using a sorted structure, arbitrary size's range are computed.
+     *
+     * @param totalSize
+     * @return a list of all size's level used by the allocator.
+     */
+    protected List<Integer> generateFreeSizesRange( final Integer totalSize )
+    {
+        List<Integer> sizes = new ArrayList<Integer>();
+
+        for ( int i = minSizeThreshold; i <= totalSize; i *= 8 )
+        {
+            sizes.add( Integer.valueOf( i ) );
+        }
+
+        // If totalSize < minSizeThreshold or totalSize is not a multiple of minSizeThreshold 
+        // we force adding an element to the map
+        if ( sizes.isEmpty() || !sizes.contains( totalSize ) )
+        {
+            sizes.add( totalSize );
+        }
+
+        return sizes;
+    }
+
+    @Override
+    public void free( final ByteBuffer buffer )
+    {
+
+        LinkedByteBuffer returningLinkedBuffer = usedPointers.remove( getHash( buffer ) );
+
+        if ( returningLinkedBuffer == null )
+        {
+            // Hu ? returned twice ? Not returned at the right place ?
+            throw new IllegalArgumentException( "The buffer " + buffer + " seems not to belong to this allocator" );
+        }
+
+        try
+        {
+            linkedStructureManipulationLock.lock();
+
+            if ( returningLinkedBuffer.getBefore() != null )
+            {
+                // if returningLinkedBuffer.getBefore is in the free list, it is free, then it's free and can be merged
+                if ( getFreeLinkedByteBufferCollection( returningLinkedBuffer.getBefore() ).contains(
+                    returningLinkedBuffer.getBefore() ) )
+                {
+                    returningLinkedBuffer = mergePointer( returningLinkedBuffer.getBefore(), returningLinkedBuffer );
+                }
+            }
+
+            if ( returningLinkedBuffer.getAfter() != null )
+            {
+                // if returningLinkedBuffer.getAfter is in the free list, it is free, it is free, then it's free and can be merged 
+                if ( getFreeLinkedByteBufferCollection( returningLinkedBuffer.getAfter() ).contains(
+                    returningLinkedBuffer.getAfter() ) )
+                {
+                    returningLinkedBuffer = mergePointer( returningLinkedBuffer, returningLinkedBuffer.getAfter() );
+                }
+            }
+
+            insertLinkedBuffer( returningLinkedBuffer );
+        }
+        finally
+        {
+            linkedStructureManipulationLock.unlock();
+        }
+    }
+
+    @Override
+    public ByteBuffer allocate( final int size )
+    {
+
+        try
+        {
+            linkedStructureManipulationLock.lock();
+
+            final SortedMap<Integer, Collection<LinkedByteBuffer>> freeMap = freePointers.tailMap( size - 1 );
+            for ( final Map.Entry<Integer, Collection<LinkedByteBuffer>> bufferQueueEntry : freeMap.entrySet() )
+            {
+
+                Iterator<LinkedByteBuffer> linkedByteBufferIterator = bufferQueueEntry.getValue().iterator();
+
+                while ( linkedByteBufferIterator.hasNext() )
+                {
+                    LinkedByteBuffer linkedBuffer = linkedByteBufferIterator.next();
+
+                    if ( linkedBuffer.getBuffer().capacity() >= size )
+                    {
+                        // Remove this element from the collection
+                        linkedByteBufferIterator.remove();
+
+                        LinkedByteBuffer returnedLinkedBuffer = linkedBuffer;
+
+                        // Check if splitting need to be performed
+                        if ( linkedBuffer.getBuffer().capacity() > minSizeThreshold
+                            && ( 1.0 * size / linkedBuffer.getBuffer().capacity() ) < sizeRatioThreshold )
+                        {
+                            // Split the buffer in a buffer that will be returned and another buffer reinserted in the corresponding queue.
+                            parentBuffer.clear();
+                            parentBuffer.position( linkedBuffer.getOffset() );
+                            parentBuffer.limit( linkedBuffer.getOffset() + size );
+                            final ByteBuffer newBuffer = parentBuffer.slice();
+
+                            returnedLinkedBuffer =
+                                new LinkedByteBuffer( linkedBuffer.getOffset(), newBuffer, linkedBuffer.getBefore(),
+                                                      null );
+
+                            if ( linkedBuffer.getBefore() != null )
+                            {
+                                linkedBuffer.getBefore().setAfter( returnedLinkedBuffer );
+                            }
+
+                            // Insert the remaining buffer into the structure
+                            parentBuffer.clear();
+                            parentBuffer.position( linkedBuffer.getOffset() + size );
+                            parentBuffer.limit( linkedBuffer.getOffset() + linkedBuffer.getBuffer().capacity() );
+                            final ByteBuffer remainingBuffer = parentBuffer.slice();
+                            final LinkedByteBuffer remainingLinkedBuffer =
+                                new LinkedByteBuffer( linkedBuffer.getOffset() + size, remainingBuffer,
+                                                      returnedLinkedBuffer, linkedBuffer.getAfter() );
+
+                            if ( linkedBuffer.getAfter() != null )
+                            {
+                                linkedBuffer.getAfter().setBefore( remainingLinkedBuffer );
+                            }
+
+                            returnedLinkedBuffer.setAfter( remainingLinkedBuffer );
+
+                            insertLinkedBuffer( remainingLinkedBuffer );
+
+                        }
+                        else
+                        {
+                            // If the buffer is not split, set the limit accordingly
+                            returnedLinkedBuffer.getBuffer().clear();
+                            returnedLinkedBuffer.getBuffer().limit( size );
+                        }
+
+                        usedPointers.put( getHash( returnedLinkedBuffer.getBuffer() ), returnedLinkedBuffer );
+
+                        return returnedLinkedBuffer.getBuffer();
+                    }
+
+                }
+            }
+
+            if ( returnNullWhenBufferIsFull )
+            {
+                return null;
+            }
+            else
+            {
+                throw new BufferOverflowException();
+            }
+
+        }
+        finally
+        {
+            linkedStructureManipulationLock.unlock();
+        }
+    }
+
+    @Override
+    public void clear()
+    {
+        usedPointers.clear();
+
+        for ( final Map.Entry<Integer, Collection<LinkedByteBuffer>> bufferQueueEntry : freePointers.entrySet() )
+        {
+            bufferQueueEntry.getValue().clear();
+        }
+
+        initFirstBuffer();
+    }
+
+    private void insertLinkedBuffer( final LinkedByteBuffer linkedBuffer )
+    {
+        getFreeLinkedByteBufferCollection( linkedBuffer ).add( linkedBuffer );
+    }
+
+    private Collection<LinkedByteBuffer> getFreeLinkedByteBufferCollection( final LinkedByteBuffer linkedBuffer )
+    {
+        final Integer size = Integer.valueOf( linkedBuffer.getBuffer().capacity() - 1 );
+        final Map.Entry<Integer, Collection<LinkedByteBuffer>> bufferCollectionEntry =
+            freePointers.ceilingEntry( size );
+        return bufferCollectionEntry.getValue();
+    }
+
+    private LinkedByteBuffer mergePointer( final LinkedByteBuffer first, final LinkedByteBuffer next )
+    {
+        parentBuffer.clear();
+        parentBuffer.position( first.getOffset() );
+        parentBuffer.limit( first.getOffset() + first.getBuffer().capacity() + next.getBuffer().capacity() );
+        final ByteBuffer newByteBuffer = parentBuffer.slice();
+
+        final LinkedByteBuffer newLinkedByteBuffer =
+            new LinkedByteBuffer( first.getOffset(), newByteBuffer, first.getBefore(), next.getAfter() );
+
+        if ( first.getBefore() != null )
+        {
+            first.getBefore().setAfter( newLinkedByteBuffer );
+        }
+
+        if ( next.getAfter() != null )
+        {
+            next.getAfter().setBefore( newLinkedByteBuffer );
+        }
+
+        // Remove the two pointers from their corresponding free lists.
+        getFreeLinkedByteBufferCollection( first ).remove( first );
+        getFreeLinkedByteBufferCollection( next ).remove( next );
+
+        return newLinkedByteBuffer;
+    }
+
+    public void setSizeRatioThreshold( final double sizeRatioThreshold )
+    {
+        this.sizeRatioThreshold = sizeRatioThreshold;
+    }
+
+    public void setMinSizeThreshold( final int minSizeThreshold )
+    {
+        this.minSizeThreshold = minSizeThreshold;
+    }
+
+    public void setReturnNullWhenBufferIsFull( boolean returnNullWhenBufferIsFull )
+    {
+        this.returnNullWhenBufferIsFull = returnNullWhenBufferIsFull;
+    }
+
+    @Override
+    public int getCapacity()
+    {
+        return parentBuffer.capacity();
+    }
+
+    private static class LinkedByteBuffer
+    {
+        private final int offset;
+
+        private final ByteBuffer buffer;
+
+        private volatile LinkedByteBuffer before;
+
+        private volatile LinkedByteBuffer after;
+
+        public LinkedByteBuffer( final int offset, final ByteBuffer buffer, final LinkedByteBuffer before,
+                                 final LinkedByteBuffer after )
+        {
+            this.offset = offset;
+            this.buffer = buffer;
+            setBefore( before );
+            setAfter( after );
+        }
+
+        public ByteBuffer getBuffer()
+        {
+            return buffer;
+        }
+
+        public int getOffset()
+        {
+            return offset;
+        }
+
+        public LinkedByteBuffer getBefore()
+        {
+            return before;
+        }
+
+        public void setBefore( final LinkedByteBuffer before )
+        {
+            this.before = before;
+        }
+
+        public LinkedByteBuffer getAfter()
+        {
+            return after;
+        }
+
+        public void setAfter( final LinkedByteBuffer after )
+        {
+            this.after = after;
+        }
+    }
+
+    @Override
+    public void close()
+        throws IOException
+    {
+        clear();
+
+        try
+        {
+            DirectByteBufferUtils.destroyDirectByteBuffer( parentBuffer );
+        }
+        catch ( Exception e )
+        {
+            // ignore error as we are on quiet mode here
+        }
+    }
+
+
+}
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/memory/allocator/SlabByteBufferAllocatorImpl.java b/directmemory-cache/src/main/java/org/apache/directmemory/memory/allocator/SlabByteBufferAllocatorImpl.java
new file mode 100644
index 0000000..5c4e9d8
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/memory/allocator/SlabByteBufferAllocatorImpl.java
@@ -0,0 +1,215 @@
+package org.apache.directmemory.memory.allocator;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.IOException;
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+import java.util.Collection;
+import java.util.Map;
+import java.util.NavigableMap;
+import java.util.concurrent.ConcurrentSkipListMap;
+
+
+/**
+ * {@link ByteBufferAllocator} implementation that uses {@link FixedSizeByteBufferAllocatorImpl}
+ * of different size to allocate best matching's size {@link ByteBuffer}
+ *
+ * @since 0.6
+ */
+public class SlabByteBufferAllocatorImpl
+    extends AbstractByteBufferAllocator
+{
+
+    // Tells if it returns null when no buffers are available
+    private boolean returnNullWhenNoBufferAvailable = true;
+
+    // Internal slabs sorted by sliceSize
+    private final NavigableMap<Integer, FixedSizeByteBufferAllocatorImpl> slabs =
+        new ConcurrentSkipListMap<Integer, FixedSizeByteBufferAllocatorImpl>();
+
+    // Tells if it is allowed to look in a bigger slab to perform the request.
+    private final boolean allowAllocationToBiggerSlab;
+
+    /**
+     * Constructor.
+     *
+     * @param number                      : internal allocator identifier
+     * @param slabs                       : {@link FixedSizeByteBufferAllocatorImpl} to use for allocation
+     * @param allowAllocationToBiggerSlab : tells if it is allowed to look in a bigger slab to perform the request.
+     */
+    public SlabByteBufferAllocatorImpl( final int number, final Collection<FixedSizeByteBufferAllocatorImpl> slabs,
+                                        final boolean allowAllocationToBiggerSlab )
+    {
+        super( number );
+
+        this.allowAllocationToBiggerSlab = allowAllocationToBiggerSlab;
+
+        for ( FixedSizeByteBufferAllocatorImpl slab : slabs )
+        {
+            this.slabs.put( slab.getSliceSize(), slab );
+        }
+
+    }
+
+
+    /**
+     * @param size
+     * @return the slab that best match the given size
+     */
+    private FixedSizeByteBufferAllocatorImpl getSlabThatMatchTheSize( final int size )
+    {
+        // Find the slab that can carry the wanted size. -1 is used because higherEntry returns a strictly higher entry.
+        final Map.Entry<Integer, FixedSizeByteBufferAllocatorImpl> entry = slabs.higherEntry( size - 1 );
+
+        if ( entry != null )
+        {
+            return entry.getValue();
+        }
+
+        // If an entry has not been found, this means that no slabs has bigger enough slices to allocate the given size
+        return null;
+    }
+
+    @Override
+    public void free( final ByteBuffer byteBuffer )
+    {
+
+        final FixedSizeByteBufferAllocatorImpl slab = getSlabThatMatchTheSize( byteBuffer.capacity() );
+
+        if ( slab == null )
+        {
+            // Hu ? where this bytebuffer come from ??
+            return;
+        }
+
+        slab.free( byteBuffer );
+
+    }
+
+    @Override
+    public ByteBuffer allocate( final int size )
+    {
+
+        final FixedSizeByteBufferAllocatorImpl slab = getSlabThatMatchTheSize( size );
+
+        if ( slab == null )
+        {
+            // unable to store such big objects
+            if ( returnNullWhenNoBufferAvailable )
+            {
+                return null;
+            }
+            else
+            {
+                throw new BufferOverflowException();
+            }
+        }
+
+        // Try to allocate the given size
+        final ByteBuffer byteBuffer = slab.allocate( size );
+
+        // If allocation succeed, return the buffer
+        if ( byteBuffer != null )
+        {
+            return byteBuffer;
+        }
+
+        // Otherwise we have the option to allow in a bigger slab.
+        if ( !allowAllocationToBiggerSlab )
+        {
+            if ( returnNullWhenNoBufferAvailable )
+            {
+                return null;
+            }
+            else
+            {
+                throw new BufferOverflowException();
+            }
+        }
+        else
+        {
+            // We can try to allocate to a bigger slab.
+            // size + 1 here because getSlabThatMatchTheSize do a size -1 and thus will return the same slab
+            final int biggerSize = slab.getSliceSize() + 1;
+            final FixedSizeByteBufferAllocatorImpl biggerSlab = getSlabThatMatchTheSize( biggerSize );
+            if ( biggerSlab == null )
+            {
+                // We were already trying to allocate in the biggest slab
+                if ( returnNullWhenNoBufferAvailable )
+                {
+                    return null;
+                }
+                else
+                {
+                    throw new BufferOverflowException();
+                }
+            }
+
+            final ByteBuffer secondByteBuffer = biggerSlab.allocate( size );
+
+            if ( secondByteBuffer == null )
+            {
+                if ( returnNullWhenNoBufferAvailable )
+                {
+                    return null;
+                }
+                else
+                {
+                    throw new BufferOverflowException();
+                }
+            }
+            else
+            {
+                return secondByteBuffer;
+            }
+        }
+    }
+
+    @Override
+    public void clear()
+    {
+        for ( final Map.Entry<Integer, FixedSizeByteBufferAllocatorImpl> entry : slabs.entrySet() )
+        {
+            entry.getValue().clear();
+        }
+    }
+
+    @Override
+    public int getCapacity()
+    {
+        int totalSize = 0;
+        for ( final Map.Entry<Integer, FixedSizeByteBufferAllocatorImpl> entry : slabs.entrySet() )
+        {
+            totalSize += entry.getValue().getCapacity();
+        }
+        return totalSize;
+    }
+
+    @Override
+    public void close()
+        throws IOException
+    {
+        for ( final Map.Entry<Integer, FixedSizeByteBufferAllocatorImpl> entry : slabs.entrySet() )
+        {
+            entry.getValue().close();
+        }
+    }
+}
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/memory/package-info.java b/directmemory-cache/src/main/java/org/apache/directmemory/memory/package-info.java
new file mode 100644
index 0000000..750e967
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/memory/package-info.java
@@ -0,0 +1,23 @@
+/**
+ * Memory management implementation.
+ */
+package org.apache.directmemory.memory;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/package-info.java b/directmemory-cache/src/main/java/org/apache/directmemory/package-info.java
new file mode 100644
index 0000000..41f42c5
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/package-info.java
@@ -0,0 +1,23 @@
+/**
+ * Apache DirectMemory cache APIs.
+ */
+package org.apache.directmemory;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/serialization/Serializer.java b/directmemory-cache/src/main/java/org/apache/directmemory/serialization/Serializer.java
new file mode 100644
index 0000000..5a4d9e9
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/serialization/Serializer.java
@@ -0,0 +1,33 @@
+package org.apache.directmemory.serialization;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.IOException;
+
+public interface Serializer
+{
+
+    <T> byte[] serialize( T obj )
+        throws IOException;
+
+    <T> T deserialize( byte[] source, Class<T> clazz )
+        throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException;
+
+}
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/serialization/SerializerFactory.java b/directmemory-cache/src/main/java/org/apache/directmemory/serialization/SerializerFactory.java
new file mode 100644
index 0000000..9758497
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/serialization/SerializerFactory.java
@@ -0,0 +1,122 @@
+package org.apache.directmemory.serialization;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import static java.lang.String.format;
+
+import java.util.Iterator;
+
+import static java.util.ServiceLoader.load;
+
+public final class SerializerFactory
+{
+
+    public static Serializer createNewSerializer()
+    {
+        return createNewSerializer( SerializerFactory.class.getClassLoader() );
+    }
+
+    public static Serializer createNewSerializer( ClassLoader classLoader )
+    {
+        Iterator<Serializer> serializers = load( Serializer.class, classLoader ).iterator();
+
+        // iterate over all found services
+        while ( serializers.hasNext() )
+        {
+            // try getting the current service and return
+            try
+            {
+                return serializers.next();
+            }
+            catch ( Throwable t )
+            {
+                // just ignore, skip and try getting the next
+            }
+        }
+
+        return new StandardSerializer();
+    }
+
+    public static <S extends Serializer> S createNewSerializer( Class<S> serializer )
+        throws SerializerNotFoundException
+    {
+        Iterator<Serializer> serializers = load( Serializer.class, serializer.getClassLoader() ).iterator();
+
+        // iterate over all found services
+        while ( serializers.hasNext() )
+        {
+            // try getting the current service and return
+            try
+            {
+                Serializer next = serializers.next();
+                if ( serializer.isInstance( next ) )
+                {
+                    return serializer.cast( next );
+                }
+            }
+            catch ( Throwable t )
+            {
+                // just ignore, skip and try getting the next
+            }
+        }
+
+        throw new SerializerNotFoundException( serializer );
+    }
+
+    public static Serializer createNewSerializer( String serializerClassName )
+                    throws SerializerNotFoundException
+    {
+        return createNewSerializer( serializerClassName, SerializerFactory.class.getClassLoader() );
+    }
+
+    public static Serializer createNewSerializer( String serializerClassName, ClassLoader classLoader )
+        throws SerializerNotFoundException
+    {
+        Class<?> anonSerializerClass;
+        try
+        {
+            anonSerializerClass = classLoader.loadClass( serializerClassName );
+        }
+        catch ( ClassNotFoundException e )
+        {
+            throw new SerializerNotFoundException( serializerClassName );
+        }
+
+        if ( Serializer.class.isAssignableFrom( anonSerializerClass ) )
+        {
+            @SuppressWarnings( "unchecked" ) // the assignment is guarded by the previous check
+            Class<? extends Serializer> serializerClass = (Class<? extends Serializer>) anonSerializerClass;
+
+            return createNewSerializer( serializerClass );
+        }
+
+        throw new IllegalArgumentException( format( "Class %s is not a valid Serializer type",
+                                                    anonSerializerClass.getName() ) );
+    }
+
+    /**
+     * Hidden constructor, this class cannot be instantiated
+     */
+    private SerializerFactory()
+    {
+        // do nothing
+    }
+
+}
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/serialization/SerializerNotFoundException.java b/directmemory-cache/src/main/java/org/apache/directmemory/serialization/SerializerNotFoundException.java
new file mode 100644
index 0000000..8cefbbd
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/serialization/SerializerNotFoundException.java
@@ -0,0 +1,43 @@
+package org.apache.directmemory.serialization;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import static java.lang.String.format;
+
+public final class SerializerNotFoundException
+    extends Exception
+{
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 5095679349348496962L;
+
+    public SerializerNotFoundException( String serializerClassName )
+    {
+        super( format( "Serializer of type '%s' has not been found in the current ClassLoader", serializerClassName ) );
+    }
+
+    public SerializerNotFoundException( Class<?> serializerType )
+    {
+        this( serializerType.getName() );
+    }
+
+}
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/serialization/StandardSerializer.java b/directmemory-cache/src/main/java/org/apache/directmemory/serialization/StandardSerializer.java
new file mode 100644
index 0000000..7117a47
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/serialization/StandardSerializer.java
@@ -0,0 +1,75 @@
+package org.apache.directmemory.serialization;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamClass;
+
+public final class StandardSerializer
+    implements Serializer
+{
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <T> byte[] serialize( T obj )
+        throws IOException
+    {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream oos = new ObjectOutputStream( baos );
+        oos.writeObject( obj );
+        oos.flush();
+        oos.close();
+        return baos.toByteArray();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <T> T deserialize( byte[] source, final Class<T> clazz )
+        throws IOException, ClassNotFoundException
+    {
+        ByteArrayInputStream bis = new ByteArrayInputStream( source );
+        ObjectInputStream ois = new ObjectInputStream( bis )
+        {
+
+            @Override
+            protected Class<?> resolveClass( ObjectStreamClass objectStreamClass )
+                throws IOException, ClassNotFoundException
+            {
+                ClassLoader classLoader = clazz.getClassLoader();
+                return classLoader != null
+                    ? classLoader.loadClass( objectStreamClass.getName() )
+                    : Class.forName( objectStreamClass.getName() );
+            }
+
+        };
+        T obj = clazz.cast( ois.readObject() );
+        ois.close();
+        return obj;
+    }
+
+}
diff --git a/directmemory-cache/src/main/java/org/apache/directmemory/serialization/package-info.java b/directmemory-cache/src/main/java/org/apache/directmemory/serialization/package-info.java
new file mode 100644
index 0000000..82871b7
--- /dev/null
+++ b/directmemory-cache/src/main/java/org/apache/directmemory/serialization/package-info.java
@@ -0,0 +1,23 @@
+/**
+ * Objects Serializer APIs.
+ */
+package org.apache.directmemory.serialization;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
diff --git a/directmemory-cache/src/main/resources/META-INF/services/org.apache.directmemory.serialization.Serializer b/directmemory-cache/src/main/resources/META-INF/services/org.apache.directmemory.serialization.Serializer
new file mode 100644
index 0000000..8744225
--- /dev/null
+++ b/directmemory-cache/src/main/resources/META-INF/services/org.apache.directmemory.serialization.Serializer
@@ -0,0 +1,18 @@
+ # Licensed to the Apache Software Foundation (ASF) under one
+ # or more contributor license agreements.  See the NOTICE file
+ # distributed with this work for additional information
+ # regarding copyright ownership.  The ASF licenses this file
+ # to you under the Apache License, Version 2.0 (the
+ # "License"); you may not use this file except in compliance
+ # with the License.  You may obtain a copy of the License at
+ #
+ #   http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing,
+ # software distributed under the License is distributed on an
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ # KIND, either express or implied.  See the License for the
+ # specific language governing permissions and limitations
+ # under the License.
+
+org.apache.directmemory.serialization.StandardSerializer
diff --git a/directmemory-cache/src/test/java/org/apache/directmemory/cache/CacheConcurrentTest.java b/directmemory-cache/src/test/java/org/apache/directmemory/cache/CacheConcurrentTest.java
new file mode 100644
index 0000000..4bd0a2c
--- /dev/null
+++ b/directmemory-cache/src/test/java/org/apache/directmemory/cache/CacheConcurrentTest.java
@@ -0,0 +1,257 @@
+package org.apache.directmemory.cache;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import com.carrotsearch.junitbenchmarks.AbstractBenchmark;
+import com.carrotsearch.junitbenchmarks.BenchmarkOptions;
+import com.carrotsearch.junitbenchmarks.annotation.AxisRange;
+import com.carrotsearch.junitbenchmarks.annotation.BenchmarkHistoryChart;
+import com.carrotsearch.junitbenchmarks.annotation.BenchmarkMethodChart;
+import com.carrotsearch.junitbenchmarks.annotation.LabelType;
+import org.apache.directmemory.cache.Cache;
+import org.apache.directmemory.measures.Monitor;
+import org.apache.directmemory.measures.Ram;
+import org.apache.directmemory.memory.MemoryManager;
+import org.apache.directmemory.memory.Pointer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Random;
+import java.util.concurrent.atomic.AtomicInteger;
+
+@AxisRange( min = 0, max = 1 )
+@BenchmarkMethodChart()
+@BenchmarkHistoryChart( labelWith = LabelType.CUSTOM_KEY, maxRuns = 5 )
+@Ignore
+public class CacheConcurrentTest
+    extends AbstractBenchmark
+{
+
+    private final static int entries = 100000;
+
+    public static AtomicInteger count = new AtomicInteger();
+
+    private static AtomicInteger got = new AtomicInteger();
+
+    private static AtomicInteger missed = new AtomicInteger();
+
+    private static AtomicInteger good = new AtomicInteger();
+
+    private static AtomicInteger bad = new AtomicInteger();
+
+    private static AtomicInteger read = new AtomicInteger();
+
+    private static AtomicInteger disposals = new AtomicInteger();
+
+    @BenchmarkOptions( benchmarkRounds = 10000, warmupRounds = 0, concurrency = 1000 )
+    @Test
+    public void store()
+    {
+        final String key = "test-" + count.incrementAndGet();
+        put( key );
+    }
+
+    @BenchmarkOptions( benchmarkRounds = 500, warmupRounds = 0, concurrency = 10 )
+    @Test
+    public void storeSomeWithExpiry()
+    {
+        final String key = "test-" + count.incrementAndGet();
+        putWithExpiry( key );
+    }
+
+    @BenchmarkOptions( benchmarkRounds = 1000000, warmupRounds = 0, concurrency = 100 )
+    @Test
+    public void retrieveCatchThemAll()
+    {
+        String key = "test-" + ( rndGen.nextInt( entries ) + 1 );
+        get( key );
+    }
+
+    @BenchmarkOptions( benchmarkRounds = 1000000, warmupRounds = 0, concurrency = 100 )
+    @Test
+    public void retrieveCatchHalfOfThem()
+    {
+        String key = "test-" + ( rndGen.nextInt( entries * 2 ) + 1 );
+        get( key );
+    }
+
+    private void get( String key )
+    {
+        Pointer<Object> p = Cache.getPointer( key );
+        @SuppressWarnings( "unused" ) byte[] check = Cache.retrieveByteArray( key );
+        read.incrementAndGet();
+        if ( p != null )
+        {
+            got.incrementAndGet();
+            byte[] payload = MemoryManager.retrieve( p );
+            if ( ( new String( payload ) ).startsWith( key ) )
+            {
+                good.incrementAndGet();
+            }
+            else
+            {
+                bad.incrementAndGet();
+            }
+        }
+        else
+        {
+            missed.incrementAndGet();
+        }
+    }
+
+    private void put( String key )
+    {
+        final StringBuilder bldr = new StringBuilder();
+        for ( int i = 0; i < 100; i++ )
+        {
+            bldr.append( key );
+        }
+        Cache.putByteArray( key, bldr.toString().getBytes() );
+    }
+
+    private void putWithExpiry( String key )
+    {
+        final StringBuilder bldr = new StringBuilder();
+        for ( int i = 0; i < 100; i++ )
+        {
+            bldr.append( key );
+        }
+        Cache.putByteArray( key, bldr.toString().getBytes(), rndGen.nextInt( 2000 ) );
+    }
+
+
+    @BenchmarkOptions( benchmarkRounds = 50000, warmupRounds = 0, concurrency = 10 )
+    @Test
+    public void write1Read8AndSomeDisposal()
+    {
+        String key = "test-" + ( rndGen.nextInt( entries * 2 ) + 1 );
+
+        int what = rndGen.nextInt( 10 );
+
+        switch ( what )
+        {
+            case 0:
+                put( key );
+                break;
+            case 1:
+            case 2:
+            case 3:
+            case 4:
+            case 5:
+            case 6:
+            case 7:
+            case 8:
+                get( key );
+                break;
+            default:
+                final int rndVal = rndGen.nextInt( 1000 );
+                if ( rndVal > 995 )
+                {
+                    disposals.incrementAndGet();
+                    final long start = System.currentTimeMillis();
+                    long howMany = MemoryManager.collectExpired();
+                    final long end = System.currentTimeMillis();
+                    logger.info( "" + howMany + " disposed in " + ( end - start ) + " milliseconds" );
+                }
+        }
+
+    }
+
+    @BenchmarkOptions( benchmarkRounds = 1000000, warmupRounds = 0, concurrency = 10 )
+    @Test
+    public void write3Read7()
+    {
+        String key = "test-" + ( rndGen.nextInt( entries * 2 ) + 1 );
+
+        int what = rndGen.nextInt( 10 );
+
+        switch ( what )
+        {
+            case 0:
+            case 1:
+            case 2:
+                put( key );
+                break;
+            default:
+                get( key );
+                break;
+        }
+    }
+
+    @BenchmarkOptions( benchmarkRounds = 1000000, warmupRounds = 0, concurrency = 10 )
+    @Test
+    public void write1Read9()
+    {
+        String key = "test-" + ( rndGen.nextInt( entries * 2 ) + 1 );
+
+        int what = rndGen.nextInt( 10 );
+
+        switch ( what )
+        {
+            case 0:
+                put( key );
+                break;
+            default:
+                get( key );
+                break;
+
+        }
+
+    }
+
+    Random rndGen = new Random();
+
+    private static Logger logger = LoggerFactory.getLogger( CacheConcurrentTest.class );
+
+    @BeforeClass
+    public static void init()
+    {
+        Cache.init( 1, Ram.Mb( 512 ) );
+        Cache.dump();
+    }
+
+    @AfterClass
+    public static void dump()
+    {
+
+        Cache.dump();
+        Monitor.dump( "cache" );
+
+        logger.info( "************************************************" );
+        logger.info( "entries: " + entries );
+        logger.info( "inserted: " + Cache.entries() );
+        logger.info( "reads: " + read );
+        logger.info( "count: " + count );
+        logger.info( "got: " + got );
+        logger.info( "missed: " + missed );
+        logger.info( "good: " + good );
+        logger.info( "bad: " + bad );
+        logger.info( "disposals: " + disposals );
+        logger.info( "************************************************" );
+    }
+
+}
+
+
+
diff --git a/directmemory-cache/src/test/java/org/apache/directmemory/cache/CacheLightConcurrentTest.java b/directmemory-cache/src/test/java/org/apache/directmemory/cache/CacheLightConcurrentTest.java
new file mode 100644
index 0000000..5ea5899
--- /dev/null
+++ b/directmemory-cache/src/test/java/org/apache/directmemory/cache/CacheLightConcurrentTest.java
@@ -0,0 +1,268 @@
+package org.apache.directmemory.cache;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.util.Random;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.directmemory.measures.Every;
+import org.apache.directmemory.measures.Monitor;
+import org.apache.directmemory.measures.Ram;
+import org.apache.directmemory.memory.MemoryManager;
+import org.apache.directmemory.memory.Pointer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.carrotsearch.junitbenchmarks.AbstractBenchmark;
+import com.carrotsearch.junitbenchmarks.BenchmarkOptions;
+import com.carrotsearch.junitbenchmarks.annotation.AxisRange;
+import com.carrotsearch.junitbenchmarks.annotation.BenchmarkHistoryChart;
+import com.carrotsearch.junitbenchmarks.annotation.BenchmarkMethodChart;
+import com.carrotsearch.junitbenchmarks.annotation.LabelType;
+
+@AxisRange( min = 0, max = 1 )
+@BenchmarkMethodChart()
+@BenchmarkHistoryChart( labelWith = LabelType.CUSTOM_KEY, maxRuns = 5 )
+
+@Ignore
+public class CacheLightConcurrentTest
+    extends AbstractBenchmark
+{
+
+    private final static int entries = 10000;
+
+    public static AtomicInteger count = new AtomicInteger();
+
+    private static AtomicInteger got = new AtomicInteger();
+
+    private static AtomicInteger missed = new AtomicInteger();
+
+    private static AtomicInteger good = new AtomicInteger();
+
+    private static AtomicInteger bad = new AtomicInteger();
+
+    private static AtomicInteger read = new AtomicInteger();
+
+    private static AtomicInteger disposals = new AtomicInteger();
+
+    @BenchmarkOptions( benchmarkRounds = 10000, warmupRounds = 0, concurrency = 100 )
+    @Test
+    public void store()
+    {
+        final String key = "test-" + count.incrementAndGet();
+        put( key );
+    }
+
+    @BenchmarkOptions( benchmarkRounds = 50, warmupRounds = 0, concurrency = 10 )
+    @Test
+    public void storeSomeWithExpiry()
+    {
+        final String key = "test-" + count.incrementAndGet();
+        putWithExpiry( key );
+    }
+
+    @BenchmarkOptions( benchmarkRounds = 100000, warmupRounds = 0, concurrency = 100 )
+    @Test
+    public void retrieveCatchThemAll()
+    {
+        String key = "test-" + ( rndGen.nextInt( entries ) + 1 );
+        getAndRetrieve( key );
+    }
+
+    @BenchmarkOptions( benchmarkRounds = 100000, warmupRounds = 0, concurrency = 100 )
+    @Test
+    public void retrieveCatchHalfOfThem()
+    {
+        String key = "test-" + ( rndGen.nextInt( entries * 2 ) + 1 );
+        getAndRetrieve( key );
+    }
+
+    @BenchmarkOptions( benchmarkRounds = 1, warmupRounds = 0, concurrency = 1 )
+    @Test
+    public void LFUEviction()
+        throws Exception
+    {
+        Cache.collectAll();
+    }
+
+    private void getAndRetrieve( String key )
+    {
+        Pointer<Object> p = Cache.getPointer( key );
+        @SuppressWarnings( "unused" ) byte[] check = Cache.retrieveByteArray( key );
+        read.incrementAndGet();
+        if ( p != null )
+        {
+            got.incrementAndGet();
+            byte[] payload = MemoryManager.retrieve( p );
+            if ( ( new String( payload ) ).startsWith( key ) )
+            {
+                good.incrementAndGet();
+            }
+            else
+            {
+                bad.incrementAndGet();
+            }
+        }
+        else
+        {
+            missed.incrementAndGet();
+        }
+    }
+
+    private void put( String key )
+    {
+        final StringBuilder bldr = new StringBuilder();
+        for ( int i = 0; i < 100; i++ )
+        {
+            bldr.append( key );
+        }
+        Cache.putByteArray( key, bldr.toString().getBytes() );
+    }
+
+    private void putWithExpiry( String key )
+    {
+        final StringBuilder bldr = new StringBuilder();
+        for ( int i = 0; i < 100; i++ )
+        {
+            bldr.append( key );
+        }
+        Cache.putByteArray( key, bldr.toString().getBytes(), rndGen.nextInt( 2000 ) );
+    }
+
+
+    @BenchmarkOptions( benchmarkRounds = 5000, warmupRounds = 0, concurrency = 10 )
+    @Test
+    public void write1Read8AndSomeDisposal()
+    {
+        String key = "test-" + ( rndGen.nextInt( entries * 2 ) + 1 );
+
+        int what = rndGen.nextInt( 10 );
+
+        switch ( what )
+        {
+            case 0:
+                put( key );
+                break;
+            case 1:
+            case 2:
+            case 3:
+            case 4:
+            case 5:
+            case 6:
+            case 7:
+            case 8:
+                getAndRetrieve( key );
+                break;
+            default:
+                final int rndVal = rndGen.nextInt( 100 );
+                if ( rndVal > 98 )
+                {
+                    disposals.incrementAndGet();
+                    final long start = System.currentTimeMillis();
+                    long howMany = MemoryManager.collectExpired();
+                    final long end = System.currentTimeMillis();
+                    logger.info( "" + howMany + " disposed in " + ( end - start ) + " milliseconds" );
+                }
+        }
+
+    }
+
+    @BenchmarkOptions( benchmarkRounds = 100000, warmupRounds = 0, concurrency = 10 )
+    @Test
+    public void write3Read7()
+    {
+        String key = "test-" + ( rndGen.nextInt( entries * 2 ) + 1 );
+
+        int what = rndGen.nextInt( 10 );
+
+        switch ( what )
+        {
+            case 0:
+            case 1:
+            case 2:
+                put( key );
+                break;
+            default:
+                getAndRetrieve( key );
+                break;
+        }
+    }
+
+    @BenchmarkOptions( benchmarkRounds = 100000, warmupRounds = 0, concurrency = 10 )
+    @Test
+    public void write1Read9()
+    {
+        String key = "test-" + ( rndGen.nextInt( entries * 2 ) + 1 );
+
+        int what = rndGen.nextInt( 10 );
+
+        switch ( what )
+        {
+            case 0:
+                put( key );
+                break;
+            default:
+                getAndRetrieve( key );
+                break;
+
+        }
+
+    }
+
+    Random rndGen = new Random();
+
+    private static Logger logger = LoggerFactory.getLogger( CacheLightConcurrentTest.class );
+
+    @BeforeClass
+    public static void init()
+    {
+        Cache.init( 1, Ram.Mb( 128 ) );
+        Cache.scheduleDisposalEvery( Every.seconds( 1 ) );
+        Cache.dump();
+    }
+
+    @AfterClass
+    public static void dump()
+    {
+
+        Cache.dump();
+        Monitor.dump( "cache" );
+
+        logger.info( "************************************************" );
+        logger.info( "entries: " + entries );
+        logger.info( "inserted: " + Cache.entries() );
+        logger.info( "reads: " + read );
+        logger.info( "count: " + count );
+        logger.info( "got: " + got );
+        logger.info( "missed: " + missed );
+        logger.info( "good: " + good );
+        logger.info( "bad: " + bad );
+        logger.info( "disposals: " + disposals );
+        logger.info( "************************************************" );
+    }
+
+}
+
+
+
diff --git a/directmemory-cache/src/test/java/org/apache/directmemory/cache/CacheServiceImplTest.java b/directmemory-cache/src/test/java/org/apache/directmemory/cache/CacheServiceImplTest.java
new file mode 100644
index 0000000..827b18d
--- /dev/null
+++ b/directmemory-cache/src/test/java/org/apache/directmemory/cache/CacheServiceImplTest.java
@@ -0,0 +1,125 @@
+package org.apache.directmemory.cache;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.directmemory.DirectMemory;
+import org.apache.directmemory.measures.Ram;
+import org.apache.directmemory.memory.AllocationPolicy;
+import org.apache.directmemory.memory.MemoryManagerService;
+import org.apache.directmemory.memory.MemoryManagerServiceImpl;
+import org.apache.directmemory.memory.Pointer;
+import org.apache.directmemory.memory.RoundRobinAllocationPolicy;
+import org.junit.Test;
+
+import java.io.Serializable;
+
+import static org.junit.Assert.*;
+
+public class CacheServiceImplTest
+{
+
+    @Test
+    public void testOffHeapExceedMemoryReturnNullWhenTrue()
+    {
+        AllocationPolicy allocationPolicy = new RoundRobinAllocationPolicy();
+        MemoryManagerService<byte[]> memoryManager = new MemoryManagerServiceImpl<byte[]>( allocationPolicy, true );
+        CacheService<Integer, byte[]> cache =
+            new DirectMemory<Integer, byte[]>().setMemoryManager( memoryManager ).setNumberOfBuffers( 1 ).setSize(
+                Ram.Mb( 1 ) ).newCacheService();
+
+        for ( int i = 0; i < 1000; i++ )
+        {
+            Pointer<byte[]> pointer = cache.put( i, new byte[1024] );
+            if ( ( i % 100 ) == 0 )
+            {
+                System.out.println( pointer );
+            }
+        }
+        assertTrue( "This test ensures that no unexpected errors/behaviours occurs when heap space is full", true );
+
+    }
+
+    private static class MyBean
+        implements Serializable
+    {
+        private static final long serialVersionUID = -8865690921195047235L;
+
+        private String name;
+
+        /**
+         * @return the name
+         */
+        public String getName()
+        {
+            return name;
+        }
+
+        /**
+         * @param name the name to set
+         */
+        public void setName( String name )
+        {
+            this.name = name;
+        }
+    }
+
+    @Test
+    public void testEntryIsNoMoreAvailableAfterExpiry()
+        throws InterruptedException
+    {
+        AllocationPolicy allocationPolicy = new RoundRobinAllocationPolicy();
+        MemoryManagerService<MyBean> memoryManager = new MemoryManagerServiceImpl<MyBean>( allocationPolicy, true );
+        CacheService<Integer, MyBean> cache =
+            new DirectMemory<Integer, MyBean>().setMemoryManager( memoryManager ).setNumberOfBuffers( 1 ).setSize(
+                Ram.Mb( 1 ) ).newCacheService();
+        /*
+         * let the scan run every 10s
+         */
+        cache.scheduleDisposalEvery( 3 * 1000 );
+        /*
+         * entry should be expired but not freed after 1s in the cache
+         */
+        MyBean originalEntry = new MyBean();
+        originalEntry.setName( "the name" );
+        cache.put( 1, originalEntry, 1 * 1000 );
+        Pointer<MyBean> pointer = cache.getPointer( 1 );
+        assertNotNull( pointer );
+        assertFalse( pointer.isExpired() );
+        assertFalse( pointer.isFree() );
+        /*
+         * wait for 2s to be sure the entry has been expired
+         */
+        Thread.sleep( 2000 );
+        pointer = cache.getPointer( 1 );
+        assertNotNull( pointer );
+        assertTrue( pointer.isExpired() );
+        assertFalse( pointer.isFree() );
+        /*
+         * wait for 11s to be sure the entry has been evicted
+         */
+        Thread.sleep( 4000 );
+        pointer = cache.getPointer( 1 );
+        assertNotNull( pointer );
+        assertTrue( pointer.isExpired() );
+        assertTrue( pointer.isFree() );
+    }
+
+
+}
diff --git a/directmemory-cache/src/test/java/org/apache/directmemory/cache/TestCachePlusSerialization.java b/directmemory-cache/src/test/java/org/apache/directmemory/cache/TestCachePlusSerialization.java
new file mode 100644
index 0000000..5c4005a
--- /dev/null
+++ b/directmemory-cache/src/test/java/org/apache/directmemory/cache/TestCachePlusSerialization.java
@@ -0,0 +1,77 @@
+package org.apache.directmemory.cache;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import com.carrotsearch.junitbenchmarks.AbstractBenchmark;
+import com.carrotsearch.junitbenchmarks.BenchmarkOptions;
+import org.apache.directmemory.cache.Cache;
+import org.apache.directmemory.measures.Monitor;
+import org.apache.directmemory.measures.Ram;
+import org.apache.directmemory.misc.DummyPojo;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Random;
+
+import static org.junit.Assert.assertEquals;
+
+
+@Ignore
+public class TestCachePlusSerialization
+    extends AbstractBenchmark
+{
+
+    private static Logger logger = LoggerFactory.getLogger( TestCachePlusSerialization.class );
+
+    Random rnd = new Random();
+
+    @BeforeClass
+    public static void init()
+    {
+        logger.info( "test started" );
+        Cache.init( 1, Ram.Mb( 100 ) );
+    }
+
+    @AfterClass
+    public static void end()
+    {
+        Cache.dump();
+        Monitor.dump();
+        logger.info( "test ended" );
+    }
+
+    @BenchmarkOptions( benchmarkRounds = 50000, warmupRounds = 0, concurrency = 1 )
+    @Test
+    public void basicBench()
+    {
+
+        DummyPojo d = new DummyPojo( "test-" + rnd.nextInt( 100000 ), 1024 + rnd.nextInt( 1024 ) );
+        Cache.put( d.name, d );
+        DummyPojo d2 = (DummyPojo) Cache.retrieve( d.name );
+
+        assertEquals( d.name, d2.name );
+
+    }
+
+}
diff --git a/directmemory-cache/src/test/java/org/apache/directmemory/memory/AbstractMemoryManagerServiceTest.java b/directmemory-cache/src/test/java/org/apache/directmemory/memory/AbstractMemoryManagerServiceTest.java
new file mode 100644
index 0000000..7d9230c
--- /dev/null
+++ b/directmemory-cache/src/test/java/org/apache/directmemory/memory/AbstractMemoryManagerServiceTest.java
@@ -0,0 +1,407 @@
+package org.apache.directmemory.memory;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+import junit.framework.Assert;
+
+import org.apache.directmemory.memory.MemoryManagerService;
+import org.apache.directmemory.memory.MemoryTestUtils;
+import org.apache.directmemory.memory.Pointer;
+import org.junit.Test;
+
+public abstract class AbstractMemoryManagerServiceTest
+{
+
+    protected static final Random R = new Random();
+
+    protected static final int SMALL_PAYLOAD_LENGTH = 4;
+    protected static final byte[] SMALL_PAYLOAD = MemoryTestUtils.generateRandomPayload( SMALL_PAYLOAD_LENGTH );
+
+
+	protected MemoryManagerService<Object> mms;
+	
+    protected abstract MemoryManagerService<Object> instanciateMemoryManagerService( int bufferSize );
+
+
+    /**
+     * Test pointers allocation, when buffer size is not aligned with the size of stored objects.
+     * Null {@link Pointer} should be returned to allow {@link MemoryManagerService} to go to next step with allocation policy.
+     */
+    @Test
+    public void testNotEnoughFreeSpace()
+    {
+
+        // Storing a first payload of 4 bytes, 1 byte remaining in the buffer. When storing a second 4 bytes payload, an null pointer should be returned.
+
+        final int BUFFER_SIZE = SMALL_PAYLOAD_LENGTH + 1;
+
+        mms = instanciateMemoryManagerService( BUFFER_SIZE );
+        
+        Pointer<Object> pointer1 = mms.store( SMALL_PAYLOAD );
+        Assert.assertNotNull( pointer1 );
+        Assert.assertFalse( pointer1.isFree() );
+
+        Pointer<Object> pointer2 = mms.store( SMALL_PAYLOAD );
+        Assert.assertNull( pointer2 );
+
+    }
+
+
+    /**
+     * Ensure no byte is leaking when allocating several objects.
+     */
+    @Test
+    public void testByteLeaking()
+    {
+
+        // Initializing 1 buffer of 10*4 bytes, should be able to allocate 10 objects of 4 bytes.
+
+        final int NUMBER_OF_OBJECTS = 10;
+        final int BUFFER_SIZE = NUMBER_OF_OBJECTS * SMALL_PAYLOAD_LENGTH;
+
+        mms = instanciateMemoryManagerService( BUFFER_SIZE );
+        
+        for ( int i = 0; i < NUMBER_OF_OBJECTS; i++ )
+        {
+            Pointer<Object> pointer = mms.store( SMALL_PAYLOAD );
+            Assert.assertNotNull( pointer );
+        }
+
+        Pointer<Object> pointerNull = mms.store( SMALL_PAYLOAD );
+        Assert.assertNull( pointerNull );
+    }
+
+    /**
+     * Ensure memory usage is reported correctly
+     */
+    @Test
+    public void testReportCorrectUsedMemory()
+    {
+
+        // Initializing 1 buffer of 4*4 bytes, storing and freeing and storing again should report correct numbers.
+
+        final int NUMBER_OF_OBJECTS = 4;
+        final int BUFFER_SIZE = NUMBER_OF_OBJECTS * SMALL_PAYLOAD_LENGTH;
+
+        mms = instanciateMemoryManagerService( BUFFER_SIZE );
+        
+        Pointer<Object> lastPointer = null;
+        for ( int i = 0; i < NUMBER_OF_OBJECTS; i++ )
+        {
+            Pointer<Object> pointer = mms.store( SMALL_PAYLOAD );
+            Assert.assertNotNull( pointer );
+            lastPointer = pointer;
+        }
+
+        // Buffer is fully used.
+        Assert.assertEquals( BUFFER_SIZE, mms.used() );
+
+        Assert.assertNotNull( lastPointer );
+        mms.free( lastPointer );
+
+        Pointer<Object> pointerNotNull = mms.store( SMALL_PAYLOAD );
+        Assert.assertNotNull( pointerNotNull );
+
+        // Buffer again fully used.
+        Assert.assertEquals( BUFFER_SIZE, mms.used() );
+
+    }
+
+    /**
+     * Completely fill the buffer, free some pointer, reallocated the freed space, clear the buffer. The entire space should be
+     */
+    @Test
+    public void testFullFillAndFreeAndClearBuffer()
+    {
+
+        final int NUMBER_OF_OBJECTS = 10;
+        final int BUFFER_SIZE = NUMBER_OF_OBJECTS * SMALL_PAYLOAD_LENGTH;
+
+        mms = instanciateMemoryManagerService( BUFFER_SIZE );
+        
+        Pointer<Object> pointerFull = mms.store( MemoryTestUtils.generateRandomPayload( BUFFER_SIZE ) );
+        Assert.assertNotNull( pointerFull );
+        mms.free( pointerFull );
+
+        final int size1 = R.nextInt( BUFFER_SIZE / 2 ) + 1;
+        Pointer<Object> pointer1 = mms.store( MemoryTestUtils.generateRandomPayload( size1 ) );
+        Assert.assertNotNull( "Cannot store " + size1 + " bytes", pointer1 );
+
+        final int size2 = R.nextInt( ( BUFFER_SIZE - size1 ) / 2 ) + 1;
+        Pointer<Object> pointer2 = mms.store( MemoryTestUtils.generateRandomPayload( size2 ) );
+        Assert.assertNotNull( "Cannot store " + size2 + " bytes", pointer2 );
+
+        final int size3 = R.nextInt( ( BUFFER_SIZE - size1 - size2 ) / 2 ) + 1;
+        Pointer<Object> pointer3 = mms.store( MemoryTestUtils.generateRandomPayload( size3 ) );
+        Assert.assertNotNull( "Cannot store " + size3 + " bytes", pointer3 );
+
+        final int size4 = BUFFER_SIZE - size1 - size2 - size3;
+        Pointer<Object> pointer4 = mms.store( MemoryTestUtils.generateRandomPayload( size4 ) );
+        Assert.assertNotNull( "Cannot store " + size4 + " bytes", pointer4 );
+
+        mms.free( pointer1 );
+        Assert.assertTrue( pointer1.isFree() );
+
+        mms.free( pointer3 );
+
+        mms.free( pointer4 );
+
+        mms.free( pointer2 );
+
+        Assert.assertEquals( 0, mms.used() );
+
+        // As all pointers have been freeed, we should be able to reallocate the whole buffer
+        Pointer<Object> pointer6 = mms.store( MemoryTestUtils.generateRandomPayload( BUFFER_SIZE ) );
+        Assert.assertNotNull( "Cannot store " + BUFFER_SIZE + " bytes", pointer6 );
+
+        mms.clear();
+
+        // As all pointers have been cleared, we should be able to reallocate the whole buffer
+        Pointer<Object> pointer7 = mms.store( MemoryTestUtils.generateRandomPayload( BUFFER_SIZE ) );
+        Assert.assertNotNull( "Cannot store " + BUFFER_SIZE + " bytes", pointer7 );
+
+        mms.clear();
+
+        // As all pointers have been cleared, we should be able to reallocate the whole buffer
+        for ( int i = 0; i < NUMBER_OF_OBJECTS; i++ )
+        {
+            Pointer<Object> pointer = mms.store( SMALL_PAYLOAD );
+            Assert.assertNotNull( pointer );
+        }
+
+        mms.clear();
+
+        // As all pointers have been cleared, we should be able to reallocate the whole buffer
+        Pointer<Object> pointer8 = mms.store( MemoryTestUtils.generateRandomPayload( BUFFER_SIZE ) );
+        Assert.assertNotNull( "Cannot store " + BUFFER_SIZE + " bytes", pointer8 );
+
+        mms.free( pointer8 );
+
+        // As all pointers have been cleared, we should be able to reallocate the whole buffer
+        for ( int i = 0; i < NUMBER_OF_OBJECTS * 10; i++ )
+        {
+            Pointer<Object> pointer = mms.store( SMALL_PAYLOAD );
+            Assert.assertNotNull( pointer );
+            mms.free( pointer );
+        }
+
+        // After a clear occurs, pointers allocated before the clear should be set as "free"
+        Assert.assertTrue( pointer6.isFree() );
+        Assert.assertTrue( pointer7.isFree() );
+
+    }
+
+    @Test
+    public void testRandomPayload()
+    {
+
+        final int NUMBER_OF_OBJECTS = 10;
+        final int BUFFER_SIZE = NUMBER_OF_OBJECTS * SMALL_PAYLOAD_LENGTH;
+
+        mms = instanciateMemoryManagerService( BUFFER_SIZE );
+        
+        for ( int i = 0; i < NUMBER_OF_OBJECTS; i++ )
+        {
+            byte[] payload = MemoryTestUtils.generateRandomPayload( SMALL_PAYLOAD_LENGTH );
+            Pointer<Object> pointer = mms.store( payload );
+            Assert.assertNotNull( pointer );
+            byte[] fetchedPayload = mms.retrieve( pointer );
+            Assert.assertEquals( new String( payload ), new String( fetchedPayload ) );
+            if ( R.nextBoolean() )
+            {
+                mms.free( pointer );
+            }
+        }
+
+        mms.clear();
+
+        for ( int i = 0; i < NUMBER_OF_OBJECTS; i++ )
+        {
+            byte[] payload = MemoryTestUtils.generateRandomPayload( SMALL_PAYLOAD_LENGTH );
+            Pointer<Object> pointer = mms.store( payload );
+            Assert.assertNotNull( pointer );
+            byte[] fetchedPayload = mms.retrieve( pointer );
+            Assert.assertEquals( new String( payload ), new String( fetchedPayload ) );
+            if ( R.nextBoolean() )
+            {
+                mms.free( pointer );
+                i--;
+            }
+        }
+
+    }
+
+    @Test
+    public void testStoreAllocAndFree()
+    {
+
+        final int NUMBER_OF_OBJECTS = 100;
+        final int BUFFER_SIZE = NUMBER_OF_OBJECTS * SMALL_PAYLOAD_LENGTH;
+
+        mms = instanciateMemoryManagerService( BUFFER_SIZE );
+        
+        List<Pointer<Object>> pointers = new ArrayList<Pointer<Object>>( NUMBER_OF_OBJECTS );
+        for ( int i = 0; i < NUMBER_OF_OBJECTS; i++ )
+        {
+            byte[] payload = MemoryTestUtils.generateRandomPayload( SMALL_PAYLOAD_LENGTH );
+            Pointer<Object> pointer = mms.store( payload );
+            Assert.assertNotNull( pointer );
+            pointers.add( pointer );
+            byte[] fetchedPayload = mms.retrieve( pointer );
+            Assert.assertEquals( new String( payload ), new String( fetchedPayload ) );
+        }
+
+        // Free 1/4 of the pointers, from 1/4 of the address space to 1/2
+        for ( int i = NUMBER_OF_OBJECTS / 4; i < NUMBER_OF_OBJECTS / 2; i++ )
+        {
+            Pointer<Object> pointer = pointers.get( i );
+            mms.free( pointer );
+        }
+
+        // Should be able to allocate NUMBER_OF_OBJECTS / 4 * SMALL_PAYLOAD_LENGTH bytes
+        Pointer<Object> pointer1 = mms.allocate( Object.class, NUMBER_OF_OBJECTS / 4 * SMALL_PAYLOAD_LENGTH, 0, 0 );
+        Assert.assertNotNull( pointer1 );
+
+        int pointerToSkip = NUMBER_OF_OBJECTS / 2 + NUMBER_OF_OBJECTS / 10;
+        for ( int i = NUMBER_OF_OBJECTS / 2; i < NUMBER_OF_OBJECTS * 3 / 4; i++ )
+        {
+            // skip one pointer
+            if ( i == pointerToSkip )
+            {
+                continue;
+            }
+            Pointer<Object> pointer = pointers.get( i );
+            mms.free( pointer );
+        }
+
+        // Should NOT be able to allocate NUMBER_OF_OBJECTS / 4 * SMALL_PAYLOAD_LENGTH bytes
+        Pointer<Object> pointer2 = mms.allocate( Object.class, NUMBER_OF_OBJECTS / 4 * SMALL_PAYLOAD_LENGTH, 0, 0 );
+        Assert.assertNull( pointer2 );
+
+        // Freeing the previously skipped pointer should then merge the whole memory space
+        mms.free( pointers.get( pointerToSkip ) );
+
+        // Should be able to allocate NUMBER_OF_OBJECTS / 4 * SMALL_PAYLOAD_LENGTH bytes
+        Pointer<Object> pointer3 = mms.allocate( Object.class, NUMBER_OF_OBJECTS / 4 * SMALL_PAYLOAD_LENGTH, 0, 0 );
+        Assert.assertNotNull( pointer3 );
+
+        byte[] payload3 = MemoryTestUtils.generateRandomPayload( NUMBER_OF_OBJECTS / 4 * SMALL_PAYLOAD_LENGTH );
+        pointer3.getDirectBuffer().put( payload3 );
+        byte[] retrievePayload3 = mms.retrieve( pointer3 );
+        Assert.assertEquals( new String( payload3 ), new String( retrievePayload3 ) );
+
+    }
+
+    @Test
+    public void testUpdate()
+    {
+
+        final int NUMBER_OF_OBJECTS = 1;
+        final int BUFFER_SIZE = NUMBER_OF_OBJECTS * SMALL_PAYLOAD_LENGTH;
+
+        mms = instanciateMemoryManagerService( BUFFER_SIZE );
+        
+        final byte[] payload = MemoryTestUtils.generateRandomPayload( SMALL_PAYLOAD_LENGTH );
+
+        final Pointer<Object> pointer = mms.store( payload );
+        Assert.assertNotNull( pointer );
+        Assert.assertEquals( new String( payload ), new String( mms.retrieve( pointer ) ) );
+
+        final byte[] otherPayload = MemoryTestUtils.generateRandomPayload( SMALL_PAYLOAD_LENGTH );
+        final Pointer<Object> otherPointer = mms.update( pointer, otherPayload );
+        Assert.assertNotNull( otherPointer );
+        Assert.assertEquals( pointer.getStart(), otherPointer.getStart() );
+        Assert.assertEquals( pointer.getEnd(), otherPointer.getEnd() );
+        Assert.assertEquals( new String( otherPayload ), new String( mms.retrieve( otherPointer ) ) );
+
+        final byte[] evenAnotherPayload = MemoryTestUtils.generateRandomPayload( SMALL_PAYLOAD_LENGTH / 2 );
+        final Pointer<Object> evenAnotherPointer = mms.update( otherPointer, evenAnotherPayload );
+        Assert.assertNotNull( evenAnotherPointer );
+        Assert.assertEquals( pointer.getStart(), evenAnotherPointer.getStart() );
+        Assert.assertEquals( pointer.getEnd(), evenAnotherPointer.getEnd() );
+        //Assert.assertEquals( 2, new String( mms.retrieve( evenAnotherPointer ) ).length() );
+        Assert.assertTrue( new String( mms.retrieve( evenAnotherPointer ) )
+            .startsWith( new String( evenAnotherPayload ) ) );
+
+    }
+
+
+    @Test
+    public void testAllocate()
+    {
+
+        final int NUMBER_OF_OBJECTS = 10;
+        final int BUFFER_SIZE = NUMBER_OF_OBJECTS * SMALL_PAYLOAD_LENGTH;
+
+        mms = instanciateMemoryManagerService( BUFFER_SIZE );
+        
+        final byte[] payload1 = MemoryTestUtils.generateRandomPayload( 8 * SMALL_PAYLOAD_LENGTH );
+        final Pointer<Object> pointer1 = mms.store( payload1 );
+        Assert.assertNotNull( pointer1 );
+        Assert.assertEquals( new String( payload1 ), new String( mms.retrieve( pointer1 ) ) );
+
+        final byte[] payload2 = MemoryTestUtils.generateRandomPayload( 2 * SMALL_PAYLOAD_LENGTH );
+        final Pointer<Object> pointer2 = mms.store( payload2 );
+        Assert.assertNotNull( pointer2 );
+        Assert.assertEquals( new String( payload2 ), new String( mms.retrieve( pointer2 ) ) );
+
+        mms.free( pointer1 );
+
+        final byte[] payload3 = MemoryTestUtils.generateRandomPayload( 2 * SMALL_PAYLOAD_LENGTH );
+        final Pointer<Object> pointer3 = mms.store( payload3 );
+        Assert.assertNotNull( pointer3 );
+        Assert.assertEquals( new String( payload3 ), new String( mms.retrieve( pointer3 ) ) );
+
+        final int size1 = 4 * SMALL_PAYLOAD_LENGTH;
+        final byte[] allocatedPayload1 = MemoryTestUtils.generateRandomPayload( size1 );
+        final Pointer<Object> allocatedPointer1 = mms.allocate( Object.class, allocatedPayload1.length, -1, -1 );
+        Assert.assertNotNull( allocatedPointer1 );
+        final ByteBuffer buffer1 = allocatedPointer1.getDirectBuffer();
+        Assert.assertNotNull( buffer1 );
+        Assert.assertEquals( 0, buffer1.position() );
+        Assert.assertEquals( size1, buffer1.limit() );
+        Assert.assertEquals( size1, buffer1.capacity() );
+        buffer1.put( allocatedPayload1 );
+        Assert.assertEquals( new String( allocatedPayload1 ), new String( mms.retrieve( allocatedPointer1 ) ) );
+
+        final int size2 = 2 * SMALL_PAYLOAD_LENGTH;
+        final byte[] allocatedPayload2 = MemoryTestUtils.generateRandomPayload( size2 );
+        final Pointer<Object> allocatedPointer2 = mms.allocate( Object.class, allocatedPayload2.length, -1, -1 );
+        Assert.assertNotNull( allocatedPointer2 );
+        final ByteBuffer buffer2 = allocatedPointer2.getDirectBuffer();
+        Assert.assertNotNull( buffer2 );
+        Assert.assertEquals( size2, buffer2.limit() );
+        Assert.assertEquals( size2, buffer2.capacity() );
+        buffer2.put( allocatedPayload2 );
+        Assert.assertEquals( new String( allocatedPayload2 ), new String( mms.retrieve( allocatedPointer2 ) ) );
+
+
+        // Ensure the new allocation has not overwritten other data
+        Assert.assertEquals( new String( payload2 ), new String( mms.retrieve( pointer2 ) ) );
+        Assert.assertEquals( new String( payload3 ), new String( mms.retrieve( pointer3 ) ) );
+
+    }
+
+}
diff --git a/directmemory-cache/src/test/java/org/apache/directmemory/memory/BaseTest.java b/directmemory-cache/src/test/java/org/apache/directmemory/memory/BaseTest.java
new file mode 100644
index 0000000..8bc84f8
--- /dev/null
+++ b/directmemory-cache/src/test/java/org/apache/directmemory/memory/BaseTest.java
@@ -0,0 +1,237 @@
+package org.apache.directmemory.memory;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.Map;
+import java.util.Random;
+import java.util.zip.CRC32;
+import java.util.zip.Checksum;
+
+import org.apache.directmemory.measures.Ram;
+import org.apache.directmemory.memory.Pointer;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.carrotsearch.junitbenchmarks.AbstractBenchmark;
+import com.carrotsearch.junitbenchmarks.BenchmarkOptions;
+import com.google.common.collect.Maps;
+
+@Ignore
+public class BaseTest
+    extends AbstractBenchmark
+{
+    
+    MemoryManagerService<Object> mem;
+    
+    @Before
+    public void initMMS()
+    {
+        mem = new MemoryManagerServiceImpl<Object>();
+        mem.init( 1, 1 * 1024 * 1024 );
+    }
+    @Test
+    public void smokeTest()
+    {
+        logger.info( "buffer size=" + mem.capacity() );
+        assertNotNull( mem );
+
+        Random rnd = new Random();
+
+        int size = rnd.nextInt( 10 ) * (int)mem.capacity() / 100;
+
+        logger.info( "size=" + size );
+
+        Pointer<Object> p = mem.store( new byte[size] );
+        assertNotNull( p );
+        assertEquals( size, p.getEnd() );
+        assertEquals( size, mem.used() );
+        mem.free( p );
+        assertEquals( 0, mem.used() );
+    }
+
+
+    private static Logger logger = LoggerFactory.getLogger( MallocTest.class );
+
+    private static Random rnd = new Random();
+
+    final static Map<String, Byte> test = Maps.newHashMap();
+
+    private static int errors;
+
+    public long crc( String str )
+    {
+        final Checksum checksum = new CRC32();
+
+        final byte bytes[] = str.getBytes();
+        checksum.update( bytes, 0, bytes.length );
+        return checksum.getValue();
+    }
+
+    @BeforeClass
+    @AfterClass
+    public static void setup()
+    {
+        rnd = new Random();
+//		logger.info("off-heap allocated: " + Ram.inMb(mem.capacity()));
+//		logger.info("off-heap used:      " + Ram.inMb(mem.used()));
+        logger.info( "test - size: " + test.size() );
+        logger.info( "test - errors: " + errors );
+        logger.info( "heap - max: " + Ram.inMb( Runtime.getRuntime().maxMemory() ) );
+        logger.info( "heap - allocated: " + Ram.inMb( Runtime.getRuntime().totalMemory() ) );
+        logger.info( "heap - free : " + Ram.inMb( Runtime.getRuntime().freeMemory() ) );
+        logger.info( "************************************************" );
+    }
+
+    @BenchmarkOptions( benchmarkRounds = 10000, warmupRounds = 0, concurrency = 10 )
+    @Test
+    public void anyDuplicates()
+    {
+        String key = "test" + rnd.nextInt( 100000 );
+        if ( test.containsKey( key ) )
+        {
+            logger.error( "key " + key + " has already been used" );
+            errors++;
+        }
+        test.put( key, (byte) 0 );
+    }
+
+    @Test
+    public void aFewEntriesWithRead()
+    {
+        logger.info( "total capacity=" + Ram.inMb( mem.capacity() ) );
+        assertNotNull( mem );
+        int howMany = 10000;
+        logger.info( "payload size is variable" );
+        logger.info( "entries=" + howMany );
+        String test = "this is a nicely crafted test";
+        for ( int i = 0; i < howMany; i++ )
+        {
+            final byte[] payload = ( test + " - " + i ).getBytes();
+            Pointer<Object> p = mem.store( payload );
+            final byte[] check = mem.retrieve( p );
+            assertNotNull( check );
+            assertEquals( test + " - " + i, new String( check ) );
+            long crc1 = crc32( payload );
+            long crc2 = crc32( check );
+            assertEquals( crc1, crc2 );
+        }
+
+        logger.info( "total used=" + Ram.inMb( mem.used() ) );
+    }
+
+    private static long crc32( byte[] payload )
+    {
+        final Checksum checksum = new CRC32();
+        checksum.update( payload, 0, payload.length );
+        return checksum.getValue();
+    }
+
+    @Test
+    public void aFewEntriesWithCheck()
+    {
+        logger.info( "total capacity=" + Ram.inMb( mem.capacity() ) );
+        assertNotNull( mem );
+        int howMany = 10;
+        logger.info( "payload size is variable" );
+        logger.info( "entries=" + howMany );
+        String test = "this is a nicely crafted test";
+        Pointer<Object> lastP = null;
+        for ( int i = 0; i < howMany; i++ )
+        {
+            byte[] payload = ( test + " - " + i ).getBytes();
+            Pointer<Object> p = mem.store( payload );
+            logger.info( "p.start=" + p.getStart() );
+            logger.info( "p.end=" + p.getEnd() );
+            if ( lastP != null )
+            {
+                assertEquals( lastP.getEnd() + 1, p.getStart() );
+            }
+            assertEquals( p.getCapacity(), payload.length );
+            lastP = p;
+            logger.info( "---" );
+        }
+
+        logger.info( "total used=" + Ram.inMb( mem.used() ) );
+    }
+
+    @Test
+    public void checkExpiration()
+        throws InterruptedException
+    {
+        assertNotNull( mem );
+        int size = 400;
+        int howMany = 5000;
+
+        logger.info( "off-heap capacity=" + Ram.inMb( mem.capacity() ) );
+        logger.info( "payload size=" + Ram.inKb( size ) );
+        logger.info( "entries=" + howMany );
+
+        byte[] payload = new byte[size];
+        for ( int i = 0; i < howMany; i++ )
+        {
+            mem.store( payload, 2000 );
+        }
+
+        assertEquals( size * howMany, mem.used() );
+
+        logger.info( "entries with relative expiration=" + ( howMany / 2 ) );
+        for ( int i = 0; i < howMany / 2; i++ )
+        {
+            mem.store( payload, 100 );
+        }
+        assertEquals( size * howMany + size * howMany / 2, mem.used() );
+
+        logger.info( "entries with absolute expiration=" + ( howMany / 2 ) );
+        for ( int i = 0; i < howMany / 2; i++ )
+        {
+            mem.store( payload, 1 );
+        }
+        assertEquals( size * howMany * 2, mem.used() );
+        logger.info( "total used=" + Ram.inMb( mem.used() ) );
+
+        Thread.sleep( 1000 );
+
+        logger.info( "calling disposeExpiredAbsolute" );
+        mem.collectExpired();
+        logger.info( "total used=" + Ram.inMb( mem.used() ) );
+        assertEquals( size * howMany + size * howMany / 2, mem.used() );
+
+        logger.info( "calling disposeExpiredRelative" );
+        mem.collectExpired();
+        logger.info( "total used=" + Ram.inMb( mem.used() ) );
+        assertEquals( size * howMany, mem.used() );
+
+        Thread.sleep( 2000 );
+
+        logger.info( "calling disposeExpiredRelative again" );
+        mem.collectExpired();
+        logger.info( "total used=" + Ram.inMb( mem.used() ) );
+        assertEquals( 0, mem.used() );
+
+    }
+}
diff --git a/directmemory-cache/src/test/java/org/apache/directmemory/memory/Concurrent2Test.java b/directmemory-cache/src/test/java/org/apache/directmemory/memory/Concurrent2Test.java
new file mode 100644
index 0000000..f16f639
--- /dev/null
+++ b/directmemory-cache/src/test/java/org/apache/directmemory/memory/Concurrent2Test.java
@@ -0,0 +1,240 @@
+package org.apache.directmemory.memory;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import com.carrotsearch.junitbenchmarks.AbstractBenchmark;
+import com.carrotsearch.junitbenchmarks.BenchmarkOptions;
+import com.carrotsearch.junitbenchmarks.annotation.AxisRange;
+import com.carrotsearch.junitbenchmarks.annotation.BenchmarkHistoryChart;
+import com.carrotsearch.junitbenchmarks.annotation.BenchmarkMethodChart;
+import com.carrotsearch.junitbenchmarks.annotation.LabelType;
+import com.google.common.collect.MapMaker;
+import org.apache.directmemory.measures.Ram;
+import org.apache.directmemory.memory.MemoryManager;
+import org.apache.directmemory.memory.Pointer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Random;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+@AxisRange( min = 0, max = 1 )
+@BenchmarkMethodChart()
+@BenchmarkHistoryChart( labelWith = LabelType.CUSTOM_KEY, maxRuns = 5 )
+@Ignore
+public class Concurrent2Test
+    extends AbstractBenchmark
+{
+
+    private final static int entries = 100000;
+
+    public static AtomicInteger count = new AtomicInteger();
+
+    private static AtomicInteger got = new AtomicInteger();
+
+    private static AtomicInteger missed = new AtomicInteger();
+
+    private static AtomicInteger good = new AtomicInteger();
+
+    private static AtomicInteger bad = new AtomicInteger();
+
+    private static AtomicInteger read = new AtomicInteger();
+
+    public static ConcurrentMap<String, Pointer<Object>> map =
+        new MapMaker().concurrencyLevel( 4 ).initialCapacity( 100000 ).makeMap();
+
+
+    @BenchmarkOptions( benchmarkRounds = 100000, warmupRounds = 0, concurrency = 100 )
+    @Test
+    public void store()
+    {
+        final String key = "test-" + count.incrementAndGet();
+        put( key );
+    }
+
+    @BenchmarkOptions( benchmarkRounds = 1000000, warmupRounds = 0, concurrency = 100 )
+    @Test
+    public void retrieveCatchThemAll()
+    {
+        String key = "test-" + ( rndGen.nextInt( entries ) + 1 );
+        Pointer<Object> p = map.get( key );
+        read.incrementAndGet();
+        if ( p != null )
+        {
+            got.incrementAndGet();
+            byte[] payload = MemoryManager.retrieve( p );
+            if ( key.equals( new String( payload ) ) )
+            {
+                good.incrementAndGet();
+            }
+            else
+            {
+                bad.incrementAndGet();
+            }
+        }
+        else
+        {
+            logger.info( "did not find key " + key );
+            missed.incrementAndGet();
+        }
+    }
+
+    @BenchmarkOptions( benchmarkRounds = 1000000, warmupRounds = 0, concurrency = 100 )
+    @Test
+    public void retrieveCatchHalfOfThem()
+    {
+        String key = "test-" + ( rndGen.nextInt( entries * 2 ) + 1 );
+        Pointer<Object> p = map.get( key );
+        read.incrementAndGet();
+        if ( p != null )
+        {
+            got.incrementAndGet();
+            byte[] payload = MemoryManager.retrieve( p );
+            if ( key.equals( new String( payload ) ) )
+            {
+                good.incrementAndGet();
+            }
+            else
+            {
+                bad.incrementAndGet();
+            }
+        }
+        else
+        {
+            missed.incrementAndGet();
+        }
+    }
+
+    private void put( String key )
+    {
+        map.put( key, MemoryManager.store( key.getBytes() ) );
+    }
+
+    @BenchmarkOptions( benchmarkRounds = 1000000, warmupRounds = 0, concurrency = 10 )
+    @Test
+    public void write3Read7()
+    {
+        String key = "test-" + ( rndGen.nextInt( entries * 2 ) + 1 );
+
+        int what = rndGen.nextInt( 10 );
+
+        switch ( what )
+        {
+            case 0:
+            case 1:
+            case 2:
+                put( key );
+                break;
+            default:
+                get( key );
+                break;
+
+        }
+
+    }
+
+    @BenchmarkOptions( benchmarkRounds = 1000000, warmupRounds = 0, concurrency = 10 )
+    @Test
+    public void write1Read9()
+    {
+        String key = "test-" + ( rndGen.nextInt( entries * 2 ) + 1 );
+
+        int what = rndGen.nextInt( 10 );
+
+        switch ( what )
+        {
+            case 0:
+                put( key );
+                break;
+            default:
+                get( key );
+                break;
+
+        }
+
+    }
+
+    private void get( String key )
+    {
+        Pointer<Object> p = map.get( key );
+        read.incrementAndGet();
+        if ( p != null )
+        {
+            got.incrementAndGet();
+            byte[] payload = MemoryManager.retrieve( p );
+            if ( key.equals( new String( payload ) ) )
+            {
+                good.incrementAndGet();
+            }
+            else
+            {
+                bad.incrementAndGet();
+            }
+        }
+        else
+        {
+            missed.incrementAndGet();
+        }
+    }
+
+    Random rndGen = new Random();
+
+    private static Logger logger = LoggerFactory.getLogger( Concurrent2Test.class );
+
+    private static void dump( MemoryManagerService<Object> mms )
+    {
+        logger.info( "off-heap - allocated: " + Ram.inMb( mms.capacity() ) );
+        logger.info( "off-heap - used:      " + Ram.inMb( mms.used() ) );
+        logger.info( "heap 	  - max: " + Ram.inMb( Runtime.getRuntime().maxMemory() ) );
+        logger.info( "heap     - allocated: " + Ram.inMb( Runtime.getRuntime().totalMemory() ) );
+        logger.info( "heap     - free : " + Ram.inMb( Runtime.getRuntime().freeMemory() ) );
+        logger.info( "************************************************" );
+    }
+
+    @BeforeClass
+    public static void init()
+    {
+        MemoryManager.init( 1, Ram.Mb( 512 ) );
+    }
+
+    @AfterClass
+    public static void dump()
+    {
+
+        dump( MemoryManager.getMemoryManager() );
+
+        logger.info( "************************************************" );
+        logger.info( "entries: " + entries );
+        logger.info( "inserted: " + map.size() );
+        logger.info( "reads: " + read );
+        logger.info( "count: " + count );
+        logger.info( "got: " + got );
+        logger.info( "missed: " + missed );
+        logger.info( "good: " + good );
+        logger.info( "bad: " + bad );
+        logger.info( "************************************************" );
+    }
+
+}
diff --git a/directmemory-cache/src/test/java/org/apache/directmemory/memory/Concurrent3Test.java b/directmemory-cache/src/test/java/org/apache/directmemory/memory/Concurrent3Test.java
new file mode 100644
index 0000000..a63c646
--- /dev/null
+++ b/directmemory-cache/src/test/java/org/apache/directmemory/memory/Concurrent3Test.java
@@ -0,0 +1,266 @@
+package org.apache.directmemory.memory;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import com.carrotsearch.junitbenchmarks.BenchmarkOptions;
+import com.carrotsearch.junitbenchmarks.annotation.AxisRange;
+import com.carrotsearch.junitbenchmarks.annotation.BenchmarkHistoryChart;
+import com.carrotsearch.junitbenchmarks.annotation.BenchmarkMethodChart;
+import com.carrotsearch.junitbenchmarks.annotation.LabelType;
+import com.google.common.collect.MapMaker;
+import org.apache.directmemory.measures.Ram;
+import org.apache.directmemory.memory.MemoryManager;
+import org.apache.directmemory.memory.Pointer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Random;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+@AxisRange( min = 0, max = 1 )
+@BenchmarkMethodChart()
+@BenchmarkHistoryChart( labelWith = LabelType.CUSTOM_KEY, maxRuns = 5 )
+@Ignore
+public class Concurrent3Test
+{
+
+    private final static int entries = 100000;
+
+    public static AtomicInteger count = new AtomicInteger();
+
+    private static AtomicInteger got = new AtomicInteger();
+
+    private static AtomicInteger missed = new AtomicInteger();
+
+    private static AtomicInteger good = new AtomicInteger();
+
+    private static AtomicInteger bad = new AtomicInteger();
+
+    private static AtomicInteger read = new AtomicInteger();
+
+    private static AtomicInteger disposals = new AtomicInteger();
+
+    public static ConcurrentMap<String, Pointer<Object>> map =
+        new MapMaker().concurrencyLevel( 4 ).initialCapacity( 100000 ).makeMap();
+
+
+    @BenchmarkOptions( benchmarkRounds = 100000, warmupRounds = 0, concurrency = 100 )
+    @Test
+    public void store()
+    {
+        final String key = "test-" + count.incrementAndGet();
+        put( key );
+    }
+
+    @BenchmarkOptions( benchmarkRounds = 500, warmupRounds = 0, concurrency = 10 )
+    @Test
+    public void storeSomeWithExpiry()
+    {
+        final String key = "test-" + count.incrementAndGet();
+        putWithExpiry( key );
+    }
+
+    @BenchmarkOptions( benchmarkRounds = 1000000, warmupRounds = 0, concurrency = 100 )
+    @Test
+    public void retrieveCatchThemAll()
+    {
+        String key = "test-" + ( rndGen.nextInt( entries ) + 1 );
+        get( key );
+    }
+
+    @BenchmarkOptions( benchmarkRounds = 1000000, warmupRounds = 0, concurrency = 100 )
+    @Test
+    public void retrieveCatchHalfOfThem()
+    {
+        String key = "test-" + ( rndGen.nextInt( entries * 2 ) + 1 );
+        get( key );
+    }
+
+    private void get( String key )
+    {
+        Pointer<Object> p = map.get( key );
+        read.incrementAndGet();
+        if ( p != null )
+        {
+            got.incrementAndGet();
+            byte[] payload = MemoryManager.retrieve( p );
+            if ( ( new String( payload ) ).startsWith( key ) )
+            {
+                good.incrementAndGet();
+            }
+            else
+            {
+                bad.incrementAndGet();
+            }
+        }
+        else
+        {
+            missed.incrementAndGet();
+        }
+    }
+
+    private void put( String key )
+    {
+        final StringBuilder bldr = new StringBuilder();
+        for ( int i = 0; i < 100; i++ )
+        {
+            bldr.append( key );
+        }
+        map.put( key, MemoryManager.store( bldr.toString().getBytes() ) );
+    }
+
+    private void putWithExpiry( String key )
+    {
+        final StringBuilder bldr = new StringBuilder();
+        for ( int i = 0; i < 100; i++ )
+        {
+            bldr.append( key );
+        }
+        map.put( key, MemoryManager.store( bldr.toString().getBytes(), rndGen.nextInt( 2000 ) ) );
+    }
+
+
+    @BenchmarkOptions( benchmarkRounds = 50000, warmupRounds = 0, concurrency = 10 )
+    @Test
+    public void write1Read8AndSomeDisposal()
+    {
+        String key = "test-" + ( rndGen.nextInt( entries * 2 ) + 1 );
+
+        int what = rndGen.nextInt( 10 );
+
+        switch ( what )
+        {
+            case 0:
+                put( key );
+                break;
+            case 1:
+            case 2:
+            case 3:
+            case 4:
+            case 5:
+            case 6:
+            case 7:
+            case 8:
+                get( key );
+                break;
+            default:
+                final int rndVal = rndGen.nextInt( 1000 );
+                if ( rndVal > 995 )
+                {
+                    disposals.incrementAndGet();
+                    final long start = System.currentTimeMillis();
+                    long howMany = MemoryManager.collectExpired();
+                    final long end = System.currentTimeMillis();
+                    logger.info( "" + howMany + " disposed in " + ( end - start ) + " milliseconds" );
+                }
+        }
+
+    }
+
+    @BenchmarkOptions( benchmarkRounds = 1000000, warmupRounds = 0, concurrency = 10 )
+    @Test
+    public void write3Read7()
+    {
+        String key = "test-" + ( rndGen.nextInt( entries * 2 ) + 1 );
+
+        int what = rndGen.nextInt( 10 );
+
+        switch ( what )
+        {
+            case 0:
+            case 1:
+            case 2:
+                put( key );
+                break;
+            default:
+                get( key );
+                break;
+        }
+    }
+
+    @BenchmarkOptions( benchmarkRounds = 1000000, warmupRounds = 0, concurrency = 10 )
+    @Test
+    public void write1Read9()
+    {
+        String key = "test-" + ( rndGen.nextInt( entries * 2 ) + 1 );
+
+        int what = rndGen.nextInt( 10 );
+
+        switch ( what )
+        {
+            case 0:
+                put( key );
+                break;
+            default:
+                get( key );
+                break;
+
+        }
+
+    }
+
+    Random rndGen = new Random();
+
+    private static Logger logger = LoggerFactory.getLogger( Concurrent3Test.class );
+
+    private static void dump( MemoryManagerService<Object> mms )
+    {
+        logger.info( "off-heap - allocated: " + Ram.inMb( mms.capacity() ) );
+        logger.info( "off-heap - used:      " + Ram.inMb( mms.used() ) );
+        logger.info( "heap    - max: " + Ram.inMb( Runtime.getRuntime().maxMemory() ) );
+        logger.info( "heap     - allocated: " + Ram.inMb( Runtime.getRuntime().totalMemory() ) );
+        logger.info( "heap     - free : " + Ram.inMb( Runtime.getRuntime().freeMemory() ) );
+        logger.info( "************************************************" );
+    }
+
+    @BeforeClass
+    public static void init()
+    {
+        MemoryManager.init( 1, Ram.Mb( 512 ) );
+    }
+
+    @AfterClass
+    public static void dump()
+    {
+
+        dump( MemoryManager.getMemoryManager() );
+
+        logger.info( "************************************************" );
+        logger.info( "entries: " + entries );
+        logger.info( "inserted: " + map.size() );
+        logger.info( "reads: " + read );
+        logger.info( "count: " + count );
+        logger.info( "got: " + got );
+        logger.info( "missed: " + missed );
+        logger.info( "good: " + good );
+        logger.info( "bad: " + bad );
+        logger.info( "disposals: " + disposals );
+        logger.info( "************************************************" );
+    }
+
+}
+
+
+
diff --git a/directmemory-cache/src/test/java/org/apache/directmemory/memory/ConcurrentTest.java b/directmemory-cache/src/test/java/org/apache/directmemory/memory/ConcurrentTest.java
new file mode 100644
index 0000000..5144044
--- /dev/null
+++ b/directmemory-cache/src/test/java/org/apache/directmemory/memory/ConcurrentTest.java
@@ -0,0 +1,239 @@
+package org.apache.directmemory.memory;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import com.carrotsearch.junitbenchmarks.AbstractBenchmark;
+import com.carrotsearch.junitbenchmarks.BenchmarkOptions;
+import com.carrotsearch.junitbenchmarks.annotation.AxisRange;
+import com.carrotsearch.junitbenchmarks.annotation.BenchmarkHistoryChart;
+import com.carrotsearch.junitbenchmarks.annotation.BenchmarkMethodChart;
+import com.carrotsearch.junitbenchmarks.annotation.LabelType;
+import com.google.common.collect.MapMaker;
+import org.apache.directmemory.measures.Ram;
+import org.apache.directmemory.memory.Pointer;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Random;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+@AxisRange( min = 0, max = 1 )
+@BenchmarkMethodChart()
+@BenchmarkHistoryChart( labelWith = LabelType.CUSTOM_KEY, maxRuns = 5 )
+
+@Ignore
+public class ConcurrentTest
+    extends AbstractBenchmark
+{
+
+    private final static int entries = 100000;
+
+    public static AtomicInteger count = new AtomicInteger();
+
+    private static AtomicInteger got = new AtomicInteger();
+
+    private static AtomicInteger missed = new AtomicInteger();
+
+    private static AtomicInteger good = new AtomicInteger();
+
+    private static AtomicInteger bad = new AtomicInteger();
+
+    private static AtomicInteger read = new AtomicInteger();
+
+    private static MemoryManagerService<Object> mem;
+
+    public static ConcurrentMap<String, Pointer<Object>> map =
+        new MapMaker().concurrencyLevel( 4 ).initialCapacity( 100000 ).makeMap();
+
+    @Before
+    public void initMMS()
+    {
+        mem = new MemoryManagerServiceImpl<Object>();
+        mem.init( 1, 512 * 1024 * 1024 );
+    }
+    
+    @BenchmarkOptions( benchmarkRounds = 100000, warmupRounds = 0, concurrency = 100 )
+    @Test
+    public void store()
+    {
+        final String key = "test-" + count.incrementAndGet();
+        map.put( key, mem.store( key.getBytes() ) );
+    }
+
+    @BenchmarkOptions( benchmarkRounds = 1000000, warmupRounds = 0, concurrency = 100 )
+    @Test
+    public void retrieveCatchThemAll()
+    {
+        String key = "test-" + ( rndGen.nextInt( entries ) + 1 );
+        Pointer<Object> p = map.get( key );
+        read.incrementAndGet();
+        if ( p != null )
+        {
+            got.incrementAndGet();
+            byte[] payload = mem.retrieve( p );
+            if ( key.equals( new String( payload ) ) )
+            {
+                good.incrementAndGet();
+            }
+            else
+            {
+                bad.incrementAndGet();
+            }
+        }
+        else
+        {
+            logger.info( "did not find key " + key );
+            missed.incrementAndGet();
+        }
+    }
+
+    @BenchmarkOptions( benchmarkRounds = 1000000, warmupRounds = 0, concurrency = 100 )
+    @Test
+    public void retrieveCatchHalfOfThem()
+    {
+        String key = "test-" + ( rndGen.nextInt( entries * 2 ) + 1 );
+        Pointer<Object> p = map.get( key );
+        read.incrementAndGet();
+        if ( p != null )
+        {
+            got.incrementAndGet();
+            byte[] payload = mem.retrieve( p );
+            if ( key.equals( new String( payload ) ) )
+            {
+                good.incrementAndGet();
+            }
+            else
+            {
+                bad.incrementAndGet();
+            }
+        }
+        else
+        {
+            missed.incrementAndGet();
+        }
+    }
+
+    private void put( String key )
+    {
+        map.put( key, mem.store( key.getBytes() ) );
+    }
+
+    @BenchmarkOptions( benchmarkRounds = 1000000, warmupRounds = 0, concurrency = 10 )
+    @Test
+    public void write3Read7()
+    {
+        String key = "test-" + ( rndGen.nextInt( entries * 2 ) + 1 );
+
+        int what = rndGen.nextInt( 10 );
+
+        switch ( what )
+        {
+            case 0:
+            case 1:
+            case 2:
+                put( key );
+                break;
+            default:
+                get( key );
+                break;
+
+        }
+
+    }
+
+    @BenchmarkOptions( benchmarkRounds = 1000000, warmupRounds = 0, concurrency = 10 )
+    @Test
+    public void write1Read9()
+    {
+        String key = "test-" + ( rndGen.nextInt( entries * 2 ) + 1 );
+
+        int what = rndGen.nextInt( 10 );
+
+        switch ( what )
+        {
+            case 0:
+                put( key );
+                break;
+            default:
+                get( key );
+                break;
+
+        }
+
+    }
+
+    private void get( String key )
+    {
+        Pointer<Object> p = map.get( key );
+        read.incrementAndGet();
+        if ( p != null )
+        {
+            got.incrementAndGet();
+            byte[] payload = mem.retrieve( p );
+            if ( key.equals( new String( payload ) ) )
+            {
+                good.incrementAndGet();
+            }
+            else
+            {
+                bad.incrementAndGet();
+            }
+        }
+        else
+        {
+            missed.incrementAndGet();
+        }
+    }
+
+    Random rndGen = new Random();
+
+    private static Logger logger = LoggerFactory.getLogger( ConcurrentTest.class );
+
+    @BeforeClass
+    @AfterClass
+    public static void dump()
+    {
+        logger.info( "off-heap allocated: " + Ram.inMb( mem.capacity() ) );
+        logger.info( "off-heap used:      " + Ram.inMb( mem.used() ) );
+        logger.info( "heap - max: " + Ram.inMb( Runtime.getRuntime().maxMemory() ) );
+        logger.info( "heap - allocated: " + Ram.inMb( Runtime.getRuntime().totalMemory() ) );
+        logger.info( "heap - free : " + Ram.inMb( Runtime.getRuntime().freeMemory() ) );
+        logger.info( "************************************************" );
+        logger.info( "entries: " + entries );
+        logger.info( "inserted: " + map.size() );
+        logger.info( "reads: " + read );
+        logger.info( "count: " + count );
+        logger.info( "got: " + got );
+        logger.info( "missed: " + missed );
+        logger.info( "good: " + good );
+        logger.info( "bad: " + bad );
+        logger.info( "************************************************" );
+    }
+
+}
+
+
+
diff --git a/directmemory-cache/src/test/java/org/apache/directmemory/memory/DefaultMemoryManagerServiceTest.java b/directmemory-cache/src/test/java/org/apache/directmemory/memory/DefaultMemoryManagerServiceTest.java
new file mode 100644
index 0000000..dbe7900
--- /dev/null
+++ b/directmemory-cache/src/test/java/org/apache/directmemory/memory/DefaultMemoryManagerServiceTest.java
@@ -0,0 +1,34 @@
+package org.apache.directmemory.memory;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+public class DefaultMemoryManagerServiceTest
+    extends AbstractMemoryManagerServiceTest
+{
+
+    @Override
+    protected MemoryManagerService<Object> instanciateMemoryManagerService( int bufferSize )
+    {
+        final MemoryManagerService<Object> mms = new MemoryManagerServiceImpl<Object>();
+        mms.init( 1, bufferSize );
+        return mms;
+    }
+
+}
diff --git a/directmemory-cache/src/test/java/org/apache/directmemory/memory/MallocTest.java b/directmemory-cache/src/test/java/org/apache/directmemory/memory/MallocTest.java
new file mode 100644
index 0000000..d400013
--- /dev/null
+++ b/directmemory-cache/src/test/java/org/apache/directmemory/memory/MallocTest.java
@@ -0,0 +1,199 @@
+package org.apache.directmemory.memory;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import com.carrotsearch.junitbenchmarks.AbstractBenchmark;
+import com.carrotsearch.junitbenchmarks.BenchmarkOptions;
+import com.carrotsearch.junitbenchmarks.annotation.AxisRange;
+import com.carrotsearch.junitbenchmarks.annotation.BenchmarkHistoryChart;
+import com.carrotsearch.junitbenchmarks.annotation.BenchmarkMethodChart;
+import com.carrotsearch.junitbenchmarks.annotation.LabelType;
+import com.google.common.collect.MapMaker;
+import org.apache.directmemory.measures.Ram;
+import org.apache.directmemory.memory.Pointer;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Random;
+import java.util.concurrent.ConcurrentMap;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+@AxisRange( min = 0, max = 1 )
+@BenchmarkMethodChart()
+@BenchmarkOptions( benchmarkRounds = 1, warmupRounds = 0 )
+@BenchmarkHistoryChart( labelWith = LabelType.CUSTOM_KEY, maxRuns = 5 )
+@Ignore
+
+public class MallocTest
+    extends AbstractBenchmark
+{
+
+    Random rnd = new Random();
+
+    private static Logger logger = LoggerFactory.getLogger( MallocTest.class );
+
+    @After
+    public void dump()
+    {
+        logger.info( "off-heap allocated: " + Ram.inMb( mem.capacity() ) );
+        logger.info( "off-heap used:      " + Ram.inMb( mem.used() ) );
+        logger.info( "heap - max: " + Ram.inMb( Runtime.getRuntime().maxMemory() ) );
+        logger.info( "heap - allocated: " + Ram.inMb( Runtime.getRuntime().totalMemory() ) );
+        logger.info( "heap - free : " + Ram.inMb( Runtime.getRuntime().freeMemory() ) );
+        logger.info( "************************************************" );
+    }
+
+    MemoryManagerService<Object> mem;
+    
+    @Before
+    public void initMMS()
+    {
+        mem = new MemoryManagerServiceImpl<Object>();
+        mem.init( 1, 512 * 1024 * 1024 );
+    }
+
+    @Test
+    public void oneMillionEntries()
+    {
+        assertNotNull( mem );
+        int howMany = 1000000;
+        int size = (int)mem.capacity() / ( howMany );
+        size -= size / 100 * 1;
+        logger.info( "payload size=" + size );
+        logger.info( "entries=" + howMany );
+
+        logger.info( "starting..." );
+
+        long start = System.currentTimeMillis();
+
+        byte[] payload = new byte[size];
+        for ( int i = 0; i < howMany; i++ )
+        {
+            mem.store( payload );
+        }
+
+        logger.info( "...done in " + ( System.currentTimeMillis() - start ) + " msecs." );
+    }
+
+    @Test
+    public void twoMillionEntries()
+    {
+
+        assertNotNull( mem );
+        int howMany = 2000000;
+        int size = (int)mem.capacity() / ( howMany );
+        size -= size / 100 * 1;
+        logger.info( "payload size=" + size );
+        logger.info( "entries=" + howMany );
+
+        logger.info( "starting..." );
+        long start = System.currentTimeMillis();
+
+        byte[] payload = new byte[size];
+        for ( int i = 0; i < howMany; i++ )
+        {
+            mem.store( payload );
+        }
+
+        logger.info( "...done in " + ( System.currentTimeMillis() - start ) + " msecs." );
+    }
+
+    @Test
+    public void fiveMillionEntries()
+    {
+
+        assertNotNull( mem );
+        int howMany = 5000000;
+        int size = (int)mem.capacity() / ( howMany );
+        size -= size / 100 * 1;
+        logger.info( "payload size=" + size );
+        logger.info( "entries=" + howMany );
+
+        logger.info( "starting..." );
+        long start = System.currentTimeMillis();
+
+        byte[] payload = new byte[size];
+        for ( int i = 0; i < howMany; i++ )
+        {
+            mem.store( payload );
+        }
+
+        logger.info( "...done in " + ( System.currentTimeMillis() - start ) + " msecs." );
+    }
+
+
+    @Test
+    public void withMap()
+    {
+
+        ConcurrentMap<Long, Pointer<Object>> map = new MapMaker().concurrencyLevel( 4 ).initialCapacity( 500000 ).makeMap();
+
+        String str = "This is the string to store into the off-heap memory";
+
+        int size = str.length();
+        int howMany = 1000000;
+        byte[] payload = str.getBytes();
+
+        logger.info( "adding " + howMany + " strings of " + size + " bytes..." );
+        for ( long i = 0; i < howMany; i++ )
+        {
+            Pointer<Object> p = mem.store( payload );
+            map.put( i, p );
+        }
+        logger.info( "...done" );
+
+    }
+
+    @Before
+    public void before()
+    {
+        mem.clear();
+    }
+
+
+    @Test
+    public void oneMillionEntriesWithRead()
+    {
+
+        logger.info( "total capacity=" + Ram.inMb( mem.capacity() ) );
+        assertNotNull( mem );
+        int size = 400;
+        int howMany = 1000000;
+        logger.info( "payload size=" + Ram.inKb( size ) );
+        logger.info( "entries=" + howMany );
+        String test = "this is a nicely crafted test";
+        byte[] payload = test.getBytes();
+        for ( int i = 0; i < howMany; i++ )
+        {
+            Pointer<Object> p = mem.store( payload );
+            byte[] check = mem.retrieve( p );
+            assertNotNull( check );
+            assertEquals( test, new String( check ) );
+        }
+
+        logger.info( "total used=" + Ram.inMb( mem.used() ) );
+    }
+}
diff --git a/directmemory-cache/src/test/java/org/apache/directmemory/memory/MemoryManagerServiceImplTest.java b/directmemory-cache/src/test/java/org/apache/directmemory/memory/MemoryManagerServiceImplTest.java
new file mode 100644
index 0000000..a78885a
--- /dev/null
+++ b/directmemory-cache/src/test/java/org/apache/directmemory/memory/MemoryManagerServiceImplTest.java
@@ -0,0 +1,202 @@
+package org.apache.directmemory.memory;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.util.Random;
+
+import junit.framework.Assert;
+
+import org.apache.directmemory.memory.MemoryManagerService;
+import org.apache.directmemory.memory.MemoryManagerServiceImpl;
+import org.apache.directmemory.memory.Pointer;
+import org.junit.Test;
+
+public class MemoryManagerServiceImplTest
+{
+
+    protected static final Random R = new Random();
+
+    protected static final byte[] SMALL_PAYLOAD = "ABCD".getBytes();
+
+    protected MemoryManagerService<Object> getMemoryManagerService()
+    {
+        return new MemoryManagerServiceImpl<Object>();
+    }
+
+    @Test
+    public void testFirstMatchBorderCase()
+    {
+
+        // Storing a first payload of 4 bytes, 1 byte remaining in the buffer.
+        // When storing a second 4 bytes payload, an BufferOverflowException is
+        // thrown instead of an easy check.
+
+        final int BUFFER_SIZE = 5;
+
+        final MemoryManagerService<Object> memoryManagerService = getMemoryManagerService();
+
+        memoryManagerService.init( 1, BUFFER_SIZE );
+
+        Pointer<Object> pointer1 = memoryManagerService.store( SMALL_PAYLOAD );
+        Assert.assertNotNull( pointer1 );
+
+        Pointer<Object> pointer2 = memoryManagerService.store( SMALL_PAYLOAD );
+        Assert.assertNull( pointer2 );
+
+    }
+
+    @Test
+    public void testAllocateMultipleBuffers()
+    {
+
+        // Initializing 4 buffers of 4 bytes, MemoryManagerService should search
+        // for available space in another buffer.
+
+        final int NUMBER_OF_OBJECTS = 4;
+
+        final MemoryManagerService<Object> memoryManagerService = getMemoryManagerService();
+
+        memoryManagerService.init( NUMBER_OF_OBJECTS, SMALL_PAYLOAD.length );
+
+        for ( int i = 0; i < NUMBER_OF_OBJECTS; i++ )
+        {
+            Pointer<Object> pointer = memoryManagerService.store( SMALL_PAYLOAD );
+            Assert.assertNotNull( pointer );
+        }
+
+        Pointer<Object> pointerNull = memoryManagerService.store( SMALL_PAYLOAD );
+        Assert.assertNull( pointerNull );
+    }
+
+    @Test
+    public void testByteLeaking()
+    {
+
+        // Initializing 1 buffer of 10*4 bytes, should be able to allocate 10
+        // objects of 4 bytes.
+
+        final int NUMBER_OF_OBJECTS = 10;
+
+        final MemoryManagerService<Object> memoryManagerService = getMemoryManagerService();
+        memoryManagerService.init( 1, NUMBER_OF_OBJECTS * SMALL_PAYLOAD.length );
+
+        for ( int i = 0; i < NUMBER_OF_OBJECTS; i++ )
+        {
+            Pointer<Object> pointer = memoryManagerService.store( SMALL_PAYLOAD );
+            Assert.assertNotNull( pointer );
+        }
+
+        Pointer<Object> pointerNull = memoryManagerService.store( SMALL_PAYLOAD );
+        Assert.assertNull( pointerNull );
+    }
+
+    @Test
+    public void testReportCorrectUsedMemory()
+    {
+
+        // Initializing 1 buffer of 4*4 bytes, storing and freeing and storing
+        // again should report correct numbers.
+
+        final int NUMBER_OF_OBJECTS = 4;
+        final int BUFFER_SIZE = NUMBER_OF_OBJECTS * SMALL_PAYLOAD.length;
+
+        final MemoryManagerService<Object> memoryManagerService = getMemoryManagerService();
+
+        memoryManagerService.init( 1, BUFFER_SIZE );
+
+        Pointer<Object> lastPointer = null;
+        for ( int i = 0; i < NUMBER_OF_OBJECTS; i++ )
+        {
+            Pointer<Object> pointer = memoryManagerService.store( SMALL_PAYLOAD );
+            Assert.assertNotNull( pointer );
+            lastPointer = pointer;
+        }
+
+        // Buffer is fully used.
+        Assert.assertEquals( BUFFER_SIZE, memoryManagerService.used() );
+
+        Assert.assertNotNull( lastPointer );
+        memoryManagerService.free( lastPointer );
+
+        Pointer<Object> pointerNotNull = memoryManagerService.store( SMALL_PAYLOAD );
+        Assert.assertNotNull( pointerNotNull );
+
+        // Buffer again fully used.
+        Assert.assertEquals( BUFFER_SIZE, memoryManagerService.used() );
+
+    }
+
+    @Test
+    public void testRandomPayload()
+    {
+
+        final int NUMBER_OF_OBJECTS = 10;
+        final int BUFFER_SIZE = NUMBER_OF_OBJECTS * SMALL_PAYLOAD.length;
+
+        final MemoryManagerService<Object> memoryManagerService = getMemoryManagerService();
+
+        memoryManagerService.init( 1, BUFFER_SIZE );
+
+        for ( int i = 0; i < NUMBER_OF_OBJECTS; i++ )
+        {
+            byte[] payload = MemoryTestUtils.generateRandomPayload( SMALL_PAYLOAD.length );
+            Pointer<Object> pointer = memoryManagerService.store( payload );
+            Assert.assertNotNull( pointer );
+            byte[] fetchedPayload = memoryManagerService.retrieve( pointer );
+            Assert.assertEquals( new String( payload ), new String( fetchedPayload ) );
+            if ( R.nextBoolean() )
+            {
+                memoryManagerService.free( pointer );
+            }
+        }
+
+        memoryManagerService.clear();
+
+        for ( int i = 0; i < NUMBER_OF_OBJECTS; i++ )
+        {
+            byte[] payload = MemoryTestUtils.generateRandomPayload( SMALL_PAYLOAD.length );
+            Pointer<Object> pointer = memoryManagerService.store( payload );
+            Assert.assertNotNull( pointer );
+            byte[] fetchedPayload = memoryManagerService.retrieve( pointer );
+            Assert.assertEquals( new String( payload ), new String( fetchedPayload ) );
+            if ( R.nextBoolean() )
+            {
+                memoryManagerService.free( pointer );
+                i--;
+            }
+        }
+
+        memoryManagerService.clear();
+
+        Pointer<Object> pointer = null;
+        do
+        {
+            byte[] payload = MemoryTestUtils.generateRandomPayload( R.nextInt( BUFFER_SIZE / 4 + 1 ) );
+            pointer = memoryManagerService.store( payload );
+            if ( pointer != null && R.nextBoolean() )
+            {
+                memoryManagerService.free( pointer );
+            }
+        }
+        while ( pointer != null );
+
+    }
+
+}
diff --git a/directmemory-cache/src/test/java/org/apache/directmemory/memory/MemoryManagerTest.java b/directmemory-cache/src/test/java/org/apache/directmemory/memory/MemoryManagerTest.java
new file mode 100644
index 0000000..32a6640
--- /dev/null
+++ b/directmemory-cache/src/test/java/org/apache/directmemory/memory/MemoryManagerTest.java
@@ -0,0 +1,106 @@
+package org.apache.directmemory.memory;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import com.carrotsearch.junitbenchmarks.AbstractBenchmark;
+import com.google.common.collect.Maps;
+import org.apache.directmemory.measures.Ram;
+import org.apache.directmemory.memory.MemoryManager;
+import org.apache.directmemory.memory.Pointer;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Map;
+import java.util.Random;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class MemoryManagerTest
+    extends AbstractBenchmark
+{
+
+
+    @BeforeClass
+    public static void init()
+    {
+        logger.info( "init" );
+        MemoryManager.init( 1, Ram.Mb( 100 ) );
+    }
+
+    @Test
+    public void smokeTest()
+    {
+        Random rnd = new Random();
+        int size = rnd.nextInt( 10 ) * (int) MemoryManager.capacity() / 100;
+        logger.info( "payload size=" + Ram.inKb( size ) );
+        Pointer<Object> p = MemoryManager.store( new byte[size] );
+        logger.info( "stored" );
+        assertNotNull( p );
+        //assertEquals(size,p.end);
+        assertEquals( size, p.getCapacity() );
+        assertEquals( size, MemoryManager.getMemoryManager().used() );
+        MemoryManager.free( p );
+        assertEquals( 0, MemoryManager.getMemoryManager().used() );
+        logger.info( "end" );
+    }
+
+    byte[] payload = "012345678901234567890123456789012345678901234567890123456789".getBytes();
+
+    @Test
+    public void fillupTest()
+    {
+        MemoryManager.clear();
+        logger.info( "payload size=" + Ram.inKb( payload.length ) );
+        long howMany = ( MemoryManager.capacity() / payload.length );
+        howMany = ( howMany * 90 ) / 100;
+
+        for ( int i = 0; i < howMany; i++ )
+        {
+            Pointer<Object> p = MemoryManager.store( payload );
+            assertNotNull( p );
+        }
+
+        logger.info( "" + howMany + " items stored" );
+    }
+
+
+    @Test
+    public void readTest()
+    {
+        for ( Pointer<Object> ptr : ((MemoryManagerServiceImpl<Object>)MemoryManager.getMemoryManager()).getPointers() )
+        {
+            if ( !ptr.isFree() )
+            {
+                byte[] res = MemoryManager.retrieve( ptr );
+                assertNotNull( res );
+                assertEquals( new String( payload ), new String( res ) );
+            }
+        }
+    }
+
+
+    private static Logger logger = LoggerFactory.getLogger( MallocTest.class );
+
+    final static Map<String, Byte> test = Maps.newHashMap();
+
+}
diff --git a/directmemory-cache/src/test/java/org/apache/directmemory/memory/MemoryTestUtils.java b/directmemory-cache/src/test/java/org/apache/directmemory/memory/MemoryTestUtils.java
new file mode 100644
index 0000000..dae116e
--- /dev/null
+++ b/directmemory-cache/src/test/java/org/apache/directmemory/memory/MemoryTestUtils.java
@@ -0,0 +1,41 @@
+package org.apache.directmemory.memory;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.util.Random;
+
+public class MemoryTestUtils
+{
+
+    private static final String PAYLOAD_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+    private static final Random R = new Random();
+
+    public static byte[] generateRandomPayload( int sizeInByte )
+    {
+        final StringBuilder sb = new StringBuilder( sizeInByte );
+        for ( int i = 0; i < sizeInByte; i++ )
+        {
+            sb.append( PAYLOAD_CHARS.charAt( R.nextInt( PAYLOAD_CHARS.length() ) ) );
+        }
+        return sb.toString().getBytes();
+    }
+
+}
diff --git a/directmemory-cache/src/test/java/org/apache/directmemory/memory/NIOTest.java b/directmemory-cache/src/test/java/org/apache/directmemory/memory/NIOTest.java
new file mode 100644
index 0000000..470c5a4
--- /dev/null
+++ b/directmemory-cache/src/test/java/org/apache/directmemory/memory/NIOTest.java
@@ -0,0 +1,89 @@
+package org.apache.directmemory.memory;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.directmemory.measures.Ram;
+import org.apache.directmemory.memory.MemoryManager;
+import org.apache.directmemory.memory.Pointer;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.nio.ByteBuffer;
+import java.util.Random;
+
+import static org.junit.Assert.*;
+
+@Ignore
+public class NIOTest
+{
+
+    private static Logger logger = LoggerFactory.getLogger( NIOTest.class );
+
+    @BeforeClass
+    public static void init()
+    {
+        byte[] payload = "012345678901234567890123456789012345678901234567890123456789".getBytes();
+
+        logger.info( "init" );
+        MemoryManager.init( 1, Ram.Mb( 100 ) );
+
+        logger.info( "payload size=" + Ram.inKb( payload.length ) );
+        long howMany = ( MemoryManager.capacity() / payload.length );
+        howMany = ( howMany * 50 ) / 100;
+
+        for ( int i = 0; i < howMany; i++ )
+        {
+            Pointer<Object> p = MemoryManager.store( payload );
+            assertNotNull( p );
+        }
+
+        logger.info( "" + howMany + " items stored" );
+    }
+
+    @Test
+    public void nioTest()
+    {
+        Random rnd = new Random();
+        int size = rnd.nextInt( 10 ) * (int) MemoryManager.capacity() / 100;
+        logger.info( "payload size=" + Ram.inKb( size ) );
+        Pointer<Object> p = MemoryManager.allocate( size );
+        ByteBuffer b = p.getDirectBuffer();
+        logger.info( "allocated" );
+        assertNotNull( p );
+        assertNotNull( b );
+
+        assertTrue( b.isDirect() );
+        assertEquals( 0, b.position() );
+        assertEquals( size, b.limit() );
+        assertEquals( size, b.capacity() );
+
+        byte[] check = MemoryManager.retrieve( p );
+
+        assertNotNull( check );
+
+        assertEquals( size, p.getCapacity() );
+        logger.info( "end" );
+    }
+
+
+}
diff --git a/directmemory-cache/src/test/java/org/apache/directmemory/memory/RoundRobinAllocationPolicyTest.java b/directmemory-cache/src/test/java/org/apache/directmemory/memory/RoundRobinAllocationPolicyTest.java
new file mode 100644
index 0000000..81ccf55
--- /dev/null
+++ b/directmemory-cache/src/test/java/org/apache/directmemory/memory/RoundRobinAllocationPolicyTest.java
@@ -0,0 +1,152 @@
+package org.apache.directmemory.memory;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.directmemory.memory.allocator.ByteBufferAllocator;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Unit test of {@link RoundRobinAllocationPolicy} class.
+ *
+ * @author benoit@noisette.ch
+ *
+ */
+public class RoundRobinAllocationPolicyTest
+{
+
+    private static final int NUMBER_OF_BUFFERS = 4;
+
+    List<ByteBufferAllocator> allocators;
+
+    RoundRobinAllocationPolicy allocationPolicy;
+
+    @Before
+    public void initAllocationPolicy()
+    {
+
+        allocators = new ArrayList<ByteBufferAllocator>();
+
+        for ( int i = 0; i < NUMBER_OF_BUFFERS; i++ )
+        {
+            allocators.add( new DummyByteBufferAllocator() );
+        }
+
+        allocationPolicy = new RoundRobinAllocationPolicy();
+        allocationPolicy.init( allocators );
+    }
+
+    @Test
+    public void testSequence()
+    {
+
+        assertEquals( allocators.get( 0 ), allocationPolicy.getActiveAllocator( null, 1 ) );
+        assertEquals( allocators.get( 1 ), allocationPolicy.getActiveAllocator( null, 1 ) );
+        assertEquals( allocators.get( 2 ), allocationPolicy.getActiveAllocator( null, 1 ) );
+        assertEquals( allocators.get( 3 ), allocationPolicy.getActiveAllocator( null, 1 ) );
+        assertEquals( allocators.get( 0 ), allocationPolicy.getActiveAllocator( null, 1 ) );
+        assertEquals( allocators.get( 1 ), allocationPolicy.getActiveAllocator( null, 1 ) );
+        assertEquals( allocators.get( 2 ), allocationPolicy.getActiveAllocator( null, 1 ) );
+        assertEquals( allocators.get( 3 ), allocationPolicy.getActiveAllocator( null, 1 ) );
+
+        assertNotNull( allocationPolicy.getActiveAllocator( null, 1 ) );
+        assertNotNull( allocationPolicy.getActiveAllocator( null, 2 ) );
+        assertNull( allocationPolicy.getActiveAllocator( null, 3 ) );
+
+        allocationPolicy.reset();
+
+        assertEquals( allocators.get( 0 ), allocationPolicy.getActiveAllocator( null, 1 ) );
+        assertEquals( allocators.get( 1 ), allocationPolicy.getActiveAllocator( null, 1 ) );
+        assertEquals( allocators.get( 2 ), allocationPolicy.getActiveAllocator( null, 1 ) );
+        assertEquals( allocators.get( 3 ), allocationPolicy.getActiveAllocator( null, 1 ) );
+        assertEquals( allocators.get( 0 ), allocationPolicy.getActiveAllocator( null, 1 ) );
+        assertEquals( allocators.get( 1 ), allocationPolicy.getActiveAllocator( null, 1 ) );
+        assertEquals( allocators.get( 2 ), allocationPolicy.getActiveAllocator( null, 1 ) );
+        assertEquals( allocators.get( 3 ), allocationPolicy.getActiveAllocator( null, 1 ) );
+
+    }
+
+
+    @Test
+    public void testMaxAllocation()
+    {
+
+        allocationPolicy.setMaxAllocations( 1 );
+
+        assertNotNull( allocationPolicy.getActiveAllocator( null, 1 ) );
+        assertNull( allocationPolicy.getActiveAllocator( null, 2 ) );
+        assertNull( allocationPolicy.getActiveAllocator( null, 3 ) );
+
+    }
+
+
+    /**
+     * Dummy {@link OffHeapMemoryBuffer} that do nothing.
+     */
+    private static class DummyByteBufferAllocator
+        implements ByteBufferAllocator
+    {
+
+        @Override
+        public void free( ByteBuffer buffer )
+        {            
+        }
+
+        @Override
+        public ByteBuffer allocate( int size )
+        {
+            return null;
+        }
+
+        @Override
+        public void clear()
+        {            
+        }
+
+        @Override
+        public int getCapacity()
+        {
+            return 0;
+        }
+
+        @Override
+        public int getNumber()
+        {
+            return 0;
+        }
+
+        @Override
+        public void close()
+            throws IOException
+        {
+            
+        }
+        
+    }
+}
diff --git a/directmemory-cache/src/test/java/org/apache/directmemory/memory/SlabMemoryManagerServiceTest.java b/directmemory-cache/src/test/java/org/apache/directmemory/memory/SlabMemoryManagerServiceTest.java
new file mode 100644
index 0000000..f32e8c2
--- /dev/null
+++ b/directmemory-cache/src/test/java/org/apache/directmemory/memory/SlabMemoryManagerServiceTest.java
@@ -0,0 +1,79 @@
+package org.apache.directmemory.memory;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.util.Collection;
+import java.util.HashSet;
+
+import org.apache.directmemory.memory.allocator.ByteBufferAllocator;
+import org.apache.directmemory.memory.allocator.FixedSizeByteBufferAllocatorImpl;
+import org.apache.directmemory.memory.allocator.SlabByteBufferAllocatorImpl;
+import org.junit.Test;
+
+public class SlabMemoryManagerServiceTest
+    extends AbstractMemoryManagerServiceTest
+{
+
+    @Override
+    protected MemoryManagerService<Object> instanciateMemoryManagerService( int bufferSize )
+    {
+        final MemoryManagerService<Object> mms = new MemoryManagerServiceImpl<Object>() {
+
+            @Override
+            protected ByteBufferAllocator instanciateByteBufferAllocator( int allocatorNumber, int size )
+            {
+                Collection<FixedSizeByteBufferAllocatorImpl> slabs = new HashSet<FixedSizeByteBufferAllocatorImpl>();
+                
+                slabs.add( new FixedSizeByteBufferAllocatorImpl(0, size, SMALL_PAYLOAD_LENGTH / 2, 1) );
+                slabs.add( new FixedSizeByteBufferAllocatorImpl(1, size, SMALL_PAYLOAD_LENGTH, 1) );
+                
+                final SlabByteBufferAllocatorImpl allocator = new SlabByteBufferAllocatorImpl( allocatorNumber, slabs, false );
+                
+                return allocator;
+            }
+            
+        };
+        mms.init( 1, bufferSize );
+        return mms;
+    }
+
+    @Override
+    @Test
+    public void testFullFillAndFreeAndClearBuffer()
+    {
+        
+    }
+    
+    @Override
+    @Test
+    public void testStoreAllocAndFree()
+    {
+        
+    }
+    
+    
+    @Override
+    @Test
+    public void testAllocate()
+    {
+        
+    }
+    
+}
diff --git a/directmemory-cache/src/test/java/org/apache/directmemory/memory/Starter.java b/directmemory-cache/src/test/java/org/apache/directmemory/memory/Starter.java
new file mode 100644
index 0000000..903d21d
--- /dev/null
+++ b/directmemory-cache/src/test/java/org/apache/directmemory/memory/Starter.java
@@ -0,0 +1,132 @@
+package org.apache.directmemory.memory;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.directmemory.measures.Ram;
+import org.apache.directmemory.memory.MemoryManager;
+import org.apache.directmemory.memory.allocator.ByteBufferAllocator;
+import org.apache.directmemory.memory.allocator.MergingByteBufferAllocatorImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.junit.Assert.assertNotNull;
+
+public class Starter
+{
+
+    private static Logger logger = LoggerFactory.getLogger( MallocTest.class );
+
+    /**
+     * @param args
+     */
+    public static void main( String[] args )
+    {
+
+        if ( args.length < 3 )
+        {
+            System.out.println( "DirectMemory (for real testers only!) - usage:" );
+            System.out.println(
+                "	java -XX:MaxDirectMemorySize=XXXXm -XmxXXXXm -XmsXXXXm -jar dm-test.jar <buffers> <Mb for each buffer> <entries>" );
+            return;
+        }
+
+        int buffers = new Integer( args[0] );
+        int mb = new Integer( args[1] );
+        int entries = new Integer( args[2] );
+
+        logger.info( "buffers: " + buffers );
+        logger.info( "mb: " + mb );
+        logger.info( "entries: " + entries );
+
+        Starter starter = new Starter();
+        starter.rawInsertMultipleBuffers( buffers, mb, entries );
+    }
+
+    
+    private static void dump( MemoryManagerService<Object> mms )
+    {
+        logger.info( "off-heap - allocated: " + Ram.inMb( mms.capacity() ) );
+        logger.info( "off-heap - used:      " + Ram.inMb( mms.used() ) );
+        logger.info( "heap    - max: " + Ram.inMb( Runtime.getRuntime().maxMemory() ) );
+        logger.info( "heap     - allocated: " + Ram.inMb( Runtime.getRuntime().totalMemory() ) );
+        logger.info( "heap     - free : " + Ram.inMb( Runtime.getRuntime().freeMemory() ) );
+        logger.info( "************************************************" );
+    }
+    
+    public void dump( ByteBufferAllocator mem )
+    {
+        logger.info( "off-heap - buffer: " + mem.getNumber() );
+        logger.info( "off-heap - allocated: " + Ram.inMb( mem.getCapacity() ) );
+        logger.info( "heap    - max: " + Ram.inMb( Runtime.getRuntime().maxMemory() ) );
+        logger.info( "heap     - allocated: " + Ram.inMb( Runtime.getRuntime().totalMemory() ) );
+        logger.info( "heap     - free : " + Ram.inMb( Runtime.getRuntime().freeMemory() ) );
+        logger.info( "************************************************" );
+    }
+    
+    public void rawInsert( int megabytes, int howMany )
+    {
+        ByteBufferAllocator allocator = new MergingByteBufferAllocatorImpl( 1, megabytes * 1024 * 1024 );
+        assertNotNull( allocator );
+        int size = allocator.getCapacity() / ( howMany );
+        size -= size / 100 * 1;
+        logger.info( "payload size=" + size );
+        logger.info( "entries=" + howMany );
+
+        logger.info( "starting..." );
+
+        long start = System.currentTimeMillis();
+
+        for ( int i = 0; i < howMany; i++ )
+        {
+            allocator.allocate( size );
+        }
+
+        logger.info( "...done in " + ( System.currentTimeMillis() - start ) + " msecs." );
+        logger.info( "---------------------------------" );
+        dump( allocator );
+    }
+
+
+    public void rawInsertMultipleBuffers( int buffers, int megabytes, int howMany )
+    {
+        MemoryManager.init( buffers, Ram.Mb( megabytes ) );
+        int size = (int) ( MemoryManager.capacity() / ( howMany ) );
+        size -= size / 100 * 1;
+        logger.info( "payload size=" + size );
+        logger.info( "entries=" + howMany );
+
+        logger.info( "starting..." );
+
+        long start = System.currentTimeMillis();
+
+        byte[] payload = new byte[size];
+        for ( int i = 0; i < howMany; i++ )
+        {
+            MemoryManager.store( payload );
+        }
+
+        logger.info( "...done in " + ( System.currentTimeMillis() - start ) + " msecs." );
+        logger.info( "---------------------------------" );
+
+        dump( MemoryManager.getMemoryManager() );
+    }
+
+
+}
diff --git a/directmemory-cache/src/test/java/org/apache/directmemory/memory/allocator/FixedSizeByteBufferAllocatorImplTest.java b/directmemory-cache/src/test/java/org/apache/directmemory/memory/allocator/FixedSizeByteBufferAllocatorImplTest.java
new file mode 100644
index 0000000..7d6ed2e
--- /dev/null
+++ b/directmemory-cache/src/test/java/org/apache/directmemory/memory/allocator/FixedSizeByteBufferAllocatorImplTest.java
@@ -0,0 +1,130 @@
+package org.apache.directmemory.memory.allocator;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.nio.ByteBuffer;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+
+public class FixedSizeByteBufferAllocatorImplTest
+{
+    @Test
+    public void allocationTest()
+    {
+        
+        ByteBufferAllocator allocator = new FixedSizeByteBufferAllocatorImpl( 0, 5000, 256, 1 );
+        
+        ByteBuffer bf1 = allocator.allocate( 250 );
+        Assert.assertEquals( 256, bf1.capacity() );
+        Assert.assertEquals( 250, bf1.limit() );
+        
+        ByteBuffer bf2 = allocator.allocate( 251 );
+        Assert.assertEquals( 256, bf2.capacity() );
+        Assert.assertEquals( 251, bf2.limit() );
+        
+        ByteBuffer bf3 = allocator.allocate( 200 );
+        Assert.assertEquals( 256, bf3.capacity() );
+        Assert.assertEquals( 200, bf3.limit() );
+        
+        ByteBuffer bf4 = allocator.allocate( 2000 );
+        Assert.assertNull( bf4 );
+        
+        ByteBuffer bf5 = allocator.allocate( 298 );
+        Assert.assertNull( bf5 );
+        
+        ByteBuffer bf6 = allocator.allocate( 128 );
+        Assert.assertEquals( 256, bf6.capacity() );
+        Assert.assertEquals( 128, bf6.limit() );
+        
+    }
+    
+    
+    @Test
+    public void releaseTest()
+    {
+        
+        ByteBufferAllocator allocator = new FixedSizeByteBufferAllocatorImpl( 0, 1000, 256, 1 );
+        
+        ByteBuffer bf1 = allocator.allocate( 250 );
+        Assert.assertEquals( 256, bf1.capacity() );
+        Assert.assertEquals( 250, bf1.limit() );
+        
+        ByteBuffer bf2 = allocator.allocate( 251 );
+        Assert.assertEquals( 256, bf2.capacity() );
+        Assert.assertEquals( 251, bf2.limit() );
+        
+        ByteBuffer bf3 = allocator.allocate( 252 );
+        Assert.assertEquals( 256, bf3.capacity() );
+        Assert.assertEquals( 252, bf3.limit() );
+        
+        ByteBuffer bf4 = allocator.allocate( 500 );
+        Assert.assertNull( bf4 );
+        
+        allocator.free( bf1 );
+        allocator.free( bf2 );
+        
+        ByteBuffer bf5 = allocator.allocate( 500 );
+        Assert.assertNull( bf5 );
+        
+        ByteBuffer bf6 = allocator.allocate( 249 );
+        Assert.assertEquals( 256, bf6.capacity() );
+        Assert.assertEquals( 249, bf6.limit() );
+        
+        ByteBuffer bf7 = allocator.allocate( 248 );
+        Assert.assertEquals( 256, bf7.capacity() );
+        Assert.assertEquals( 248, bf7.limit() );
+        
+    }
+    
+    @Test
+    public void allocateAndFreeTest()
+    {
+        
+        ByteBufferAllocator allocator = new FixedSizeByteBufferAllocatorImpl( 0, 1000, 256, 1 );
+        
+        for (int i = 0; i < 1000; i++)
+        {
+            ByteBuffer bf1 = allocator.allocate( 250 );
+            Assert.assertEquals( 256, bf1.capacity() );
+            Assert.assertEquals( 250, bf1.limit() );
+            
+            allocator.free( bf1 );
+        }
+        
+        
+        ByteBuffer bf2 = allocator.allocate( 1000 );
+        Assert.assertNull( bf2 );
+        
+        for (int i = 0; i < 3; i++)
+        {
+            ByteBuffer bf3 = allocator.allocate( 250 );
+            Assert.assertEquals( 256, bf3.capacity() );
+            Assert.assertEquals( 250, bf3.limit() );
+            
+        }
+        
+        ByteBuffer bf4 = allocator.allocate( 238 );
+        Assert.assertNull( bf4 );
+        
+    }
+    
+}
diff --git a/directmemory-cache/src/test/java/org/apache/directmemory/memory/allocator/MergingByteBufferAllocatorImplTest.java b/directmemory-cache/src/test/java/org/apache/directmemory/memory/allocator/MergingByteBufferAllocatorImplTest.java
new file mode 100644
index 0000000..6eefb31
--- /dev/null
+++ b/directmemory-cache/src/test/java/org/apache/directmemory/memory/allocator/MergingByteBufferAllocatorImplTest.java
@@ -0,0 +1,188 @@
+package org.apache.directmemory.memory.allocator;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+
+public class MergingByteBufferAllocatorImplTest
+{
+    @Test
+    public void allocationTest()
+    {
+        
+        ByteBufferAllocator allocator = new MergingByteBufferAllocatorImpl( 0, 5000 );
+        
+        ByteBuffer bf1 = allocator.allocate( 250 );
+        Assert.assertEquals( 250, bf1.capacity() );
+        Assert.assertEquals( 250, bf1.limit() );
+        
+        ByteBuffer bf2 = allocator.allocate( 251 );
+        Assert.assertEquals( 251, bf2.capacity() );
+        Assert.assertEquals( 251, bf2.limit() );
+        
+        ByteBuffer bf3 = allocator.allocate( 200 );
+        Assert.assertEquals( 200, bf3.capacity() );
+        Assert.assertEquals( 200, bf3.limit() );
+        
+        ByteBuffer bf4 = allocator.allocate( 2000 );
+        Assert.assertEquals( 2000, bf4.capacity() );
+        Assert.assertEquals( 2000, bf4.limit() );
+        
+        ByteBuffer bf5 = allocator.allocate( 2001 );
+        Assert.assertEquals( 2001, bf5.capacity() );
+        Assert.assertEquals( 2001, bf5.limit() );
+        
+        ByteBuffer bf6 = allocator.allocate( 298 );
+        Assert.assertEquals( 298, bf6.capacity() );
+        Assert.assertEquals( 298, bf6.limit() );
+        
+        ByteBuffer bf7 = allocator.allocate( 128 );
+        Assert.assertNull( bf7 );
+        
+    }
+    
+    
+    @Test
+    public void releaseTest()
+    {
+        
+        ByteBufferAllocator allocator = new MergingByteBufferAllocatorImpl( 0, 1000 );
+        
+        ByteBuffer bf1 = allocator.allocate( 250 );
+        Assert.assertEquals( 250, bf1.capacity() );
+        Assert.assertEquals( 250, bf1.limit() );
+        
+        ByteBuffer bf2 = allocator.allocate( 251 );
+        Assert.assertEquals( 251, bf2.capacity() );
+        Assert.assertEquals( 251, bf2.limit() );
+        
+        ByteBuffer bf3 = allocator.allocate( 252 );
+        Assert.assertEquals( 252, bf3.capacity() );
+        Assert.assertEquals( 252, bf3.limit() );
+        
+        ByteBuffer bf4 = allocator.allocate( 500 );
+        Assert.assertNull( bf4 );
+        
+        allocator.free( bf1 );
+        allocator.free( bf2 );
+        
+        ByteBuffer bf5 = allocator.allocate( 500 );
+        Assert.assertEquals( 501, bf5.capacity() );
+        Assert.assertEquals( 500, bf5.limit() );
+        
+    }
+    
+    @Test
+    public void allocateAndFreeTest()
+    {
+        
+        ByteBufferAllocator allocator = new MergingByteBufferAllocatorImpl( 0, 1000 );
+        
+        for (int i = 0; i < 1000; i++)
+        {
+            ByteBuffer bf1 = allocator.allocate( 250 );
+            Assert.assertEquals( 250, bf1.capacity() );
+            Assert.assertEquals( 250, bf1.limit() );
+            
+            allocator.free( bf1 );
+        }
+        
+        
+        ByteBuffer bf2 = allocator.allocate( 1000 );
+        Assert.assertEquals( 1000, bf2.capacity() );
+        Assert.assertEquals( 1000, bf2.limit() );
+        
+    }
+    
+    @Test
+    public void allocationWithoutSplittingPointerTest()
+    {
+        
+        ByteBufferAllocator allocator = new MergingByteBufferAllocatorImpl( 0, 200 );
+        
+        ByteBuffer bf1 = allocator.allocate( 180 );
+        Assert.assertEquals( 200, bf1.capacity() );
+        Assert.assertEquals( 180, bf1.limit() );
+        
+        ByteBuffer bf2 = allocator.allocate( 5 );
+        Assert.assertNull( bf2 );
+        
+        allocator.free( bf1 );
+        
+        
+        ByteBuffer bf3 = allocator.allocate( 10 );
+        Assert.assertEquals( 10, bf3.capacity() );
+        Assert.assertEquals( 10, bf3.limit() );
+        
+        ByteBuffer bf4 = allocator.allocate( 20 );
+        Assert.assertEquals( 20, bf4.capacity() );
+        Assert.assertEquals( 20, bf4.limit() );
+        
+        ByteBuffer bf5 = allocator.allocate( 30 );
+        Assert.assertEquals( 30, bf5.capacity() );
+        Assert.assertEquals( 30, bf5.limit() );
+        
+        allocator.free( bf4 );
+        allocator.free( bf3 );
+        
+        ByteBuffer bf6 = allocator.allocate( 25 );
+        Assert.assertEquals( 30, bf6.capacity() );
+        Assert.assertEquals( 25, bf6.limit() );
+        
+    }
+    
+    @Test
+    public void allocationWithDifferentRatioTest()
+    {
+        
+        MergingByteBufferAllocatorImpl allocator = new MergingByteBufferAllocatorImpl( 0, 200 );
+        allocator.setSizeRatioThreshold( 0.95 );
+        
+        allocator.setSizeRatioThreshold( 10 );
+        
+        ByteBuffer bf1 = allocator.allocate( 180 );
+        Assert.assertEquals( 180, bf1.capacity() );
+        Assert.assertEquals( 180, bf1.limit() );
+        
+        ByteBuffer bf2 = allocator.allocate( 10 );
+        Assert.assertEquals( 20, bf2.capacity() );
+        Assert.assertEquals( 10, bf2.limit() );
+        
+    }
+    
+    
+    @Test(expected = BufferOverflowException.class)
+    public void allocationThrowingBOExceptionTest()
+    {
+        
+        MergingByteBufferAllocatorImpl allocator = new MergingByteBufferAllocatorImpl( 0, 200 );
+        allocator.setReturnNullWhenBufferIsFull( false );
+        
+        allocator.allocate( 210 );
+        Assert.fail();
+    }
+    
+    
+}
diff --git a/directmemory-cache/src/test/java/org/apache/directmemory/memory/allocator/SlabByteBufferAllocatorImplTest.java b/directmemory-cache/src/test/java/org/apache/directmemory/memory/allocator/SlabByteBufferAllocatorImplTest.java
new file mode 100644
index 0000000..2d16337
--- /dev/null
+++ b/directmemory-cache/src/test/java/org/apache/directmemory/memory/allocator/SlabByteBufferAllocatorImplTest.java
@@ -0,0 +1,76 @@
+package org.apache.directmemory.memory.allocator;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+
+public class SlabByteBufferAllocatorImplTest
+{
+    @Test
+    public void allocationTest()
+    {
+        
+        List<FixedSizeByteBufferAllocatorImpl> slabs = new ArrayList<FixedSizeByteBufferAllocatorImpl>();
+        slabs.add( new FixedSizeByteBufferAllocatorImpl( 0, 1024, 128, 1 ) );
+        slabs.add( new FixedSizeByteBufferAllocatorImpl( 1, 1024, 256, 1 ) );
+        slabs.add( new FixedSizeByteBufferAllocatorImpl( 2, 1024, 512, 1 ) );
+        slabs.add( new FixedSizeByteBufferAllocatorImpl( 3, 1024, 1024, 1 ) );
+        
+        
+        ByteBufferAllocator allocator = new SlabByteBufferAllocatorImpl( 0, slabs, false );
+        
+        ByteBuffer bf1 = allocator.allocate( 250 );
+        Assert.assertEquals( 256, bf1.capacity() );
+        Assert.assertEquals( 250, bf1.limit() );
+        
+        ByteBuffer bf2 = allocator.allocate( 251 );
+        Assert.assertEquals( 256, bf2.capacity() );
+        Assert.assertEquals( 251, bf2.limit() );
+        
+        ByteBuffer bf3 = allocator.allocate( 200 );
+        Assert.assertEquals( 256, bf3.capacity() );
+        Assert.assertEquals( 200, bf3.limit() );
+        
+        ByteBuffer bf4 = allocator.allocate( 100 );
+        Assert.assertEquals( 128, bf4.capacity() );
+        Assert.assertEquals( 100, bf4.limit() );
+        
+        ByteBuffer bf5 = allocator.allocate( 550 );
+        Assert.assertEquals( 1024, bf5.capacity() );
+        Assert.assertEquals( 550, bf5.limit() );
+        
+        ByteBuffer bf6 = allocator.allocate( 800 );
+        Assert.assertNull( bf6 );
+
+        allocator.free( bf5 );
+        
+        ByteBuffer bf7 = allocator.allocate( 800 );
+        Assert.assertEquals( 1024, bf7.capacity() );
+        Assert.assertEquals( 800, bf7.limit() );
+        
+    }
+    
+}
diff --git a/directmemory-cache/src/test/java/org/apache/directmemory/misc/DummyPojo.java b/directmemory-cache/src/test/java/org/apache/directmemory/misc/DummyPojo.java
new file mode 100644
index 0000000..a41ad33
--- /dev/null
+++ b/directmemory-cache/src/test/java/org/apache/directmemory/misc/DummyPojo.java
@@ -0,0 +1,50 @@
+package org.apache.directmemory.misc;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.Serializable;
+
+
+public class DummyPojo
+    implements Serializable
+{
+    /**
+     * A dummy pojo implementation for test purposes
+     */
+    private static final long serialVersionUID = 1L;
+
+    public DummyPojo()
+    {
+
+    }
+
+    public DummyPojo( String name, int size )
+    {
+        this.name = name;
+        this.size = size;
+        payLoad = new String( new byte[size] );
+    }
+
+    public String name;
+
+    public int size;
+
+    public String payLoad;
+}
diff --git a/directmemory-cache/src/test/java/org/apache/directmemory/preliminary/MicroBenchmark.java b/directmemory-cache/src/test/java/org/apache/directmemory/preliminary/MicroBenchmark.java
new file mode 100644
index 0000000..d6369fb
--- /dev/null
+++ b/directmemory-cache/src/test/java/org/apache/directmemory/preliminary/MicroBenchmark.java
@@ -0,0 +1,211 @@
+package org.apache.directmemory.preliminary;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import com.carrotsearch.junitbenchmarks.AbstractBenchmark;
+import com.carrotsearch.junitbenchmarks.BenchmarkOptions;
+import com.carrotsearch.junitbenchmarks.annotation.AxisRange;
+import com.carrotsearch.junitbenchmarks.annotation.BenchmarkHistoryChart;
+import com.carrotsearch.junitbenchmarks.annotation.BenchmarkMethodChart;
+import com.carrotsearch.junitbenchmarks.annotation.LabelType;
+import com.google.common.collect.MapMaker;
+import com.google.common.collect.Maps;
+import org.apache.directmemory.measures.Ram;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.nio.ByteBuffer;
+import java.util.Map;
+import java.util.concurrent.ConcurrentMap;
+
+@AxisRange( min = 0, max = 1 )
+@BenchmarkMethodChart( filePrefix = "latest-microbench" )
+@BenchmarkOptions( benchmarkRounds = 1, warmupRounds = 0 )
+@BenchmarkHistoryChart( labelWith = LabelType.CUSTOM_KEY, maxRuns = 5 )
+
+public class MicroBenchmark
+    extends AbstractBenchmark
+{
+
+    private static Logger logger = LoggerFactory.getLogger( MicroBenchmark.class );
+
+
+    private int many = 3000000;
+
+    private int less = 300000;
+
+    @Before
+    public void cleanup()
+    {
+        dump( "Before cleanup" );
+        //Runtime.getRuntime().gc();
+        //dump("After cleanup");
+        logger.info( "************************************************" );
+    }
+
+    private void dump( String message )
+    {
+        logger.info( message );
+        logger.info( "Memory - max: " + Ram.inMb( Runtime.getRuntime().maxMemory() ) );
+        logger.info( "Memory - allocated: " + Ram.inMb( Runtime.getRuntime().totalMemory() ) );
+        logger.info( "Memory - free : " + Ram.inMb( Runtime.getRuntime().freeMemory() ) );
+    }
+
+    @Test
+    public void manySmallInHeapWithHashmap()
+    {
+        final Map<String, byte[]> test = Maps.newHashMap();
+        final byte payload[] = new byte[450];
+        long ops = many;
+        for ( int i = 0; i < ops; i++ )
+        {
+            final String key = "test-" + i;
+            test.put( key, payload.clone() );
+        }
+        logger.info( "many=" + ops );
+        logger.info( "payload.length=" + payload.length );
+        logger.info( "stored " + Ram.inMb( payload.length * ops ) );
+    }
+
+
+    @Test
+    public void manySmallInHeapWithMapMaker()
+    {
+        final byte payload[] = new byte[450];
+        int ops = many;
+
+        logger.info( "many=" + ops );
+        logger.info( "payload.length=" + payload.length );
+        pumpTheHeap( ops, payload );
+
+    }
+
+    @Test
+    public void manySmallOffHeap()
+    {
+
+        final byte payload[] = new byte[450];
+        int ops = many;
+
+        logger.info( "many=" + ops );
+        logger.info( "payload.length=" + payload.length );
+        pumpOffHeap( ops, payload );
+
+    }
+
+
+    @Test
+    public void lessButLargerOffHeap()
+    {
+
+        final byte payload[] = new byte[5120];
+        int ops = less;
+
+        logger.info( "less=" + ops );
+        logger.info( "payload.length=" + payload.length );
+        pumpOffHeap( ops, payload );
+
+    }
+
+    @Test
+    public void lessButLargerInHeap()
+    {
+
+        final byte payload[] = new byte[5120];
+        int ops = less;
+
+        logger.info( "less=" + ops );
+        logger.info( "payload.length=" + payload.length );
+        pumpTheHeap( ops, payload );
+
+    }
+
+    /*
+      *
+      *
+      * ExecutorService executor = Executors.newCachedThreadPool();
+ Callable<Object> task = new Callable<Object>() {
+    public Object call() {
+       return something.blockingMethod();
+    }
+ }
+ Future<Object> future = executor.submit(task);
+ try {
+    Object result = future.get(5, TimeUnit.SECONDS);
+ } catch (TimeoutException ex) {
+    // handle the timeout
+ } finally {
+    future.cancel(); // may or may not desire this
+ }
+      */
+
+
+    private void pumpOffHeap( int ops, byte[] payload )
+    {
+
+        ConcurrentMap<String, ByteBuffer> test = new MapMaker().concurrencyLevel( 4 ).makeMap();
+
+        logger.info( Ram.inMb( ops * payload.length ) + " in " + ops + " slices to store" );
+
+        ByteBuffer bulk = ByteBuffer.allocateDirect( ops * payload.length );
+
+        double started = System.currentTimeMillis();
+
+        for ( int i = 0; i < ops; i++ )
+        {
+            bulk.position( i * payload.length );
+            final ByteBuffer buf = bulk.duplicate();
+            buf.put( payload );
+            test.put( "test-" + i, buf );
+        }
+
+        double finished = System.currentTimeMillis();
+
+        logger.info( "done in " + ( finished - started ) / 1000 + " seconds" );
+
+        for ( ByteBuffer buf : test.values() )
+        {
+            buf.clear();
+        }
+    }
+
+    private void pumpTheHeap( int ops, byte[] payload )
+    {
+
+        ConcurrentMap<String, byte[]> test = new MapMaker().concurrencyLevel( 4 ).makeMap();
+
+        logger.info( Ram.inMb( ops * payload.length ) + " in " + ops + " slices to store" );
+
+        double started = System.currentTimeMillis();
+
+        for ( int i = 0; i < ops; i++ )
+        {
+            test.put( "test-" + i, payload.clone() );
+        }
+
+        double finished = System.currentTimeMillis();
+
+        logger.info( "done in " + ( finished - started ) / 1000 + " seconds" );
+    }
+
+
+}
diff --git a/directmemory-cache/src/test/java/org/apache/directmemory/preliminary/PreliminarBenchmark.java b/directmemory-cache/src/test/java/org/apache/directmemory/preliminary/PreliminarBenchmark.java
new file mode 100644
index 0000000..01e2ef7
--- /dev/null
+++ b/directmemory-cache/src/test/java/org/apache/directmemory/preliminary/PreliminarBenchmark.java
@@ -0,0 +1,236 @@
+package org.apache.directmemory.preliminary;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import com.carrotsearch.junitbenchmarks.AbstractBenchmark;
+import com.carrotsearch.junitbenchmarks.BenchmarkOptions;
+import com.google.common.collect.MapMaker;
+import com.google.common.collect.Maps;
+import org.apache.directmemory.measures.Ram;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.nio.ByteBuffer;
+import java.util.Map;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.TimeUnit;
+
+import static org.junit.Assert.assertNotNull;
+
+public class PreliminarBenchmark
+    extends AbstractBenchmark
+{
+
+    private static Logger logger = LoggerFactory.getLogger( PreliminarBenchmark.class );
+
+    final static byte payload[] = new byte[1024];
+
+    //	@Before
+//	@After
+    public void cleanup()
+    {
+        dump( "Before cleanup" );
+        Runtime.getRuntime().gc();
+        dump( "After cleanup" );
+        logger.info( "************************************************" );
+    }
+
+    private void dump( String message )
+    {
+        logger.info( message );
+        logger.info( "Memory - max: " + Ram.inMb( Runtime.getRuntime().maxMemory() ) );
+        logger.info( "Memory - allocated: " + Ram.inMb( Runtime.getRuntime().totalMemory() ) );
+        logger.info( "Memory - free : " + Ram.inMb( Runtime.getRuntime().freeMemory() ) );
+    }
+
+    @BenchmarkOptions( benchmarkRounds = 5, warmupRounds = 0 )
+    @Test
+    public void justMap()
+    {
+        final Map<String, byte[]> test = Maps.newHashMap();
+        long ops = 100000;
+        for ( int i = 0; i < ops; i++ )
+        {
+            final String key = "test-" + i;
+            test.put( key, payload.clone() );
+        }
+        logger.info( "stored " + Ram.inMb( payload.length * ops ) );
+    }
+
+    @BenchmarkOptions( benchmarkRounds = 1, warmupRounds = 0 )
+    @Test
+    public void oneMillionSmallWithDirectBuffersOneAllocation()
+    {
+
+        logger.info( "payload is " + payload.length + " bytes" );
+        final byte payload[] = new byte[500];
+        int ops = 1000000;
+
+        pumpWithOneAllocation( ops, payload );
+
+    }
+
+    @BenchmarkOptions( benchmarkRounds = 1, warmupRounds = 0 )
+    @Test
+    public void lessButLargerWithDirectBuffersOneAllocation()
+    {
+
+        logger.info( "payload is " + payload.length + " bytes" );
+        final byte payload[] = new byte[2048];
+        int ops = 210000;
+
+        pumpWithOneAllocation( ops, payload );
+
+    }
+
+    /*
+      *
+      *
+      * ExecutorService executor = Executors.newCachedThreadPool();
+ Callable<Object> task = new Callable<Object>() {
+    public Object call() {
+       return something.blockingMethod();
+    }
+ }
+ Future<Object> future = executor.submit(task);
+ try {
+    Object result = future.get(5, TimeUnit.SECONDS);
+ } catch (TimeoutException ex) {
+    // handle the timeout
+ } finally {
+    future.cancel(); // may or may not desire this
+ }
+      */
+
+    @BenchmarkOptions( benchmarkRounds = 5, warmupRounds = 0 )
+    @Test
+    public void withDirectBuffers150k()
+    {
+
+        logger.info( "payload is " + payload.length + " bytes" );
+        int ops = 150000;
+
+        pump( ops );
+    }
+
+    @BenchmarkOptions( benchmarkRounds = 5, warmupRounds = 0 )
+    @Test
+    public void withDirectBuffers180k()
+    {
+
+        logger.info( "payload is " + payload.length + " bytes" );
+        int ops = 180000;
+
+        pump( ops );
+    }
+
+    @BenchmarkOptions( benchmarkRounds = 5, warmupRounds = 0 )
+    @Test
+    public void withDirectBuffers150kAgain()
+    {
+
+        logger.info( "payload is " + payload.length + " bytes" );
+        int ops = 150000;
+
+        pump( ops );
+    }
+
+    @BenchmarkOptions( benchmarkRounds = 1, warmupRounds = 0 )
+    @Test
+    public void testAllocation()
+    {
+
+        logger.info( "payload is " + payload.length + " bytes" );
+        logger.info( "allocating " + Ram.inMb( payload.length * 200000 ) );
+        ByteBuffer buf = ByteBuffer.allocateDirect( payload.length * 200000 );
+        assertNotNull( buf );
+        logger.info( "done" );
+    }
+
+
+    private void pumpWithOneAllocation( int ops, byte[] payload )
+    {
+
+        ConcurrentMap<String, ByteBuffer> test =
+            new MapMaker().concurrencyLevel( 4 ).maximumSize( ops ).expireAfterWrite( 10, TimeUnit.MINUTES ).makeMap();
+
+        logger.info( Ram.inMb( ops * payload.length ) + " in " + ops + " slices to store" );
+
+        ByteBuffer bulk = ByteBuffer.allocateDirect( ops * payload.length );
+
+        double started = System.currentTimeMillis();
+
+        for ( int i = 0; i < ops; i++ )
+        {
+            bulk.position( i * payload.length );
+            final ByteBuffer buf = bulk.duplicate();
+            buf.put( payload );
+            test.put( "test-" + i, buf );
+        }
+
+        double finished = System.currentTimeMillis();
+
+        logger.info( "done in " + ( finished - started ) / 1000 + " seconds" );
+
+        for ( ByteBuffer buf : test.values() )
+        {
+            buf.clear();
+        }
+    }
+
+    @BenchmarkOptions( benchmarkRounds = 5, warmupRounds = 0 )
+    @Test
+    public void withDirectBuffers100k()
+    {
+
+        logger.info( "payload is " + payload.length + " bytes" );
+        int ops = 100000;
+
+        pump( ops );
+    }
+
+    private void pump( int ops )
+    {
+        ConcurrentMap<String, ByteBuffer> test =
+            new MapMaker().concurrencyLevel( 4 ).maximumSize( ops ).expireAfterWrite( 10, TimeUnit.MINUTES ).makeMap();
+
+        logger.info( Ram.inMb( ops * payload.length ) + " to store" );
+
+        double started = System.currentTimeMillis();
+
+        for ( int i = 0; i < ops; i++ )
+        {
+            ByteBuffer buf = ByteBuffer.allocateDirect( payload.length );
+            buf.put( payload );
+            test.put( "test-" + i, buf );
+        }
+
+        double finished = System.currentTimeMillis();
+
+        logger.info( "done in " + ( finished - started ) / 1000 + " seconds" );
+
+        for ( ByteBuffer buf : test.values() )
+        {
+            buf.clear();
+        }
+    }
+
+}
diff --git a/directmemory-cache/src/test/java/org/apache/directmemory/serialization/DummyPojoSerializer.java b/directmemory-cache/src/test/java/org/apache/directmemory/serialization/DummyPojoSerializer.java
new file mode 100644
index 0000000..ce5ad6c
--- /dev/null
+++ b/directmemory-cache/src/test/java/org/apache/directmemory/serialization/DummyPojoSerializer.java
@@ -0,0 +1,69 @@
+package org.apache.directmemory.serialization;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+
+import org.apache.directmemory.measures.Ram;
+import org.apache.directmemory.misc.DummyPojo;
+
+public final class DummyPojoSerializer
+    implements Serializer
+{
+
+    final DummyPojo pojo = new DummyPojo( "test", Ram.Kb( 2 ) );
+
+    final byte[] data;
+
+    public DummyPojoSerializer()
+    {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try
+        {
+            ObjectOutputStream oos = new ObjectOutputStream( baos );
+            oos.writeObject( pojo );
+            oos.flush();
+            oos.close();
+        }
+        catch ( Exception e )
+        {
+            // should not happen
+        }
+        data = baos.toByteArray();
+    }
+
+    @Override
+    public <T> T deserialize( byte[] source, Class<T> clazz )
+        throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException
+    {
+        // testing puts only
+        return (T) pojo;
+    }
+
+    @Override
+    public <T> byte[] serialize( T obj )
+        throws IOException
+    {
+        return data;
+    }
+
+}
diff --git a/directmemory-cache/src/test/java/org/apache/directmemory/serialization/SerializerFactoryTestCase.java b/directmemory-cache/src/test/java/org/apache/directmemory/serialization/SerializerFactoryTestCase.java
new file mode 100644
index 0000000..2685c6c
--- /dev/null
+++ b/directmemory-cache/src/test/java/org/apache/directmemory/serialization/SerializerFactoryTestCase.java
@@ -0,0 +1,41 @@
+package org.apache.directmemory.serialization;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import static org.apache.directmemory.serialization.SerializerFactory.createNewSerializer;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public final class SerializerFactoryTestCase
+{
+
+    /*
+     * TODO please update the test once DM will be modularized!
+     */
+    @Test
+    public void verifySerializerInstantiation()
+    {
+        Serializer serializer = createNewSerializer();
+
+        assertTrue( serializer instanceof StandardSerializer );
+    }
+
+}
diff --git a/directmemory-cache/src/test/java/org/apache/directmemory/serialization/SerializerTest.java b/directmemory-cache/src/test/java/org/apache/directmemory/serialization/SerializerTest.java
new file mode 100644
index 0000000..7682816
--- /dev/null
+++ b/directmemory-cache/src/test/java/org/apache/directmemory/serialization/SerializerTest.java
@@ -0,0 +1,85 @@
+package org.apache.directmemory.serialization;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.IOException;
+
+import org.apache.directmemory.measures.Monitor;
+import org.apache.directmemory.measures.MonitorService;
+import org.apache.directmemory.measures.Ram;
+import org.apache.directmemory.misc.DummyPojo;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.carrotsearch.junitbenchmarks.AbstractBenchmark;
+import com.carrotsearch.junitbenchmarks.BenchmarkOptions;
+import com.carrotsearch.junitbenchmarks.annotation.AxisRange;
+import com.carrotsearch.junitbenchmarks.annotation.BenchmarkHistoryChart;
+import com.carrotsearch.junitbenchmarks.annotation.BenchmarkMethodChart;
+import com.carrotsearch.junitbenchmarks.annotation.LabelType;
+
+@AxisRange( min = 0, max = 1 )
+@BenchmarkMethodChart()
+@BenchmarkHistoryChart( labelWith = LabelType.CUSTOM_KEY, maxRuns = 5 )
+@BenchmarkOptions( benchmarkRounds = 2, warmupRounds = 1, concurrency = 1 )
+
+public class SerializerTest
+    extends AbstractBenchmark
+{
+
+    private static Logger logger = LoggerFactory.getLogger( SerializerTest.class );
+
+    private void testSerializer( String name, Serializer serializer, int size, int howMany )
+        throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException
+    {
+        logger.info( "begin " + serializer.getClass().toString() );
+        MonitorService stopWatch = Monitor.get( "serializer." + name + "." + size + "bytes" );
+        MonitorService stopWatch2 = Monitor.get( "deserializer." + name + "." + size + "bytes" );
+        DummyPojo pojo = new DummyPojo( "test", size );
+        for ( int i = 0; i < howMany; i++ )
+        {
+            long split = stopWatch.start();
+            final byte[] array = serializer.serialize( pojo );
+            stopWatch.stop( split );
+            long split2 = stopWatch2.start();
+            DummyPojo check = (DummyPojo) serializer.deserialize( array, pojo.getClass() );
+            stopWatch2.stop( split2 );
+            assertNotNull( "object has not been serialized", check );
+            assertEquals( pojo.name, check.name );
+        }
+        logger.info( "end serialize " + serializer.getClass().toString() + "\r\n" + stopWatch.toString() );
+        logger.info( "end deserialize " + serializer.getClass().toString() + "\r\n" + stopWatch2.toString() );
+    }
+
+    @Test
+    public void StandardTest()
+        throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException
+    {
+        testSerializer( "java-serialization", new StandardSerializer(), Ram.Kb( 1 ), 20000 );
+        testSerializer( "java-serialization", new StandardSerializer(), Ram.Kb( 2 ), 20000 );
+        testSerializer( "java-serialization", new StandardSerializer(), Ram.Kb( 3 ), 20000 );
+        testSerializer( "java-serialization", new StandardSerializer(), Ram.Kb( 4 ), 20000 );
+    }
+
+}
diff --git a/directmemory-cache/src/test/java/org/apache/directmemory/serialization/StandardSerializerTest.java b/directmemory-cache/src/test/java/org/apache/directmemory/serialization/StandardSerializerTest.java
new file mode 100644
index 0000000..a35caff
--- /dev/null
+++ b/directmemory-cache/src/test/java/org/apache/directmemory/serialization/StandardSerializerTest.java
@@ -0,0 +1,215 @@
+package org.apache.directmemory.serialization;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.Random;
+
+import static org.junit.Assert.*;
+
+public class StandardSerializerTest
+{
+
+    private static Serializer serializer;
+
+    private static final Random r = new Random();
+
+    @BeforeClass
+    public static void init()
+    {
+        serializer = new StandardSerializer();
+    }
+
+    @Test
+    public void validateBooleanSerialization()
+        throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException
+    {
+        byte[] payload = serializer.serialize( true );
+        boolean res = serializer.deserialize( payload, Boolean.class );
+        assertEquals( true, res );
+    }
+
+    @Test
+    public void validateBooleanArraySerialization()
+        throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException
+    {
+        byte[] payload = serializer.serialize( new boolean[]{ true } );
+        boolean[] res = serializer.deserialize( payload, boolean[].class );
+        assertEquals( 1, res.length );
+        assertTrue( res[0] );
+    }
+
+    @Test
+    public void validateByteSerialization()
+        throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException
+    {
+        byte[] payload = serializer.serialize( (byte) 127 );
+        byte res = serializer.deserialize( payload, Byte.class );
+        assertEquals( (byte) 127, res );
+    }
+
+    @Test
+    public void validateByteArraySerialization()
+        throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException
+    {
+        byte[] value = new byte[1024];
+        r.nextBytes( value );
+        byte[] payload = serializer.serialize( value );
+        byte[] res = serializer.deserialize( payload, byte[].class );
+        assertArrayEquals( value, res );
+    }
+
+    @Test
+    public void validateCharacterSerialization()
+        throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException
+    {
+        byte[] payload = serializer.serialize( 'z' );
+        char res = serializer.deserialize( payload, Character.class );
+        assertEquals( 'z', res );
+    }
+
+    @Test
+    public void validateCharacterArraySerialization()
+        throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException
+    {
+        char[] value = new char[]{ 'a', 'z', 'x', ' ', '-', '-' };
+        byte[] payload = serializer.serialize( value );
+        char[] res = serializer.deserialize( payload, char[].class );
+        assertArrayEquals( value, res );
+    }
+
+    @Test
+    public void validateDoubleSerialization()
+        throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException
+    {
+        byte[] payload = serializer.serialize( 1.2d );
+        double res = serializer.deserialize( payload, Double.class );
+        assertEquals( 1.2d, res, 0.0d );
+    }
+
+    @Test
+    public void validateDoubleArraySerialization()
+        throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException
+    {
+        double[] value = new double[]{ 1.1d, 3.1d, 0.1d };
+        byte[] payload = serializer.serialize( value );
+        double[] res = serializer.deserialize( payload, double[].class );
+        assertArrayEquals( value, res, 0.0d );
+    }
+
+    @Test
+    public void validateFloatSerialization()
+        throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException
+    {
+        byte[] payload = serializer.serialize( 1.2f );
+        float res = serializer.deserialize( payload, Float.class );
+        assertEquals( 1.2f, res, 0.0d );
+    }
+
+    @Test
+    public void validateFloatArraySerialization()
+        throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException
+    {
+        float[] value = new float[]{ 1.1f, 4.05f, 55.5f };
+        byte[] payload = serializer.serialize( value );
+        float[] res = serializer.deserialize( payload, float[].class );
+        assertArrayEquals( value, res, 0.0f );
+    }
+
+    @Test
+    public void validateIntegerSerialization()
+        throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException
+    {
+        byte[] payload = serializer.serialize( 1 );
+        int res = serializer.deserialize( payload, Integer.class );
+        assertEquals( 1, res );
+    }
+
+    @Test
+    public void validateIntegerArraySerialization()
+        throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException
+    {
+        int[] value = new int[]{ 3, 1, -1 };
+        byte[] payload = serializer.serialize( value );
+        int[] res = serializer.deserialize( payload, int[].class );
+        assertArrayEquals( value, res );
+    }
+
+    @Test
+    public void validateLongSerialization()
+        throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException
+    {
+        byte[] payload = serializer.serialize( 1L );
+        long res = serializer.deserialize( payload, Long.class );
+        assertEquals( 1, res );
+    }
+
+    @Test
+    public void validateLongArraySerialization()
+        throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException
+    {
+        long[] value = new long[]{ 1l, 3l, 1212121212121l };
+        byte[] payload = serializer.serialize( value );
+        long[] res = serializer.deserialize( payload, long[].class );
+        assertArrayEquals( value, res );
+    }
+
+    @Test
+    public void validateShortSerialization()
+        throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException
+    {
+        byte[] payload = serializer.serialize( (short) 1234 );
+        short res = serializer.deserialize( payload, Short.class );
+        assertEquals( 1234, res );
+    }
+
+    @Test
+    public void validateShortArraySerialization()
+        throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException
+    {
+        short[] value = new short[]{ 1, -1, 4, 32767 };
+        byte[] payload = serializer.serialize( value );
+        short[] res = serializer.deserialize( payload, short[].class );
+        assertArrayEquals( value, res );
+    }
+
+    @Test
+    public void validateStringSerialization()
+        throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException
+    {
+        String value = "a sample string to serialize";
+        byte[] payload = serializer.serialize( value );
+        String res = serializer.deserialize( payload, String.class );
+        assertEquals( value, res );
+    }
+
+    @Test
+    public void validateStringArraySerialization()
+        throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException
+    {
+        String[] value = new String[]{ "String1", "", "String2" };
+        byte[] payload = serializer.serialize( value );
+        String[] res = serializer.deserialize( payload, String[].class );
+        assertArrayEquals( value, res );
+    }
+}
diff --git a/directmemory-cache/src/test/resources/logback-test.xml b/directmemory-cache/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..de5484e
--- /dev/null
+++ b/directmemory-cache/src/test/resources/logback-test.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<!--

+  ~ Licensed to the Apache Software Foundation (ASF) under one

+  ~ or more contributor license agreements.  See the NOTICE file

+  ~ distributed with this work for additional information

+  ~ regarding copyright ownership.  The ASF licenses this file

+  ~ to you under the Apache License, Version 2.0 (the

+  ~ "License"); you may not use this file except in compliance

+  ~ with the License.  You may obtain a copy of the License at

+  ~

+  ~   http://www.apache.org/licenses/LICENSE-2.0

+  ~

+  ~ Unless required by applicable law or agreed to in writing,

+  ~ software distributed under the License is distributed on an

+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+  ~ KIND, either express or implied.  See the License for the

+  ~ specific language governing permissions and limitations

+  ~ under the License.

+  -->

+<configuration>

+

+  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">

+    <encoder>

+      <Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %method - %msg%n</Pattern>

+    </encoder>

+  </appender>

+

+

+  <logger name="org.apache.directmemory.serialization" level="warn">

+    <appender-ref ref="STDOUT"/>

+

+  </logger>

+

+  <logger name="org.apache.directmemory.measures" level="info">

+    <appender-ref ref="STDOUT"/>

+

+  </logger>

+

+  <logger name="org.apache.directmemory.memory" level="info">

+    <appender-ref ref="STDOUT"/>

+

+  </logger>

+

+  <logger name="org.apache.directmemory.cache" level="info">

+    <appender-ref ref="STDOUT"/>

+

+  </logger>

+

+</configuration>
\ No newline at end of file
diff --git a/directmemory-tests/pom.xml b/directmemory-tests/pom.xml
new file mode 100644
index 0000000..1dc9a37
--- /dev/null
+++ b/directmemory-tests/pom.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directmemory</groupId>
+    <artifactId>directmemory</artifactId>
+    <version>0.1-incubating</version>
+  </parent>
+
+
+  <artifactId>directmemory-tests</artifactId>
+  <packaging>jar</packaging>
+
+  <name>Apache DirectMemory :: Tests</name>
+  <description>${project.name}</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.directmemory</groupId>
+      <artifactId>directmemory-cache</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>compile</scope>
+    </dependency>
+  </dependencies>
+
+</project>
diff --git a/directmemory-tests/src/main/java/org/apache/directmemory/test/AbstractSerializerTest.java b/directmemory-tests/src/main/java/org/apache/directmemory/test/AbstractSerializerTest.java
new file mode 100644
index 0000000..e0605ae
--- /dev/null
+++ b/directmemory-tests/src/main/java/org/apache/directmemory/test/AbstractSerializerTest.java
@@ -0,0 +1,73 @@
+package org.apache.directmemory.test;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.directmemory.serialization.Serializer;
+import org.apache.directmemory.serialization.SerializerFactory;
+import org.apache.directmemory.serialization.SerializerNotFoundException;
+import org.junit.Test;
+
+import static junit.framework.Assert.assertEquals;
+
+/**
+ * A kind of tck test for serializer.
+ */
+public abstract class AbstractSerializerTest
+{
+    public abstract String getSerializerClassName();
+
+    @Test
+    public void factoryWithFQDN()
+        throws Exception
+    {
+        assertEquals( getSerializerClassName(),
+                      SerializerFactory.createNewSerializer( getSerializerClassName() ).getClass().getName() );
+    }
+
+    @Test
+    public void simpleSerialization()
+        throws Exception
+    {
+        Wine wine = getWineInstance();
+
+        Serializer serializer = SerializerFactory.createNewSerializer( getSerializerClassName() );
+
+        byte[] bytes = serializer.serialize( wine );
+
+        Wine newWine = serializer.deserialize( bytes, Wine.class );
+
+        assertEquals( wine.getName(), newWine.getName() );
+        assertEquals( wine.getDescription(), newWine.getDescription() );
+
+    }
+
+    protected Wine getWineInstance()
+    {
+        return new Wine( "Gevrey-Chambertin", "nice French wine from Bourgogne" );
+    }
+
+    @Test( expected = SerializerNotFoundException.class )
+    public void serialiazerNotFoundException()
+        throws Exception
+    {
+        // toto.titi means foo.bar in French :-)
+        SerializerFactory.createNewSerializer( "toto.titi" );
+    }
+}
diff --git a/directmemory-tests/src/main/java/org/apache/directmemory/test/Wine.java b/directmemory-tests/src/main/java/org/apache/directmemory/test/Wine.java
new file mode 100644
index 0000000..5abd2e8
--- /dev/null
+++ b/directmemory-tests/src/main/java/org/apache/directmemory/test/Wine.java
@@ -0,0 +1,64 @@
+package org.apache.directmemory.test;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.Serializable;
+
+/**
+ * @author Olivier Lamy
+ */
+public class Wine
+    implements Serializable
+{
+    private String name;
+
+    private String description;
+
+    public Wine()
+    {
+        // no op
+    }
+
+    public Wine( String name, String description )
+    {
+        this.name = name;
+        this.description = description;
+    }
+
+    public String getName()
+    {
+        return name;
+    }
+
+    public void setName( String name )
+    {
+        this.name = name;
+    }
+
+    public String getDescription()
+    {
+        return description;
+    }
+
+    public void setDescription( String description )
+    {
+        this.description = description;
+    }
+}
diff --git a/directmemory-tests/src/test/java/org/apache/directmemory/test/StandardSerializerTest.java b/directmemory-tests/src/test/java/org/apache/directmemory/test/StandardSerializerTest.java
new file mode 100644
index 0000000..de85d16
--- /dev/null
+++ b/directmemory-tests/src/test/java/org/apache/directmemory/test/StandardSerializerTest.java
@@ -0,0 +1,34 @@
+package org.apache.directmemory.test;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.directmemory.serialization.StandardSerializer;
+
+/**
+ * @author Olivier Lamy
+ */
+public class StandardSerializerTest
+    extends AbstractSerializerTest
+{
+    @Override
+    public String getSerializerClassName()
+    {
+        return StandardSerializer.class.getName();
+    }
+}
diff --git a/examples/pom.xml b/examples/pom.xml
new file mode 100644
index 0000000..c9c88e2
--- /dev/null
+++ b/examples/pom.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <groupId>org.apache.directmemory</groupId>
+    <artifactId>directmemory</artifactId>
+    <version>0.1-incubating</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+
+  <artifactId>examples</artifactId>
+  <packaging>pom</packaging>
+  <name>Apache DirectMemory :: Examples</name>
+  <description>${project.name}</description>
+
+  <modules>
+    <module>server-example</module>
+  </modules>
+
+
+</project>
\ No newline at end of file
diff --git a/examples/server-example/pom.xml b/examples/server-example/pom.xml
new file mode 100644
index 0000000..72b86de
--- /dev/null
+++ b/examples/server-example/pom.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <groupId>org.apache.directmemory</groupId>
+    <artifactId>examples</artifactId>
+    <version>0.1-incubating</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+
+  <artifactId>server-example</artifactId>
+  <packaging>war</packaging>
+  <name>Apache DirectMemory :: Examples :: Server Javascript</name>
+  <description>${project.name}</description>
+
+  <properties>
+    <tomcatRunPort>9091</tomcatRunPort>
+    <tomcatRunPath>/dm</tomcatRunPath>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.directmemory.server</groupId>
+      <artifactId>directmemory-server</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.directmemory</groupId>
+      <artifactId>directmemory-protostuff</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>javax.servlet</groupId>
+      <artifactId>servlet-api</artifactId>
+      <version>2.5</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-log4j12</artifactId>
+      <version>${slf4j.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>log4j</groupId>
+      <artifactId>log4j</artifactId>
+      <version>1.2.16</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.tomcat.maven</groupId>
+        <artifactId>tomcat7-maven-plugin</artifactId>
+        <configuration>
+          <port>${tomcatRunPort}</port>
+          <path>${tomcatRunPath}</path>
+          <warSourceDirectory>${basedir}/src/main/webapp</warSourceDirectory>
+          <systemProperties>
+            <directMemory.size>1000</directMemory.size>
+          </systemProperties>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
\ No newline at end of file
diff --git a/examples/server-example/src/main/resources/log4j.xml b/examples/server-example/src/main/resources/log4j.xml
new file mode 100644
index 0000000..04b1f88
--- /dev/null
+++ b/examples/server-example/src/main/resources/log4j.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
+
+  <appender name="console" class="org.apache.log4j.ConsoleAppender">
+    <layout class="org.apache.log4j.PatternLayout">
+      <param name="ConversionPattern" value="%d %-5p %c %x - %m%n"/>
+    </layout>
+  </appender>
+
+
+  <logger name="org.apache.directmemory">
+    <level value="debug"/>
+  </logger>
+
+  <root>
+    <priority value ="info" />
+    <appender-ref ref="console" />
+  </root>
+
+</log4j:configuration>
diff --git a/examples/server-example/src/main/webapp/WEB-INF/web.xml b/examples/server-example/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..f10e085
--- /dev/null
+++ b/examples/server-example/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  ~ Copyright 2005-2006 The Apache Software Foundation.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<web-app xmlns="http://java.sun.com/xml/ns/j2ee" version="2.4"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
+
+  <display-name>Apache DirectMemory</display-name>
+  
+  <servlet>
+    <servlet-name>DirectMemoryServlet</servlet-name>
+    <servlet-class>org.apache.directmemory.server.services.DirectMemoryServlet</servlet-class>
+    <load-on-startup>1</load-on-startup>
+  </servlet>
+  
+  <servlet-mapping>
+    <servlet-name>DirectMemoryServlet</servlet-name>
+    <url-pattern>/cache/*</url-pattern>
+  </servlet-mapping>
+
+  
+</web-app>  
\ No newline at end of file
diff --git a/examples/server-example/src/main/webapp/css/bootstrap.2.0.4.css b/examples/server-example/src/main/webapp/css/bootstrap.2.0.4.css
new file mode 100644
index 0000000..bb40c85
--- /dev/null
+++ b/examples/server-example/src/main/webapp/css/bootstrap.2.0.4.css
@@ -0,0 +1,4983 @@
+/*!
+ * Bootstrap v2.0.4
+ *
+ * Copyright 2012 Twitter, Inc
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
+ */
+
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+nav,
+section {
+  display: block;
+}
+
+audio,
+canvas,
+video {
+  display: inline-block;
+  *display: inline;
+  *zoom: 1;
+}
+
+audio:not([controls]) {
+  display: none;
+}
+
+html {
+  font-size: 100%;
+  -webkit-text-size-adjust: 100%;
+      -ms-text-size-adjust: 100%;
+}
+
+a:focus {
+  outline: thin dotted #333;
+  outline: 5px auto -webkit-focus-ring-color;
+  outline-offset: -2px;
+}
+
+a:hover,
+a:active {
+  outline: 0;
+}
+
+sub,
+sup {
+  position: relative;
+  font-size: 75%;
+  line-height: 0;
+  vertical-align: baseline;
+}
+
+sup {
+  top: -0.5em;
+}
+
+sub {
+  bottom: -0.25em;
+}
+
+img {
+  max-width: 100%;
+  vertical-align: middle;
+  border: 0;
+  -ms-interpolation-mode: bicubic;
+}
+
+#map_canvas img {
+  max-width: none;
+}
+
+button,
+input,
+select,
+textarea {
+  margin: 0;
+  font-size: 100%;
+  vertical-align: middle;
+}
+
+button,
+input {
+  *overflow: visible;
+  line-height: normal;
+}
+
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+  padding: 0;
+  border: 0;
+}
+
+button,
+input[type="button"],
+input[type="reset"],
+input[type="submit"] {
+  cursor: pointer;
+  -webkit-appearance: button;
+}
+
+input[type="search"] {
+  -webkit-box-sizing: content-box;
+     -moz-box-sizing: content-box;
+          box-sizing: content-box;
+  -webkit-appearance: textfield;
+}
+
+input[type="search"]::-webkit-search-decoration,
+input[type="search"]::-webkit-search-cancel-button {
+  -webkit-appearance: none;
+}
+
+textarea {
+  overflow: auto;
+  vertical-align: top;
+}
+
+.clearfix {
+  *zoom: 1;
+}
+
+.clearfix:before,
+.clearfix:after {
+  display: table;
+  content: "";
+}
+
+.clearfix:after {
+  clear: both;
+}
+
+.hide-text {
+  font: 0/0 a;
+  color: transparent;
+  text-shadow: none;
+  background-color: transparent;
+  border: 0;
+}
+
+.input-block-level {
+  display: block;
+  width: 100%;
+  min-height: 28px;
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+      -ms-box-sizing: border-box;
+          box-sizing: border-box;
+}
+
+body {
+  margin: 0;
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+  font-size: 13px;
+  line-height: 18px;
+  color: #333333;
+  background-color: #ffffff;
+}
+
+a {
+  color: #0088cc;
+  text-decoration: none;
+}
+
+a:hover {
+  color: #005580;
+  text-decoration: underline;
+}
+
+.row {
+  margin-left: -20px;
+  *zoom: 1;
+}
+
+.row:before,
+.row:after {
+  display: table;
+  content: "";
+}
+
+.row:after {
+  clear: both;
+}
+
+[class*="span"] {
+  float: left;
+  margin-left: 20px;
+}
+
+.container,
+.navbar-fixed-top .container,
+.navbar-fixed-bottom .container {
+  width: 940px;
+}
+
+.span12 {
+  width: 940px;
+}
+
+.span11 {
+  width: 860px;
+}
+
+.span10 {
+  width: 780px;
+}
+
+.span9 {
+  width: 700px;
+}
+
+.span8 {
+  width: 620px;
+}
+
+.span7 {
+  width: 540px;
+}
+
+.span6 {
+  width: 460px;
+}
+
+.span5 {
+  width: 380px;
+}
+
+.span4 {
+  width: 300px;
+}
+
+.span3 {
+  width: 220px;
+}
+
+.span2 {
+  width: 140px;
+}
+
+.span1 {
+  width: 60px;
+}
+
+.offset12 {
+  margin-left: 980px;
+}
+
+.offset11 {
+  margin-left: 900px;
+}
+
+.offset10 {
+  margin-left: 820px;
+}
+
+.offset9 {
+  margin-left: 740px;
+}
+
+.offset8 {
+  margin-left: 660px;
+}
+
+.offset7 {
+  margin-left: 580px;
+}
+
+.offset6 {
+  margin-left: 500px;
+}
+
+.offset5 {
+  margin-left: 420px;
+}
+
+.offset4 {
+  margin-left: 340px;
+}
+
+.offset3 {
+  margin-left: 260px;
+}
+
+.offset2 {
+  margin-left: 180px;
+}
+
+.offset1 {
+  margin-left: 100px;
+}
+
+.row-fluid {
+  width: 100%;
+  *zoom: 1;
+}
+
+.row-fluid:before,
+.row-fluid:after {
+  display: table;
+  content: "";
+}
+
+.row-fluid:after {
+  clear: both;
+}
+
+.row-fluid [class*="span"] {
+  display: block;
+  float: left;
+  width: 100%;
+  min-height: 28px;
+  margin-left: 2.127659574%;
+  *margin-left: 2.0744680846382977%;
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+      -ms-box-sizing: border-box;
+          box-sizing: border-box;
+}
+
+.row-fluid [class*="span"]:first-child {
+  margin-left: 0;
+}
+
+.row-fluid .span12 {
+  width: 99.99999998999999%;
+  *width: 99.94680850063828%;
+}
+
+.row-fluid .span11 {
+  width: 91.489361693%;
+  *width: 91.4361702036383%;
+}
+
+.row-fluid .span10 {
+  width: 82.97872339599999%;
+  *width: 82.92553190663828%;
+}
+
+.row-fluid .span9 {
+  width: 74.468085099%;
+  *width: 74.4148936096383%;
+}
+
+.row-fluid .span8 {
+  width: 65.95744680199999%;
+  *width: 65.90425531263828%;
+}
+
+.row-fluid .span7 {
+  width: 57.446808505%;
+  *width: 57.3936170156383%;
+}
+
+.row-fluid .span6 {
+  width: 48.93617020799999%;
+  *width: 48.88297871863829%;
+}
+
+.row-fluid .span5 {
+  width: 40.425531911%;
+  *width: 40.3723404216383%;
+}
+
+.row-fluid .span4 {
+  width: 31.914893614%;
+  *width: 31.8617021246383%;
+}
+
+.row-fluid .span3 {
+  width: 23.404255317%;
+  *width: 23.3510638276383%;
+}
+
+.row-fluid .span2 {
+  width: 14.89361702%;
+  *width: 14.8404255306383%;
+}
+
+.row-fluid .span1 {
+  width: 6.382978723%;
+  *width: 6.329787233638298%;
+}
+
+.container {
+  margin-right: auto;
+  margin-left: auto;
+  *zoom: 1;
+}
+
+.container:before,
+.container:after {
+  display: table;
+  content: "";
+}
+
+.container:after {
+  clear: both;
+}
+
+.container-fluid {
+  padding-right: 20px;
+  padding-left: 20px;
+  *zoom: 1;
+}
+
+.container-fluid:before,
+.container-fluid:after {
+  display: table;
+  content: "";
+}
+
+.container-fluid:after {
+  clear: both;
+}
+
+p {
+  margin: 0 0 9px;
+}
+
+p small {
+  font-size: 11px;
+  color: #999999;
+}
+
+.lead {
+  margin-bottom: 18px;
+  font-size: 20px;
+  font-weight: 200;
+  line-height: 27px;
+}
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+  margin: 0;
+  font-family: inherit;
+  font-weight: bold;
+  color: inherit;
+  text-rendering: optimizelegibility;
+}
+
+h1 small,
+h2 small,
+h3 small,
+h4 small,
+h5 small,
+h6 small {
+  font-weight: normal;
+  color: #999999;
+}
+
+h1 {
+  font-size: 30px;
+  line-height: 36px;
+}
+
+h1 small {
+  font-size: 18px;
+}
+
+h2 {
+  font-size: 24px;
+  line-height: 36px;
+}
+
+h2 small {
+  font-size: 18px;
+}
+
+h3 {
+  font-size: 18px;
+  line-height: 27px;
+}
+
+h3 small {
+  font-size: 14px;
+}
+
+h4,
+h5,
+h6 {
+  line-height: 18px;
+}
+
+h4 {
+  font-size: 14px;
+}
+
+h4 small {
+  font-size: 12px;
+}
+
+h5 {
+  font-size: 12px;
+}
+
+h6 {
+  font-size: 11px;
+  color: #999999;
+  text-transform: uppercase;
+}
+
+.page-header {
+  padding-bottom: 17px;
+  margin: 18px 0;
+  border-bottom: 1px solid #eeeeee;
+}
+
+.page-header h1 {
+  line-height: 1;
+}
+
+ul,
+ol {
+  padding: 0;
+  margin: 0 0 9px 25px;
+}
+
+ul ul,
+ul ol,
+ol ol,
+ol ul {
+  margin-bottom: 0;
+}
+
+ul {
+  list-style: disc;
+}
+
+ol {
+  list-style: decimal;
+}
+
+li {
+  line-height: 18px;
+}
+
+ul.unstyled,
+ol.unstyled {
+  margin-left: 0;
+  list-style: none;
+}
+
+dl {
+  margin-bottom: 18px;
+}
+
+dt,
+dd {
+  line-height: 18px;
+}
+
+dt {
+  font-weight: bold;
+  line-height: 17px;
+}
+
+dd {
+  margin-left: 9px;
+}
+
+.dl-horizontal dt {
+  float: left;
+  width: 120px;
+  overflow: hidden;
+  clear: left;
+  text-align: right;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.dl-horizontal dd {
+  margin-left: 130px;
+}
+
+hr {
+  margin: 18px 0;
+  border: 0;
+  border-top: 1px solid #eeeeee;
+  border-bottom: 1px solid #ffffff;
+}
+
+strong {
+  font-weight: bold;
+}
+
+em {
+  font-style: italic;
+}
+
+.muted {
+  color: #999999;
+}
+
+abbr[title] {
+  cursor: help;
+  border-bottom: 1px dotted #999999;
+}
+
+abbr.initialism {
+  font-size: 90%;
+  text-transform: uppercase;
+}
+
+blockquote {
+  padding: 0 0 0 15px;
+  margin: 0 0 18px;
+  border-left: 5px solid #eeeeee;
+}
+
+blockquote p {
+  margin-bottom: 0;
+  font-size: 16px;
+  font-weight: 300;
+  line-height: 22.5px;
+}
+
+blockquote small {
+  display: block;
+  line-height: 18px;
+  color: #999999;
+}
+
+blockquote small:before {
+  content: '\2014 \00A0';
+}
+
+blockquote.pull-right {
+  float: right;
+  padding-right: 15px;
+  padding-left: 0;
+  border-right: 5px solid #eeeeee;
+  border-left: 0;
+}
+
+blockquote.pull-right p,
+blockquote.pull-right small {
+  text-align: right;
+}
+
+q:before,
+q:after,
+blockquote:before,
+blockquote:after {
+  content: "";
+}
+
+address {
+  display: block;
+  margin-bottom: 18px;
+  font-style: normal;
+  line-height: 18px;
+}
+
+small {
+  font-size: 100%;
+}
+
+cite {
+  font-style: normal;
+}
+
+code,
+pre {
+  padding: 0 3px 2px;
+  font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
+  font-size: 12px;
+  color: #333333;
+  -webkit-border-radius: 3px;
+     -moz-border-radius: 3px;
+          border-radius: 3px;
+}
+
+code {
+  padding: 2px 4px;
+  color: #d14;
+  background-color: #f7f7f9;
+  border: 1px solid #e1e1e8;
+}
+
+pre {
+  display: block;
+  padding: 8.5px;
+  margin: 0 0 9px;
+  font-size: 12.025px;
+  line-height: 18px;
+  word-break: break-all;
+  word-wrap: break-word;
+  white-space: pre;
+  white-space: pre-wrap;
+  background-color: #f5f5f5;
+  border: 1px solid #ccc;
+  border: 1px solid rgba(0, 0, 0, 0.15);
+  -webkit-border-radius: 4px;
+     -moz-border-radius: 4px;
+          border-radius: 4px;
+}
+
+pre.prettyprint {
+  margin-bottom: 18px;
+}
+
+pre code {
+  padding: 0;
+  color: inherit;
+  background-color: transparent;
+  border: 0;
+}
+
+.pre-scrollable {
+  max-height: 340px;
+  overflow-y: scroll;
+}
+
+form {
+  margin: 0 0 18px;
+}
+
+fieldset {
+  padding: 0;
+  margin: 0;
+  border: 0;
+}
+
+legend {
+  display: block;
+  width: 100%;
+  padding: 0;
+  margin-bottom: 27px;
+  font-size: 19.5px;
+  line-height: 36px;
+  color: #333333;
+  border: 0;
+  border-bottom: 1px solid #e5e5e5;
+}
+
+legend small {
+  font-size: 13.5px;
+  color: #999999;
+}
+
+label,
+input,
+button,
+select,
+textarea {
+  font-size: 13px;
+  font-weight: normal;
+  line-height: 18px;
+}
+
+input,
+button,
+select,
+textarea {
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+}
+
+label {
+  display: block;
+  margin-bottom: 5px;
+}
+
+select,
+textarea,
+input[type="text"],
+input[type="password"],
+input[type="datetime"],
+input[type="datetime-local"],
+input[type="date"],
+input[type="month"],
+input[type="time"],
+input[type="week"],
+input[type="number"],
+input[type="email"],
+input[type="url"],
+input[type="search"],
+input[type="tel"],
+input[type="color"],
+.uneditable-input {
+  display: inline-block;
+  height: 18px;
+  padding: 4px;
+  margin-bottom: 9px;
+  font-size: 13px;
+  line-height: 18px;
+  color: #555555;
+}
+
+input,
+textarea {
+  width: 210px;
+}
+
+textarea {
+  height: auto;
+}
+
+textarea,
+input[type="text"],
+input[type="password"],
+input[type="datetime"],
+input[type="datetime-local"],
+input[type="date"],
+input[type="month"],
+input[type="time"],
+input[type="week"],
+input[type="number"],
+input[type="email"],
+input[type="url"],
+input[type="search"],
+input[type="tel"],
+input[type="color"],
+.uneditable-input {
+  background-color: #ffffff;
+  border: 1px solid #cccccc;
+  -webkit-border-radius: 3px;
+     -moz-border-radius: 3px;
+          border-radius: 3px;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+  -webkit-transition: border linear 0.2s, box-shadow linear 0.2s;
+     -moz-transition: border linear 0.2s, box-shadow linear 0.2s;
+      -ms-transition: border linear 0.2s, box-shadow linear 0.2s;
+       -o-transition: border linear 0.2s, box-shadow linear 0.2s;
+          transition: border linear 0.2s, box-shadow linear 0.2s;
+}
+
+textarea:focus,
+input[type="text"]:focus,
+input[type="password"]:focus,
+input[type="datetime"]:focus,
+input[type="datetime-local"]:focus,
+input[type="date"]:focus,
+input[type="month"]:focus,
+input[type="time"]:focus,
+input[type="week"]:focus,
+input[type="number"]:focus,
+input[type="email"]:focus,
+input[type="url"]:focus,
+input[type="search"]:focus,
+input[type="tel"]:focus,
+input[type="color"]:focus,
+.uneditable-input:focus {
+  border-color: rgba(82, 168, 236, 0.8);
+  outline: 0;
+  outline: thin dotted \9;
+  /* IE6-9 */
+
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
+     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
+          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
+}
+
+input[type="radio"],
+input[type="checkbox"] {
+  margin: 3px 0;
+  *margin-top: 0;
+  /* IE7 */
+
+  line-height: normal;
+  cursor: pointer;
+}
+
+input[type="submit"],
+input[type="reset"],
+input[type="button"],
+input[type="radio"],
+input[type="checkbox"] {
+  width: auto;
+}
+
+.uneditable-textarea {
+  width: auto;
+  height: auto;
+}
+
+select,
+input[type="file"] {
+  height: 28px;
+  /* In IE7, the height of the select element cannot be changed by height, only font-size */
+
+  *margin-top: 4px;
+  /* For IE7, add top margin to align select with labels */
+
+  line-height: 28px;
+}
+
+select {
+  width: 220px;
+  border: 1px solid #bbb;
+}
+
+select[multiple],
+select[size] {
+  height: auto;
+}
+
+select:focus,
+input[type="file"]:focus,
+input[type="radio"]:focus,
+input[type="checkbox"]:focus {
+  outline: thin dotted #333;
+  outline: 5px auto -webkit-focus-ring-color;
+  outline-offset: -2px;
+}
+
+.radio,
+.checkbox {
+  min-height: 18px;
+  padding-left: 18px;
+}
+
+.radio input[type="radio"],
+.checkbox input[type="checkbox"] {
+  float: left;
+  margin-left: -18px;
+}
+
+.controls > .radio:first-child,
+.controls > .checkbox:first-child {
+  padding-top: 5px;
+}
+
+.radio.inline,
+.checkbox.inline {
+  display: inline-block;
+  padding-top: 5px;
+  margin-bottom: 0;
+  vertical-align: middle;
+}
+
+.radio.inline + .radio.inline,
+.checkbox.inline + .checkbox.inline {
+  margin-left: 10px;
+}
+
+.input-mini {
+  width: 60px;
+}
+
+.input-small {
+  width: 90px;
+}
+
+.input-medium {
+  width: 150px;
+}
+
+.input-large {
+  width: 210px;
+}
+
+.input-xlarge {
+  width: 270px;
+}
+
+.input-xxlarge {
+  width: 530px;
+}
+
+input[class*="span"],
+select[class*="span"],
+textarea[class*="span"],
+.uneditable-input[class*="span"],
+.row-fluid input[class*="span"],
+.row-fluid select[class*="span"],
+.row-fluid textarea[class*="span"],
+.row-fluid .uneditable-input[class*="span"] {
+  float: none;
+  margin-left: 0;
+}
+
+.input-append input[class*="span"],
+.input-append .uneditable-input[class*="span"],
+.input-prepend input[class*="span"],
+.input-prepend .uneditable-input[class*="span"],
+.row-fluid .input-prepend [class*="span"],
+.row-fluid .input-append [class*="span"] {
+  display: inline-block;
+}
+
+input,
+textarea,
+.uneditable-input {
+  margin-left: 0;
+}
+
+input.span12,
+textarea.span12,
+.uneditable-input.span12 {
+  width: 930px;
+}
+
+input.span11,
+textarea.span11,
+.uneditable-input.span11 {
+  width: 850px;
+}
+
+input.span10,
+textarea.span10,
+.uneditable-input.span10 {
+  width: 770px;
+}
+
+input.span9,
+textarea.span9,
+.uneditable-input.span9 {
+  width: 690px;
+}
+
+input.span8,
+textarea.span8,
+.uneditable-input.span8 {
+  width: 610px;
+}
+
+input.span7,
+textarea.span7,
+.uneditable-input.span7 {
+  width: 530px;
+}
+
+input.span6,
+textarea.span6,
+.uneditable-input.span6 {
+  width: 450px;
+}
+
+input.span5,
+textarea.span5,
+.uneditable-input.span5 {
+  width: 370px;
+}
+
+input.span4,
+textarea.span4,
+.uneditable-input.span4 {
+  width: 290px;
+}
+
+input.span3,
+textarea.span3,
+.uneditable-input.span3 {
+  width: 210px;
+}
+
+input.span2,
+textarea.span2,
+.uneditable-input.span2 {
+  width: 130px;
+}
+
+input.span1,
+textarea.span1,
+.uneditable-input.span1 {
+  width: 50px;
+}
+
+input[disabled],
+select[disabled],
+textarea[disabled],
+input[readonly],
+select[readonly],
+textarea[readonly] {
+  cursor: not-allowed;
+  background-color: #eeeeee;
+  border-color: #ddd;
+}
+
+input[type="radio"][disabled],
+input[type="checkbox"][disabled],
+input[type="radio"][readonly],
+input[type="checkbox"][readonly] {
+  background-color: transparent;
+}
+
+.control-group.warning > label,
+.control-group.warning .help-block,
+.control-group.warning .help-inline {
+  color: #c09853;
+}
+
+.control-group.warning .checkbox,
+.control-group.warning .radio,
+.control-group.warning input,
+.control-group.warning select,
+.control-group.warning textarea {
+  color: #c09853;
+  border-color: #c09853;
+}
+
+.control-group.warning .checkbox:focus,
+.control-group.warning .radio:focus,
+.control-group.warning input:focus,
+.control-group.warning select:focus,
+.control-group.warning textarea:focus {
+  border-color: #a47e3c;
+  -webkit-box-shadow: 0 0 6px #dbc59e;
+     -moz-box-shadow: 0 0 6px #dbc59e;
+          box-shadow: 0 0 6px #dbc59e;
+}
+
+.control-group.warning .input-prepend .add-on,
+.control-group.warning .input-append .add-on {
+  color: #c09853;
+  background-color: #fcf8e3;
+  border-color: #c09853;
+}
+
+.control-group.error > label,
+.control-group.error .help-block,
+.control-group.error .help-inline {
+  color: #b94a48;
+}
+
+.control-group.error .checkbox,
+.control-group.error .radio,
+.control-group.error input,
+.control-group.error select,
+.control-group.error textarea {
+  color: #b94a48;
+  border-color: #b94a48;
+}
+
+.control-group.error .checkbox:focus,
+.control-group.error .radio:focus,
+.control-group.error input:focus,
+.control-group.error select:focus,
+.control-group.error textarea:focus {
+  border-color: #953b39;
+  -webkit-box-shadow: 0 0 6px #d59392;
+     -moz-box-shadow: 0 0 6px #d59392;
+          box-shadow: 0 0 6px #d59392;
+}
+
+.control-group.error .input-prepend .add-on,
+.control-group.error .input-append .add-on {
+  color: #b94a48;
+  background-color: #f2dede;
+  border-color: #b94a48;
+}
+
+.control-group.success > label,
+.control-group.success .help-block,
+.control-group.success .help-inline {
+  color: #468847;
+}
+
+.control-group.success .checkbox,
+.control-group.success .radio,
+.control-group.success input,
+.control-group.success select,
+.control-group.success textarea {
+  color: #468847;
+  border-color: #468847;
+}
+
+.control-group.success .checkbox:focus,
+.control-group.success .radio:focus,
+.control-group.success input:focus,
+.control-group.success select:focus,
+.control-group.success textarea:focus {
+  border-color: #356635;
+  -webkit-box-shadow: 0 0 6px #7aba7b;
+     -moz-box-shadow: 0 0 6px #7aba7b;
+          box-shadow: 0 0 6px #7aba7b;
+}
+
+.control-group.success .input-prepend .add-on,
+.control-group.success .input-append .add-on {
+  color: #468847;
+  background-color: #dff0d8;
+  border-color: #468847;
+}
+
+input:focus:required:invalid,
+textarea:focus:required:invalid,
+select:focus:required:invalid {
+  color: #b94a48;
+  border-color: #ee5f5b;
+}
+
+input:focus:required:invalid:focus,
+textarea:focus:required:invalid:focus,
+select:focus:required:invalid:focus {
+  border-color: #e9322d;
+  -webkit-box-shadow: 0 0 6px #f8b9b7;
+     -moz-box-shadow: 0 0 6px #f8b9b7;
+          box-shadow: 0 0 6px #f8b9b7;
+}
+
+.form-actions {
+  padding: 17px 20px 18px;
+  margin-top: 18px;
+  margin-bottom: 18px;
+  background-color: #f5f5f5;
+  border-top: 1px solid #e5e5e5;
+  *zoom: 1;
+}
+
+.form-actions:before,
+.form-actions:after {
+  display: table;
+  content: "";
+}
+
+.form-actions:after {
+  clear: both;
+}
+
+.uneditable-input {
+  overflow: hidden;
+  white-space: nowrap;
+  cursor: not-allowed;
+  background-color: #ffffff;
+  border-color: #eee;
+  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);
+     -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);
+          box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);
+}
+
+:-moz-placeholder {
+  color: #999999;
+}
+
+:-ms-input-placeholder {
+  color: #999999;
+}
+
+::-webkit-input-placeholder {
+  color: #999999;
+}
+
+.help-block,
+.help-inline {
+  color: #555555;
+}
+
+.help-block {
+  display: block;
+  margin-bottom: 9px;
+}
+
+.help-inline {
+  display: inline-block;
+  *display: inline;
+  padding-left: 5px;
+  vertical-align: middle;
+  *zoom: 1;
+}
+
+.input-prepend,
+.input-append {
+  margin-bottom: 5px;
+}
+
+.input-prepend input,
+.input-append input,
+.input-prepend select,
+.input-append select,
+.input-prepend .uneditable-input,
+.input-append .uneditable-input {
+  position: relative;
+  margin-bottom: 0;
+  *margin-left: 0;
+  vertical-align: middle;
+  -webkit-border-radius: 0 3px 3px 0;
+     -moz-border-radius: 0 3px 3px 0;
+          border-radius: 0 3px 3px 0;
+}
+
+.input-prepend input:focus,
+.input-append input:focus,
+.input-prepend select:focus,
+.input-append select:focus,
+.input-prepend .uneditable-input:focus,
+.input-append .uneditable-input:focus {
+  z-index: 2;
+}
+
+.input-prepend .uneditable-input,
+.input-append .uneditable-input {
+  border-left-color: #ccc;
+}
+
+.input-prepend .add-on,
+.input-append .add-on {
+  display: inline-block;
+  width: auto;
+  height: 18px;
+  min-width: 16px;
+  padding: 4px 5px;
+  font-weight: normal;
+  line-height: 18px;
+  text-align: center;
+  text-shadow: 0 1px 0 #ffffff;
+  vertical-align: middle;
+  background-color: #eeeeee;
+  border: 1px solid #ccc;
+}
+
+.input-prepend .add-on,
+.input-append .add-on,
+.input-prepend .btn,
+.input-append .btn {
+  margin-left: -1px;
+  -webkit-border-radius: 0;
+     -moz-border-radius: 0;
+          border-radius: 0;
+}
+
+.input-prepend .active,
+.input-append .active {
+  background-color: #a9dba9;
+  border-color: #46a546;
+}
+
+.input-prepend .add-on,
+.input-prepend .btn {
+  margin-right: -1px;
+}
+
+.input-prepend .add-on:first-child,
+.input-prepend .btn:first-child {
+  -webkit-border-radius: 3px 0 0 3px;
+     -moz-border-radius: 3px 0 0 3px;
+          border-radius: 3px 0 0 3px;
+}
+
+.input-append input,
+.input-append select,
+.input-append .uneditable-input {
+  -webkit-border-radius: 3px 0 0 3px;
+     -moz-border-radius: 3px 0 0 3px;
+          border-radius: 3px 0 0 3px;
+}
+
+.input-append .uneditable-input {
+  border-right-color: #ccc;
+  border-left-color: #eee;
+}
+
+.input-append .add-on:last-child,
+.input-append .btn:last-child {
+  -webkit-border-radius: 0 3px 3px 0;
+     -moz-border-radius: 0 3px 3px 0;
+          border-radius: 0 3px 3px 0;
+}
+
+.input-prepend.input-append input,
+.input-prepend.input-append select,
+.input-prepend.input-append .uneditable-input {
+  -webkit-border-radius: 0;
+     -moz-border-radius: 0;
+          border-radius: 0;
+}
+
+.input-prepend.input-append .add-on:first-child,
+.input-prepend.input-append .btn:first-child {
+  margin-right: -1px;
+  -webkit-border-radius: 3px 0 0 3px;
+     -moz-border-radius: 3px 0 0 3px;
+          border-radius: 3px 0 0 3px;
+}
+
+.input-prepend.input-append .add-on:last-child,
+.input-prepend.input-append .btn:last-child {
+  margin-left: -1px;
+  -webkit-border-radius: 0 3px 3px 0;
+     -moz-border-radius: 0 3px 3px 0;
+          border-radius: 0 3px 3px 0;
+}
+
+.search-query {
+  padding-right: 14px;
+  padding-right: 4px \9;
+  padding-left: 14px;
+  padding-left: 4px \9;
+  /* IE7-8 doesn't have border-radius, so don't indent the padding */
+
+  margin-bottom: 0;
+  -webkit-border-radius: 14px;
+     -moz-border-radius: 14px;
+          border-radius: 14px;
+}
+
+.form-search input,
+.form-inline input,
+.form-horizontal input,
+.form-search textarea,
+.form-inline textarea,
+.form-horizontal textarea,
+.form-search select,
+.form-inline select,
+.form-horizontal select,
+.form-search .help-inline,
+.form-inline .help-inline,
+.form-horizontal .help-inline,
+.form-search .uneditable-input,
+.form-inline .uneditable-input,
+.form-horizontal .uneditable-input,
+.form-search .input-prepend,
+.form-inline .input-prepend,
+.form-horizontal .input-prepend,
+.form-search .input-append,
+.form-inline .input-append,
+.form-horizontal .input-append {
+  display: inline-block;
+  *display: inline;
+  margin-bottom: 0;
+  *zoom: 1;
+}
+
+.form-search .hide,
+.form-inline .hide,
+.form-horizontal .hide {
+  display: none;
+}
+
+.form-search label,
+.form-inline label {
+  display: inline-block;
+}
+
+.form-search .input-append,
+.form-inline .input-append,
+.form-search .input-prepend,
+.form-inline .input-prepend {
+  margin-bottom: 0;
+}
+
+.form-search .radio,
+.form-search .checkbox,
+.form-inline .radio,
+.form-inline .checkbox {
+  padding-left: 0;
+  margin-bottom: 0;
+  vertical-align: middle;
+}
+
+.form-search .radio input[type="radio"],
+.form-search .checkbox input[type="checkbox"],
+.form-inline .radio input[type="radio"],
+.form-inline .checkbox input[type="checkbox"] {
+  float: left;
+  margin-right: 3px;
+  margin-left: 0;
+}
+
+.control-group {
+  margin-bottom: 9px;
+}
+
+legend + .control-group {
+  margin-top: 18px;
+  -webkit-margin-top-collapse: separate;
+}
+
+.form-horizontal .control-group {
+  margin-bottom: 18px;
+  *zoom: 1;
+}
+
+.form-horizontal .control-group:before,
+.form-horizontal .control-group:after {
+  display: table;
+  content: "";
+}
+
+.form-horizontal .control-group:after {
+  clear: both;
+}
+
+.form-horizontal .control-label {
+  float: left;
+  width: 140px;
+  padding-top: 5px;
+  text-align: right;
+}
+
+.form-horizontal .controls {
+  *display: inline-block;
+  *padding-left: 20px;
+  margin-left: 160px;
+  *margin-left: 0;
+}
+
+.form-horizontal .controls:first-child {
+  *padding-left: 160px;
+}
+
+.form-horizontal .help-block {
+  margin-top: 9px;
+  margin-bottom: 0;
+}
+
+.form-horizontal .form-actions {
+  padding-left: 160px;
+}
+
+table {
+  max-width: 100%;
+  background-color: transparent;
+  border-collapse: collapse;
+  border-spacing: 0;
+}
+
+.table {
+  width: 100%;
+  margin-bottom: 18px;
+}
+
+.table th,
+.table td {
+  padding: 8px;
+  line-height: 18px;
+  text-align: left;
+  vertical-align: top;
+  border-top: 1px solid #dddddd;
+}
+
+.table th {
+  font-weight: bold;
+}
+
+.table thead th {
+  vertical-align: bottom;
+}
+
+.table caption + thead tr:first-child th,
+.table caption + thead tr:first-child td,
+.table colgroup + thead tr:first-child th,
+.table colgroup + thead tr:first-child td,
+.table thead:first-child tr:first-child th,
+.table thead:first-child tr:first-child td {
+  border-top: 0;
+}
+
+.table tbody + tbody {
+  border-top: 2px solid #dddddd;
+}
+
+.table-condensed th,
+.table-condensed td {
+  padding: 4px 5px;
+}
+
+.table-bordered {
+  border: 1px solid #dddddd;
+  border-collapse: separate;
+  *border-collapse: collapsed;
+  border-left: 0;
+  -webkit-border-radius: 4px;
+     -moz-border-radius: 4px;
+          border-radius: 4px;
+}
+
+.table-bordered th,
+.table-bordered td {
+  border-left: 1px solid #dddddd;
+}
+
+.table-bordered caption + thead tr:first-child th,
+.table-bordered caption + tbody tr:first-child th,
+.table-bordered caption + tbody tr:first-child td,
+.table-bordered colgroup + thead tr:first-child th,
+.table-bordered colgroup + tbody tr:first-child th,
+.table-bordered colgroup + tbody tr:first-child td,
+.table-bordered thead:first-child tr:first-child th,
+.table-bordered tbody:first-child tr:first-child th,
+.table-bordered tbody:first-child tr:first-child td {
+  border-top: 0;
+}
+
+.table-bordered thead:first-child tr:first-child th:first-child,
+.table-bordered tbody:first-child tr:first-child td:first-child {
+  -webkit-border-top-left-radius: 4px;
+          border-top-left-radius: 4px;
+  -moz-border-radius-topleft: 4px;
+}
+
+.table-bordered thead:first-child tr:first-child th:last-child,
+.table-bordered tbody:first-child tr:first-child td:last-child {
+  -webkit-border-top-right-radius: 4px;
+          border-top-right-radius: 4px;
+  -moz-border-radius-topright: 4px;
+}
+
+.table-bordered thead:last-child tr:last-child th:first-child,
+.table-bordered tbody:last-child tr:last-child td:first-child {
+  -webkit-border-radius: 0 0 0 4px;
+     -moz-border-radius: 0 0 0 4px;
+          border-radius: 0 0 0 4px;
+  -webkit-border-bottom-left-radius: 4px;
+          border-bottom-left-radius: 4px;
+  -moz-border-radius-bottomleft: 4px;
+}
+
+.table-bordered thead:last-child tr:last-child th:last-child,
+.table-bordered tbody:last-child tr:last-child td:last-child {
+  -webkit-border-bottom-right-radius: 4px;
+          border-bottom-right-radius: 4px;
+  -moz-border-radius-bottomright: 4px;
+}
+
+.table-striped tbody tr:nth-child(odd) td,
+.table-striped tbody tr:nth-child(odd) th {
+  background-color: #f9f9f9;
+}
+
+.table tbody tr:hover td,
+.table tbody tr:hover th {
+  background-color: #f5f5f5;
+}
+
+table .span1 {
+  float: none;
+  width: 44px;
+  margin-left: 0;
+}
+
+table .span2 {
+  float: none;
+  width: 124px;
+  margin-left: 0;
+}
+
+table .span3 {
+  float: none;
+  width: 204px;
+  margin-left: 0;
+}
+
+table .span4 {
+  float: none;
+  width: 284px;
+  margin-left: 0;
+}
+
+table .span5 {
+  float: none;
+  width: 364px;
+  margin-left: 0;
+}
+
+table .span6 {
+  float: none;
+  width: 444px;
+  margin-left: 0;
+}
+
+table .span7 {
+  float: none;
+  width: 524px;
+  margin-left: 0;
+}
+
+table .span8 {
+  float: none;
+  width: 604px;
+  margin-left: 0;
+}
+
+table .span9 {
+  float: none;
+  width: 684px;
+  margin-left: 0;
+}
+
+table .span10 {
+  float: none;
+  width: 764px;
+  margin-left: 0;
+}
+
+table .span11 {
+  float: none;
+  width: 844px;
+  margin-left: 0;
+}
+
+table .span12 {
+  float: none;
+  width: 924px;
+  margin-left: 0;
+}
+
+table .span13 {
+  float: none;
+  width: 1004px;
+  margin-left: 0;
+}
+
+table .span14 {
+  float: none;
+  width: 1084px;
+  margin-left: 0;
+}
+
+table .span15 {
+  float: none;
+  width: 1164px;
+  margin-left: 0;
+}
+
+table .span16 {
+  float: none;
+  width: 1244px;
+  margin-left: 0;
+}
+
+table .span17 {
+  float: none;
+  width: 1324px;
+  margin-left: 0;
+}
+
+table .span18 {
+  float: none;
+  width: 1404px;
+  margin-left: 0;
+}
+
+table .span19 {
+  float: none;
+  width: 1484px;
+  margin-left: 0;
+}
+
+table .span20 {
+  float: none;
+  width: 1564px;
+  margin-left: 0;
+}
+
+table .span21 {
+  float: none;
+  width: 1644px;
+  margin-left: 0;
+}
+
+table .span22 {
+  float: none;
+  width: 1724px;
+  margin-left: 0;
+}
+
+table .span23 {
+  float: none;
+  width: 1804px;
+  margin-left: 0;
+}
+
+table .span24 {
+  float: none;
+  width: 1884px;
+  margin-left: 0;
+}
+
+[class^="icon-"],
+[class*=" icon-"] {
+  display: inline-block;
+  width: 14px;
+  height: 14px;
+  *margin-right: .3em;
+  line-height: 14px;
+  vertical-align: text-top;
+  background-image: url("../img/glyphicons-halflings.png");
+  background-position: 14px 14px;
+  background-repeat: no-repeat;
+}
+
+[class^="icon-"]:last-child,
+[class*=" icon-"]:last-child {
+  *margin-left: 0;
+}
+
+.icon-white {
+  background-image: url("../img/glyphicons-halflings-white.png");
+}
+
+.icon-glass {
+  background-position: 0      0;
+}
+
+.icon-music {
+  background-position: -24px 0;
+}
+
+.icon-search {
+  background-position: -48px 0;
+}
+
+.icon-envelope {
+  background-position: -72px 0;
+}
+
+.icon-heart {
+  background-position: -96px 0;
+}
+
+.icon-star {
+  background-position: -120px 0;
+}
+
+.icon-star-empty {
+  background-position: -144px 0;
+}
+
+.icon-user {
+  background-position: -168px 0;
+}
+
+.icon-film {
+  background-position: -192px 0;
+}
+
+.icon-th-large {
+  background-position: -216px 0;
+}
+
+.icon-th {
+  background-position: -240px 0;
+}
+
+.icon-th-list {
+  background-position: -264px 0;
+}
+
+.icon-ok {
+  background-position: -288px 0;
+}
+
+.icon-remove {
+  background-position: -312px 0;
+}
+
+.icon-zoom-in {
+  background-position: -336px 0;
+}
+
+.icon-zoom-out {
+  background-position: -360px 0;
+}
+
+.icon-off {
+  background-position: -384px 0;
+}
+
+.icon-signal {
+  background-position: -408px 0;
+}
+
+.icon-cog {
+  background-position: -432px 0;
+}
+
+.icon-trash {
+  background-position: -456px 0;
+}
+
+.icon-home {
+  background-position: 0 -24px;
+}
+
+.icon-file {
+  background-position: -24px -24px;
+}
+
+.icon-time {
+  background-position: -48px -24px;
+}
+
+.icon-road {
+  background-position: -72px -24px;
+}
+
+.icon-download-alt {
+  background-position: -96px -24px;
+}
+
+.icon-download {
+  background-position: -120px -24px;
+}
+
+.icon-upload {
+  background-position: -144px -24px;
+}
+
+.icon-inbox {
+  background-position: -168px -24px;
+}
+
+.icon-play-circle {
+  background-position: -192px -24px;
+}
+
+.icon-repeat {
+  background-position: -216px -24px;
+}
+
+.icon-refresh {
+  background-position: -240px -24px;
+}
+
+.icon-list-alt {
+  background-position: -264px -24px;
+}
+
+.icon-lock {
+  background-position: -287px -24px;
+}
+
+.icon-flag {
+  background-position: -312px -24px;
+}
+
+.icon-headphones {
+  background-position: -336px -24px;
+}
+
+.icon-volume-off {
+  background-position: -360px -24px;
+}
+
+.icon-volume-down {
+  background-position: -384px -24px;
+}
+
+.icon-volume-up {
+  background-position: -408px -24px;
+}
+
+.icon-qrcode {
+  background-position: -432px -24px;
+}
+
+.icon-barcode {
+  background-position: -456px -24px;
+}
+
+.icon-tag {
+  background-position: 0 -48px;
+}
+
+.icon-tags {
+  background-position: -25px -48px;
+}
+
+.icon-book {
+  background-position: -48px -48px;
+}
+
+.icon-bookmark {
+  background-position: -72px -48px;
+}
+
+.icon-print {
+  background-position: -96px -48px;
+}
+
+.icon-camera {
+  background-position: -120px -48px;
+}
+
+.icon-font {
+  background-position: -144px -48px;
+}
+
+.icon-bold {
+  background-position: -167px -48px;
+}
+
+.icon-italic {
+  background-position: -192px -48px;
+}
+
+.icon-text-height {
+  background-position: -216px -48px;
+}
+
+.icon-text-width {
+  background-position: -240px -48px;
+}
+
+.icon-align-left {
+  background-position: -264px -48px;
+}
+
+.icon-align-center {
+  background-position: -288px -48px;
+}
+
+.icon-align-right {
+  background-position: -312px -48px;
+}
+
+.icon-align-justify {
+  background-position: -336px -48px;
+}
+
+.icon-list {
+  background-position: -360px -48px;
+}
+
+.icon-indent-left {
+  background-position: -384px -48px;
+}
+
+.icon-indent-right {
+  background-position: -408px -48px;
+}
+
+.icon-facetime-video {
+  background-position: -432px -48px;
+}
+
+.icon-picture {
+  background-position: -456px -48px;
+}
+
+.icon-pencil {
+  background-position: 0 -72px;
+}
+
+.icon-map-marker {
+  background-position: -24px -72px;
+}
+
+.icon-adjust {
+  background-position: -48px -72px;
+}
+
+.icon-tint {
+  background-position: -72px -72px;
+}
+
+.icon-edit {
+  background-position: -96px -72px;
+}
+
+.icon-share {
+  background-position: -120px -72px;
+}
+
+.icon-check {
+  background-position: -144px -72px;
+}
+
+.icon-move {
+  background-position: -168px -72px;
+}
+
+.icon-step-backward {
+  background-position: -192px -72px;
+}
+
+.icon-fast-backward {
+  background-position: -216px -72px;
+}
+
+.icon-backward {
+  background-position: -240px -72px;
+}
+
+.icon-play {
+  background-position: -264px -72px;
+}
+
+.icon-pause {
+  background-position: -288px -72px;
+}
+
+.icon-stop {
+  background-position: -312px -72px;
+}
+
+.icon-forward {
+  background-position: -336px -72px;
+}
+
+.icon-fast-forward {
+  background-position: -360px -72px;
+}
+
+.icon-step-forward {
+  background-position: -384px -72px;
+}
+
+.icon-eject {
+  background-position: -408px -72px;
+}
+
+.icon-chevron-left {
+  background-position: -432px -72px;
+}
+
+.icon-chevron-right {
+  background-position: -456px -72px;
+}
+
+.icon-plus-sign {
+  background-position: 0 -96px;
+}
+
+.icon-minus-sign {
+  background-position: -24px -96px;
+}
+
+.icon-remove-sign {
+  background-position: -48px -96px;
+}
+
+.icon-ok-sign {
+  background-position: -72px -96px;
+}
+
+.icon-question-sign {
+  background-position: -96px -96px;
+}
+
+.icon-info-sign {
+  background-position: -120px -96px;
+}
+
+.icon-screenshot {
+  background-position: -144px -96px;
+}
+
+.icon-remove-circle {
+  background-position: -168px -96px;
+}
+
+.icon-ok-circle {
+  background-position: -192px -96px;
+}
+
+.icon-ban-circle {
+  background-position: -216px -96px;
+}
+
+.icon-arrow-left {
+  background-position: -240px -96px;
+}
+
+.icon-arrow-right {
+  background-position: -264px -96px;
+}
+
+.icon-arrow-up {
+  background-position: -289px -96px;
+}
+
+.icon-arrow-down {
+  background-position: -312px -96px;
+}
+
+.icon-share-alt {
+  background-position: -336px -96px;
+}
+
+.icon-resize-full {
+  background-position: -360px -96px;
+}
+
+.icon-resize-small {
+  background-position: -384px -96px;
+}
+
+.icon-plus {
+  background-position: -408px -96px;
+}
+
+.icon-minus {
+  background-position: -433px -96px;
+}
+
+.icon-asterisk {
+  background-position: -456px -96px;
+}
+
+.icon-exclamation-sign {
+  background-position: 0 -120px;
+}
+
+.icon-gift {
+  background-position: -24px -120px;
+}
+
+.icon-leaf {
+  background-position: -48px -120px;
+}
+
+.icon-fire {
+  background-position: -72px -120px;
+}
+
+.icon-eye-open {
+  background-position: -96px -120px;
+}
+
+.icon-eye-close {
+  background-position: -120px -120px;
+}
+
+.icon-warning-sign {
+  background-position: -144px -120px;
+}
+
+.icon-plane {
+  background-position: -168px -120px;
+}
+
+.icon-calendar {
+  background-position: -192px -120px;
+}
+
+.icon-random {
+  background-position: -216px -120px;
+}
+
+.icon-comment {
+  background-position: -240px -120px;
+}
+
+.icon-magnet {
+  background-position: -264px -120px;
+}
+
+.icon-chevron-up {
+  background-position: -288px -120px;
+}
+
+.icon-chevron-down {
+  background-position: -313px -119px;
+}
+
+.icon-retweet {
+  background-position: -336px -120px;
+}
+
+.icon-shopping-cart {
+  background-position: -360px -120px;
+}
+
+.icon-folder-close {
+  background-position: -384px -120px;
+}
+
+.icon-folder-open {
+  background-position: -408px -120px;
+}
+
+.icon-resize-vertical {
+  background-position: -432px -119px;
+}
+
+.icon-resize-horizontal {
+  background-position: -456px -118px;
+}
+
+.icon-hdd {
+  background-position: 0 -144px;
+}
+
+.icon-bullhorn {
+  background-position: -24px -144px;
+}
+
+.icon-bell {
+  background-position: -48px -144px;
+}
+
+.icon-certificate {
+  background-position: -72px -144px;
+}
+
+.icon-thumbs-up {
+  background-position: -96px -144px;
+}
+
+.icon-thumbs-down {
+  background-position: -120px -144px;
+}
+
+.icon-hand-right {
+  background-position: -144px -144px;
+}
+
+.icon-hand-left {
+  background-position: -168px -144px;
+}
+
+.icon-hand-up {
+  background-position: -192px -144px;
+}
+
+.icon-hand-down {
+  background-position: -216px -144px;
+}
+
+.icon-circle-arrow-right {
+  background-position: -240px -144px;
+}
+
+.icon-circle-arrow-left {
+  background-position: -264px -144px;
+}
+
+.icon-circle-arrow-up {
+  background-position: -288px -144px;
+}
+
+.icon-circle-arrow-down {
+  background-position: -312px -144px;
+}
+
+.icon-globe {
+  background-position: -336px -144px;
+}
+
+.icon-wrench {
+  background-position: -360px -144px;
+}
+
+.icon-tasks {
+  background-position: -384px -144px;
+}
+
+.icon-filter {
+  background-position: -408px -144px;
+}
+
+.icon-briefcase {
+  background-position: -432px -144px;
+}
+
+.icon-fullscreen {
+  background-position: -456px -144px;
+}
+
+.dropup,
+.dropdown {
+  position: relative;
+}
+
+.dropdown-toggle {
+  *margin-bottom: -3px;
+}
+
+.dropdown-toggle:active,
+.open .dropdown-toggle {
+  outline: 0;
+}
+
+.caret {
+  display: inline-block;
+  width: 0;
+  height: 0;
+  vertical-align: top;
+  border-top: 4px solid #000000;
+  border-right: 4px solid transparent;
+  border-left: 4px solid transparent;
+  content: "";
+  opacity: 0.3;
+  filter: alpha(opacity=30);
+}
+
+.dropdown .caret {
+  margin-top: 8px;
+  margin-left: 2px;
+}
+
+.dropdown:hover .caret,
+.open .caret {
+  opacity: 1;
+  filter: alpha(opacity=100);
+}
+
+.dropdown-menu {
+  position: absolute;
+  top: 100%;
+  left: 0;
+  z-index: 1000;
+  display: none;
+  float: left;
+  min-width: 160px;
+  padding: 4px 0;
+  margin: 1px 0 0;
+  list-style: none;
+  background-color: #ffffff;
+  border: 1px solid #ccc;
+  border: 1px solid rgba(0, 0, 0, 0.2);
+  *border-right-width: 2px;
+  *border-bottom-width: 2px;
+  -webkit-border-radius: 5px;
+     -moz-border-radius: 5px;
+          border-radius: 5px;
+  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+     -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+          box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+  -webkit-background-clip: padding-box;
+     -moz-background-clip: padding;
+          background-clip: padding-box;
+}
+
+.dropdown-menu.pull-right {
+  right: 0;
+  left: auto;
+}
+
+.dropdown-menu .divider {
+  *width: 100%;
+  height: 1px;
+  margin: 8px 1px;
+  *margin: -5px 0 5px;
+  overflow: hidden;
+  background-color: #e5e5e5;
+  border-bottom: 1px solid #ffffff;
+}
+
+.dropdown-menu a {
+  display: block;
+  padding: 3px 15px;
+  clear: both;
+  font-weight: normal;
+  line-height: 18px;
+  color: #333333;
+  white-space: nowrap;
+}
+
+.dropdown-menu li > a:hover,
+.dropdown-menu .active > a,
+.dropdown-menu .active > a:hover {
+  color: #ffffff;
+  text-decoration: none;
+  background-color: #0088cc;
+}
+
+.open {
+  *z-index: 1000;
+}
+
+.open > .dropdown-menu {
+  display: block;
+}
+
+.pull-right > .dropdown-menu {
+  right: 0;
+  left: auto;
+}
+
+.dropup .caret,
+.navbar-fixed-bottom .dropdown .caret {
+  border-top: 0;
+  border-bottom: 4px solid #000000;
+  content: "\2191";
+}
+
+.dropup .dropdown-menu,
+.navbar-fixed-bottom .dropdown .dropdown-menu {
+  top: auto;
+  bottom: 100%;
+  margin-bottom: 1px;
+}
+
+.typeahead {
+  margin-top: 2px;
+  -webkit-border-radius: 4px;
+     -moz-border-radius: 4px;
+          border-radius: 4px;
+}
+
+.well {
+  min-height: 20px;
+  padding: 19px;
+  margin-bottom: 20px;
+  background-color: #f5f5f5;
+  border: 1px solid #eee;
+  border: 1px solid rgba(0, 0, 0, 0.05);
+  -webkit-border-radius: 4px;
+     -moz-border-radius: 4px;
+          border-radius: 4px;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+}
+
+.well blockquote {
+  border-color: #ddd;
+  border-color: rgba(0, 0, 0, 0.15);
+}
+
+.well-large {
+  padding: 24px;
+  -webkit-border-radius: 6px;
+     -moz-border-radius: 6px;
+          border-radius: 6px;
+}
+
+.well-small {
+  padding: 9px;
+  -webkit-border-radius: 3px;
+     -moz-border-radius: 3px;
+          border-radius: 3px;
+}
+
+.fade {
+  opacity: 0;
+  -webkit-transition: opacity 0.15s linear;
+     -moz-transition: opacity 0.15s linear;
+      -ms-transition: opacity 0.15s linear;
+       -o-transition: opacity 0.15s linear;
+          transition: opacity 0.15s linear;
+}
+
+.fade.in {
+  opacity: 1;
+}
+
+.collapse {
+  position: relative;
+  height: 0;
+  overflow: hidden;
+  -webkit-transition: height 0.35s ease;
+     -moz-transition: height 0.35s ease;
+      -ms-transition: height 0.35s ease;
+       -o-transition: height 0.35s ease;
+          transition: height 0.35s ease;
+}
+
+.collapse.in {
+  height: auto;
+}
+
+.close {
+  float: right;
+  font-size: 20px;
+  font-weight: bold;
+  line-height: 18px;
+  color: #000000;
+  text-shadow: 0 1px 0 #ffffff;
+  opacity: 0.2;
+  filter: alpha(opacity=20);
+}
+
+.close:hover {
+  color: #000000;
+  text-decoration: none;
+  cursor: pointer;
+  opacity: 0.4;
+  filter: alpha(opacity=40);
+}
+
+button.close {
+  padding: 0;
+  cursor: pointer;
+  background: transparent;
+  border: 0;
+  -webkit-appearance: none;
+}
+
+.btn {
+  display: inline-block;
+  *display: inline;
+  padding: 4px 10px 4px;
+  margin-bottom: 0;
+  *margin-left: .3em;
+  font-size: 13px;
+  line-height: 18px;
+  *line-height: 20px;
+  color: #333333;
+  text-align: center;
+  text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
+  vertical-align: middle;
+  cursor: pointer;
+  background-color: #f5f5f5;
+  *background-color: #e6e6e6;
+  background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6);
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));
+  background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);
+  background-image: -o-linear-gradient(top, #ffffff, #e6e6e6);
+  background-image: linear-gradient(top, #ffffff, #e6e6e6);
+  background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);
+  background-repeat: repeat-x;
+  border: 1px solid #cccccc;
+  *border: 0;
+  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+  border-color: #e6e6e6 #e6e6e6 #bfbfbf;
+  border-bottom-color: #b3b3b3;
+  -webkit-border-radius: 4px;
+     -moz-border-radius: 4px;
+          border-radius: 4px;
+  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);
+  filter: progid:dximagetransform.microsoft.gradient(enabled=false);
+  *zoom: 1;
+  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+     -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+          box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+}
+
+.btn:hover,
+.btn:active,
+.btn.active,
+.btn.disabled,
+.btn[disabled] {
+  background-color: #e6e6e6;
+  *background-color: #d9d9d9;
+}
+
+.btn:active,
+.btn.active {
+  background-color: #cccccc \9;
+}
+
+.btn:first-child {
+  *margin-left: 0;
+}
+
+.btn:hover {
+  color: #333333;
+  text-decoration: none;
+  background-color: #e6e6e6;
+  *background-color: #d9d9d9;
+  /* Buttons in IE7 don't get borders, so darken on hover */
+
+  background-position: 0 -15px;
+  -webkit-transition: background-position 0.1s linear;
+     -moz-transition: background-position 0.1s linear;
+      -ms-transition: background-position 0.1s linear;
+       -o-transition: background-position 0.1s linear;
+          transition: background-position 0.1s linear;
+}
+
+.btn:focus {
+  outline: thin dotted #333;
+  outline: 5px auto -webkit-focus-ring-color;
+  outline-offset: -2px;
+}
+
+.btn.active,
+.btn:active {
+  background-color: #e6e6e6;
+  background-color: #d9d9d9 \9;
+  background-image: none;
+  outline: 0;
+  -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
+     -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
+          box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
+}
+
+.btn.disabled,
+.btn[disabled] {
+  cursor: default;
+  background-color: #e6e6e6;
+  background-image: none;
+  opacity: 0.65;
+  filter: alpha(opacity=65);
+  -webkit-box-shadow: none;
+     -moz-box-shadow: none;
+          box-shadow: none;
+}
+
+.btn-large {
+  padding: 9px 14px;
+  font-size: 15px;
+  line-height: normal;
+  -webkit-border-radius: 5px;
+     -moz-border-radius: 5px;
+          border-radius: 5px;
+}
+
+.btn-large [class^="icon-"] {
+  margin-top: 1px;
+}
+
+.btn-small {
+  padding: 5px 9px;
+  font-size: 11px;
+  line-height: 16px;
+}
+
+.btn-small [class^="icon-"] {
+  margin-top: -1px;
+}
+
+.btn-mini {
+  padding: 2px 6px;
+  font-size: 11px;
+  line-height: 14px;
+}
+
+.btn-primary,
+.btn-primary:hover,
+.btn-warning,
+.btn-warning:hover,
+.btn-danger,
+.btn-danger:hover,
+.btn-success,
+.btn-success:hover,
+.btn-info,
+.btn-info:hover,
+.btn-inverse,
+.btn-inverse:hover {
+  color: #ffffff;
+  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+}
+
+.btn-primary.active,
+.btn-warning.active,
+.btn-danger.active,
+.btn-success.active,
+.btn-info.active,
+.btn-inverse.active {
+  color: rgba(255, 255, 255, 0.75);
+}
+
+.btn {
+  border-color: #ccc;
+  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+}
+
+.btn-primary {
+  background-color: #0074cc;
+  *background-color: #0055cc;
+  background-image: -ms-linear-gradient(top, #0088cc, #0055cc);
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0055cc));
+  background-image: -webkit-linear-gradient(top, #0088cc, #0055cc);
+  background-image: -o-linear-gradient(top, #0088cc, #0055cc);
+  background-image: -moz-linear-gradient(top, #0088cc, #0055cc);
+  background-image: linear-gradient(top, #0088cc, #0055cc);
+  background-repeat: repeat-x;
+  border-color: #0055cc #0055cc #003580;
+  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#0088cc', endColorstr='#0055cc', GradientType=0);
+  filter: progid:dximagetransform.microsoft.gradient(enabled=false);
+}
+
+.btn-primary:hover,
+.btn-primary:active,
+.btn-primary.active,
+.btn-primary.disabled,
+.btn-primary[disabled] {
+  background-color: #0055cc;
+  *background-color: #004ab3;
+}
+
+.btn-primary:active,
+.btn-primary.active {
+  background-color: #004099 \9;
+}
+
+.btn-warning {
+  background-color: #faa732;
+  *background-color: #f89406;
+  background-image: -ms-linear-gradient(top, #fbb450, #f89406);
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));
+  background-image: -webkit-linear-gradient(top, #fbb450, #f89406);
+  background-image: -o-linear-gradient(top, #fbb450, #f89406);
+  background-image: -moz-linear-gradient(top, #fbb450, #f89406);
+  background-image: linear-gradient(top, #fbb450, #f89406);
+  background-repeat: repeat-x;
+  border-color: #f89406 #f89406 #ad6704;
+  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);
+  filter: progid:dximagetransform.microsoft.gradient(enabled=false);
+}
+
+.btn-warning:hover,
+.btn-warning:active,
+.btn-warning.active,
+.btn-warning.disabled,
+.btn-warning[disabled] {
+  background-color: #f89406;
+  *background-color: #df8505;
+}
+
+.btn-warning:active,
+.btn-warning.active {
+  background-color: #c67605 \9;
+}
+
+.btn-danger {
+  background-color: #da4f49;
+  *background-color: #bd362f;
+  background-image: -ms-linear-gradient(top, #ee5f5b, #bd362f);
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));
+  background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f);
+  background-image: -o-linear-gradient(top, #ee5f5b, #bd362f);
+  background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f);
+  background-image: linear-gradient(top, #ee5f5b, #bd362f);
+  background-repeat: repeat-x;
+  border-color: #bd362f #bd362f #802420;
+  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0);
+  filter: progid:dximagetransform.microsoft.gradient(enabled=false);
+}
+
+.btn-danger:hover,
+.btn-danger:active,
+.btn-danger.active,
+.btn-danger.disabled,
+.btn-danger[disabled] {
+  background-color: #bd362f;
+  *background-color: #a9302a;
+}
+
+.btn-danger:active,
+.btn-danger.active {
+  background-color: #942a25 \9;
+}
+
+.btn-success {
+  background-color: #5bb75b;
+  *background-color: #51a351;
+  background-image: -ms-linear-gradient(top, #62c462, #51a351);
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));
+  background-image: -webkit-linear-gradient(top, #62c462, #51a351);
+  background-image: -o-linear-gradient(top, #62c462, #51a351);
+  background-image: -moz-linear-gradient(top, #62c462, #51a351);
+  background-image: linear-gradient(top, #62c462, #51a351);
+  background-repeat: repeat-x;
+  border-color: #51a351 #51a351 #387038;
+  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0);
+  filter: progid:dximagetransform.microsoft.gradient(enabled=false);
+}
+
+.btn-success:hover,
+.btn-success:active,
+.btn-success.active,
+.btn-success.disabled,
+.btn-success[disabled] {
+  background-color: #51a351;
+  *background-color: #499249;
+}
+
+.btn-success:active,
+.btn-success.active {
+  background-color: #408140 \9;
+}
+
+.btn-info {
+  background-color: #49afcd;
+  *background-color: #2f96b4;
+  background-image: -ms-linear-gradient(top, #5bc0de, #2f96b4);
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));
+  background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4);
+  background-image: -o-linear-gradient(top, #5bc0de, #2f96b4);
+  background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4);
+  background-image: linear-gradient(top, #5bc0de, #2f96b4);
+  background-repeat: repeat-x;
+  border-color: #2f96b4 #2f96b4 #1f6377;
+  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0);
+  filter: progid:dximagetransform.microsoft.gradient(enabled=false);
+}
+
+.btn-info:hover,
+.btn-info:active,
+.btn-info.active,
+.btn-info.disabled,
+.btn-info[disabled] {
+  background-color: #2f96b4;
+  *background-color: #2a85a0;
+}
+
+.btn-info:active,
+.btn-info.active {
+  background-color: #24748c \9;
+}
+
+.btn-inverse {
+  background-color: #414141;
+  *background-color: #222222;
+  background-image: -ms-linear-gradient(top, #555555, #222222);
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#555555), to(#222222));
+  background-image: -webkit-linear-gradient(top, #555555, #222222);
+  background-image: -o-linear-gradient(top, #555555, #222222);
+  background-image: -moz-linear-gradient(top, #555555, #222222);
+  background-image: linear-gradient(top, #555555, #222222);
+  background-repeat: repeat-x;
+  border-color: #222222 #222222 #000000;
+  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#555555', endColorstr='#222222', GradientType=0);
+  filter: progid:dximagetransform.microsoft.gradient(enabled=false);
+}
+
+.btn-inverse:hover,
+.btn-inverse:active,
+.btn-inverse.active,
+.btn-inverse.disabled,
+.btn-inverse[disabled] {
+  background-color: #222222;
+  *background-color: #151515;
+}
+
+.btn-inverse:active,
+.btn-inverse.active {
+  background-color: #080808 \9;
+}
+
+button.btn,
+input[type="submit"].btn {
+  *padding-top: 2px;
+  *padding-bottom: 2px;
+}
+
+button.btn::-moz-focus-inner,
+input[type="submit"].btn::-moz-focus-inner {
+  padding: 0;
+  border: 0;
+}
+
+button.btn.btn-large,
+input[type="submit"].btn.btn-large {
+  *padding-top: 7px;
+  *padding-bottom: 7px;
+}
+
+button.btn.btn-small,
+input[type="submit"].btn.btn-small {
+  *padding-top: 3px;
+  *padding-bottom: 3px;
+}
+
+button.btn.btn-mini,
+input[type="submit"].btn.btn-mini {
+  *padding-top: 1px;
+  *padding-bottom: 1px;
+}
+
+.btn-group {
+  position: relative;
+  *margin-left: .3em;
+  *zoom: 1;
+}
+
+.btn-group:before,
+.btn-group:after {
+  display: table;
+  content: "";
+}
+
+.btn-group:after {
+  clear: both;
+}
+
+.btn-group:first-child {
+  *margin-left: 0;
+}
+
+.btn-group + .btn-group {
+  margin-left: 5px;
+}
+
+.btn-toolbar {
+  margin-top: 9px;
+  margin-bottom: 9px;
+}
+
+.btn-toolbar .btn-group {
+  display: inline-block;
+  *display: inline;
+  /* IE7 inline-block hack */
+
+  *zoom: 1;
+}
+
+.btn-group > .btn {
+  position: relative;
+  float: left;
+  margin-left: -1px;
+  -webkit-border-radius: 0;
+     -moz-border-radius: 0;
+          border-radius: 0;
+}
+
+.btn-group > .btn:first-child {
+  margin-left: 0;
+  -webkit-border-bottom-left-radius: 4px;
+          border-bottom-left-radius: 4px;
+  -webkit-border-top-left-radius: 4px;
+          border-top-left-radius: 4px;
+  -moz-border-radius-bottomleft: 4px;
+  -moz-border-radius-topleft: 4px;
+}
+
+.btn-group > .btn:last-child,
+.btn-group > .dropdown-toggle {
+  -webkit-border-top-right-radius: 4px;
+          border-top-right-radius: 4px;
+  -webkit-border-bottom-right-radius: 4px;
+          border-bottom-right-radius: 4px;
+  -moz-border-radius-topright: 4px;
+  -moz-border-radius-bottomright: 4px;
+}
+
+.btn-group > .btn.large:first-child {
+  margin-left: 0;
+  -webkit-border-bottom-left-radius: 6px;
+          border-bottom-left-radius: 6px;
+  -webkit-border-top-left-radius: 6px;
+          border-top-left-radius: 6px;
+  -moz-border-radius-bottomleft: 6px;
+  -moz-border-radius-topleft: 6px;
+}
+
+.btn-group > .btn.large:last-child,
+.btn-group > .large.dropdown-toggle {
+  -webkit-border-top-right-radius: 6px;
+          border-top-right-radius: 6px;
+  -webkit-border-bottom-right-radius: 6px;
+          border-bottom-right-radius: 6px;
+  -moz-border-radius-topright: 6px;
+  -moz-border-radius-bottomright: 6px;
+}
+
+.btn-group > .btn:hover,
+.btn-group > .btn:focus,
+.btn-group > .btn:active,
+.btn-group > .btn.active {
+  z-index: 2;
+}
+
+.btn-group .dropdown-toggle:active,
+.btn-group.open .dropdown-toggle {
+  outline: 0;
+}
+
+.btn-group > .dropdown-toggle {
+  *padding-top: 4px;
+  padding-right: 8px;
+  *padding-bottom: 4px;
+  padding-left: 8px;
+  -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+     -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+          box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+}
+
+.btn-group > .btn-mini.dropdown-toggle {
+  padding-right: 5px;
+  padding-left: 5px;
+}
+
+.btn-group > .btn-small.dropdown-toggle {
+  *padding-top: 4px;
+  *padding-bottom: 4px;
+}
+
+.btn-group > .btn-large.dropdown-toggle {
+  padding-right: 12px;
+  padding-left: 12px;
+}
+
+.btn-group.open .dropdown-toggle {
+  background-image: none;
+  -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
+     -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
+          box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
+}
+
+.btn-group.open .btn.dropdown-toggle {
+  background-color: #e6e6e6;
+}
+
+.btn-group.open .btn-primary.dropdown-toggle {
+  background-color: #0055cc;
+}
+
+.btn-group.open .btn-warning.dropdown-toggle {
+  background-color: #f89406;
+}
+
+.btn-group.open .btn-danger.dropdown-toggle {
+  background-color: #bd362f;
+}
+
+.btn-group.open .btn-success.dropdown-toggle {
+  background-color: #51a351;
+}
+
+.btn-group.open .btn-info.dropdown-toggle {
+  background-color: #2f96b4;
+}
+
+.btn-group.open .btn-inverse.dropdown-toggle {
+  background-color: #222222;
+}
+
+.btn .caret {
+  margin-top: 7px;
+  margin-left: 0;
+}
+
+.btn:hover .caret,
+.open.btn-group .caret {
+  opacity: 1;
+  filter: alpha(opacity=100);
+}
+
+.btn-mini .caret {
+  margin-top: 5px;
+}
+
+.btn-small .caret {
+  margin-top: 6px;
+}
+
+.btn-large .caret {
+  margin-top: 6px;
+  border-top-width: 5px;
+  border-right-width: 5px;
+  border-left-width: 5px;
+}
+
+.dropup .btn-large .caret {
+  border-top: 0;
+  border-bottom: 5px solid #000000;
+}
+
+.btn-primary .caret,
+.btn-warning .caret,
+.btn-danger .caret,
+.btn-info .caret,
+.btn-success .caret,
+.btn-inverse .caret {
+  border-top-color: #ffffff;
+  border-bottom-color: #ffffff;
+  opacity: 0.75;
+  filter: alpha(opacity=75);
+}
+
+.alert {
+  padding: 8px 35px 8px 14px;
+  margin-bottom: 18px;
+  color: #c09853;
+  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
+  background-color: #fcf8e3;
+  border: 1px solid #fbeed5;
+  -webkit-border-radius: 4px;
+     -moz-border-radius: 4px;
+          border-radius: 4px;
+}
+
+.alert-heading {
+  color: inherit;
+}
+
+.alert .close {
+  position: relative;
+  top: -2px;
+  right: -21px;
+  line-height: 18px;
+}
+
+.alert-success {
+  color: #468847;
+  background-color: #dff0d8;
+  border-color: #d6e9c6;
+}
+
+.alert-danger,
+.alert-error {
+  color: #b94a48;
+  background-color: #f2dede;
+  border-color: #eed3d7;
+}
+
+.alert-info {
+  color: #3a87ad;
+  background-color: #d9edf7;
+  border-color: #bce8f1;
+}
+
+.alert-block {
+  padding-top: 14px;
+  padding-bottom: 14px;
+}
+
+.alert-block > p,
+.alert-block > ul {
+  margin-bottom: 0;
+}
+
+.alert-block p + p {
+  margin-top: 5px;
+}
+
+.nav {
+  margin-bottom: 18px;
+  margin-left: 0;
+  list-style: none;
+}
+
+.nav > li > a {
+  display: block;
+}
+
+.nav > li > a:hover {
+  text-decoration: none;
+  background-color: #eeeeee;
+}
+
+.nav > .pull-right {
+  float: right;
+}
+
+.nav .nav-header {
+  display: block;
+  padding: 3px 15px;
+  font-size: 11px;
+  font-weight: bold;
+  line-height: 18px;
+  color: #999999;
+  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
+  text-transform: uppercase;
+}
+
+.nav li + .nav-header {
+  margin-top: 9px;
+}
+
+.nav-list {
+  padding-right: 15px;
+  padding-left: 15px;
+  margin-bottom: 0;
+}
+
+.nav-list > li > a,
+.nav-list .nav-header {
+  margin-right: -15px;
+  margin-left: -15px;
+  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
+}
+
+.nav-list > li > a {
+  padding: 3px 15px;
+}
+
+.nav-list > .active > a,
+.nav-list > .active > a:hover {
+  color: #ffffff;
+  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);
+  background-color: #0088cc;
+}
+
+.nav-list [class^="icon-"] {
+  margin-right: 2px;
+}
+
+.nav-list .divider {
+  *width: 100%;
+  height: 1px;
+  margin: 8px 1px;
+  *margin: -5px 0 5px;
+  overflow: hidden;
+  background-color: #e5e5e5;
+  border-bottom: 1px solid #ffffff;
+}
+
+.nav-tabs,
+.nav-pills {
+  *zoom: 1;
+}
+
+.nav-tabs:before,
+.nav-pills:before,
+.nav-tabs:after,
+.nav-pills:after {
+  display: table;
+  content: "";
+}
+
+.nav-tabs:after,
+.nav-pills:after {
+  clear: both;
+}
+
+.nav-tabs > li,
+.nav-pills > li {
+  float: left;
+}
+
+.nav-tabs > li > a,
+.nav-pills > li > a {
+  padding-right: 12px;
+  padding-left: 12px;
+  margin-right: 2px;
+  line-height: 14px;
+}
+
+.nav-tabs {
+  border-bottom: 1px solid #ddd;
+}
+
+.nav-tabs > li {
+  margin-bottom: -1px;
+}
+
+.nav-tabs > li > a {
+  padding-top: 8px;
+  padding-bottom: 8px;
+  line-height: 18px;
+  border: 1px solid transparent;
+  -webkit-border-radius: 4px 4px 0 0;
+     -moz-border-radius: 4px 4px 0 0;
+          border-radius: 4px 4px 0 0;
+}
+
+.nav-tabs > li > a:hover {
+  border-color: #eeeeee #eeeeee #dddddd;
+}
+
+.nav-tabs > .active > a,
+.nav-tabs > .active > a:hover {
+  color: #555555;
+  cursor: default;
+  background-color: #ffffff;
+  border: 1px solid #ddd;
+  border-bottom-color: transparent;
+}
+
+.nav-pills > li > a {
+  padding-top: 8px;
+  padding-bottom: 8px;
+  margin-top: 2px;
+  margin-bottom: 2px;
+  -webkit-border-radius: 5px;
+     -moz-border-radius: 5px;
+          border-radius: 5px;
+}
+
+.nav-pills > .active > a,
+.nav-pills > .active > a:hover {
+  color: #ffffff;
+  background-color: #0088cc;
+}
+
+.nav-stacked > li {
+  float: none;
+}
+
+.nav-stacked > li > a {
+  margin-right: 0;
+}
+
+.nav-tabs.nav-stacked {
+  border-bottom: 0;
+}
+
+.nav-tabs.nav-stacked > li > a {
+  border: 1px solid #ddd;
+  -webkit-border-radius: 0;
+     -moz-border-radius: 0;
+          border-radius: 0;
+}
+
+.nav-tabs.nav-stacked > li:first-child > a {
+  -webkit-border-radius: 4px 4px 0 0;
+     -moz-border-radius: 4px 4px 0 0;
+          border-radius: 4px 4px 0 0;
+}
+
+.nav-tabs.nav-stacked > li:last-child > a {
+  -webkit-border-radius: 0 0 4px 4px;
+     -moz-border-radius: 0 0 4px 4px;
+          border-radius: 0 0 4px 4px;
+}
+
+.nav-tabs.nav-stacked > li > a:hover {
+  z-index: 2;
+  border-color: #ddd;
+}
+
+.nav-pills.nav-stacked > li > a {
+  margin-bottom: 3px;
+}
+
+.nav-pills.nav-stacked > li:last-child > a {
+  margin-bottom: 1px;
+}
+
+.nav-tabs .dropdown-menu {
+  -webkit-border-radius: 0 0 5px 5px;
+     -moz-border-radius: 0 0 5px 5px;
+          border-radius: 0 0 5px 5px;
+}
+
+.nav-pills .dropdown-menu {
+  -webkit-border-radius: 4px;
+     -moz-border-radius: 4px;
+          border-radius: 4px;
+}
+
+.nav-tabs .dropdown-toggle .caret,
+.nav-pills .dropdown-toggle .caret {
+  margin-top: 6px;
+  border-top-color: #0088cc;
+  border-bottom-color: #0088cc;
+}
+
+.nav-tabs .dropdown-toggle:hover .caret,
+.nav-pills .dropdown-toggle:hover .caret {
+  border-top-color: #005580;
+  border-bottom-color: #005580;
+}
+
+.nav-tabs .active .dropdown-toggle .caret,
+.nav-pills .active .dropdown-toggle .caret {
+  border-top-color: #333333;
+  border-bottom-color: #333333;
+}
+
+.nav > .dropdown.active > a:hover {
+  color: #000000;
+  cursor: pointer;
+}
+
+.nav-tabs .open .dropdown-toggle,
+.nav-pills .open .dropdown-toggle,
+.nav > li.dropdown.open.active > a:hover {
+  color: #ffffff;
+  background-color: #999999;
+  border-color: #999999;
+}
+
+.nav li.dropdown.open .caret,
+.nav li.dropdown.open.active .caret,
+.nav li.dropdown.open a:hover .caret {
+  border-top-color: #ffffff;
+  border-bottom-color: #ffffff;
+  opacity: 1;
+  filter: alpha(opacity=100);
+}
+
+.tabs-stacked .open > a:hover {
+  border-color: #999999;
+}
+
+.tabbable {
+  *zoom: 1;
+}
+
+.tabbable:before,
+.tabbable:after {
+  display: table;
+  content: "";
+}
+
+.tabbable:after {
+  clear: both;
+}
+
+.tab-content {
+  overflow: auto;
+}
+
+.tabs-below > .nav-tabs,
+.tabs-right > .nav-tabs,
+.tabs-left > .nav-tabs {
+  border-bottom: 0;
+}
+
+.tab-content > .tab-pane,
+.pill-content > .pill-pane {
+  display: none;
+}
+
+.tab-content > .active,
+.pill-content > .active {
+  display: block;
+}
+
+.tabs-below > .nav-tabs {
+  border-top: 1px solid #ddd;
+}
+
+.tabs-below > .nav-tabs > li {
+  margin-top: -1px;
+  margin-bottom: 0;
+}
+
+.tabs-below > .nav-tabs > li > a {
+  -webkit-border-radius: 0 0 4px 4px;
+     -moz-border-radius: 0 0 4px 4px;
+          border-radius: 0 0 4px 4px;
+}
+
+.tabs-below > .nav-tabs > li > a:hover {
+  border-top-color: #ddd;
+  border-bottom-color: transparent;
+}
+
+.tabs-below > .nav-tabs > .active > a,
+.tabs-below > .nav-tabs > .active > a:hover {
+  border-color: transparent #ddd #ddd #ddd;
+}
+
+.tabs-left > .nav-tabs > li,
+.tabs-right > .nav-tabs > li {
+  float: none;
+}
+
+.tabs-left > .nav-tabs > li > a,
+.tabs-right > .nav-tabs > li > a {
+  min-width: 74px;
+  margin-right: 0;
+  margin-bottom: 3px;
+}
+
+.tabs-left > .nav-tabs {
+  float: left;
+  margin-right: 19px;
+  border-right: 1px solid #ddd;
+}
+
+.tabs-left > .nav-tabs > li > a {
+  margin-right: -1px;
+  -webkit-border-radius: 4px 0 0 4px;
+     -moz-border-radius: 4px 0 0 4px;
+          border-radius: 4px 0 0 4px;
+}
+
+.tabs-left > .nav-tabs > li > a:hover {
+  border-color: #eeeeee #dddddd #eeeeee #eeeeee;
+}
+
+.tabs-left > .nav-tabs .active > a,
+.tabs-left > .nav-tabs .active > a:hover {
+  border-color: #ddd transparent #ddd #ddd;
+  *border-right-color: #ffffff;
+}
+
+.tabs-right > .nav-tabs {
+  float: right;
+  margin-left: 19px;
+  border-left: 1px solid #ddd;
+}
+
+.tabs-right > .nav-tabs > li > a {
+  margin-left: -1px;
+  -webkit-border-radius: 0 4px 4px 0;
+     -moz-border-radius: 0 4px 4px 0;
+          border-radius: 0 4px 4px 0;
+}
+
+.tabs-right > .nav-tabs > li > a:hover {
+  border-color: #eeeeee #eeeeee #eeeeee #dddddd;
+}
+
+.tabs-right > .nav-tabs .active > a,
+.tabs-right > .nav-tabs .active > a:hover {
+  border-color: #ddd #ddd #ddd transparent;
+  *border-left-color: #ffffff;
+}
+
+.navbar {
+  *position: relative;
+  *z-index: 2;
+  margin-bottom: 18px;
+  overflow: visible;
+}
+
+.navbar-inner {
+  min-height: 40px;
+  padding-right: 20px;
+  padding-left: 20px;
+  background-color: #2c2c2c;
+  background-image: -moz-linear-gradient(top, #333333, #222222);
+  background-image: -ms-linear-gradient(top, #333333, #222222);
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));
+  background-image: -webkit-linear-gradient(top, #333333, #222222);
+  background-image: -o-linear-gradient(top, #333333, #222222);
+  background-image: linear-gradient(top, #333333, #222222);
+  background-repeat: repeat-x;
+  -webkit-border-radius: 4px;
+     -moz-border-radius: 4px;
+          border-radius: 4px;
+  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);
+  -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1);
+     -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1);
+          box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1);
+}
+
+.navbar .container {
+  width: auto;
+}
+
+.nav-collapse.collapse {
+  height: auto;
+}
+
+.navbar {
+  color: #999999;
+}
+
+.navbar .brand:hover {
+  text-decoration: none;
+}
+
+.navbar .brand {
+  display: block;
+  float: left;
+  padding: 8px 20px 12px;
+  margin-left: -20px;
+  font-size: 20px;
+  font-weight: 200;
+  line-height: 1;
+  color: #999999;
+}
+
+.navbar .navbar-text {
+  margin-bottom: 0;
+  line-height: 40px;
+}
+
+.navbar .navbar-link {
+  color: #999999;
+}
+
+.navbar .navbar-link:hover {
+  color: #ffffff;
+}
+
+.navbar .btn,
+.navbar .btn-group {
+  margin-top: 5px;
+}
+
+.navbar .btn-group .btn {
+  margin: 0;
+}
+
+.navbar-form {
+  margin-bottom: 0;
+  *zoom: 1;
+}
+
+.navbar-form:before,
+.navbar-form:after {
+  display: table;
+  content: "";
+}
+
+.navbar-form:after {
+  clear: both;
+}
+
+.navbar-form input,
+.navbar-form select,
+.navbar-form .radio,
+.navbar-form .checkbox {
+  margin-top: 5px;
+}
+
+.navbar-form input,
+.navbar-form select {
+  display: inline-block;
+  margin-bottom: 0;
+}
+
+.navbar-form input[type="image"],
+.navbar-form input[type="checkbox"],
+.navbar-form input[type="radio"] {
+  margin-top: 3px;
+}
+
+.navbar-form .input-append,
+.navbar-form .input-prepend {
+  margin-top: 6px;
+  white-space: nowrap;
+}
+
+.navbar-form .input-append input,
+.navbar-form .input-prepend input {
+  margin-top: 0;
+}
+
+.navbar-search {
+  position: relative;
+  float: left;
+  margin-top: 6px;
+  margin-bottom: 0;
+}
+
+.navbar-search .search-query {
+  padding: 4px 9px;
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+  font-size: 13px;
+  font-weight: normal;
+  line-height: 1;
+  color: #ffffff;
+  background-color: #626262;
+  border: 1px solid #151515;
+  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);
+     -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);
+          box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);
+  -webkit-transition: none;
+     -moz-transition: none;
+      -ms-transition: none;
+       -o-transition: none;
+          transition: none;
+}
+
+.navbar-search .search-query:-moz-placeholder {
+  color: #cccccc;
+}
+
+.navbar-search .search-query:-ms-input-placeholder {
+  color: #cccccc;
+}
+
+.navbar-search .search-query::-webkit-input-placeholder {
+  color: #cccccc;
+}
+
+.navbar-search .search-query:focus,
+.navbar-search .search-query.focused {
+  padding: 5px 10px;
+  color: #333333;
+  text-shadow: 0 1px 0 #ffffff;
+  background-color: #ffffff;
+  border: 0;
+  outline: 0;
+  -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);
+     -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);
+          box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);
+}
+
+.navbar-fixed-top,
+.navbar-fixed-bottom {
+  position: fixed;
+  right: 0;
+  left: 0;
+  z-index: 1030;
+  margin-bottom: 0;
+}
+
+.navbar-fixed-top .navbar-inner,
+.navbar-fixed-bottom .navbar-inner {
+  padding-right: 0;
+  padding-left: 0;
+  -webkit-border-radius: 0;
+     -moz-border-radius: 0;
+          border-radius: 0;
+}
+
+.navbar-fixed-top .container,
+.navbar-fixed-bottom .container {
+  width: 940px;
+}
+
+.navbar-fixed-top {
+  top: 0;
+}
+
+.navbar-fixed-bottom {
+  bottom: 0;
+}
+
+.navbar .nav {
+  position: relative;
+  left: 0;
+  display: block;
+  float: left;
+  margin: 0 10px 0 0;
+}
+
+.navbar .nav.pull-right {
+  float: right;
+}
+
+.navbar .nav > li {
+  display: block;
+  float: left;
+}
+
+.navbar .nav > li > a {
+  float: none;
+  padding: 9px 10px 11px;
+  line-height: 19px;
+  color: #999999;
+  text-decoration: none;
+  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+}
+
+.navbar .btn {
+  display: inline-block;
+  padding: 4px 10px 4px;
+  margin: 5px 5px 6px;
+  line-height: 18px;
+}
+
+.navbar .btn-group {
+  padding: 5px 5px 6px;
+  margin: 0;
+}
+
+.navbar .nav > li > a:hover {
+  color: #ffffff;
+  text-decoration: none;
+  background-color: transparent;
+}
+
+.navbar .nav .active > a,
+.navbar .nav .active > a:hover {
+  color: #ffffff;
+  text-decoration: none;
+  background-color: #222222;
+}
+
+.navbar .divider-vertical {
+  width: 1px;
+  height: 40px;
+  margin: 0 9px;
+  overflow: hidden;
+  background-color: #222222;
+  border-right: 1px solid #333333;
+}
+
+.navbar .nav.pull-right {
+  margin-right: 0;
+  margin-left: 10px;
+}
+
+.navbar .btn-navbar {
+  display: none;
+  float: right;
+  padding: 7px 10px;
+  margin-right: 5px;
+  margin-left: 5px;
+  background-color: #2c2c2c;
+  *background-color: #222222;
+  background-image: -ms-linear-gradient(top, #333333, #222222);
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));
+  background-image: -webkit-linear-gradient(top, #333333, #222222);
+  background-image: -o-linear-gradient(top, #333333, #222222);
+  background-image: linear-gradient(top, #333333, #222222);
+  background-image: -moz-linear-gradient(top, #333333, #222222);
+  background-repeat: repeat-x;
+  border-color: #222222 #222222 #000000;
+  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);
+  filter: progid:dximagetransform.microsoft.gradient(enabled=false);
+  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);
+     -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);
+          box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);
+}
+
+.navbar .btn-navbar:hover,
+.navbar .btn-navbar:active,
+.navbar .btn-navbar.active,
+.navbar .btn-navbar.disabled,
+.navbar .btn-navbar[disabled] {
+  background-color: #222222;
+  *background-color: #151515;
+}
+
+.navbar .btn-navbar:active,
+.navbar .btn-navbar.active {
+  background-color: #080808 \9;
+}
+
+.navbar .btn-navbar .icon-bar {
+  display: block;
+  width: 18px;
+  height: 2px;
+  background-color: #f5f5f5;
+  -webkit-border-radius: 1px;
+     -moz-border-radius: 1px;
+          border-radius: 1px;
+  -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
+     -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
+          box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
+}
+
+.btn-navbar .icon-bar + .icon-bar {
+  margin-top: 3px;
+}
+
+.navbar .dropdown-menu:before {
+  position: absolute;
+  top: -7px;
+  left: 9px;
+  display: inline-block;
+  border-right: 7px solid transparent;
+  border-bottom: 7px solid #ccc;
+  border-left: 7px solid transparent;
+  border-bottom-color: rgba(0, 0, 0, 0.2);
+  content: '';
+}
+
+.navbar .dropdown-menu:after {
+  position: absolute;
+  top: -6px;
+  left: 10px;
+  display: inline-block;
+  border-right: 6px solid transparent;
+  border-bottom: 6px solid #ffffff;
+  border-left: 6px solid transparent;
+  content: '';
+}
+
+.navbar-fixed-bottom .dropdown-menu:before {
+  top: auto;
+  bottom: -7px;
+  border-top: 7px solid #ccc;
+  border-bottom: 0;
+  border-top-color: rgba(0, 0, 0, 0.2);
+}
+
+.navbar-fixed-bottom .dropdown-menu:after {
+  top: auto;
+  bottom: -6px;
+  border-top: 6px solid #ffffff;
+  border-bottom: 0;
+}
+
+.navbar .nav li.dropdown .dropdown-toggle .caret,
+.navbar .nav li.dropdown.open .caret {
+  border-top-color: #ffffff;
+  border-bottom-color: #ffffff;
+}
+
+.navbar .nav li.dropdown.active .caret {
+  opacity: 1;
+  filter: alpha(opacity=100);
+}
+
+.navbar .nav li.dropdown.open > .dropdown-toggle,
+.navbar .nav li.dropdown.active > .dropdown-toggle,
+.navbar .nav li.dropdown.open.active > .dropdown-toggle {
+  background-color: transparent;
+}
+
+.navbar .nav li.dropdown.active > .dropdown-toggle:hover {
+  color: #ffffff;
+}
+
+.navbar .pull-right .dropdown-menu,
+.navbar .dropdown-menu.pull-right {
+  right: 0;
+  left: auto;
+}
+
+.navbar .pull-right .dropdown-menu:before,
+.navbar .dropdown-menu.pull-right:before {
+  right: 12px;
+  left: auto;
+}
+
+.navbar .pull-right .dropdown-menu:after,
+.navbar .dropdown-menu.pull-right:after {
+  right: 13px;
+  left: auto;
+}
+
+.breadcrumb {
+  padding: 7px 14px;
+  margin: 0 0 18px;
+  list-style: none;
+  background-color: #fbfbfb;
+  background-image: -moz-linear-gradient(top, #ffffff, #f5f5f5);
+  background-image: -ms-linear-gradient(top, #ffffff, #f5f5f5);
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5));
+  background-image: -webkit-linear-gradient(top, #ffffff, #f5f5f5);
+  background-image: -o-linear-gradient(top, #ffffff, #f5f5f5);
+  background-image: linear-gradient(top, #ffffff, #f5f5f5);
+  background-repeat: repeat-x;
+  border: 1px solid #ddd;
+  -webkit-border-radius: 3px;
+     -moz-border-radius: 3px;
+          border-radius: 3px;
+  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0);
+  -webkit-box-shadow: inset 0 1px 0 #ffffff;
+     -moz-box-shadow: inset 0 1px 0 #ffffff;
+          box-shadow: inset 0 1px 0 #ffffff;
+}
+
+.breadcrumb li {
+  display: inline-block;
+  *display: inline;
+  text-shadow: 0 1px 0 #ffffff;
+  *zoom: 1;
+}
+
+.breadcrumb .divider {
+  padding: 0 5px;
+  color: #999999;
+}
+
+.breadcrumb .active a {
+  color: #333333;
+}
+
+.pagination {
+  height: 36px;
+  margin: 18px 0;
+}
+
+.pagination ul {
+  display: inline-block;
+  *display: inline;
+  margin-bottom: 0;
+  margin-left: 0;
+  -webkit-border-radius: 3px;
+     -moz-border-radius: 3px;
+          border-radius: 3px;
+  *zoom: 1;
+  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+     -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+          box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+}
+
+.pagination li {
+  display: inline;
+}
+
+.pagination a {
+  float: left;
+  padding: 0 14px;
+  line-height: 34px;
+  text-decoration: none;
+  border: 1px solid #ddd;
+  border-left-width: 0;
+}
+
+.pagination a:hover,
+.pagination .active a {
+  background-color: #f5f5f5;
+}
+
+.pagination .active a {
+  color: #999999;
+  cursor: default;
+}
+
+.pagination .disabled span,
+.pagination .disabled a,
+.pagination .disabled a:hover {
+  color: #999999;
+  cursor: default;
+  background-color: transparent;
+}
+
+.pagination li:first-child a {
+  border-left-width: 1px;
+  -webkit-border-radius: 3px 0 0 3px;
+     -moz-border-radius: 3px 0 0 3px;
+          border-radius: 3px 0 0 3px;
+}
+
+.pagination li:last-child a {
+  -webkit-border-radius: 0 3px 3px 0;
+     -moz-border-radius: 0 3px 3px 0;
+          border-radius: 0 3px 3px 0;
+}
+
+.pagination-centered {
+  text-align: center;
+}
+
+.pagination-right {
+  text-align: right;
+}
+
+.pager {
+  margin-bottom: 18px;
+  margin-left: 0;
+  text-align: center;
+  list-style: none;
+  *zoom: 1;
+}
+
+.pager:before,
+.pager:after {
+  display: table;
+  content: "";
+}
+
+.pager:after {
+  clear: both;
+}
+
+.pager li {
+  display: inline;
+}
+
+.pager a {
+  display: inline-block;
+  padding: 5px 14px;
+  background-color: #fff;
+  border: 1px solid #ddd;
+  -webkit-border-radius: 15px;
+     -moz-border-radius: 15px;
+          border-radius: 15px;
+}
+
+.pager a:hover {
+  text-decoration: none;
+  background-color: #f5f5f5;
+}
+
+.pager .next a {
+  float: right;
+}
+
+.pager .previous a {
+  float: left;
+}
+
+.pager .disabled a,
+.pager .disabled a:hover {
+  color: #999999;
+  cursor: default;
+  background-color: #fff;
+}
+
+.modal-open .dropdown-menu {
+  z-index: 2050;
+}
+
+.modal-open .dropdown.open {
+  *z-index: 2050;
+}
+
+.modal-open .popover {
+  z-index: 2060;
+}
+
+.modal-open .tooltip {
+  z-index: 2070;
+}
+
+.modal-backdrop {
+  position: fixed;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  z-index: 1040;
+  background-color: #000000;
+}
+
+.modal-backdrop.fade {
+  opacity: 0;
+}
+
+.modal-backdrop,
+.modal-backdrop.fade.in {
+  opacity: 0.8;
+  filter: alpha(opacity=80);
+}
+
+.modal {
+  position: fixed;
+  top: 50%;
+  left: 50%;
+  z-index: 1050;
+  width: 560px;
+  margin: -250px 0 0 -280px;
+  overflow: auto;
+  background-color: #ffffff;
+  border: 1px solid #999;
+  border: 1px solid rgba(0, 0, 0, 0.3);
+  *border: 1px solid #999;
+  -webkit-border-radius: 6px;
+     -moz-border-radius: 6px;
+          border-radius: 6px;
+  -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+     -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+          box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+  -webkit-background-clip: padding-box;
+     -moz-background-clip: padding-box;
+          background-clip: padding-box;
+}
+
+.modal.fade {
+  top: -25%;
+  -webkit-transition: opacity 0.3s linear, top 0.3s ease-out;
+     -moz-transition: opacity 0.3s linear, top 0.3s ease-out;
+      -ms-transition: opacity 0.3s linear, top 0.3s ease-out;
+       -o-transition: opacity 0.3s linear, top 0.3s ease-out;
+          transition: opacity 0.3s linear, top 0.3s ease-out;
+}
+
+.modal.fade.in {
+  top: 50%;
+}
+
+.modal-header {
+  padding: 9px 15px;
+  border-bottom: 1px solid #eee;
+}
+
+.modal-header .close {
+  margin-top: 2px;
+}
+
+.modal-body {
+  max-height: 400px;
+  padding: 15px;
+  overflow-y: auto;
+}
+
+.modal-form {
+  margin-bottom: 0;
+}
+
+.modal-footer {
+  padding: 14px 15px 15px;
+  margin-bottom: 0;
+  text-align: right;
+  background-color: #f5f5f5;
+  border-top: 1px solid #ddd;
+  -webkit-border-radius: 0 0 6px 6px;
+     -moz-border-radius: 0 0 6px 6px;
+          border-radius: 0 0 6px 6px;
+  *zoom: 1;
+  -webkit-box-shadow: inset 0 1px 0 #ffffff;
+     -moz-box-shadow: inset 0 1px 0 #ffffff;
+          box-shadow: inset 0 1px 0 #ffffff;
+}
+
+.modal-footer:before,
+.modal-footer:after {
+  display: table;
+  content: "";
+}
+
+.modal-footer:after {
+  clear: both;
+}
+
+.modal-footer .btn + .btn {
+  margin-bottom: 0;
+  margin-left: 5px;
+}
+
+.modal-footer .btn-group .btn + .btn {
+  margin-left: -1px;
+}
+
+.tooltip {
+  position: absolute;
+  z-index: 1020;
+  display: block;
+  padding: 5px;
+  font-size: 11px;
+  opacity: 0;
+  filter: alpha(opacity=0);
+  visibility: visible;
+}
+
+.tooltip.in {
+  opacity: 0.8;
+  filter: alpha(opacity=80);
+}
+
+.tooltip.top {
+  margin-top: -2px;
+}
+
+.tooltip.right {
+  margin-left: 2px;
+}
+
+.tooltip.bottom {
+  margin-top: 2px;
+}
+
+.tooltip.left {
+  margin-left: -2px;
+}
+
+.tooltip.top .tooltip-arrow {
+  bottom: 0;
+  left: 50%;
+  margin-left: -5px;
+  border-top: 5px solid #000000;
+  border-right: 5px solid transparent;
+  border-left: 5px solid transparent;
+}
+
+.tooltip.left .tooltip-arrow {
+  top: 50%;
+  right: 0;
+  margin-top: -5px;
+  border-top: 5px solid transparent;
+  border-bottom: 5px solid transparent;
+  border-left: 5px solid #000000;
+}
+
+.tooltip.bottom .tooltip-arrow {
+  top: 0;
+  left: 50%;
+  margin-left: -5px;
+  border-right: 5px solid transparent;
+  border-bottom: 5px solid #000000;
+  border-left: 5px solid transparent;
+}
+
+.tooltip.right .tooltip-arrow {
+  top: 50%;
+  left: 0;
+  margin-top: -5px;
+  border-top: 5px solid transparent;
+  border-right: 5px solid #000000;
+  border-bottom: 5px solid transparent;
+}
+
+.tooltip-inner {
+  max-width: 200px;
+  padding: 3px 8px;
+  color: #ffffff;
+  text-align: center;
+  text-decoration: none;
+  background-color: #000000;
+  -webkit-border-radius: 4px;
+     -moz-border-radius: 4px;
+          border-radius: 4px;
+}
+
+.tooltip-arrow {
+  position: absolute;
+  width: 0;
+  height: 0;
+}
+
+.popover {
+  position: absolute;
+  top: 0;
+  left: 0;
+  z-index: 1010;
+  display: none;
+  padding: 5px;
+}
+
+.popover.top {
+  margin-top: -5px;
+}
+
+.popover.right {
+  margin-left: 5px;
+}
+
+.popover.bottom {
+  margin-top: 5px;
+}
+
+.popover.left {
+  margin-left: -5px;
+}
+
+.popover.top .arrow {
+  bottom: 0;
+  left: 50%;
+  margin-left: -5px;
+  border-top: 5px solid #000000;
+  border-right: 5px solid transparent;
+  border-left: 5px solid transparent;
+}
+
+.popover.right .arrow {
+  top: 50%;
+  left: 0;
+  margin-top: -5px;
+  border-top: 5px solid transparent;
+  border-right: 5px solid #000000;
+  border-bottom: 5px solid transparent;
+}
+
+.popover.bottom .arrow {
+  top: 0;
+  left: 50%;
+  margin-left: -5px;
+  border-right: 5px solid transparent;
+  border-bottom: 5px solid #000000;
+  border-left: 5px solid transparent;
+}
+
+.popover.left .arrow {
+  top: 50%;
+  right: 0;
+  margin-top: -5px;
+  border-top: 5px solid transparent;
+  border-bottom: 5px solid transparent;
+  border-left: 5px solid #000000;
+}
+
+.popover .arrow {
+  position: absolute;
+  width: 0;
+  height: 0;
+}
+
+.popover-inner {
+  width: 280px;
+  padding: 3px;
+  overflow: hidden;
+  background: #000000;
+  background: rgba(0, 0, 0, 0.8);
+  -webkit-border-radius: 6px;
+     -moz-border-radius: 6px;
+          border-radius: 6px;
+  -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+     -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+          box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+}
+
+.popover-title {
+  padding: 9px 15px;
+  line-height: 1;
+  background-color: #f5f5f5;
+  border-bottom: 1px solid #eee;
+  -webkit-border-radius: 3px 3px 0 0;
+     -moz-border-radius: 3px 3px 0 0;
+          border-radius: 3px 3px 0 0;
+}
+
+.popover-content {
+  padding: 14px;
+  background-color: #ffffff;
+  -webkit-border-radius: 0 0 3px 3px;
+     -moz-border-radius: 0 0 3px 3px;
+          border-radius: 0 0 3px 3px;
+  -webkit-background-clip: padding-box;
+     -moz-background-clip: padding-box;
+          background-clip: padding-box;
+}
+
+.popover-content p,
+.popover-content ul,
+.popover-content ol {
+  margin-bottom: 0;
+}
+
+.thumbnails {
+  margin-left: -20px;
+  list-style: none;
+  *zoom: 1;
+}
+
+.thumbnails:before,
+.thumbnails:after {
+  display: table;
+  content: "";
+}
+
+.thumbnails:after {
+  clear: both;
+}
+
+.row-fluid .thumbnails {
+  margin-left: 0;
+}
+
+.thumbnails > li {
+  float: left;
+  margin-bottom: 18px;
+  margin-left: 20px;
+}
+
+.thumbnail {
+  display: block;
+  padding: 4px;
+  line-height: 1;
+  border: 1px solid #ddd;
+  -webkit-border-radius: 4px;
+     -moz-border-radius: 4px;
+          border-radius: 4px;
+  -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075);
+     -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075);
+          box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075);
+}
+
+a.thumbnail:hover {
+  border-color: #0088cc;
+  -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25);
+     -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25);
+          box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25);
+}
+
+.thumbnail > img {
+  display: block;
+  max-width: 100%;
+  margin-right: auto;
+  margin-left: auto;
+}
+
+.thumbnail .caption {
+  padding: 9px;
+}
+
+.label,
+.badge {
+  font-size: 10.998px;
+  font-weight: bold;
+  line-height: 14px;
+  color: #ffffff;
+  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+  white-space: nowrap;
+  vertical-align: baseline;
+  background-color: #999999;
+}
+
+.label {
+  padding: 1px 4px 2px;
+  -webkit-border-radius: 3px;
+     -moz-border-radius: 3px;
+          border-radius: 3px;
+}
+
+.badge {
+  padding: 1px 9px 2px;
+  -webkit-border-radius: 9px;
+     -moz-border-radius: 9px;
+          border-radius: 9px;
+}
+
+a.label:hover,
+a.badge:hover {
+  color: #ffffff;
+  text-decoration: none;
+  cursor: pointer;
+}
+
+.label-important,
+.badge-important {
+  background-color: #b94a48;
+}
+
+.label-important[href],
+.badge-important[href] {
+  background-color: #953b39;
+}
+
+.label-warning,
+.badge-warning {
+  background-color: #f89406;
+}
+
+.label-warning[href],
+.badge-warning[href] {
+  background-color: #c67605;
+}
+
+.label-success,
+.badge-success {
+  background-color: #468847;
+}
+
+.label-success[href],
+.badge-success[href] {
+  background-color: #356635;
+}
+
+.label-info,
+.badge-info {
+  background-color: #3a87ad;
+}
+
+.label-info[href],
+.badge-info[href] {
+  background-color: #2d6987;
+}
+
+.label-inverse,
+.badge-inverse {
+  background-color: #333333;
+}
+
+.label-inverse[href],
+.badge-inverse[href] {
+  background-color: #1a1a1a;
+}
+
+@-webkit-keyframes progress-bar-stripes {
+  from {
+    background-position: 40px 0;
+  }
+  to {
+    background-position: 0 0;
+  }
+}
+
+@-moz-keyframes progress-bar-stripes {
+  from {
+    background-position: 40px 0;
+  }
+  to {
+    background-position: 0 0;
+  }
+}
+
+@-ms-keyframes progress-bar-stripes {
+  from {
+    background-position: 40px 0;
+  }
+  to {
+    background-position: 0 0;
+  }
+}
+
+@-o-keyframes progress-bar-stripes {
+  from {
+    background-position: 0 0;
+  }
+  to {
+    background-position: 40px 0;
+  }
+}
+
+@keyframes progress-bar-stripes {
+  from {
+    background-position: 40px 0;
+  }
+  to {
+    background-position: 0 0;
+  }
+}
+
+.progress {
+  height: 18px;
+  margin-bottom: 18px;
+  overflow: hidden;
+  background-color: #f7f7f7;
+  background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9);
+  background-image: -ms-linear-gradient(top, #f5f5f5, #f9f9f9);
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));
+  background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9);
+  background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9);
+  background-image: linear-gradient(top, #f5f5f5, #f9f9f9);
+  background-repeat: repeat-x;
+  -webkit-border-radius: 4px;
+     -moz-border-radius: 4px;
+          border-radius: 4px;
+  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0);
+  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
+     -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
+          box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
+}
+
+.progress .bar {
+  width: 0;
+  height: 18px;
+  font-size: 12px;
+  color: #ffffff;
+  text-align: center;
+  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+  background-color: #0e90d2;
+  background-image: -moz-linear-gradient(top, #149bdf, #0480be);
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));
+  background-image: -webkit-linear-gradient(top, #149bdf, #0480be);
+  background-image: -o-linear-gradient(top, #149bdf, #0480be);
+  background-image: linear-gradient(top, #149bdf, #0480be);
+  background-image: -ms-linear-gradient(top, #149bdf, #0480be);
+  background-repeat: repeat-x;
+  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0);
+  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
+     -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
+          box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+      -ms-box-sizing: border-box;
+          box-sizing: border-box;
+  -webkit-transition: width 0.6s ease;
+     -moz-transition: width 0.6s ease;
+      -ms-transition: width 0.6s ease;
+       -o-transition: width 0.6s ease;
+          transition: width 0.6s ease;
+}
+
+.progress-striped .bar {
+  background-color: #149bdf;
+  background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));
+  background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  -webkit-background-size: 40px 40px;
+     -moz-background-size: 40px 40px;
+       -o-background-size: 40px 40px;
+          background-size: 40px 40px;
+}
+
+.progress.active .bar {
+  -webkit-animation: progress-bar-stripes 2s linear infinite;
+     -moz-animation: progress-bar-stripes 2s linear infinite;
+      -ms-animation: progress-bar-stripes 2s linear infinite;
+       -o-animation: progress-bar-stripes 2s linear infinite;
+          animation: progress-bar-stripes 2s linear infinite;
+}
+
+.progress-danger .bar {
+  background-color: #dd514c;
+  background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35);
+  background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35);
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));
+  background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);
+  background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);
+  background-image: linear-gradient(top, #ee5f5b, #c43c35);
+  background-repeat: repeat-x;
+  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);
+}
+
+.progress-danger.progress-striped .bar {
+  background-color: #ee5f5b;
+  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));
+  background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+}
+
+.progress-success .bar {
+  background-color: #5eb95e;
+  background-image: -moz-linear-gradient(top, #62c462, #57a957);
+  background-image: -ms-linear-gradient(top, #62c462, #57a957);
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));
+  background-image: -webkit-linear-gradient(top, #62c462, #57a957);
+  background-image: -o-linear-gradient(top, #62c462, #57a957);
+  background-image: linear-gradient(top, #62c462, #57a957);
+  background-repeat: repeat-x;
+  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);
+}
+
+.progress-success.progress-striped .bar {
+  background-color: #62c462;
+  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));
+  background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+}
+
+.progress-info .bar {
+  background-color: #4bb1cf;
+  background-image: -moz-linear-gradient(top, #5bc0de, #339bb9);
+  background-image: -ms-linear-gradient(top, #5bc0de, #339bb9);
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));
+  background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9);
+  background-image: -o-linear-gradient(top, #5bc0de, #339bb9);
+  background-image: linear-gradient(top, #5bc0de, #339bb9);
+  background-repeat: repeat-x;
+  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);
+}
+
+.progress-info.progress-striped .bar {
+  background-color: #5bc0de;
+  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));
+  background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+}
+
+.progress-warning .bar {
+  background-color: #faa732;
+  background-image: -moz-linear-gradient(top, #fbb450, #f89406);
+  background-image: -ms-linear-gradient(top, #fbb450, #f89406);
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));
+  background-image: -webkit-linear-gradient(top, #fbb450, #f89406);
+  background-image: -o-linear-gradient(top, #fbb450, #f89406);
+  background-image: linear-gradient(top, #fbb450, #f89406);
+  background-repeat: repeat-x;
+  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);
+}
+
+.progress-warning.progress-striped .bar {
+  background-color: #fbb450;
+  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));
+  background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+}
+
+.accordion {
+  margin-bottom: 18px;
+}
+
+.accordion-group {
+  margin-bottom: 2px;
+  border: 1px solid #e5e5e5;
+  -webkit-border-radius: 4px;
+     -moz-border-radius: 4px;
+          border-radius: 4px;
+}
+
+.accordion-heading {
+  border-bottom: 0;
+}
+
+.accordion-heading .accordion-toggle {
+  display: block;
+  padding: 8px 15px;
+}
+
+.accordion-toggle {
+  cursor: pointer;
+}
+
+.accordion-inner {
+  padding: 9px 15px;
+  border-top: 1px solid #e5e5e5;
+}
+
+.carousel {
+  position: relative;
+  margin-bottom: 18px;
+  line-height: 1;
+}
+
+.carousel-inner {
+  position: relative;
+  width: 100%;
+  overflow: hidden;
+}
+
+.carousel .item {
+  position: relative;
+  display: none;
+  -webkit-transition: 0.6s ease-in-out left;
+     -moz-transition: 0.6s ease-in-out left;
+      -ms-transition: 0.6s ease-in-out left;
+       -o-transition: 0.6s ease-in-out left;
+          transition: 0.6s ease-in-out left;
+}
+
+.carousel .item > img {
+  display: block;
+  line-height: 1;
+}
+
+.carousel .active,
+.carousel .next,
+.carousel .prev {
+  display: block;
+}
+
+.carousel .active {
+  left: 0;
+}
+
+.carousel .next,
+.carousel .prev {
+  position: absolute;
+  top: 0;
+  width: 100%;
+}
+
+.carousel .next {
+  left: 100%;
+}
+
+.carousel .prev {
+  left: -100%;
+}
+
+.carousel .next.left,
+.carousel .prev.right {
+  left: 0;
+}
+
+.carousel .active.left {
+  left: -100%;
+}
+
+.carousel .active.right {
+  left: 100%;
+}
+
+.carousel-control {
+  position: absolute;
+  top: 40%;
+  left: 15px;
+  width: 40px;
+  height: 40px;
+  margin-top: -20px;
+  font-size: 60px;
+  font-weight: 100;
+  line-height: 30px;
+  color: #ffffff;
+  text-align: center;
+  background: #222222;
+  border: 3px solid #ffffff;
+  -webkit-border-radius: 23px;
+     -moz-border-radius: 23px;
+          border-radius: 23px;
+  opacity: 0.5;
+  filter: alpha(opacity=50);
+}
+
+.carousel-control.right {
+  right: 15px;
+  left: auto;
+}
+
+.carousel-control:hover {
+  color: #ffffff;
+  text-decoration: none;
+  opacity: 0.9;
+  filter: alpha(opacity=90);
+}
+
+.carousel-caption {
+  position: absolute;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  padding: 10px 15px 5px;
+  background: #333333;
+  background: rgba(0, 0, 0, 0.75);
+}
+
+.carousel-caption h4,
+.carousel-caption p {
+  color: #ffffff;
+}
+
+.hero-unit {
+  padding: 60px;
+  margin-bottom: 30px;
+  background-color: #eeeeee;
+  -webkit-border-radius: 6px;
+     -moz-border-radius: 6px;
+          border-radius: 6px;
+}
+
+.hero-unit h1 {
+  margin-bottom: 0;
+  font-size: 60px;
+  line-height: 1;
+  letter-spacing: -1px;
+  color: inherit;
+}
+
+.hero-unit p {
+  font-size: 18px;
+  font-weight: 200;
+  line-height: 27px;
+  color: inherit;
+}
+
+.pull-right {
+  float: right;
+}
+
+.pull-left {
+  float: left;
+}
+
+.hide {
+  display: none;
+}
+
+.show {
+  display: block;
+}
+
+.invisible {
+  visibility: hidden;
+}
diff --git a/examples/server-example/src/main/webapp/index.html b/examples/server-example/src/main/webapp/index.html
new file mode 100644
index 0000000..bcb941b
--- /dev/null
+++ b/examples/server-example/src/main/webapp/index.html
@@ -0,0 +1,137 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+<!DOCTYPE html>
+<html>
+<head>
+  <link rel="stylesheet" href="css/bootstrap.2.0.4.css">
+
+  <script type="text/javascript" src="js/jquery-1.7.2.js"></script>
+  <script type="text/javascript" src="js/bootstrap.2.0.4.js"></script>
+  <script type="text/javascript" src="js/sample.js"></script>
+  <script type="text/javascript" src="js/jquery.json-2.3.js"></script>
+  <script type="text/javascript" src="js/jquery-tmpl.js"></script>
+  <title>Apache DirectMemory Sample</title>
+
+</head>
+
+<body style="padding-top: 1px;">
+
+<div id="topbar-menu-container"></div>
+
+<div class="container-fluid" style="min-height: 450px">
+  <div class="row-fluid">
+
+    <div class="span10 columns">
+      <div class="content">
+
+
+          <div id="wine-result">
+            <div class="page-header"><h4>Results</h4></div>
+            <div id="result-content"></div>
+          </div>
+
+          <div class="accordion" id="accordion-div">
+
+            <div class="accordion-group">
+              <div class="accordion-heading">
+                <a class="accordion-toggle" href="#collapse-put" data-parent="#accordion-div" data-toggle="collapse"><h4>Put in cache</h4></a>
+              </div>
+              <div id="collapse-put" class="accordion-body collapse" style="height: auto;">
+                <div class="well">
+                  Wine Name:&nbsp<input type="text" id="wine_name" name="wine_name">
+                  Wine Description:&nbsp<input type="text" id="wine_description" name="wine_description">
+                  ExpiresIn:&nbsp<input type="text" id="expires-in" name="expires-in">
+                  Serializer:&nbsp;
+                  <select name="serialize" id="serializer" class="span8">
+                    <option value="org.apache.directmemory.serialization.StandardSerializer">org.apache.directmemory.serialization.StandardSerializer</option>
+                    <option value="org.apache.directmemory.serialization.protostuff.ProtoStuffWithLinkedBufferSerializer">org.apache.directmemory.serialization.protostuff.ProtoStuffWithLinkedBufferSerializer</option>
+                  </select>
+                  <br/>
+                  <button class="btn" id="put-cache-btn">Put</button>
+                </div>
+              </div>
+            </div>
+
+            <div class="accordion-group">
+              <div class="accordion-heading">
+                <a class="accordion-toggle" href="#collapse-get" data-parent="#accordion-div" data-toggle="collapse"><h4>Get from cache</h4></a>
+              </div>
+              <div id="collapse-get" class="accordion-body collapse" style="height: 0px;">
+                <div class="well">
+                  Wine Key:&nbsp<input type="text" id="wine_name_cache" name="wine_name_cache">
+                  <br/>
+                  <button class="btn" id="get_cache_btn">Get</button>
+                </div>
+              </div>
+
+            </div>
+
+            <div class="accordion-group">
+              <div class="accordion-heading">
+                <a class="accordion-toggle" href="#collapse-delete" data-parent="#accordion-div" data-toggle="collapse"><h4>Delete from cache</h4></a>
+              </div>
+              <div id="collapse-delete" class="accordion-body collapse" style="height: 0px;">
+                <div class="well">
+                  Wine Key:&nbsp<input type="text" id="wine_key_cache" name="wine_key_cache">
+                  <br/>
+                  <button class="btn" id="delete_cache_btn">Delete</button>
+                </div>
+              </div>
+
+            </div>
+
+
+    </div>
+  </div>
+  </div>
+
+</div>
+
+<footer id="footer-content" style="vertical-align: bottom">
+  <div class="pull-left">
+    <a href="http://incubator.apache.org/directmemory" target="_blank">Apache DirectMemory Sample</a>
+  </div>
+  <div class="pull-right">
+    Copyright &copy; 2005 - 2012 <a href="http://www.apache.org/" target="_blank">The Apache Software Foundation</a>
+  </div>
+</footer>
+</body>
+
+<script id='alert-message-error' type='text/html'>
+  <div class="alert fade in alert-error" data-alert="alert">
+    <a class="close" href="#" data-dismiss="alert" id='alert-message-error-close-a'>&#215;</a>
+    ${message}
+  </div>
+</script>
+<script id='alert-message-warning' type='text/html'>
+  <div class="alert fade in alert-heading" data-alert="alert">
+    <a class="close" href="#" data-dismiss="alert" id='alert-message-warning-close-a'>&#215;</a>
+    ${message}
+  </div>
+</script>
+<script id='alert-message-info' type='text/html'>
+  <div class="alert fade in alert-info" data-alert="alert">
+    <a class="close" href="#" data-dismiss="alert" id='alert-message-info-close-a'>&#215;</a>
+    ${message}
+  </div>
+</script>
+
+</html>
+
+
diff --git a/examples/server-example/src/main/webapp/js/bootstrap.2.0.4.js b/examples/server-example/src/main/webapp/js/bootstrap.2.0.4.js
new file mode 100644
index 0000000..5d6e65b
--- /dev/null
+++ b/examples/server-example/src/main/webapp/js/bootstrap.2.0.4.js
@@ -0,0 +1,1825 @@
+/* ===================================================
+ * bootstrap-transition.js v2.0.4
+ * http://twitter.github.com/bootstrap/javascript.html#transitions
+ * ===================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================================================== */
+
+
+!function ($) {
+
+  $(function () {
+
+    "use strict"; // jshint ;_;
+
+
+    /* CSS TRANSITION SUPPORT (http://www.modernizr.com/)
+     * ======================================================= */
+
+    $.support.transition = (function () {
+
+      var transitionEnd = (function () {
+
+        var el = document.createElement('bootstrap')
+          , transEndEventNames = {
+               'WebkitTransition' : 'webkitTransitionEnd'
+            ,  'MozTransition'    : 'transitionend'
+            ,  'OTransition'      : 'oTransitionEnd'
+            ,  'msTransition'     : 'MSTransitionEnd'
+            ,  'transition'       : 'transitionend'
+            }
+          , name
+
+        for (name in transEndEventNames){
+          if (el.style[name] !== undefined) {
+            return transEndEventNames[name]
+          }
+        }
+
+      }())
+
+      return transitionEnd && {
+        end: transitionEnd
+      }
+
+    })()
+
+  })
+
+}(window.jQuery);/* ==========================================================
+ * bootstrap-alert.js v2.0.4
+ * http://twitter.github.com/bootstrap/javascript.html#alerts
+ * ==========================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================================================== */
+
+
+!function ($) {
+
+  "use strict"; // jshint ;_;
+
+
+ /* ALERT CLASS DEFINITION
+  * ====================== */
+
+  var dismiss = '[data-dismiss="alert"]'
+    , Alert = function (el) {
+        $(el).on('click', dismiss, this.close)
+      }
+
+  Alert.prototype.close = function (e) {
+    var $this = $(this)
+      , selector = $this.attr('data-target')
+      , $parent
+
+    if (!selector) {
+      selector = $this.attr('href')
+      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
+    }
+
+    $parent = $(selector)
+
+    e && e.preventDefault()
+
+    $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent())
+
+    $parent.trigger(e = $.Event('close'))
+
+    if (e.isDefaultPrevented()) return
+
+    $parent.removeClass('in')
+
+    function removeElement() {
+      $parent
+        .trigger('closed')
+        .remove()
+    }
+
+    $.support.transition && $parent.hasClass('fade') ?
+      $parent.on($.support.transition.end, removeElement) :
+      removeElement()
+  }
+
+
+ /* ALERT PLUGIN DEFINITION
+  * ======================= */
+
+  $.fn.alert = function (option) {
+    return this.each(function () {
+      var $this = $(this)
+        , data = $this.data('alert')
+      if (!data) $this.data('alert', (data = new Alert(this)))
+      if (typeof option == 'string') data[option].call($this)
+    })
+  }
+
+  $.fn.alert.Constructor = Alert
+
+
+ /* ALERT DATA-API
+  * ============== */
+
+  $(function () {
+    $('body').on('click.alert.data-api', dismiss, Alert.prototype.close)
+  })
+
+}(window.jQuery);/* ============================================================
+ * bootstrap-button.js v2.0.4
+ * http://twitter.github.com/bootstrap/javascript.html#buttons
+ * ============================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============================================================ */
+
+
+!function ($) {
+
+  "use strict"; // jshint ;_;
+
+
+ /* BUTTON PUBLIC CLASS DEFINITION
+  * ============================== */
+
+  var Button = function (element, options) {
+    this.$element = $(element)
+    this.options = $.extend({}, $.fn.button.defaults, options)
+  }
+
+  Button.prototype.setState = function (state) {
+    var d = 'disabled'
+      , $el = this.$element
+      , data = $el.data()
+      , val = $el.is('input') ? 'val' : 'html'
+
+    state = state + 'Text'
+    data.resetText || $el.data('resetText', $el[val]())
+
+    $el[val](data[state] || this.options[state])
+
+    // push to event loop to allow forms to submit
+    setTimeout(function () {
+      state == 'loadingText' ?
+        $el.addClass(d).attr(d, d) :
+        $el.removeClass(d).removeAttr(d)
+    }, 0)
+  }
+
+  Button.prototype.toggle = function () {
+    var $parent = this.$element.parent('[data-toggle="buttons-radio"]')
+
+    $parent && $parent
+      .find('.active')
+      .removeClass('active')
+
+    this.$element.toggleClass('active')
+  }
+
+
+ /* BUTTON PLUGIN DEFINITION
+  * ======================== */
+
+  $.fn.button = function (option) {
+    return this.each(function () {
+      var $this = $(this)
+        , data = $this.data('button')
+        , options = typeof option == 'object' && option
+      if (!data) $this.data('button', (data = new Button(this, options)))
+      if (option == 'toggle') data.toggle()
+      else if (option) data.setState(option)
+    })
+  }
+
+  $.fn.button.defaults = {
+    loadingText: 'loading...'
+  }
+
+  $.fn.button.Constructor = Button
+
+
+ /* BUTTON DATA-API
+  * =============== */
+
+  $(function () {
+    $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) {
+      var $btn = $(e.target)
+      if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
+      $btn.button('toggle')
+    })
+  })
+
+}(window.jQuery);/* ==========================================================
+ * bootstrap-carousel.js v2.0.4
+ * http://twitter.github.com/bootstrap/javascript.html#carousel
+ * ==========================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================================================== */
+
+
+!function ($) {
+
+  "use strict"; // jshint ;_;
+
+
+ /* CAROUSEL CLASS DEFINITION
+  * ========================= */
+
+  var Carousel = function (element, options) {
+    this.$element = $(element)
+    this.options = options
+    this.options.slide && this.slide(this.options.slide)
+    this.options.pause == 'hover' && this.$element
+      .on('mouseenter', $.proxy(this.pause, this))
+      .on('mouseleave', $.proxy(this.cycle, this))
+  }
+
+  Carousel.prototype = {
+
+    cycle: function (e) {
+      if (!e) this.paused = false
+      this.options.interval
+        && !this.paused
+        && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
+      return this
+    }
+
+  , to: function (pos) {
+      var $active = this.$element.find('.active')
+        , children = $active.parent().children()
+        , activePos = children.index($active)
+        , that = this
+
+      if (pos > (children.length - 1) || pos < 0) return
+
+      if (this.sliding) {
+        return this.$element.one('slid', function () {
+          that.to(pos)
+        })
+      }
+
+      if (activePos == pos) {
+        return this.pause().cycle()
+      }
+
+      return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos]))
+    }
+
+  , pause: function (e) {
+      if (!e) this.paused = true
+      clearInterval(this.interval)
+      this.interval = null
+      return this
+    }
+
+  , next: function () {
+      if (this.sliding) return
+      return this.slide('next')
+    }
+
+  , prev: function () {
+      if (this.sliding) return
+      return this.slide('prev')
+    }
+
+  , slide: function (type, next) {
+      var $active = this.$element.find('.active')
+        , $next = next || $active[type]()
+        , isCycling = this.interval
+        , direction = type == 'next' ? 'left' : 'right'
+        , fallback  = type == 'next' ? 'first' : 'last'
+        , that = this
+        , e = $.Event('slide')
+
+      this.sliding = true
+
+      isCycling && this.pause()
+
+      $next = $next.length ? $next : this.$element.find('.item')[fallback]()
+
+      if ($next.hasClass('active')) return
+
+      if ($.support.transition && this.$element.hasClass('slide')) {
+        this.$element.trigger(e)
+        if (e.isDefaultPrevented()) return
+        $next.addClass(type)
+        $next[0].offsetWidth // force reflow
+        $active.addClass(direction)
+        $next.addClass(direction)
+        this.$element.one($.support.transition.end, function () {
+          $next.removeClass([type, direction].join(' ')).addClass('active')
+          $active.removeClass(['active', direction].join(' '))
+          that.sliding = false
+          setTimeout(function () { that.$element.trigger('slid') }, 0)
+        })
+      } else {
+        this.$element.trigger(e)
+        if (e.isDefaultPrevented()) return
+        $active.removeClass('active')
+        $next.addClass('active')
+        this.sliding = false
+        this.$element.trigger('slid')
+      }
+
+      isCycling && this.cycle()
+
+      return this
+    }
+
+  }
+
+
+ /* CAROUSEL PLUGIN DEFINITION
+  * ========================== */
+
+  $.fn.carousel = function (option) {
+    return this.each(function () {
+      var $this = $(this)
+        , data = $this.data('carousel')
+        , options = $.extend({}, $.fn.carousel.defaults, typeof option == 'object' && option)
+      if (!data) $this.data('carousel', (data = new Carousel(this, options)))
+      if (typeof option == 'number') data.to(option)
+      else if (typeof option == 'string' || (option = options.slide)) data[option]()
+      else if (options.interval) data.cycle()
+    })
+  }
+
+  $.fn.carousel.defaults = {
+    interval: 5000
+  , pause: 'hover'
+  }
+
+  $.fn.carousel.Constructor = Carousel
+
+
+ /* CAROUSEL DATA-API
+  * ================= */
+
+  $(function () {
+    $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) {
+      var $this = $(this), href
+        , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
+        , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data())
+      $target.carousel(options)
+      e.preventDefault()
+    })
+  })
+
+}(window.jQuery);/* =============================================================
+ * bootstrap-collapse.js v2.0.4
+ * http://twitter.github.com/bootstrap/javascript.html#collapse
+ * =============================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============================================================ */
+
+
+!function ($) {
+
+  "use strict"; // jshint ;_;
+
+
+ /* COLLAPSE PUBLIC CLASS DEFINITION
+  * ================================ */
+
+  var Collapse = function (element, options) {
+    this.$element = $(element)
+    this.options = $.extend({}, $.fn.collapse.defaults, options)
+
+    if (this.options.parent) {
+      this.$parent = $(this.options.parent)
+    }
+
+    this.options.toggle && this.toggle()
+  }
+
+  Collapse.prototype = {
+
+    constructor: Collapse
+
+  , dimension: function () {
+      var hasWidth = this.$element.hasClass('width')
+      return hasWidth ? 'width' : 'height'
+    }
+
+  , show: function () {
+      var dimension
+        , scroll
+        , actives
+        , hasData
+
+      if (this.transitioning) return
+
+      dimension = this.dimension()
+      scroll = $.camelCase(['scroll', dimension].join('-'))
+      actives = this.$parent && this.$parent.find('> .accordion-group > .in')
+
+      if (actives && actives.length) {
+        hasData = actives.data('collapse')
+        if (hasData && hasData.transitioning) return
+        actives.collapse('hide')
+        hasData || actives.data('collapse', null)
+      }
+
+      this.$element[dimension](0)
+      this.transition('addClass', $.Event('show'), 'shown')
+      this.$element[dimension](this.$element[0][scroll])
+    }
+
+  , hide: function () {
+      var dimension
+      if (this.transitioning) return
+      dimension = this.dimension()
+      this.reset(this.$element[dimension]())
+      this.transition('removeClass', $.Event('hide'), 'hidden')
+      this.$element[dimension](0)
+    }
+
+  , reset: function (size) {
+      var dimension = this.dimension()
+
+      this.$element
+        .removeClass('collapse')
+        [dimension](size || 'auto')
+        [0].offsetWidth
+
+      this.$element[size !== null ? 'addClass' : 'removeClass']('collapse')
+
+      return this
+    }
+
+  , transition: function (method, startEvent, completeEvent) {
+      var that = this
+        , complete = function () {
+            if (startEvent.type == 'show') that.reset()
+            that.transitioning = 0
+            that.$element.trigger(completeEvent)
+          }
+
+      this.$element.trigger(startEvent)
+
+      if (startEvent.isDefaultPrevented()) return
+
+      this.transitioning = 1
+
+      this.$element[method]('in')
+
+      $.support.transition && this.$element.hasClass('collapse') ?
+        this.$element.one($.support.transition.end, complete) :
+        complete()
+    }
+
+  , toggle: function () {
+      this[this.$element.hasClass('in') ? 'hide' : 'show']()
+    }
+
+  }
+
+
+ /* COLLAPSIBLE PLUGIN DEFINITION
+  * ============================== */
+
+  $.fn.collapse = function (option) {
+    return this.each(function () {
+      var $this = $(this)
+        , data = $this.data('collapse')
+        , options = typeof option == 'object' && option
+      if (!data) $this.data('collapse', (data = new Collapse(this, options)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  $.fn.collapse.defaults = {
+    toggle: true
+  }
+
+  $.fn.collapse.Constructor = Collapse
+
+
+ /* COLLAPSIBLE DATA-API
+  * ==================== */
+
+  $(function () {
+    $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) {
+      var $this = $(this), href
+        , target = $this.attr('data-target')
+          || e.preventDefault()
+          || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
+        , option = $(target).data('collapse') ? 'toggle' : $this.data()
+      $(target).collapse(option)
+    })
+  })
+
+}(window.jQuery);/* ============================================================
+ * bootstrap-dropdown.js v2.0.4
+ * http://twitter.github.com/bootstrap/javascript.html#dropdowns
+ * ============================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============================================================ */
+
+
+!function ($) {
+
+  "use strict"; // jshint ;_;
+
+
+ /* DROPDOWN CLASS DEFINITION
+  * ========================= */
+
+  var toggle = '[data-toggle="dropdown"]'
+    , Dropdown = function (element) {
+        var $el = $(element).on('click.dropdown.data-api', this.toggle)
+        $('html').on('click.dropdown.data-api', function () {
+          $el.parent().removeClass('open')
+        })
+      }
+
+  Dropdown.prototype = {
+
+    constructor: Dropdown
+
+  , toggle: function (e) {
+      var $this = $(this)
+        , $parent
+        , selector
+        , isActive
+
+      if ($this.is('.disabled, :disabled')) return
+
+      selector = $this.attr('data-target')
+
+      if (!selector) {
+        selector = $this.attr('href')
+        selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
+      }
+
+      $parent = $(selector)
+      $parent.length || ($parent = $this.parent())
+
+      isActive = $parent.hasClass('open')
+
+      clearMenus()
+
+      if (!isActive) $parent.toggleClass('open')
+
+      return false
+    }
+
+  }
+
+  function clearMenus() {
+    $(toggle).parent().removeClass('open')
+  }
+
+
+  /* DROPDOWN PLUGIN DEFINITION
+   * ========================== */
+
+  $.fn.dropdown = function (option) {
+    return this.each(function () {
+      var $this = $(this)
+        , data = $this.data('dropdown')
+      if (!data) $this.data('dropdown', (data = new Dropdown(this)))
+      if (typeof option == 'string') data[option].call($this)
+    })
+  }
+
+  $.fn.dropdown.Constructor = Dropdown
+
+
+  /* APPLY TO STANDARD DROPDOWN ELEMENTS
+   * =================================== */
+
+  $(function () {
+    $('html').on('click.dropdown.data-api', clearMenus)
+    $('body')
+      .on('click.dropdown', '.dropdown form', function (e) { e.stopPropagation() })
+      .on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle)
+  })
+
+}(window.jQuery);/* =========================================================
+ * bootstrap-modal.js v2.0.4
+ * http://twitter.github.com/bootstrap/javascript.html#modals
+ * =========================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================================================= */
+
+
+!function ($) {
+
+  "use strict"; // jshint ;_;
+
+
+ /* MODAL CLASS DEFINITION
+  * ====================== */
+
+  var Modal = function (content, options) {
+    this.options = options
+    this.$element = $(content)
+      .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this))
+  }
+
+  Modal.prototype = {
+
+      constructor: Modal
+
+    , toggle: function () {
+        return this[!this.isShown ? 'show' : 'hide']()
+      }
+
+    , show: function () {
+        var that = this
+          , e = $.Event('show')
+
+        this.$element.trigger(e)
+
+        if (this.isShown || e.isDefaultPrevented()) return
+
+        $('body').addClass('modal-open')
+
+        this.isShown = true
+
+        escape.call(this)
+        backdrop.call(this, function () {
+          var transition = $.support.transition && that.$element.hasClass('fade')
+
+          if (!that.$element.parent().length) {
+            that.$element.appendTo(document.body) //don't move modals dom position
+          }
+
+          that.$element
+            .show()
+
+          if (transition) {
+            that.$element[0].offsetWidth // force reflow
+          }
+
+          that.$element.addClass('in')
+
+          transition ?
+            that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) :
+            that.$element.trigger('shown')
+
+        })
+      }
+
+    , hide: function (e) {
+        e && e.preventDefault()
+
+        var that = this
+
+        e = $.Event('hide')
+
+        this.$element.trigger(e)
+
+        if (!this.isShown || e.isDefaultPrevented()) return
+
+        this.isShown = false
+
+        $('body').removeClass('modal-open')
+
+        escape.call(this)
+
+        this.$element.removeClass('in')
+
+        $.support.transition && this.$element.hasClass('fade') ?
+          hideWithTransition.call(this) :
+          hideModal.call(this)
+      }
+
+  }
+
+
+ /* MODAL PRIVATE METHODS
+  * ===================== */
+
+  function hideWithTransition() {
+    var that = this
+      , timeout = setTimeout(function () {
+          that.$element.off($.support.transition.end)
+          hideModal.call(that)
+        }, 500)
+
+    this.$element.one($.support.transition.end, function () {
+      clearTimeout(timeout)
+      hideModal.call(that)
+    })
+  }
+
+  function hideModal(that) {
+    this.$element
+      .hide()
+      .trigger('hidden')
+
+    backdrop.call(this)
+  }
+
+  function backdrop(callback) {
+    var that = this
+      , animate = this.$element.hasClass('fade') ? 'fade' : ''
+
+    if (this.isShown && this.options.backdrop) {
+      var doAnimate = $.support.transition && animate
+
+      this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
+        .appendTo(document.body)
+
+      if (this.options.backdrop != 'static') {
+        this.$backdrop.click($.proxy(this.hide, this))
+      }
+
+      if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
+
+      this.$backdrop.addClass('in')
+
+      doAnimate ?
+        this.$backdrop.one($.support.transition.end, callback) :
+        callback()
+
+    } else if (!this.isShown && this.$backdrop) {
+      this.$backdrop.removeClass('in')
+
+      $.support.transition && this.$element.hasClass('fade')?
+        this.$backdrop.one($.support.transition.end, $.proxy(removeBackdrop, this)) :
+        removeBackdrop.call(this)
+
+    } else if (callback) {
+      callback()
+    }
+  }
+
+  function removeBackdrop() {
+    this.$backdrop.remove()
+    this.$backdrop = null
+  }
+
+  function escape() {
+    var that = this
+    if (this.isShown && this.options.keyboard) {
+      $(document).on('keyup.dismiss.modal', function ( e ) {
+        e.which == 27 && that.hide()
+      })
+    } else if (!this.isShown) {
+      $(document).off('keyup.dismiss.modal')
+    }
+  }
+
+
+ /* MODAL PLUGIN DEFINITION
+  * ======================= */
+
+  $.fn.modal = function (option) {
+    return this.each(function () {
+      var $this = $(this)
+        , data = $this.data('modal')
+        , options = $.extend({}, $.fn.modal.defaults, $this.data(), typeof option == 'object' && option)
+      if (!data) $this.data('modal', (data = new Modal(this, options)))
+      if (typeof option == 'string') data[option]()
+      else if (options.show) data.show()
+    })
+  }
+
+  $.fn.modal.defaults = {
+      backdrop: true
+    , keyboard: true
+    , show: true
+  }
+
+  $.fn.modal.Constructor = Modal
+
+
+ /* MODAL DATA-API
+  * ============== */
+
+  $(function () {
+    $('body').on('click.modal.data-api', '[data-toggle="modal"]', function ( e ) {
+      var $this = $(this), href
+        , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
+        , option = $target.data('modal') ? 'toggle' : $.extend({}, $target.data(), $this.data())
+
+      e.preventDefault()
+      $target.modal(option)
+    })
+  })
+
+}(window.jQuery);/* ===========================================================
+ * bootstrap-tooltip.js v2.0.4
+ * http://twitter.github.com/bootstrap/javascript.html#tooltips
+ * Inspired by the original jQuery.tipsy by Jason Frame
+ * ===========================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================================================== */
+
+
+!function ($) {
+
+  "use strict"; // jshint ;_;
+
+
+ /* TOOLTIP PUBLIC CLASS DEFINITION
+  * =============================== */
+
+  var Tooltip = function (element, options) {
+    this.init('tooltip', element, options)
+  }
+
+  Tooltip.prototype = {
+
+    constructor: Tooltip
+
+  , init: function (type, element, options) {
+      var eventIn
+        , eventOut
+
+      this.type = type
+      this.$element = $(element)
+      this.options = this.getOptions(options)
+      this.enabled = true
+
+      if (this.options.trigger != 'manual') {
+        eventIn  = this.options.trigger == 'hover' ? 'mouseenter' : 'focus'
+        eventOut = this.options.trigger == 'hover' ? 'mouseleave' : 'blur'
+        this.$element.on(eventIn, this.options.selector, $.proxy(this.enter, this))
+        this.$element.on(eventOut, this.options.selector, $.proxy(this.leave, this))
+      }
+
+      this.options.selector ?
+        (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
+        this.fixTitle()
+    }
+
+  , getOptions: function (options) {
+      options = $.extend({}, $.fn[this.type].defaults, options, this.$element.data())
+
+      if (options.delay && typeof options.delay == 'number') {
+        options.delay = {
+          show: options.delay
+        , hide: options.delay
+        }
+      }
+
+      return options
+    }
+
+  , enter: function (e) {
+      var self = $(e.currentTarget)[this.type](this._options).data(this.type)
+
+      if (!self.options.delay || !self.options.delay.show) return self.show()
+
+      clearTimeout(this.timeout)
+      self.hoverState = 'in'
+      this.timeout = setTimeout(function() {
+        if (self.hoverState == 'in') self.show()
+      }, self.options.delay.show)
+    }
+
+  , leave: function (e) {
+      var self = $(e.currentTarget)[this.type](this._options).data(this.type)
+
+      if (this.timeout) clearTimeout(this.timeout)
+      if (!self.options.delay || !self.options.delay.hide) return self.hide()
+
+      self.hoverState = 'out'
+      this.timeout = setTimeout(function() {
+        if (self.hoverState == 'out') self.hide()
+      }, self.options.delay.hide)
+    }
+
+  , show: function () {
+      var $tip
+        , inside
+        , pos
+        , actualWidth
+        , actualHeight
+        , placement
+        , tp
+
+      if (this.hasContent() && this.enabled) {
+        $tip = this.tip()
+        this.setContent()
+
+        if (this.options.animation) {
+          $tip.addClass('fade')
+        }
+
+        placement = typeof this.options.placement == 'function' ?
+          this.options.placement.call(this, $tip[0], this.$element[0]) :
+          this.options.placement
+
+        inside = /in/.test(placement)
+
+        $tip
+          .remove()
+          .css({ top: 0, left: 0, display: 'block' })
+          .appendTo(inside ? this.$element : document.body)
+
+        pos = this.getPosition(inside)
+
+        actualWidth = $tip[0].offsetWidth
+        actualHeight = $tip[0].offsetHeight
+
+        switch (inside ? placement.split(' ')[1] : placement) {
+          case 'bottom':
+            tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2}
+            break
+          case 'top':
+            tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2}
+            break
+          case 'left':
+            tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth}
+            break
+          case 'right':
+            tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width}
+            break
+        }
+
+        $tip
+          .css(tp)
+          .addClass(placement)
+          .addClass('in')
+      }
+    }
+
+  , isHTML: function(text) {
+      // html string detection logic adapted from jQuery
+      return typeof text != 'string'
+        || ( text.charAt(0) === "<"
+          && text.charAt( text.length - 1 ) === ">"
+          && text.length >= 3
+        ) || /^(?:[^<]*<[\w\W]+>[^>]*$)/.exec(text)
+    }
+
+  , setContent: function () {
+      var $tip = this.tip()
+        , title = this.getTitle()
+
+      $tip.find('.tooltip-inner')[this.isHTML(title) ? 'html' : 'text'](title)
+      $tip.removeClass('fade in top bottom left right')
+    }
+
+  , hide: function () {
+      var that = this
+        , $tip = this.tip()
+
+      $tip.removeClass('in')
+