You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2013/06/03 19:49:00 UTC

[4/6] git commit: Add smarter caching to the Less compiler

Add smarter caching to the Less compiler

Include a slightly modified version of Bootstrap 2.3.2 to test the Less compiler


Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/554ed703
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/554ed703
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/554ed703

Branch: refs/heads/master
Commit: 554ed7030545ca45421718b5c979aadacbd3789e
Parents: 512ee31
Author: Howard M. Lewis Ship <hl...@apache.org>
Authored: Mon Jun 3 10:22:33 2013 -0700
Committer: Howard M. Lewis Ship <hl...@apache.org>
Committed: Mon Jun 3 10:22:33 2013 -0700

----------------------------------------------------------------------
 .../internal/wro4j/ContentChangeTracker.java       |   68 +
 .../internal/wro4j/LessResourceTransformer.java    |  106 +-
 .../wro4j/ResourceDependenciesSplitter.java        |   40 +
 .../internal/wro4j/ResourceTransformUtils.java     |   38 +
 .../wro4j/ResourceTransformerFactoryImpl.java      |   35 +-
 .../src/test/java/t5/wro4j/services/AppModule.java |   14 +
 .../src/test/resources/META-INF/assets/colors.less |    2 +-
 .../src/test/webapp/bootstrap/css/accordion.less   |   34 +
 .../src/test/webapp/bootstrap/css/alerts.less      |   79 +
 .../src/test/webapp/bootstrap/css/bootstrap.less   |   63 +
 .../src/test/webapp/bootstrap/css/breadcrumbs.less |   24 +
 .../test/webapp/bootstrap/css/button-groups.less   |  229 ++
 .../src/test/webapp/bootstrap/css/buttons.less     |  228 ++
 .../src/test/webapp/bootstrap/css/carousel.less    |  158 +
 .../src/test/webapp/bootstrap/css/close.less       |   32 +
 .../src/test/webapp/bootstrap/css/code.less        |   61 +
 .../webapp/bootstrap/css/component-animations.less |   22 +
 .../src/test/webapp/bootstrap/css/dropdowns.less   |  248 ++
 .../src/test/webapp/bootstrap/css/forms.less       |  690 +++++
 .../src/test/webapp/bootstrap/css/grid.less        |   21 +
 .../src/test/webapp/bootstrap/css/hero-unit.less   |   25 +
 .../test/webapp/bootstrap/css/labels-badges.less   |   84 +
 .../src/test/webapp/bootstrap/css/layouts.less     |   16 +
 .../src/test/webapp/bootstrap/css/media.less       |   55 +
 .../src/test/webapp/bootstrap/css/mixins.less      |  702 +++++
 .../src/test/webapp/bootstrap/css/modals.less      |   95 +
 .../src/test/webapp/bootstrap/css/navbar.less      |  497 ++++
 .../src/test/webapp/bootstrap/css/navs.less        |  409 +++
 .../src/test/webapp/bootstrap/css/pager.less       |   43 +
 .../src/test/webapp/bootstrap/css/pagination.less  |  123 +
 .../src/test/webapp/bootstrap/css/popovers.less    |  133 +
 .../test/webapp/bootstrap/css/progress-bars.less   |  122 +
 .../src/test/webapp/bootstrap/css/reset.less       |  216 ++
 .../bootstrap/css/responsive-1200px-min.less       |   28 +
 .../webapp/bootstrap/css/responsive-767px-max.less |  193 ++
 .../bootstrap/css/responsive-768px-979px.less      |   19 +
 .../webapp/bootstrap/css/responsive-navbar.less    |  189 ++
 .../webapp/bootstrap/css/responsive-utilities.less |   59 +
 .../src/test/webapp/bootstrap/css/responsive.less  |   48 +
 .../src/test/webapp/bootstrap/css/scaffolding.less |   53 +
 .../src/test/webapp/bootstrap/css/sprites.less     |  197 ++
 .../src/test/webapp/bootstrap/css/tables.less      |  244 ++
 .../src/test/webapp/bootstrap/css/thumbnails.less  |   53 +
 .../src/test/webapp/bootstrap/css/tooltip.less     |   70 +
 .../src/test/webapp/bootstrap/css/type.less        |  247 ++
 .../src/test/webapp/bootstrap/css/utilities.less   |   30 +
 .../src/test/webapp/bootstrap/css/variables.less   |  301 ++
 .../src/test/webapp/bootstrap/css/wells.less       |   29 +
 .../bootstrap/img/glyphicons-halflings-white.png   |  Bin 0 -> 8777 bytes
 .../webapp/bootstrap/img/glyphicons-halflings.png  |  Bin 0 -> 12799 bytes
 .../src/test/webapp/bootstrap/js/bootstrap.js      | 2280 +++++++++++++++
 51 files changed, 8692 insertions(+), 60 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/554ed703/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ContentChangeTracker.java
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ContentChangeTracker.java b/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ContentChangeTracker.java
new file mode 100644
index 0000000..770509e
--- /dev/null
+++ b/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ContentChangeTracker.java
@@ -0,0 +1,68 @@
+// Copyright 2013 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.
+
+package org.apache.tapestry5.internal.wro4j;
+
+import org.apache.tapestry5.ioc.Resource;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.services.assets.ResourceDependencies;
+
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * Manages a collection of Resources and can check to see if any resource's actual content has changed.
+ *
+ * @since 5.4
+ */
+public class ContentChangeTracker implements ResourceDependencies
+{
+    private final Map<Resource, Long> checksums = CollectionFactory.newMap();
+
+    public void addDependency(Resource dependency)
+    {
+        try
+        {
+            long checksum = ResourceTransformUtils.toChecksum(dependency);
+
+            checksums.put(dependency, checksum);
+        } catch (IOException e)
+        {
+            throw new RuntimeException(e);
+        }
+
+    }
+
+    /**
+     * Checks all resources tracked by this instance and returns true if any resource's content has changed.
+     *
+     * @return true if a change has occurred
+     */
+    public boolean changes() throws IOException
+    {
+        for (Map.Entry<Resource, Long> e : checksums.entrySet())
+        {
+            long current = ResourceTransformUtils.toChecksum(e.getKey());
+
+            if (current != e.getValue().longValue())
+            {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/554ed703/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/LessResourceTransformer.java
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/LessResourceTransformer.java b/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/LessResourceTransformer.java
index 1b655f9..b5f3709 100644
--- a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/LessResourceTransformer.java
+++ b/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/LessResourceTransformer.java
@@ -19,15 +19,19 @@ import com.github.sommeri.less4j.LessCompiler;
 import com.github.sommeri.less4j.LessSource;
 import com.github.sommeri.less4j.core.DefaultLessCompiler;
 import org.apache.commons.io.IOUtils;
+import org.apache.tapestry5.SymbolConstants;
 import org.apache.tapestry5.internal.services.assets.BytestreamCache;
 import org.apache.tapestry5.ioc.IOOperation;
 import org.apache.tapestry5.ioc.OperationTracker;
 import org.apache.tapestry5.ioc.Resource;
+import org.apache.tapestry5.ioc.annotations.Symbol;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.services.assets.ResourceDependencies;
 import org.apache.tapestry5.services.assets.ResourceTransformer;
 import org.slf4j.Logger;
 
 import java.io.*;
+import java.util.Map;
 
 /**
  * Direct wrapper around the LessCompiler, so that Less source files may use {@code @import}, which isn't
@@ -41,10 +45,35 @@ public class LessResourceTransformer implements ResourceTransformer
 
     private final Logger logger;
 
-    public LessResourceTransformer(OperationTracker tracker, Logger logger)
+    private final boolean cacheEnabled;
+
+    private final Map<Resource, Cached> cache = CollectionFactory.newConcurrentMap();
+
+    static class Cached
+    {
+        final BytestreamCache compiled;
+
+        final ContentChangeTracker tracker;
+
+        Cached(BytestreamCache compiled, ContentChangeTracker tracker)
+        {
+            this.compiled = compiled;
+            this.tracker = tracker;
+        }
+
+        InputStream openStream() throws IOException
+        {
+            return compiled.openStream();
+        }
+    }
+
+
+    public LessResourceTransformer(OperationTracker tracker, Logger logger, @Symbol(SymbolConstants.PRODUCTION_MODE) boolean productionMode)
     {
         this.tracker = tracker;
         this.logger = logger;
+
+        cacheEnabled = !productionMode;
     }
 
     public String getTransformedContentType()
@@ -105,43 +134,70 @@ public class LessResourceTransformer implements ResourceTransformer
 
     public InputStream transform(final Resource source, final ResourceDependencies dependencies) throws IOException
     {
-        return tracker.perform(String.format("Compiling %s from Less to CSS", source), new IOOperation<InputStream>()
+        if (cacheEnabled)
         {
-            public InputStream perform() throws IOException
+            Cached cached = cache.get(source);
+
+            if (cached != null && !cached.tracker.changes())
             {
-                long start = System.nanoTime();
+                logger.info(String.format("Resource %s (and any dependencies) are unchanged; serving compiled Less content from cache",
+                        source));
 
-                InputStream result = compile(source, dependencies);
+                return cached.openStream();
+            }
 
-                long complete = System.nanoTime();
+            ContentChangeTracker tracker1 = new ContentChangeTracker();
+            tracker1.addDependency(source);
 
-                logger.info(String.format("Compiled %s to Less in %.2f ms",
-                        source, ResourceTransformUtils.nanosToMillis(complete - start)));
+            BytestreamCache compiled = invokeLessCompiler(source, new ResourceDependenciesSplitter(dependencies, tracker1));
 
-                return result;
-            }
-        });
+            cached = new Cached(compiled, tracker1);
+
+            cache.put(source, cached);
+
+            return cached.openStream();
+        } else
+        {
+
+            BytestreamCache compiled = invokeLessCompiler(source, dependencies);
+
+            return compiled.openStream();
+        }
     }
 
-    private InputStream compile(Resource source, ResourceDependencies dependencies) throws IOException
+    private BytestreamCache invokeLessCompiler(final Resource source, final ResourceDependencies dependencies) throws IOException
     {
-        try
+
+        return tracker.perform(String.format("Compiling %s from Less to CSS", source), new IOOperation<BytestreamCache>()
         {
-            LessSource lessSource = new ResourceLessSource(source, dependencies);
+            public BytestreamCache perform() throws IOException
+            {
+                long start = System.nanoTime();
 
-            LessCompiler.CompilationResult result = compiler.compile(lessSource);
+                try
+                {
+                    LessSource lessSource = new ResourceLessSource(source, dependencies);
 
-            // Currently, ignoring any warnings.
+                    LessCompiler.CompilationResult compilationResult = compiler.compile(lessSource);
 
-            BytestreamCache cache = new BytestreamCache(result.getCss().getBytes("utf-8"));
+                    BytestreamCache result = new BytestreamCache(compilationResult.getCss().getBytes("utf-8"));
 
-            return cache.openStream();
-        } catch (Less4jException ex)
-        {
-            throw new IOException(ex);
-        } catch (UnsupportedEncodingException ex)
-        {
-            throw new IOException(ex);
-        }
+                    logger.info(String.format("Compiled %s to Less in %.2f ms",
+                            source, ResourceTransformUtils.nanosToMillis(System.nanoTime() - start)));
+
+                    // Currently, ignoring any warnings.
+
+                    return result;
+
+                } catch (Less4jException ex)
+                {
+                    throw new IOException(ex);
+                } catch (UnsupportedEncodingException ex)
+                {
+                    throw new IOException(ex);
+                }
+
+            }
+        });
     }
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/554ed703/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceDependenciesSplitter.java
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceDependenciesSplitter.java b/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceDependenciesSplitter.java
new file mode 100644
index 0000000..7b69916
--- /dev/null
+++ b/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceDependenciesSplitter.java
@@ -0,0 +1,40 @@
+// Copyright 2013 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.
+
+package org.apache.tapestry5.internal.wro4j;
+
+import org.apache.tapestry5.ioc.Resource;
+import org.apache.tapestry5.services.assets.ResourceDependencies;
+
+/**
+ * A wrapper around two ResourceDependencies.
+ *
+ * @since 5.4
+ */
+public class ResourceDependenciesSplitter implements ResourceDependencies
+{
+    private final ResourceDependencies left, right;
+
+    public ResourceDependenciesSplitter(ResourceDependencies left, ResourceDependencies right)
+    {
+        this.left = left;
+        this.right = right;
+    }
+
+    public void addDependency(Resource dependency)
+    {
+        left.addDependency(dependency);
+        right.addDependency(dependency);
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/554ed703/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformUtils.java b/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformUtils.java
index eed495f..b236633 100644
--- a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformUtils.java
+++ b/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformUtils.java
@@ -14,6 +14,12 @@
 
 package org.apache.tapestry5.internal.wro4j;
 
+import org.apache.tapestry5.ioc.Resource;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.Adler32;
+
 /**
  * @since 5.4
  */
@@ -25,4 +31,36 @@ public class ResourceTransformUtils
     {
         return ((double) nanos) * NANOS_TO_MILLIS;
     }
+
+    public static long toChecksum(Resource resource) throws IOException
+    {
+        Adler32 checksum = new Adler32();
+
+        byte[] buffer = new byte[1024];
+
+        InputStream is = null;
+
+        try
+        {
+            is = resource.openStream();
+
+            while (true)
+            {
+                int length = is.read(buffer);
+
+                if (length < 0)
+                {
+                    break;
+                }
+
+                checksum.update(buffer, 0, length);
+            }
+
+            // Reduces it down to just 32 bits which we express in hex.'
+            return checksum.getValue();
+        } finally
+        {
+            is.close();
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/554ed703/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformerFactoryImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformerFactoryImpl.java b/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformerFactoryImpl.java
index 99d438f..f8f3dec 100644
--- a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformerFactoryImpl.java
+++ b/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformerFactoryImpl.java
@@ -30,7 +30,6 @@ import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.Map;
-import java.util.zip.Adler32;
 
 public class ResourceTransformerFactoryImpl implements ResourceTransformerFactory
 {
@@ -78,38 +77,6 @@ public class ResourceTransformerFactoryImpl implements ResourceTransformerFactor
         }
     }
 
-    private long toChecksum(Resource resource) throws IOException
-    {
-        Adler32 checksum = new Adler32();
-
-        byte[] buffer = new byte[1024];
-
-        InputStream is = null;
-
-        try
-        {
-            is = resource.openStream();
-
-            while (true)
-            {
-                int length = is.read(buffer);
-
-                if (length < 0)
-                {
-                    break;
-                }
-
-                checksum.update(buffer, 0, length);
-            }
-
-            // Reduces it down to just 32 bits which we express in hex.'
-            return checksum.getValue();
-        } finally
-        {
-            is.close();
-        }
-    }
-
     public ResourceTransformer createCompiler(final String contentType, String processorName, final String sourceName, final String targetName, boolean enableCache)
     {
         // This does the real work:
@@ -177,7 +144,7 @@ public class ResourceTransformerFactoryImpl implements ResourceTransformerFactor
 
             public InputStream transform(Resource source, ResourceDependencies dependencies) throws IOException
             {
-                long checksum = toChecksum(source);
+                long checksum = ResourceTransformUtils.toChecksum(source);
 
                 Compiled compiled = cache.get(source);
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/554ed703/tapestry-wro4j/src/test/java/t5/wro4j/services/AppModule.java
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/test/java/t5/wro4j/services/AppModule.java b/tapestry-wro4j/src/test/java/t5/wro4j/services/AppModule.java
index 0d7f1e0..49d96dc 100644
--- a/tapestry-wro4j/src/test/java/t5/wro4j/services/AppModule.java
+++ b/tapestry-wro4j/src/test/java/t5/wro4j/services/AppModule.java
@@ -2,12 +2,17 @@ package t5.wro4j.services;
 
 import org.apache.tapestry5.SymbolConstants;
 import org.apache.tapestry5.ioc.MappedConfiguration;
+import org.apache.tapestry5.ioc.OrderedConfiguration;
 import org.apache.tapestry5.ioc.annotations.Contribute;
 import org.apache.tapestry5.ioc.annotations.SubModule;
 import org.apache.tapestry5.ioc.services.ApplicationDefaults;
 import org.apache.tapestry5.ioc.services.SymbolProvider;
+import org.apache.tapestry5.services.Core;
 import org.apache.tapestry5.services.compatibility.Compatibility;
 import org.apache.tapestry5.services.compatibility.Trait;
+import org.apache.tapestry5.services.javascript.JavaScriptStack;
+import org.apache.tapestry5.services.javascript.StackExtension;
+import org.apache.tapestry5.services.javascript.StackExtensionType;
 import org.apache.tapestry5.wro4j.modules.WRO4JModule;
 
 @SubModule(WRO4JModule.class)
@@ -26,5 +31,14 @@ public class AppModule
     {
         configuration.add(SymbolConstants.JAVASCRIPT_INFRASTRUCTURE_PROVIDER, "jquery");
         configuration.add(SymbolConstants.MINIFICATION_ENABLED, true);
+        configuration.add(SymbolConstants.BOOTSTRAP_ROOT, "context:bootstrap");
+    }
+
+    @Contribute(JavaScriptStack.class)
+    @Core
+    public static void overrideBootstrapCSS(OrderedConfiguration<StackExtension> configuration)
+    {
+        configuration.override("bootstrap.css",
+                new StackExtension(StackExtensionType.STYLESHEET, "context:bootstrap/css/bootstrap.less"), "before:tapestry.css");
     }
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/554ed703/tapestry-wro4j/src/test/resources/META-INF/assets/colors.less
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/test/resources/META-INF/assets/colors.less b/tapestry-wro4j/src/test/resources/META-INF/assets/colors.less
index 923c7c5..bea670b 100644
--- a/tapestry-wro4j/src/test/resources/META-INF/assets/colors.less
+++ b/tapestry-wro4j/src/test/resources/META-INF/assets/colors.less
@@ -1,2 +1,2 @@
 @primary: blue;
-@secondary: lighten(@primary, 25%);
\ No newline at end of file
+@secondary: lighten(@primary, 35%);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/554ed703/tapestry-wro4j/src/test/webapp/bootstrap/css/accordion.less
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/test/webapp/bootstrap/css/accordion.less b/tapestry-wro4j/src/test/webapp/bootstrap/css/accordion.less
new file mode 100644
index 0000000..d63523b
--- /dev/null
+++ b/tapestry-wro4j/src/test/webapp/bootstrap/css/accordion.less
@@ -0,0 +1,34 @@
+//
+// Accordion
+// --------------------------------------------------
+
+
+// Parent container
+.accordion {
+  margin-bottom: @baseLineHeight;
+}
+
+// Group == heading + body
+.accordion-group {
+  margin-bottom: 2px;
+  border: 1px solid #e5e5e5;
+  .border-radius(@baseBorderRadius);
+}
+.accordion-heading {
+  border-bottom: 0;
+}
+.accordion-heading .accordion-toggle {
+  display: block;
+  padding: 8px 15px;
+}
+
+// General toggle styles
+.accordion-toggle {
+  cursor: pointer;
+}
+
+// Inner needs the styles because you can't animate properly with any styles on the element
+.accordion-inner {
+  padding: 9px 15px;
+  border-top: 1px solid #e5e5e5;
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/554ed703/tapestry-wro4j/src/test/webapp/bootstrap/css/alerts.less
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/test/webapp/bootstrap/css/alerts.less b/tapestry-wro4j/src/test/webapp/bootstrap/css/alerts.less
new file mode 100644
index 0000000..0116b19
--- /dev/null
+++ b/tapestry-wro4j/src/test/webapp/bootstrap/css/alerts.less
@@ -0,0 +1,79 @@
+//
+// Alerts
+// --------------------------------------------------
+
+
+// Base styles
+// -------------------------
+
+.alert {
+  padding: 8px 35px 8px 14px;
+  margin-bottom: @baseLineHeight;
+  text-shadow: 0 1px 0 rgba(255,255,255,.5);
+  background-color: @warningBackground;
+  border: 1px solid @warningBorder;
+  .border-radius(@baseBorderRadius);
+}
+.alert,
+.alert h4 {
+  // Specified for the h4 to prevent conflicts of changing @headingsColor
+  color: @warningText;
+}
+.alert h4 {
+  margin: 0;
+}
+
+// Adjust close link position
+.alert .close {
+  position: relative;
+  top: -2px;
+  right: -21px;
+  line-height: @baseLineHeight;
+}
+
+
+// Alternate styles
+// -------------------------
+
+.alert-success {
+  background-color: @successBackground;
+  border-color: @successBorder;
+  color: @successText;
+}
+.alert-success h4 {
+  color: @successText;
+}
+.alert-danger,
+.alert-error {
+  background-color: @errorBackground;
+  border-color: @errorBorder;
+  color: @errorText;
+}
+.alert-danger h4,
+.alert-error h4 {
+  color: @errorText;
+}
+.alert-info {
+  background-color: @infoBackground;
+  border-color: @infoBorder;
+  color: @infoText;
+}
+.alert-info h4 {
+  color: @infoText;
+}
+
+
+// Block alerts
+// -------------------------
+
+.alert-block {
+  padding-top: 14px;
+  padding-bottom: 14px;
+}
+.alert-block > p,
+.alert-block > ul {
+  margin-bottom: 0;
+}
+.alert-block p + p {
+  margin-top: 5px;
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/554ed703/tapestry-wro4j/src/test/webapp/bootstrap/css/bootstrap.less
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/test/webapp/bootstrap/css/bootstrap.less b/tapestry-wro4j/src/test/webapp/bootstrap/css/bootstrap.less
new file mode 100644
index 0000000..d4ebf37
--- /dev/null
+++ b/tapestry-wro4j/src/test/webapp/bootstrap/css/bootstrap.less
@@ -0,0 +1,63 @@
+/*!
+ * Bootstrap v2.3.2
+ *
+ * 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.
+ */
+
+// Core variables and mixins
+@import "variables.less"; // Modify this for custom colors, font-sizes, etc
+@import "mixins.less";
+
+// CSS Reset
+@import "reset.less";
+
+// Grid system and page structure
+@import "scaffolding.less";
+@import "grid.less";
+@import "layouts.less";
+
+// Base CSS
+@import "type.less";
+@import "code.less";
+@import "forms.less";
+@import "tables.less";
+
+// Components: common
+@import "sprites.less";
+@import "dropdowns.less";
+@import "wells.less";
+@import "component-animations.less";
+@import "close.less";
+
+// Components: Buttons & Alerts
+@import "buttons.less";
+@import "button-groups.less";
+@import "alerts.less"; // Note: alerts share common CSS with buttons and thus have styles in buttons.less
+
+// Components: Nav
+@import "navs.less";
+@import "navbar.less";
+@import "breadcrumbs.less";
+@import "pagination.less";
+@import "pager.less";
+
+// Components: Popovers
+@import "modals.less";
+@import "tooltip.less";
+@import "popovers.less";
+
+// Components: Misc
+@import "thumbnails.less";
+@import "media.less";
+@import "labels-badges.less";
+@import "progress-bars.less";
+@import "accordion.less";
+@import "carousel.less";
+@import "hero-unit.less";
+
+// Utility classes
+@import "utilities.less"; // Has to be last to override when necessary

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/554ed703/tapestry-wro4j/src/test/webapp/bootstrap/css/breadcrumbs.less
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/test/webapp/bootstrap/css/breadcrumbs.less b/tapestry-wro4j/src/test/webapp/bootstrap/css/breadcrumbs.less
new file mode 100644
index 0000000..f753df6
--- /dev/null
+++ b/tapestry-wro4j/src/test/webapp/bootstrap/css/breadcrumbs.less
@@ -0,0 +1,24 @@
+//
+// Breadcrumbs
+// --------------------------------------------------
+
+
+.breadcrumb {
+  padding: 8px 15px;
+  margin: 0 0 @baseLineHeight;
+  list-style: none;
+  background-color: #f5f5f5;
+  .border-radius(@baseBorderRadius);
+  > li {
+    display: inline-block;
+    .ie7-inline-block();
+    text-shadow: 0 1px 0 @white;
+    > .divider {
+      padding: 0 5px;
+      color: #ccc;
+    }
+  }
+  > .active {
+    color: @grayLight;
+  }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/554ed703/tapestry-wro4j/src/test/webapp/bootstrap/css/button-groups.less
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/test/webapp/bootstrap/css/button-groups.less b/tapestry-wro4j/src/test/webapp/bootstrap/css/button-groups.less
new file mode 100644
index 0000000..55cdc60
--- /dev/null
+++ b/tapestry-wro4j/src/test/webapp/bootstrap/css/button-groups.less
@@ -0,0 +1,229 @@
+//
+// Button groups
+// --------------------------------------------------
+
+
+// Make the div behave like a button
+.btn-group {
+  position: relative;
+  display: inline-block;
+  .ie7-inline-block();
+  font-size: 0; // remove as part 1 of font-size inline-block hack
+  vertical-align: middle; // match .btn alignment given font-size hack above
+  white-space: nowrap; // prevent buttons from wrapping when in tight spaces (e.g., the table on the tests page)
+  .ie7-restore-left-whitespace();
+}
+
+// Space out series of button groups
+.btn-group + .btn-group {
+  margin-left: 5px;
+}
+
+// Optional: Group multiple button groups together for a toolbar
+.btn-toolbar {
+  font-size: 0; // Hack to remove whitespace that results from using inline-block
+  margin-top: @baseLineHeight / 2;
+  margin-bottom: @baseLineHeight / 2;
+  > .btn + .btn,
+  > .btn-group + .btn,
+  > .btn + .btn-group {
+    margin-left: 5px;
+  }
+}
+
+// Float them, remove border radius, then re-add to first and last elements
+.btn-group > .btn {
+  position: relative;
+  .border-radius(0);
+}
+.btn-group > .btn + .btn {
+  margin-left: -1px;
+}
+.btn-group > .btn,
+.btn-group > .dropdown-menu,
+.btn-group > .popover {
+  font-size: @baseFontSize; // redeclare as part 2 of font-size inline-block hack
+}
+
+// Reset fonts for other sizes
+.btn-group > .btn-mini {
+  font-size: @fontSizeMini;
+}
+.btn-group > .btn-small {
+  font-size: @fontSizeSmall;
+}
+.btn-group > .btn-large {
+  font-size: @fontSizeLarge;
+}
+
+// Set corners individual because sometimes a single button can be in a .btn-group and we need :first-child and :last-child to both match
+.btn-group > .btn:first-child {
+  margin-left: 0;
+  .border-top-left-radius(@baseBorderRadius);
+  .border-bottom-left-radius(@baseBorderRadius);
+}
+// Need .dropdown-toggle since :last-child doesn't apply given a .dropdown-menu immediately after it
+.btn-group > .btn:last-child,
+.btn-group > .dropdown-toggle {
+  .border-top-right-radius(@baseBorderRadius);
+  .border-bottom-right-radius(@baseBorderRadius);
+}
+// Reset corners for large buttons
+.btn-group > .btn.large:first-child {
+  margin-left: 0;
+  .border-top-left-radius(@borderRadiusLarge);
+  .border-bottom-left-radius(@borderRadiusLarge);
+}
+.btn-group > .btn.large:last-child,
+.btn-group > .large.dropdown-toggle {
+  .border-top-right-radius(@borderRadiusLarge);
+  .border-bottom-right-radius(@borderRadiusLarge);
+}
+
+// On hover/focus/active, bring the proper btn to front
+.btn-group > .btn:hover,
+.btn-group > .btn:focus,
+.btn-group > .btn:active,
+.btn-group > .btn.active {
+  z-index: 2;
+}
+
+// On active and open, don't show outline
+.btn-group .dropdown-toggle:active,
+.btn-group.open .dropdown-toggle {
+  outline: 0;
+}
+
+
+
+// Split button dropdowns
+// ----------------------
+
+// Give the line between buttons some depth
+.btn-group > .btn + .dropdown-toggle {
+  padding-left: 8px;
+  padding-right: 8px;
+  .box-shadow(~"inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05)");
+  *padding-top: 5px;
+  *padding-bottom: 5px;
+}
+.btn-group > .btn-mini + .dropdown-toggle {
+  padding-left: 5px;
+  padding-right: 5px;
+  *padding-top: 2px;
+  *padding-bottom: 2px;
+}
+.btn-group > .btn-small + .dropdown-toggle {
+  *padding-top: 5px;
+  *padding-bottom: 4px;
+}
+.btn-group > .btn-large + .dropdown-toggle {
+  padding-left: 12px;
+  padding-right: 12px;
+  *padding-top: 7px;
+  *padding-bottom: 7px;
+}
+
+.btn-group.open {
+
+  // The clickable button for toggling the menu
+  // Remove the gradient and set the same inset shadow as the :active state
+  .dropdown-toggle {
+    background-image: none;
+    .box-shadow(~"inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05)");
+  }
+
+  // Keep the hover's background when dropdown is open
+  .btn.dropdown-toggle {
+    background-color: @btnBackgroundHighlight;
+  }
+  .btn-primary.dropdown-toggle {
+    background-color: @btnPrimaryBackgroundHighlight;
+  }
+  .btn-warning.dropdown-toggle {
+    background-color: @btnWarningBackgroundHighlight;
+  }
+  .btn-danger.dropdown-toggle {
+    background-color: @btnDangerBackgroundHighlight;
+  }
+  .btn-success.dropdown-toggle {
+    background-color: @btnSuccessBackgroundHighlight;
+  }
+  .btn-info.dropdown-toggle {
+    background-color: @btnInfoBackgroundHighlight;
+  }
+  .btn-inverse.dropdown-toggle {
+    background-color: @btnInverseBackgroundHighlight;
+  }
+}
+
+
+// Reposition the caret
+.btn .caret {
+  margin-top: 8px;
+  margin-left: 0;
+}
+// Carets in other button sizes
+.btn-large .caret {
+  margin-top: 6px;
+}
+.btn-large .caret {
+  border-left-width:  5px;
+  border-right-width: 5px;
+  border-top-width:   5px;
+}
+.btn-mini .caret,
+.btn-small .caret {
+  margin-top: 8px;
+}
+// Upside down carets for .dropup
+.dropup .btn-large .caret {
+  border-bottom-width: 5px;
+}
+
+
+
+// Account for other colors
+.btn-primary,
+.btn-warning,
+.btn-danger,
+.btn-info,
+.btn-success,
+.btn-inverse {
+  .caret {
+    border-top-color: @white;
+    border-bottom-color: @white;
+  }
+}
+
+
+
+// Vertical button groups
+// ----------------------
+
+.btn-group-vertical {
+  display: inline-block; // makes buttons only take up the width they need
+  .ie7-inline-block();
+}
+.btn-group-vertical > .btn {
+  display: block;
+  float: none;
+  max-width: 100%;
+  .border-radius(0);
+}
+.btn-group-vertical > .btn + .btn {
+  margin-left: 0;
+  margin-top: -1px;
+}
+.btn-group-vertical > .btn:first-child {
+  .border-radius(@baseBorderRadius @baseBorderRadius 0 0);
+}
+.btn-group-vertical > .btn:last-child {
+  .border-radius(0 0 @baseBorderRadius @baseBorderRadius);
+}
+.btn-group-vertical > .btn-large:first-child {
+  .border-radius(@borderRadiusLarge @borderRadiusLarge 0 0);
+}
+.btn-group-vertical > .btn-large:last-child {
+  .border-radius(0 0 @borderRadiusLarge @borderRadiusLarge);
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/554ed703/tapestry-wro4j/src/test/webapp/bootstrap/css/buttons.less
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/test/webapp/bootstrap/css/buttons.less b/tapestry-wro4j/src/test/webapp/bootstrap/css/buttons.less
new file mode 100644
index 0000000..4cd4d86
--- /dev/null
+++ b/tapestry-wro4j/src/test/webapp/bootstrap/css/buttons.less
@@ -0,0 +1,228 @@
+//
+// Buttons
+// --------------------------------------------------
+
+
+// Base styles
+// --------------------------------------------------
+
+// Core
+.btn {
+  display: inline-block;
+  .ie7-inline-block();
+  padding: 4px 12px;
+  margin-bottom: 0; // For input.btn
+  font-size: @baseFontSize;
+  line-height: @baseLineHeight;
+  text-align: center;
+  vertical-align: middle;
+  cursor: pointer;
+  .buttonBackground(@btnBackground, @btnBackgroundHighlight, @grayDark, 0 1px 1px rgba(255,255,255,.75));
+  border: 1px solid @btnBorder;
+  *border: 0; // Remove the border to prevent IE7's black border on input:focus
+  border-bottom-color: darken(@btnBorder, 10%);
+  .border-radius(@baseBorderRadius);
+  .ie7-restore-left-whitespace(); // Give IE7 some love
+  .box-shadow(~"inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05)");
+
+  // Hover/focus state
+  &:hover,
+  &:focus {
+    color: @grayDark;
+    text-decoration: none;
+    background-position: 0 -15px;
+
+    // transition is only when going to hover/focus, otherwise the background
+    // behind the gradient (there for IE<=9 fallback) gets mismatched
+    .transition(background-position .1s linear);
+  }
+
+  // Focus state for keyboard and accessibility
+  &:focus {
+    .tab-focus();
+  }
+
+  // Active state
+  &.active,
+  &:active {
+    background-image: none;
+    outline: 0;
+    .box-shadow(~"inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05)");
+  }
+
+  // Disabled state
+  &.disabled,
+  &[disabled] {
+    cursor: default;
+    background-image: none;
+    .opacity(65);
+    .box-shadow(none);
+  }
+
+}
+
+
+
+// Button Sizes
+// --------------------------------------------------
+
+// Large
+.btn-large {
+  padding: @paddingLarge;
+  font-size: @fontSizeLarge;
+  .border-radius(@borderRadiusLarge);
+}
+.btn-large [class^="icon-"],
+.btn-large [class*=" icon-"] {
+  margin-top: 4px;
+}
+
+// Small
+.btn-small {
+  padding: @paddingSmall;
+  font-size: @fontSizeSmall;
+  .border-radius(@borderRadiusSmall);
+}
+.btn-small [class^="icon-"],
+.btn-small [class*=" icon-"] {
+  margin-top: 0;
+}
+.btn-mini [class^="icon-"],
+.btn-mini [class*=" icon-"] {
+  margin-top: -1px;
+}
+
+// Mini
+.btn-mini {
+  padding: @paddingMini;
+  font-size: @fontSizeMini;
+  .border-radius(@borderRadiusSmall);
+}
+
+
+// Block button
+// -------------------------
+
+.btn-block {
+  display: block;
+  width: 100%;
+  padding-left: 0;
+  padding-right: 0;
+  .box-sizing(border-box);
+}
+
+// Vertically space out multiple block buttons
+.btn-block + .btn-block {
+  margin-top: 5px;
+}
+
+// Specificity overrides
+input[type="submit"],
+input[type="reset"],
+input[type="button"] {
+  &.btn-block {
+    width: 100%;
+  }
+}
+
+
+
+// Alternate buttons
+// --------------------------------------------------
+
+// Provide *some* extra contrast for those who can get it
+.btn-primary.active,
+.btn-warning.active,
+.btn-danger.active,
+.btn-success.active,
+.btn-info.active,
+.btn-inverse.active {
+  color: rgba(255,255,255,.75);
+}
+
+// Set the backgrounds
+// -------------------------
+.btn-primary {
+  .buttonBackground(@btnPrimaryBackground, @btnPrimaryBackgroundHighlight);
+}
+// Warning appears are orange
+.btn-warning {
+  .buttonBackground(@btnWarningBackground, @btnWarningBackgroundHighlight);
+}
+// Danger and error appear as red
+.btn-danger {
+  .buttonBackground(@btnDangerBackground, @btnDangerBackgroundHighlight);
+}
+// Success appears as green
+.btn-success {
+  .buttonBackground(@btnSuccessBackground, @btnSuccessBackgroundHighlight);
+}
+// Info appears as a neutral blue
+.btn-info {
+  .buttonBackground(@btnInfoBackground, @btnInfoBackgroundHighlight);
+}
+// Inverse appears as dark gray
+.btn-inverse {
+  .buttonBackground(@btnInverseBackground, @btnInverseBackgroundHighlight);
+}
+
+
+// Cross-browser Jank
+// --------------------------------------------------
+
+button.btn,
+input[type="submit"].btn {
+
+  // Firefox 3.6 only I believe
+  &::-moz-focus-inner {
+    padding: 0;
+    border: 0;
+  }
+
+  // IE7 has some default padding on button controls
+  *padding-top: 3px;
+  *padding-bottom: 3px;
+
+  &.btn-large {
+    *padding-top: 7px;
+    *padding-bottom: 7px;
+  }
+  &.btn-small {
+    *padding-top: 3px;
+    *padding-bottom: 3px;
+  }
+  &.btn-mini {
+    *padding-top: 1px;
+    *padding-bottom: 1px;
+  }
+}
+
+
+// Link buttons
+// --------------------------------------------------
+
+// Make a button look and behave like a link
+.btn-link,
+.btn-link:active,
+.btn-link[disabled] {
+  background-color: transparent;
+  background-image: none;
+  .box-shadow(none);
+}
+.btn-link {
+  border-color: transparent;
+  cursor: pointer;
+  color: @linkColor;
+  .border-radius(0);
+}
+.btn-link:hover,
+.btn-link:focus {
+  color: @linkColorHover;
+  text-decoration: underline;
+  background-color: transparent;
+}
+.btn-link[disabled]:hover,
+.btn-link[disabled]:focus {
+  color: @grayDark;
+  text-decoration: none;
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/554ed703/tapestry-wro4j/src/test/webapp/bootstrap/css/carousel.less
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/test/webapp/bootstrap/css/carousel.less b/tapestry-wro4j/src/test/webapp/bootstrap/css/carousel.less
new file mode 100644
index 0000000..55bc050
--- /dev/null
+++ b/tapestry-wro4j/src/test/webapp/bootstrap/css/carousel.less
@@ -0,0 +1,158 @@
+//
+// Carousel
+// --------------------------------------------------
+
+
+.carousel {
+  position: relative;
+  margin-bottom: @baseLineHeight;
+  line-height: 1;
+}
+
+.carousel-inner {
+  overflow: hidden;
+  width: 100%;
+  position: relative;
+}
+
+.carousel-inner {
+
+  > .item {
+    display: none;
+    position: relative;
+    .transition(.6s ease-in-out left);
+
+    // Account for jankitude on images
+    > img,
+    > a > img {
+      display: block;
+      line-height: 1;
+    }
+  }
+
+  > .active,
+  > .next,
+  > .prev { display: block; }
+
+  > .active {
+    left: 0;
+  }
+
+  > .next,
+  > .prev {
+    position: absolute;
+    top: 0;
+    width: 100%;
+  }
+
+  > .next {
+    left: 100%;
+  }
+  > .prev {
+    left: -100%;
+  }
+  > .next.left,
+  > .prev.right {
+    left: 0;
+  }
+
+  > .active.left {
+    left: -100%;
+  }
+  > .active.right {
+    left: 100%;
+  }
+
+}
+
+// Left/right controls for nav
+// ---------------------------
+
+.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: @white;
+  text-align: center;
+  background: @grayDarker;
+  border: 3px solid @white;
+  .border-radius(23px);
+  .opacity(50);
+
+  // we can't have this transition here
+  // because webkit cancels the carousel
+  // animation if you trip this while
+  // in the middle of another animation
+  // ;_;
+  // .transition(opacity .2s linear);
+
+  // Reposition the right one
+  &.right {
+    left: auto;
+    right: 15px;
+  }
+
+  // Hover/focus state
+  &:hover,
+  &:focus {
+    color: @white;
+    text-decoration: none;
+    .opacity(90);
+  }
+}
+
+// Carousel indicator pips
+// -----------------------------
+.carousel-indicators {
+  position: absolute;
+  top: 15px;
+  right: 15px;
+  z-index: 5;
+  margin: 0;
+  list-style: none;
+
+  li {
+    display: block;
+    float: left;
+    width: 10px;
+    height: 10px;
+    margin-left: 5px;
+    text-indent: -999px;
+    background-color: #ccc;
+    background-color: rgba(255,255,255,.25);
+    border-radius: 5px;
+  }
+  .active {
+    background-color: #fff;
+  }
+}
+
+// Caption for text below images
+// -----------------------------
+
+.carousel-caption {
+  position: absolute;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  padding: 15px;
+  background: @grayDark;
+  background: rgba(0,0,0,.75);
+}
+.carousel-caption h4,
+.carousel-caption p {
+  color: @white;
+  line-height: @baseLineHeight;
+}
+.carousel-caption h4 {
+  margin: 0 0 5px;
+}
+.carousel-caption p {
+  margin-bottom: 0;
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/554ed703/tapestry-wro4j/src/test/webapp/bootstrap/css/close.less
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/test/webapp/bootstrap/css/close.less b/tapestry-wro4j/src/test/webapp/bootstrap/css/close.less
new file mode 100644
index 0000000..4c626bd
--- /dev/null
+++ b/tapestry-wro4j/src/test/webapp/bootstrap/css/close.less
@@ -0,0 +1,32 @@
+//
+// Close icons
+// --------------------------------------------------
+
+
+.close {
+  float: right;
+  font-size: 20px;
+  font-weight: bold;
+  line-height: @baseLineHeight;
+  color: @black;
+  text-shadow: 0 1px 0 rgba(255,255,255,1);
+  .opacity(20);
+  &:hover,
+  &:focus {
+    color: @black;
+    text-decoration: none;
+    cursor: pointer;
+    .opacity(40);
+  }
+}
+
+// Additional properties for button version
+// iOS requires the button element instead of an anchor tag.
+// If you want the anchor version, it requires `href="#"`.
+button.close {
+  padding: 0;
+  cursor: pointer;
+  background: transparent;
+  border: 0;
+  -webkit-appearance: none;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/554ed703/tapestry-wro4j/src/test/webapp/bootstrap/css/code.less
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/test/webapp/bootstrap/css/code.less b/tapestry-wro4j/src/test/webapp/bootstrap/css/code.less
new file mode 100644
index 0000000..266a926
--- /dev/null
+++ b/tapestry-wro4j/src/test/webapp/bootstrap/css/code.less
@@ -0,0 +1,61 @@
+//
+// Code (inline and blocK)
+// --------------------------------------------------
+
+
+// Inline and block code styles
+code,
+pre {
+  padding: 0 3px 2px;
+  #font > #family > .monospace;
+  font-size: @baseFontSize - 2;
+  color: @grayDark;
+  .border-radius(3px);
+}
+
+// Inline code
+code {
+  padding: 2px 4px;
+  color: #d14;
+  background-color: #f7f7f9;
+  border: 1px solid #e1e1e8;
+  white-space: nowrap;
+}
+
+// Blocks of code
+pre {
+  display: block;
+  padding: (@baseLineHeight - 1) / 2;
+  margin: 0 0 @baseLineHeight / 2;
+  font-size: @baseFontSize - 1; // 14px to 13px
+  line-height: @baseLineHeight;
+  word-break: break-all;
+  word-wrap: break-word;
+  white-space: pre;
+  white-space: pre-wrap;
+  background-color: #f5f5f5;
+  border: 1px solid #ccc; // fallback for IE7-8
+  border: 1px solid rgba(0,0,0,.15);
+  .border-radius(@baseBorderRadius);
+
+  // Make prettyprint styles more spaced out for readability
+  &.prettyprint {
+    margin-bottom: @baseLineHeight;
+  }
+
+  // Account for some code outputs that place code tags in pre tags
+  code {
+    padding: 0;
+    color: inherit;
+    white-space: pre;
+    white-space: pre-wrap;
+    background-color: transparent;
+    border: 0;
+  }
+}
+
+// Enable scrollable blocks of code
+.pre-scrollable {
+  max-height: 340px;
+  overflow-y: scroll;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/554ed703/tapestry-wro4j/src/test/webapp/bootstrap/css/component-animations.less
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/test/webapp/bootstrap/css/component-animations.less b/tapestry-wro4j/src/test/webapp/bootstrap/css/component-animations.less
new file mode 100644
index 0000000..d614263
--- /dev/null
+++ b/tapestry-wro4j/src/test/webapp/bootstrap/css/component-animations.less
@@ -0,0 +1,22 @@
+//
+// Component animations
+// --------------------------------------------------
+
+
+.fade {
+  opacity: 0;
+  .transition(opacity .15s linear);
+  &.in {
+    opacity: 1;
+  }
+}
+
+.collapse {
+  position: relative;
+  height: 0;
+  overflow: hidden;
+  .transition(height .35s ease);
+  &.in {
+    height: auto;
+  }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/554ed703/tapestry-wro4j/src/test/webapp/bootstrap/css/dropdowns.less
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/test/webapp/bootstrap/css/dropdowns.less b/tapestry-wro4j/src/test/webapp/bootstrap/css/dropdowns.less
new file mode 100644
index 0000000..9e47b47
--- /dev/null
+++ b/tapestry-wro4j/src/test/webapp/bootstrap/css/dropdowns.less
@@ -0,0 +1,248 @@
+//
+// Dropdown menus
+// --------------------------------------------------
+
+
+// Use the .menu class on any <li> element within the topbar or ul.tabs and you'll get some superfancy dropdowns
+.dropup,
+.dropdown {
+  position: relative;
+}
+.dropdown-toggle {
+  // The caret makes the toggle a bit too tall in IE7
+  *margin-bottom: -3px;
+}
+.dropdown-toggle:active,
+.open .dropdown-toggle {
+  outline: 0;
+}
+
+// Dropdown arrow/caret
+// --------------------
+.caret {
+  display: inline-block;
+  width: 0;
+  height: 0;
+  vertical-align: top;
+  border-top:   4px solid @black;
+  border-right: 4px solid transparent;
+  border-left:  4px solid transparent;
+  content: "";
+}
+
+// Place the caret
+.dropdown .caret {
+  margin-top: 8px;
+  margin-left: 2px;
+}
+
+// The dropdown menu (ul)
+// ----------------------
+.dropdown-menu {
+  position: absolute;
+  top: 100%;
+  left: 0;
+  z-index: @zindexDropdown;
+  display: none; // none by default, but block on "open" of the menu
+  float: left;
+  min-width: 160px;
+  padding: 5px 0;
+  margin: 2px 0 0; // override default ul
+  list-style: none;
+  background-color: @dropdownBackground;
+  border: 1px solid #ccc; // Fallback for IE7-8
+  border: 1px solid @dropdownBorder;
+  *border-right-width: 2px;
+  *border-bottom-width: 2px;
+  .border-radius(6px);
+  .box-shadow(0 5px 10px rgba(0,0,0,.2));
+  -webkit-background-clip: padding-box;
+     -moz-background-clip: padding;
+          background-clip: padding-box;
+
+  // Aligns the dropdown menu to right
+  &.pull-right {
+    right: 0;
+    left: auto;
+  }
+
+  // Dividers (basically an hr) within the dropdown
+  .divider {
+    .nav-divider(@dropdownDividerTop, @dropdownDividerBottom);
+  }
+
+  // Links within the dropdown menu
+  > li > a {
+    display: block;
+    padding: 3px 20px;
+    clear: both;
+    font-weight: normal;
+    line-height: @baseLineHeight;
+    color: @dropdownLinkColor;
+    white-space: nowrap;
+  }
+}
+
+// Hover/Focus state
+// -----------
+.dropdown-menu > li > a:hover,
+.dropdown-menu > li > a:focus,
+.dropdown-submenu:hover > a,
+.dropdown-submenu:focus > a {
+  text-decoration: none;
+  color: @dropdownLinkColorHover;
+  #gradient > .vertical(@dropdownLinkBackgroundHover, darken(@dropdownLinkBackgroundHover, 5%));
+}
+
+// Active state
+// ------------
+.dropdown-menu > .active > a,
+.dropdown-menu > .active > a:hover,
+.dropdown-menu > .active > a:focus {
+  color: @dropdownLinkColorActive;
+  text-decoration: none;
+  outline: 0;
+  #gradient > .vertical(@dropdownLinkBackgroundActive, darken(@dropdownLinkBackgroundActive, 5%));
+}
+
+// Disabled state
+// --------------
+// Gray out text and ensure the hover/focus state remains gray
+.dropdown-menu > .disabled > a,
+.dropdown-menu > .disabled > a:hover,
+.dropdown-menu > .disabled > a:focus {
+  color: @grayLight;
+}
+// Nuke hover/focus effects
+.dropdown-menu > .disabled > a:hover,
+.dropdown-menu > .disabled > a:focus {
+  text-decoration: none;
+  background-color: transparent;
+  background-image: none; // Remove CSS gradient
+  .reset-filter();
+  cursor: default;
+}
+
+// Open state for the dropdown
+// ---------------------------
+.open {
+  // IE7's z-index only goes to the nearest positioned ancestor, which would
+  // make the menu appear below buttons that appeared later on the page
+  *z-index: @zindexDropdown;
+
+  & > .dropdown-menu {
+    display: block;
+  }
+}
+
+// Backdrop to catch body clicks on mobile, etc.
+// ---------------------------
+.dropdown-backdrop {
+  position: fixed;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  top: 0;
+  z-index: @zindexDropdown - 10;
+}
+
+// Right aligned dropdowns
+// ---------------------------
+.pull-right > .dropdown-menu {
+  right: 0;
+  left: auto;
+}
+
+// Allow for dropdowns to go bottom up (aka, dropup-menu)
+// ------------------------------------------------------
+// Just add .dropup after the standard .dropdown class and you're set, bro.
+// TODO: abstract this so that the navbar fixed styles are not placed here?
+.dropup,
+.navbar-fixed-bottom .dropdown {
+  // Reverse the caret
+  .caret {
+    border-top: 0;
+    border-bottom: 4px solid @black;
+    content: "";
+  }
+  // Different positioning for bottom up menu
+  .dropdown-menu {
+    top: auto;
+    bottom: 100%;
+    margin-bottom: 1px;
+  }
+}
+
+// Sub menus
+// ---------------------------
+.dropdown-submenu {
+  position: relative;
+}
+// Default dropdowns
+.dropdown-submenu > .dropdown-menu {
+  top: 0;
+  left: 100%;
+  margin-top: -6px;
+  margin-left: -1px;
+  .border-radius(0 6px 6px 6px);
+}
+.dropdown-submenu:hover > .dropdown-menu {
+  display: block;
+}
+
+// Dropups
+.dropup .dropdown-submenu > .dropdown-menu {
+  top: auto;
+  bottom: 0;
+  margin-top: 0;
+  margin-bottom: -2px;
+  .border-radius(5px 5px 5px 0);
+}
+
+// Caret to indicate there is a submenu
+.dropdown-submenu > a:after {
+  display: block;
+  content: " ";
+  float: right;
+  width: 0;
+  height: 0;
+  border-color: transparent;
+  border-style: solid;
+  border-width: 5px 0 5px 5px;
+  border-left-color: darken(@dropdownBackground, 20%);
+  margin-top: 5px;
+  margin-right: -10px;
+}
+.dropdown-submenu:hover > a:after {
+  border-left-color: @dropdownLinkColorHover;
+}
+
+// Left aligned submenus
+.dropdown-submenu.pull-left {
+  // Undo the float
+  // Yes, this is awkward since .pull-left adds a float, but it sticks to our conventions elsewhere.
+  float: none;
+
+  // Positioning the submenu
+  > .dropdown-menu {
+    left: -100%;
+    margin-left: 10px;
+    .border-radius(6px 0 6px 6px);
+  }
+}
+
+// Tweak nav headers
+// -----------------
+// Increase padding from 15px to 20px on sides
+.dropdown .dropdown-menu .nav-header {
+  padding-left: 20px;
+  padding-right: 20px;
+}
+
+// Typeahead
+// ---------
+.typeahead {
+  z-index: 1051;
+  margin-top: 2px; // give it some space to breathe
+  .border-radius(@baseBorderRadius);
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/554ed703/tapestry-wro4j/src/test/webapp/bootstrap/css/forms.less
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/test/webapp/bootstrap/css/forms.less b/tapestry-wro4j/src/test/webapp/bootstrap/css/forms.less
new file mode 100644
index 0000000..06767bd
--- /dev/null
+++ b/tapestry-wro4j/src/test/webapp/bootstrap/css/forms.less
@@ -0,0 +1,690 @@
+//
+// Forms
+// --------------------------------------------------
+
+
+// GENERAL STYLES
+// --------------
+
+// Make all forms have space below them
+form {
+  margin: 0 0 @baseLineHeight;
+}
+
+fieldset {
+  padding: 0;
+  margin: 0;
+  border: 0;
+}
+
+// Groups of fields with labels on top (legends)
+legend {
+  display: block;
+  width: 100%;
+  padding: 0;
+  margin-bottom: @baseLineHeight;
+  font-size: @baseFontSize * 1.5;
+  line-height: @baseLineHeight * 2;
+  color: @grayDark;
+  border: 0;
+  border-bottom: 1px solid #e5e5e5;
+
+  // Small
+  small {
+    font-size: @baseLineHeight * .75;
+    color: @grayLight;
+  }
+}
+
+// Set font for forms
+label,
+input,
+button,
+select,
+textarea {
+  #font > .shorthand(@baseFontSize,normal,@baseLineHeight); // Set size, weight, line-height here
+}
+input,
+button,
+select,
+textarea {
+  font-family: @baseFontFamily; // And only set font-family here for those that need it (note the missing label element)
+}
+
+// Identify controls by their labels
+label {
+  display: block;
+  margin-bottom: 5px;
+}
+
+// Form controls
+// -------------------------
+
+// Shared size and type resets
+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: @baseLineHeight;
+  padding: 4px 6px;
+  margin-bottom: @baseLineHeight / 2;
+  font-size: @baseFontSize;
+  line-height: @baseLineHeight;
+  color: @gray;
+  .border-radius(@inputBorderRadius);
+  vertical-align: middle;
+}
+
+// Reset appearance properties for textual inputs and textarea
+// Declare width for legacy (can't be on input[type=*] selectors or it's too specific)
+input,
+textarea,
+.uneditable-input {
+  width: 206px; // plus 12px padding and 2px border
+}
+// Reset height since textareas have rows
+textarea {
+  height: auto;
+}
+// Everything else
+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: @inputBackground;
+  border: 1px solid @inputBorder;
+  .box-shadow(inset 0 1px 1px rgba(0,0,0,.075));
+  .transition(~"border linear .2s, box-shadow linear .2s");
+
+  // Focus state
+  &:focus {
+    border-color: rgba(82,168,236,.8);
+    outline: 0;
+    outline: thin dotted \9; /* IE6-9 */
+    .box-shadow(~"inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6)");
+  }
+}
+
+// Position radios and checkboxes better
+input[type="radio"],
+input[type="checkbox"] {
+  margin: 4px 0 0;
+  *margin-top: 0; /* IE7 */
+  margin-top: 1px \9; /* IE8-9 */
+  line-height: normal;
+}
+
+// Reset width of input images, buttons, radios, checkboxes
+input[type="file"],
+input[type="image"],
+input[type="submit"],
+input[type="reset"],
+input[type="button"],
+input[type="radio"],
+input[type="checkbox"] {
+  width: auto; // Override of generic input selector
+}
+
+// Set the height of select and file controls to match text inputs
+select,
+input[type="file"] {
+  height: @inputHeight; /* 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: @inputHeight;
+}
+
+// Make select elements obey height by applying a border
+select {
+  width: 220px; // default input width + 10px of padding that doesn't get applied
+  border: 1px solid @inputBorder;
+  background-color: @inputBackground; // Chrome on Linux and Mobile Safari need background-color
+}
+
+// Make multiple select elements height not fixed
+select[multiple],
+select[size] {
+  height: auto;
+}
+
+// Focus for select, file, radio, and checkbox
+select:focus,
+input[type="file"]:focus,
+input[type="radio"]:focus,
+input[type="checkbox"]:focus {
+  .tab-focus();
+}
+
+
+// Uneditable inputs
+// -------------------------
+
+// Make uneditable inputs look inactive
+.uneditable-input,
+.uneditable-textarea {
+  color: @grayLight;
+  background-color: darken(@inputBackground, 1%);
+  border-color: @inputBorder;
+  .box-shadow(inset 0 1px 2px rgba(0,0,0,.025));
+  cursor: not-allowed;
+}
+
+// For text that needs to appear as an input but should not be an input
+.uneditable-input {
+  overflow: hidden; // prevent text from wrapping, but still cut it off like an input does
+  white-space: nowrap;
+}
+
+// Make uneditable textareas behave like a textarea
+.uneditable-textarea {
+  width: auto;
+  height: auto;
+}
+
+
+// Placeholder
+// -------------------------
+
+// Placeholder text gets special styles because when browsers invalidate entire lines if it doesn't understand a selector
+input,
+textarea {
+  .placeholder();
+}
+
+
+// CHECKBOXES & RADIOS
+// -------------------
+
+// Indent the labels to position radios/checkboxes as hanging
+.radio,
+.checkbox {
+  min-height: @baseLineHeight; // clear the floating input if there is no label text
+  padding-left: 20px;
+}
+.radio input[type="radio"],
+.checkbox input[type="checkbox"] {
+  float: left;
+  margin-left: -20px;
+}
+
+// Move the options list down to align with labels
+.controls > .radio:first-child,
+.controls > .checkbox:first-child {
+  padding-top: 5px; // has to be padding because margin collaspes
+}
+
+// Radios and checkboxes on same line
+// TODO v3: Convert .inline to .control-inline
+.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; // space out consecutive inline controls
+}
+
+
+
+// INPUT SIZES
+// -----------
+
+// General classes for quick sizes
+.input-mini       { width: 60px; }
+.input-small      { width: 90px; }
+.input-medium     { width: 150px; }
+.input-large      { width: 210px; }
+.input-xlarge     { width: 270px; }
+.input-xxlarge    { width: 530px; }
+
+// Grid style input sizes
+input[class*="span"],
+select[class*="span"],
+textarea[class*="span"],
+.uneditable-input[class*="span"],
+// Redeclare since the fluid row class is more specific
+.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;
+}
+// Ensure input-prepend/append never wraps
+.input-append input[class*="span"],
+.input-append .uneditable-input[class*="span"],
+.input-prepend input[class*="span"],
+.input-prepend .uneditable-input[class*="span"],
+.row-fluid input[class*="span"],
+.row-fluid select[class*="span"],
+.row-fluid textarea[class*="span"],
+.row-fluid .uneditable-input[class*="span"],
+.row-fluid .input-prepend [class*="span"],
+.row-fluid .input-append [class*="span"] {
+  display: inline-block;
+}
+
+
+
+// GRID SIZING FOR INPUTS
+// ----------------------
+
+// Grid sizes
+#grid > .input(@gridColumnWidth, @gridGutterWidth);
+
+// Control row for multiple inputs per line
+.controls-row {
+  .clearfix(); // Clear the float from controls
+}
+
+// Float to collapse white-space for proper grid alignment
+.controls-row [class*="span"],
+// Redeclare the fluid grid collapse since we undo the float for inputs
+.row-fluid .controls-row [class*="span"] {
+  float: left;
+}
+// Explicity set top padding on all checkboxes/radios, not just first-child
+.controls-row .checkbox[class*="span"],
+.controls-row .radio[class*="span"] {
+  padding-top: 5px;
+}
+
+
+
+
+// DISABLED STATE
+// --------------
+
+// Disabled and read-only inputs
+input[disabled],
+select[disabled],
+textarea[disabled],
+input[readonly],
+select[readonly],
+textarea[readonly] {
+  cursor: not-allowed;
+  background-color: @inputDisabledBackground;
+}
+// Explicitly reset the colors here
+input[type="radio"][disabled],
+input[type="checkbox"][disabled],
+input[type="radio"][readonly],
+input[type="checkbox"][readonly] {
+  background-color: transparent;
+}
+
+
+
+
+// FORM FIELD FEEDBACK STATES
+// --------------------------
+
+// Warning
+.control-group.warning {
+  .formFieldState(@warningText, @warningText, @warningBackground);
+}
+// Error
+.control-group.error {
+  .formFieldState(@errorText, @errorText, @errorBackground);
+}
+// Success
+.control-group.success {
+  .formFieldState(@successText, @successText, @successBackground);
+}
+// Success
+.control-group.info {
+  .formFieldState(@infoText, @infoText, @infoBackground);
+}
+
+// HTML5 invalid states
+// Shares styles with the .control-group.error above
+input:focus:invalid,
+textarea:focus:invalid,
+select:focus:invalid {
+  color: #b94a48;
+  border-color: #ee5f5b;
+  &:focus {
+    border-color: darken(#ee5f5b, 10%);
+    @shadow: 0 0 6px lighten(#ee5f5b, 20%);
+    .box-shadow(@shadow);
+  }
+}
+
+
+
+// FORM ACTIONS
+// ------------
+
+.form-actions {
+  padding: (@baseLineHeight - 1) 20px @baseLineHeight;
+  margin-top: @baseLineHeight;
+  margin-bottom: @baseLineHeight;
+  background-color: @formActionsBackground;
+  border-top: 1px solid #e5e5e5;
+  .clearfix(); // Adding clearfix to allow for .pull-right button containers
+}
+
+
+
+// HELP TEXT
+// ---------
+
+.help-block,
+.help-inline {
+  color: lighten(@textColor, 15%); // lighten the text some for contrast
+}
+
+.help-block {
+  display: block; // account for any element using help-block
+  margin-bottom: @baseLineHeight / 2;
+}
+
+.help-inline {
+  display: inline-block;
+  .ie7-inline-block();
+  vertical-align: middle;
+  padding-left: 5px;
+}
+
+
+
+// INPUT GROUPS
+// ------------
+
+// Allow us to put symbols and text within the input field for a cleaner look
+.input-append,
+.input-prepend {
+  display: inline-block;
+  margin-bottom: @baseLineHeight / 2;
+  vertical-align: middle;
+  font-size: 0; // white space collapse hack
+  white-space: nowrap; // Prevent span and input from separating
+
+  // Reset the white space collapse hack
+  input,
+  select,
+  .uneditable-input,
+  .dropdown-menu,
+  .popover {
+    font-size: @baseFontSize;
+  }
+
+  input,
+  select,
+  .uneditable-input {
+    position: relative; // placed here by default so that on :focus we can place the input above the .add-on for full border and box-shadow goodness
+    margin-bottom: 0; // prevent bottom margin from screwing up alignment in stacked forms
+    *margin-left: 0;
+    vertical-align: top;
+    .border-radius(0 @inputBorderRadius @inputBorderRadius 0);
+    // Make input on top when focused so blue border and shadow always show
+    &:focus {
+      z-index: 2;
+    }
+  }
+  .add-on {
+    display: inline-block;
+    width: auto;
+    height: @baseLineHeight;
+    min-width: 16px;
+    padding: 4px 5px;
+    font-size: @baseFontSize;
+    font-weight: normal;
+    line-height: @baseLineHeight;
+    text-align: center;
+    text-shadow: 0 1px 0 @white;
+    background-color: @grayLighter;
+    border: 1px solid #ccc;
+  }
+  .add-on,
+  .btn,
+  .btn-group > .dropdown-toggle {
+    vertical-align: top;
+    .border-radius(0);
+  }
+  .active {
+    background-color: lighten(@green, 30);
+    border-color: @green;
+  }
+}
+
+.input-prepend {
+  .add-on,
+  .btn {
+    margin-right: -1px;
+  }
+  .add-on:first-child,
+  .btn:first-child {
+    // FYI, `.btn:first-child` accounts for a button group that's prepended
+    .border-radius(@inputBorderRadius 0 0 @inputBorderRadius);
+  }
+}
+
+.input-append {
+  input,
+  select,
+  .uneditable-input {
+    .border-radius(@inputBorderRadius 0 0 @inputBorderRadius);
+    + .btn-group .btn:last-child {
+      .border-radius(0 @inputBorderRadius @inputBorderRadius 0);
+    }
+  }
+  .add-on,
+  .btn,
+  .btn-group {
+    margin-left: -1px;
+  }
+  .add-on:last-child,
+  .btn:last-child,
+  .btn-group:last-child > .dropdown-toggle {
+    .border-radius(0 @inputBorderRadius @inputBorderRadius 0);
+  }
+}
+
+// Remove all border-radius for inputs with both prepend and append
+.input-prepend.input-append {
+  input,
+  select,
+  .uneditable-input {
+    .border-radius(0);
+    + .btn-group .btn {
+      .border-radius(0 @inputBorderRadius @inputBorderRadius 0);
+    }
+  }
+  .add-on:first-child,
+  .btn:first-child {
+    margin-right: -1px;
+    .border-radius(@inputBorderRadius 0 0 @inputBorderRadius);
+  }
+  .add-on:last-child,
+  .btn:last-child {
+    margin-left: -1px;
+    .border-radius(0 @inputBorderRadius @inputBorderRadius 0);
+  }
+  .btn-group:first-child {
+    margin-left: 0;
+  }
+}
+
+
+
+
+// SEARCH FORM
+// -----------
+
+input.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; // Remove the default margin on all inputs
+  .border-radius(15px);
+}
+
+/* Allow for input prepend/append in search forms */
+.form-search .input-append .search-query,
+.form-search .input-prepend .search-query {
+  .border-radius(0); // Override due to specificity
+}
+.form-search .input-append .search-query {
+  .border-radius(14px 0 0 14px);
+}
+.form-search .input-append .btn {
+  .border-radius(0 14px 14px 0);
+}
+.form-search .input-prepend .search-query {
+  .border-radius(0 14px 14px 0);
+}
+.form-search .input-prepend .btn {
+  .border-radius(14px 0 0 14px);
+}
+
+
+
+
+// HORIZONTAL & VERTICAL FORMS
+// ---------------------------
+
+// Common properties
+// -----------------
+
+.form-search,
+.form-inline,
+.form-horizontal {
+  input,
+  textarea,
+  select,
+  .help-inline,
+  .uneditable-input,
+  .input-prepend,
+  .input-append {
+    display: inline-block;
+    .ie7-inline-block();
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  // Re-hide hidden elements due to specifity
+  .hide {
+    display: none;
+  }
+}
+.form-search label,
+.form-inline label,
+.form-search .btn-group,
+.form-inline .btn-group {
+  display: inline-block;
+}
+// Remove margin for input-prepend/-append
+.form-search .input-append,
+.form-inline .input-append,
+.form-search .input-prepend,
+.form-inline .input-prepend {
+  margin-bottom: 0;
+}
+// Inline checkbox/radio labels (remove padding on left)
+.form-search .radio,
+.form-search .checkbox,
+.form-inline .radio,
+.form-inline .checkbox {
+  padding-left: 0;
+  margin-bottom: 0;
+  vertical-align: middle;
+}
+// Remove float and margin, set to inline-block
+.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;
+}
+
+
+// Margin to space out fieldsets
+.control-group {
+  margin-bottom: @baseLineHeight / 2;
+}
+
+// Legend collapses margin, so next element is responsible for spacing
+legend + .control-group {
+  margin-top: @baseLineHeight;
+  -webkit-margin-top-collapse: separate;
+}
+
+// Horizontal-specific styles
+// --------------------------
+
+.form-horizontal {
+  // Increase spacing between groups
+  .control-group {
+    margin-bottom: @baseLineHeight;
+    .clearfix();
+  }
+  // Float the labels left
+  .control-label {
+    float: left;
+    width: @horizontalComponentOffset - 20;
+    padding-top: 5px;
+    text-align: right;
+  }
+  // Move over all input controls and content
+  .controls {
+    // Super jank IE7 fix to ensure the inputs in .input-append and input-prepend
+    // don't inherit the margin of the parent, in this case .controls
+    *display: inline-block;
+    *padding-left: 20px;
+    margin-left: @horizontalComponentOffset;
+    *margin-left: 0;
+    &:first-child {
+      *padding-left: @horizontalComponentOffset;
+    }
+  }
+  // Remove bottom margin on block level help text since that's accounted for on .control-group
+  .help-block {
+    margin-bottom: 0;
+  }
+  // And apply it only to .help-block instances that follow a form control
+  input,
+  select,
+  textarea,
+  .uneditable-input,
+  .input-prepend,
+  .input-append {
+    + .help-block {
+      margin-top: @baseLineHeight / 2;
+    }
+  }
+  // Move over buttons in .form-actions to align with .controls
+  .form-actions {
+    padding-left: @horizontalComponentOffset;
+  }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/554ed703/tapestry-wro4j/src/test/webapp/bootstrap/css/grid.less
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/test/webapp/bootstrap/css/grid.less b/tapestry-wro4j/src/test/webapp/bootstrap/css/grid.less
new file mode 100644
index 0000000..750d203
--- /dev/null
+++ b/tapestry-wro4j/src/test/webapp/bootstrap/css/grid.less
@@ -0,0 +1,21 @@
+//
+// Grid system
+// --------------------------------------------------
+
+
+// Fixed (940px)
+#grid > .core(@gridColumnWidth, @gridGutterWidth);
+
+// Fluid (940px)
+#grid > .fluid(@fluidGridColumnWidth, @fluidGridGutterWidth);
+
+// Reset utility classes due to specificity
+[class*="span"].hide,
+.row-fluid [class*="span"].hide {
+  display: none;
+}
+
+[class*="span"].pull-right,
+.row-fluid [class*="span"].pull-right {
+  float: right;
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/554ed703/tapestry-wro4j/src/test/webapp/bootstrap/css/hero-unit.less
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/test/webapp/bootstrap/css/hero-unit.less b/tapestry-wro4j/src/test/webapp/bootstrap/css/hero-unit.less
new file mode 100644
index 0000000..763d86a
--- /dev/null
+++ b/tapestry-wro4j/src/test/webapp/bootstrap/css/hero-unit.less
@@ -0,0 +1,25 @@
+//
+// Hero unit
+// --------------------------------------------------
+
+
+.hero-unit {
+  padding: 60px;
+  margin-bottom: 30px;
+  font-size: 18px;
+  font-weight: 200;
+  line-height: @baseLineHeight * 1.5;
+  color: @heroUnitLeadColor;
+  background-color: @heroUnitBackground;
+  .border-radius(6px);
+  h1 {
+    margin-bottom: 0;
+    font-size: 60px;
+    line-height: 1;
+    color: @heroUnitHeadingColor;
+    letter-spacing: -1px;
+  }
+  li {
+    line-height: @baseLineHeight * 1.5; // Reset since we specify in type.less
+  }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/554ed703/tapestry-wro4j/src/test/webapp/bootstrap/css/labels-badges.less
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/test/webapp/bootstrap/css/labels-badges.less b/tapestry-wro4j/src/test/webapp/bootstrap/css/labels-badges.less
new file mode 100644
index 0000000..bc321fe
--- /dev/null
+++ b/tapestry-wro4j/src/test/webapp/bootstrap/css/labels-badges.less
@@ -0,0 +1,84 @@
+//
+// Labels and badges
+// --------------------------------------------------
+
+
+// Base classes
+.label,
+.badge {
+  display: inline-block;
+  padding: 2px 4px;
+  font-size: @baseFontSize * .846;
+  font-weight: bold;
+  line-height: 14px; // ensure proper line-height if floated
+  color: @white;
+  vertical-align: baseline;
+  white-space: nowrap;
+  text-shadow: 0 -1px 0 rgba(0,0,0,.25);
+  background-color: @grayLight;
+}
+// Set unique padding and border-radii
+.label {
+  .border-radius(3px);
+}
+.badge {
+  padding-left: 9px;
+  padding-right: 9px;
+  .border-radius(9px);
+}
+
+// Empty labels/badges collapse
+.label,
+.badge {
+  &:empty {
+    display: none;
+  }
+}
+
+// Hover/focus state, but only for links
+a {
+  &.label:hover,
+  &.label:focus,
+  &.badge:hover,
+  &.badge:focus {
+    color: @white;
+    text-decoration: none;
+    cursor: pointer;
+  }
+}
+
+// Colors
+// Only give background-color difference to links (and to simplify, we don't qualifty with `a` but [href] attribute)
+.label,
+.badge {
+  // Important (red)
+  &-important         { background-color: @errorText; }
+  &-important[href]   { background-color: darken(@errorText, 10%); }
+  // Warnings (orange)
+  &-warning           { background-color: @orange; }
+  &-warning[href]     { background-color: darken(@orange, 10%); }
+  // Success (green)
+  &-success           { background-color: @successText; }
+  &-success[href]     { background-color: darken(@successText, 10%); }
+  // Info (turquoise)
+  &-info              { background-color: @infoText; }
+  &-info[href]        { background-color: darken(@infoText, 10%); }
+  // Inverse (black)
+  &-inverse           { background-color: @grayDark; }
+  &-inverse[href]     { background-color: darken(@grayDark, 10%); }
+}
+
+// Quick fix for labels/badges in buttons
+.btn {
+  .label,
+  .badge {
+    position: relative;
+    top: -1px;
+  }
+}
+.btn-mini {
+  .label,
+  .badge {
+    top: 0;
+  }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/554ed703/tapestry-wro4j/src/test/webapp/bootstrap/css/layouts.less
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/test/webapp/bootstrap/css/layouts.less b/tapestry-wro4j/src/test/webapp/bootstrap/css/layouts.less
new file mode 100644
index 0000000..24a2062
--- /dev/null
+++ b/tapestry-wro4j/src/test/webapp/bootstrap/css/layouts.less
@@ -0,0 +1,16 @@
+//
+// Layouts
+// --------------------------------------------------
+
+
+// Container (centered, fixed-width layouts)
+.container {
+  .container-fixed();
+}
+
+// Fluid layouts (left aligned, with sidebar, min- & max-width content)
+.container-fluid {
+  padding-right: @gridGutterWidth;
+  padding-left: @gridGutterWidth;
+  .clearfix();
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/554ed703/tapestry-wro4j/src/test/webapp/bootstrap/css/media.less
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/test/webapp/bootstrap/css/media.less b/tapestry-wro4j/src/test/webapp/bootstrap/css/media.less
new file mode 100644
index 0000000..e461e44
--- /dev/null
+++ b/tapestry-wro4j/src/test/webapp/bootstrap/css/media.less
@@ -0,0 +1,55 @@
+// Media objects
+// Source: http://stubbornella.org/content/?p=497
+// --------------------------------------------------
+
+
+// Common styles
+// -------------------------
+
+// Clear the floats
+.media,
+.media-body {
+  overflow: hidden;
+  *overflow: visible;
+  zoom: 1;
+}
+
+// Proper spacing between instances of .media
+.media,
+.media .media {
+  margin-top: 15px;
+}
+.media:first-child {
+  margin-top: 0;
+}
+
+// For images and videos, set to block
+.media-object {
+  display: block;
+}
+
+// Reset margins on headings for tighter default spacing
+.media-heading {
+  margin: 0 0 5px;
+}
+
+
+// Media image alignment
+// -------------------------
+
+.media > .pull-left {
+  margin-right: 10px;
+}
+.media > .pull-right {
+  margin-left: 10px;
+}
+
+
+// Media list variation
+// -------------------------
+
+// Undo default ul/ol styles
+.media-list {
+  margin-left: 0;
+  list-style: none;
+}