Merge branch 'kafka-timestamp' of https://github.com/fedexist/logging-log4j2 into fedexist-kafka-timestamp
diff --git a/.travis.yml b/.travis.yml
index d9841dd..d6c5ee2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -13,7 +13,7 @@
 language: java
 dist: xenial
 jdk:
-  - openjdk8
+  - openjdk11
 
 env:
   global:
@@ -25,11 +25,9 @@
 before_cache:
   - rm -rf $HOME/.m2/repository/org/apache/logging/log4j
 
-install:
-  - mvn -t .travis-toolchains.xml install -DskipTests=true -Dmaven.javadoc.skip=true -B -V
-
 script:
-  - mvn -t .travis-toolchains.xml test -B -V
+  - jdk_switcher use openjdk8
+  - mvn -t .travis-toolchains.xml install -B -V
 
 after_success:
   - mvn -t .travis-toolchains.xml -pl !log4j-bom jacoco:prepare-agent test jacoco:report coveralls:report -B -V
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/AppenderSkeleton.java b/log4j-1.2-api/src/main/java/org/apache/log4j/AppenderSkeleton.java
index a4c5231..1353dae 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/AppenderSkeleton.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/AppenderSkeleton.java
@@ -56,7 +56,7 @@
     }
 
     @Override
-    public void addFilter(Filter newFilter) {
+    public void addFilter(final Filter newFilter) {
         if(headFilter == null) {
             headFilter = tailFilter = newFilter;
         } else {
@@ -104,7 +104,7 @@
         return threshold;
     }
 
-    public boolean isAsSevereAsThreshold(Priority priority) {
+    public boolean isAsSevereAsThreshold(final Priority priority) {
         return ((threshold == null) || priority.isGreaterOrEqual(threshold));
     }
 
@@ -113,7 +113,8 @@
      * @param event The LoggingEvent.
      */
     @Override
-    public void doAppend(LoggingEvent event) {
+    public void doAppend(final LoggingEvent event) {
+        append(event);
     }
 
     /**
@@ -122,54 +123,54 @@
      * @since 0.9.0
      */
     @Override
-    public synchronized void setErrorHandler(ErrorHandler eh) {
+    public synchronized void setErrorHandler(final ErrorHandler eh) {
         if (eh != null) {
             this.errorHandler = eh;
         }
     }
 
     @Override
-    public void setLayout(Layout layout) {
+    public void setLayout(final Layout layout) {
         this.layout = layout;
     }
 
     @Override
-    public void setName(String name) {
+    public void setName(final String name) {
         this.name = name;
     }
 
-    public void setThreshold(Priority threshold) {
+    public void setThreshold(final Priority threshold) {
         this.threshold = threshold;
     }
 
     public static class NoOpErrorHandler implements ErrorHandler {
         @Override
-        public void setLogger(Logger logger) {
+        public void setLogger(final Logger logger) {
 
         }
 
         @Override
-        public void error(String message, Exception e, int errorCode) {
+        public void error(final String message, final Exception e, final int errorCode) {
 
         }
 
         @Override
-        public void error(String message) {
+        public void error(final String message) {
 
         }
 
         @Override
-        public void error(String message, Exception e, int errorCode, LoggingEvent event) {
+        public void error(final String message, final Exception e, final int errorCode, final LoggingEvent event) {
 
         }
 
         @Override
-        public void setAppender(Appender appender) {
+        public void setAppender(final Appender appender) {
 
         }
 
         @Override
-        public void setBackupAppender(Appender appender) {
+        public void setBackupAppender(final Appender appender) {
 
         }
     }
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/Category.java b/log4j-1.2-api/src/main/java/org/apache/log4j/Category.java
index 1da4560..2608c6c 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/Category.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/Category.java
@@ -25,10 +25,13 @@
 
 import org.apache.log4j.helpers.NullEnumeration;
 import org.apache.log4j.legacy.core.CategoryUtil;
+import org.apache.log4j.or.ObjectRenderer;
+import org.apache.log4j.or.RendererSupport;
 import org.apache.log4j.spi.LoggerFactory;
 import org.apache.log4j.spi.LoggingEvent;
+import org.apache.logging.log4j.message.MapMessage;
+import org.apache.logging.log4j.spi.ExtendedLogger;
 import org.apache.logging.log4j.spi.LoggerContext;
-import org.apache.logging.log4j.util.NameUtil;
 import org.apache.logging.log4j.message.LocalizedMessage;
 import org.apache.logging.log4j.message.Message;
 import org.apache.logging.log4j.message.ObjectMessage;
@@ -50,6 +53,7 @@
 
     private static final boolean isCoreAvailable;
 
+    private final Map<Class<?>, ObjectRenderer> rendererMap;
 
     static {
         boolean available;
@@ -76,6 +80,7 @@
      */
     protected Category(final LoggerContext context, final String name) {
         this.logger = context.getLogger(name);
+        rendererMap = ((RendererSupport) LogManager.getLoggerRepository()).getRendererMap();
     }
 
     /**
@@ -88,6 +93,7 @@
 
     private Category(final org.apache.logging.log4j.Logger logger) {
         this.logger = logger;
+        rendererMap = ((RendererSupport) LogManager.getLoggerRepository()).getRendererMap();
     }
 
     public static Category getInstance(final String name) {
@@ -373,11 +379,19 @@
     public static void shutdown() {
     }
 
-
     public void forcedLog(final String fqcn, final Priority level, final Object message, final Throwable t) {
         final org.apache.logging.log4j.Level lvl = org.apache.logging.log4j.Level.toLevel(level.toString());
-        final Message msg = message instanceof Message ? (Message) message : new ObjectMessage(message);
-        logger.logMessage(lvl, null, fqcn, null, msg, t);
+        if (logger instanceof ExtendedLogger) {
+            @SuppressWarnings("unchecked")
+            Message msg = message instanceof Message ? (Message) message : message instanceof Map ?
+                    new MapMessage((Map) message) : new ObjectMessage(message);
+            ((ExtendedLogger) logger).logMessage(fqcn, lvl, null, msg, t);
+        } else {
+            ObjectRenderer renderer = get(message.getClass());
+            final Message msg = message instanceof Message ? (Message) message : renderer != null ?
+                    new RenderedMessage(renderer, message) : new ObjectMessage(message);
+            logger.log(lvl, msg, t);
+        }
     }
 
     public boolean exists(final String name) {
@@ -407,7 +421,7 @@
             LoggerContext ctx = CategoryUtil.getLoggerContext(logger);
             if (ctx != null) {
                 final ConcurrentMap<String, Logger> loggers = getLoggersMap(ctx);
-                while ((name = NameUtil.getSubName(name)) != null) {
+                while ((name = getSubName(name)) != null) {
                     final Logger subLogger = loggers.get(name);
                     if (subLogger != null) {
                         final ResourceBundle rb = subLogger.bundle;
@@ -421,6 +435,14 @@
         return null;
     }
 
+    private static  String getSubName(final String name) {
+        if (Strings.isEmpty(name)) {
+            return null;
+        }
+        final int i = name.lastIndexOf('.');
+        return i > 0 ? name.substring(0, i) : Strings.EMPTY;
+    }
+
     /**
      If <code>assertion</code> parameter is {@code false}, then
      logs <code>msg</code> as an {@link #error(Object) error} statement.
@@ -457,14 +479,16 @@
 
     public void log(final Priority priority, final Object message, final Throwable t) {
         if (isEnabledFor(priority)) {
-            final Message msg = new ObjectMessage(message);
+            @SuppressWarnings("unchecked")
+            final Message msg = message instanceof Map ? new MapMessage((Map) message) : new ObjectMessage(message);
             forcedLog(FQCN, priority, msg, t);
         }
     }
 
     public void log(final Priority priority, final Object message) {
         if (isEnabledFor(priority)) {
-            final Message msg = new ObjectMessage(message);
+            @SuppressWarnings("unchecked")
+            final Message msg = message instanceof Map ? new MapMessage((Map) message) : new ObjectMessage(message);
             forcedLog(FQCN, priority, msg, null);
         }
     }
@@ -479,7 +503,13 @@
     private void maybeLog(final String fqcn, final org.apache.logging.log4j.Level level,
             final Object message, final Throwable throwable) {
         if (logger.isEnabled(level)) {
-            logger.logMessage(level, null, fqcn, null, new ObjectMessage(message), throwable);
+            @SuppressWarnings("unchecked")
+            Message msg = message instanceof Map ? new MapMessage((Map) message) : new ObjectMessage(message);
+            if (logger instanceof ExtendedLogger) {
+                ((ExtendedLogger) logger).logMessage(fqcn, level, null, msg, throwable);
+            } else {
+                logger.log(level, msg, throwable);
+            }
         }
     }
 
@@ -515,4 +545,35 @@
         return logger.isEnabled(level);
     }
 
+    private ObjectRenderer get(Class clazz) {
+        ObjectRenderer renderer = null;
+        for(Class c = clazz; c != null; c = c.getSuperclass()) {
+            renderer = rendererMap.get(c);
+            if (renderer != null) {
+                return renderer;
+            }
+            renderer = searchInterfaces(c);
+            if (renderer != null) {
+                return renderer;
+            }
+        }
+        return null;
+    }
+
+    ObjectRenderer searchInterfaces(Class c) {
+        ObjectRenderer renderer = rendererMap.get(c);
+        if(renderer != null) {
+            return renderer;
+        } else {
+            Class[] ia = c.getInterfaces();
+            for (Class clazz : ia) {
+                renderer = searchInterfaces(clazz);
+                if (renderer != null) {
+                    return renderer;
+                }
+            }
+        }
+        return null;
+    }
+
 }
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/ConsoleAppender.java b/log4j-1.2-api/src/main/java/org/apache/log4j/ConsoleAppender.java
index 0e841c5..605fac7 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/ConsoleAppender.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/ConsoleAppender.java
@@ -45,7 +45,7 @@
    * {@inheritDoc}
    */
   @Override
-  protected void append(LoggingEvent theEvent)
+  protected void append(final LoggingEvent theEvent)
   {
   }
 
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/Layout.java b/log4j-1.2-api/src/main/java/org/apache/log4j/Layout.java
index d0b9943..dbd2291 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/Layout.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/Layout.java
@@ -25,7 +25,7 @@
 public abstract class Layout {
 
     public final static String LINE_SEP = Strings.LINE_SEPARATOR;
-    
+
     /** Note that the line.separator property can be looked up even by applets. */
     public static final int LINE_SEP_LEN = Strings.LINE_SEPARATOR.length();
 
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/LogManager.java b/log4j-1.2-api/src/main/java/org/apache/log4j/LogManager.java
index a4b6802..d595988 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/LogManager.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/LogManager.java
@@ -17,9 +17,13 @@
 package org.apache.log4j;

 

 import java.util.Enumeration;

+import java.util.HashMap;

+import java.util.Map;

 

 import org.apache.log4j.helpers.NullEnumeration;

 import org.apache.log4j.legacy.core.ContextUtil;

+import org.apache.log4j.or.ObjectRenderer;

+import org.apache.log4j.or.RendererSupport;

 import org.apache.log4j.spi.HierarchyEventListener;

 import org.apache.log4j.spi.LoggerFactory;

 import org.apache.log4j.spi.LoggerRepository;

@@ -146,7 +150,15 @@
     /**

      * The Repository.

      */

-    private static class Repository implements LoggerRepository {

+    private static class Repository implements LoggerRepository, RendererSupport {

+

+        private final Map<Class<?>, ObjectRenderer> rendererMap = new HashMap<>();

+

+        @Override

+        public Map<Class<?>, ObjectRenderer> getRendererMap() {

+            return rendererMap;

+        }

+

         @Override

         public void addHierarchyEventListener(final HierarchyEventListener listener) {

 

diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/Logger.java b/log4j-1.2-api/src/main/java/org/apache/log4j/Logger.java
index c228338..fe1f26a 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/Logger.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/Logger.java
@@ -56,7 +56,7 @@
         private static final String FQCN = Logger.class.getName();
 
         public static LoggerContext getContext() {
-            return (LoggerContext) getContext(FQCN, false);
+            return getContext(FQCN, false);
         }
 
         public static org.apache.logging.log4j.Logger getLogger(final String name) {
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/RenderedMessage.java b/log4j-1.2-api/src/main/java/org/apache/log4j/RenderedMessage.java
new file mode 100644
index 0000000..422a565
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/RenderedMessage.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j;
+
+import org.apache.log4j.or.ObjectRenderer;
+import org.apache.logging.log4j.message.Message;
+
+/**
+ * Implements object rendering for Log4j 1.x compatibility.
+ */
+public class RenderedMessage implements Message {
+
+    private final ObjectRenderer renderer;
+    private final Object object;
+    private String rendered = null;
+
+    public RenderedMessage(ObjectRenderer renderer, Object object) {
+        this.renderer = renderer;
+        this.object = object;
+    }
+
+
+    @Override
+    public String getFormattedMessage() {
+        if (rendered == null) {
+            rendered = renderer.doRender(object);
+        }
+
+        return rendered;
+    }
+
+    @Override
+    public String getFormat() {
+        return getFormattedMessage();
+    }
+
+    @Override
+    public Object[] getParameters() {
+        return null;
+    }
+
+    @Override
+    public Throwable getThrowable() {
+        return null;
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/SimpleLayout.java b/log4j-1.2-api/src/main/java/org/apache/log4j/SimpleLayout.java
index 3b2374c..c77b9be 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/SimpleLayout.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/SimpleLayout.java
@@ -29,7 +29,7 @@
    * {@inheritDoc}
    */
   @Override
-  public String format(LoggingEvent theEvent)
+  public String format(final LoggingEvent theEvent)
   {
     return Strings.EMPTY;
   }
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/WriterAppender.java b/log4j-1.2-api/src/main/java/org/apache/log4j/WriterAppender.java
new file mode 100644
index 0000000..f026bfa
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/WriterAppender.java
@@ -0,0 +1,378 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j;
+
+import org.apache.log4j.helpers.QuietWriter;
+import org.apache.log4j.spi.ErrorHandler;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.logging.log4j.status.StatusLogger;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+
+
+/**
+ * WriterAppender appends log events to a {@link Writer} or an
+ * {@link OutputStream} depending on the user's choice.
+ */
+public class WriterAppender extends AppenderSkeleton {
+    private static final org.apache.logging.log4j.Logger LOGGER = StatusLogger.getLogger();
+
+    /**
+     * Immediate flush means that the underlying writer or output stream
+     * will be flushed at the end of each append operation unless shouldFlush()
+     * is overridden. Immediate
+     * flush is slower but ensures that each append request is actually
+     * written. If <code>immediateFlush</code> is set to
+     * <code>false</code>, then there is a good chance that the last few
+     * logs events are not actually written to persistent media if and
+     * when the application crashes.
+     *
+     * <p>The <code>immediateFlush</code> variable is set to
+     * <code>true</code> by default.
+     */
+    protected boolean immediateFlush = true;
+
+    /**
+     * The encoding to use when writing.  <p>The
+     * <code>encoding</code> variable is set to <code>null</null> by
+     * default which results in the utilization of the system's default
+     * encoding.
+     */
+    protected String encoding;
+
+    /**
+     * This is the {@link QuietWriter quietWriter} where we will write
+     * to.
+     */
+    protected QuietWriter qw;
+
+
+    /**
+     * This default constructor does nothing.
+     */
+    public WriterAppender() {
+    }
+
+    /**
+     * Instantiate a WriterAppender and set the output destination to a
+     * new {@link OutputStreamWriter} initialized with <code>os</code>
+     * as its {@link OutputStream}.
+     */
+    public WriterAppender(Layout layout, OutputStream os) {
+        this(layout, new OutputStreamWriter(os));
+    }
+
+    /**
+     * Instantiate a WriterAppender and set the output destination to
+     * <code>writer</code>.
+     *
+     * <p>The <code>writer</code> must have been previously opened by
+     * the user.
+     */
+    public WriterAppender(Layout layout, Writer writer) {
+        this.layout = layout;
+        this.setWriter(writer);
+    }
+
+    /**
+     * Returns value of the <b>ImmediateFlush</b> option.
+     */
+    public boolean getImmediateFlush() {
+        return immediateFlush;
+    }
+
+    /**
+     * If the <b>ImmediateFlush</b> option is set to
+     * <code>true</code>, the appender will flush at the end of each
+     * write. This is the default behavior. If the option is set to
+     * <code>false</code>, then the underlying stream can defer writing
+     * to physical medium to a later time.
+     *
+     * <p>Avoiding the flush operation at the end of each append results in
+     * a performance gain of 10 to 20 percent. However, there is safety
+     * tradeoff involved in skipping flushing. Indeed, when flushing is
+     * skipped, then it is likely that the last few log events will not
+     * be recorded on disk when the application exits. This is a high
+     * price to pay even for a 20% performance gain.
+     */
+    public void setImmediateFlush(boolean value) {
+        immediateFlush = value;
+    }
+
+    /**
+     * Does nothing.
+     */
+    public void activateOptions() {
+    }
+
+
+    /**
+     * This method is called by the {@link AppenderSkeleton#doAppend}
+     * method.
+     *
+     * <p>If the output stream exists and is writable then write a log
+     * statement to the output stream. Otherwise, write a single warning
+     * message to <code>System.err</code>.
+     *
+     * <p>The format of the output will depend on this appender's
+     * layout.
+     */
+    public void append(LoggingEvent event) {
+
+        // Reminder: the nesting of calls is:
+        //
+        //    doAppend()
+        //      - check threshold
+        //      - filter
+        //      - append();
+        //        - checkEntryConditions();
+        //        - subAppend();
+
+        if (!checkEntryConditions()) {
+            return;
+        }
+        subAppend(event);
+    }
+
+    /**
+     * This method determines if there is a sense in attempting to append.
+     *
+     * <p>It checks whether there is a set output target and also if
+     * there is a set layout. If these checks fail, then the boolean
+     * value <code>false</code> is returned.
+     */
+    protected boolean checkEntryConditions() {
+        if (this.closed) {
+            LOGGER.warn("Not allowed to write to a closed appender.");
+            return false;
+        }
+
+        if (this.qw == null) {
+            errorHandler.error("No output stream or file set for the appender named [" + name + "].");
+            return false;
+        }
+
+        if (this.layout == null) {
+            errorHandler.error("No layout set for the appender named [" + name + "].");
+            return false;
+        }
+        return true;
+    }
+
+
+    /**
+     * Close this appender instance. The underlying stream or writer is
+     * also closed.
+     *
+     * <p>Closed appenders cannot be reused.
+     *
+     * @see #setWriter
+     * @since 0.8.4
+     */
+    public
+    synchronized void close() {
+        if (this.closed) {
+            return;
+        }
+        this.closed = true;
+        writeFooter();
+        reset();
+    }
+
+    /**
+     * Close the underlying {@link Writer}.
+     */
+    protected void closeWriter() {
+        if (qw != null) {
+            try {
+                qw.close();
+            } catch (IOException e) {
+                if (e instanceof InterruptedIOException) {
+                    Thread.currentThread().interrupt();
+                }
+                // There is do need to invoke an error handler at this late
+                // stage.
+                LOGGER.error("Could not close " + qw, e);
+            }
+        }
+    }
+
+    /**
+     * Returns an OutputStreamWriter when passed an OutputStream.  The
+     * encoding used will depend on the value of the
+     * <code>encoding</code> property.  If the encoding value is
+     * specified incorrectly the writer will be opened using the default
+     * system encoding (an error message will be printed to the LOGGER.
+     */
+    protected OutputStreamWriter createWriter(OutputStream os) {
+        OutputStreamWriter retval = null;
+
+        String enc = getEncoding();
+        if (enc != null) {
+            try {
+                retval = new OutputStreamWriter(os, enc);
+            } catch (IOException e) {
+                if (e instanceof InterruptedIOException) {
+                    Thread.currentThread().interrupt();
+                }
+                LOGGER.warn("Error initializing output writer.");
+                LOGGER.warn("Unsupported encoding?");
+            }
+        }
+        if (retval == null) {
+            retval = new OutputStreamWriter(os);
+        }
+        return retval;
+    }
+
+    public String getEncoding() {
+        return encoding;
+    }
+
+    public void setEncoding(String value) {
+        encoding = value;
+    }
+
+
+    /**
+     * Set the {@link ErrorHandler} for this WriterAppender and also the
+     * underlying {@link QuietWriter} if any.
+     */
+    public synchronized void setErrorHandler(ErrorHandler eh) {
+        if (eh == null) {
+            LOGGER.warn("You have tried to set a null error-handler.");
+        } else {
+            this.errorHandler = eh;
+            if (this.qw != null) {
+                this.qw.setErrorHandler(eh);
+            }
+        }
+    }
+
+    /**
+     * <p>Sets the Writer where the log output will go. The
+     * specified Writer must be opened by the user and be
+     * writable.
+     *
+     * <p>The <code>java.io.Writer</code> will be closed when the
+     * appender instance is closed.
+     *
+     *
+     * <p><b>WARNING:</b> Logging to an unopened Writer will fail.
+     * <p>
+     *
+     * @param writer An already opened Writer.
+     */
+    public synchronized void setWriter(Writer writer) {
+        reset();
+        this.qw = new QuietWriter(writer, errorHandler);
+        //this.tp = new TracerPrintWriter(qw);
+        writeHeader();
+    }
+
+
+    /**
+     * Actual writing occurs here.
+     *
+     * <p>Most subclasses of <code>WriterAppender</code> will need to
+     * override this method.
+     *
+     * @since 0.9.0
+     */
+    protected void subAppend(LoggingEvent event) {
+        this.qw.write(this.layout.format(event));
+
+        if (layout.ignoresThrowable()) {
+            String[] s = event.getThrowableStrRep();
+            if (s != null) {
+                int len = s.length;
+                for (int i = 0; i < len; i++) {
+                    this.qw.write(s[i]);
+                    this.qw.write(Layout.LINE_SEP);
+                }
+            }
+        }
+
+        if (shouldFlush(event)) {
+            this.qw.flush();
+        }
+    }
+
+
+    /**
+     * The WriterAppender requires a layout. Hence, this method returns
+     * <code>true</code>.
+     */
+    public boolean requiresLayout() {
+        return true;
+    }
+
+    /**
+     * Clear internal references to the writer and other variables.
+     * <p>
+     * Subclasses can override this method for an alternate closing
+     * behavior.
+     */
+    protected void reset() {
+        closeWriter();
+        this.qw = null;
+        //this.tp = null;
+    }
+
+
+    /**
+     * Write a footer as produced by the embedded layout's {@link
+     * Layout#getFooter} method.
+     */
+    protected void writeFooter() {
+        if (layout != null) {
+            String f = layout.getFooter();
+            if (f != null && this.qw != null) {
+                this.qw.write(f);
+                this.qw.flush();
+            }
+        }
+    }
+
+    /**
+     * Write a header as produced by the embedded layout's {@link
+     * Layout#getHeader} method.
+     */
+    protected void writeHeader() {
+        if (layout != null) {
+            String h = layout.getHeader();
+            if (h != null && this.qw != null) {
+                this.qw.write(h);
+            }
+        }
+    }
+
+    /**
+     * Determines whether the writer should be flushed after
+     * this event is written.
+     *
+     * @since 1.2.16
+     */
+    protected boolean shouldFlush(final LoggingEvent event) {
+        return immediateFlush;
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/AppenderAdapter.java b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/AppenderAdapter.java
new file mode 100644
index 0000000..f2dd2c1
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/AppenderAdapter.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.bridge;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Appender;
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.appender.AbstractAppender;
+import org.apache.logging.log4j.core.config.Property;
+import org.apache.logging.log4j.core.filter.CompositeFilter;
+
+/**
+ * Binds a Log4j 1.x Appender to Log4j 2.
+ */
+public class AppenderAdapter {
+
+    private final Appender appender;
+    private final Adapter adapter;
+
+    /**
+     * Constructor.
+     */
+    public AppenderAdapter(Appender appender) {
+        this.appender = appender;
+        org.apache.logging.log4j.core.Filter appenderFilter = null;
+        if (appender.getFilter() != null) {
+            if (appender.getFilter().getNext() != null) {
+                org.apache.log4j.spi.Filter filter = appender.getFilter();
+                List<org.apache.logging.log4j.core.Filter> filters = new ArrayList<>();
+                while (filter != null) {
+                    filters.add(new FilterAdapter(filter));
+                    filter = filter.getNext();
+                }
+                appenderFilter = CompositeFilter.createFilters(filters.toArray(new Filter[0]));
+            } else {
+                appenderFilter = new FilterAdapter(appender.getFilter());
+            }
+        }
+        this.adapter = new Adapter(appender.getName(), appenderFilter, null, true, null);
+    }
+
+    public Adapter getAdapter() {
+        return adapter;
+    }
+
+    public class Adapter extends AbstractAppender {
+
+        protected Adapter(final String name, final Filter filter, final Layout<? extends Serializable> layout,
+            final boolean ignoreExceptions, final Property[] properties) {
+            super(name, filter, layout, ignoreExceptions, properties);
+        }
+
+        @Override
+        public void append(LogEvent event) {
+            appender.doAppend(new LogEventAdapter(event));
+        }
+
+        @Override
+        public void stop() {
+            appender.close();
+        }
+
+        public Appender getAppender() {
+            return appender;
+        }
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/AppenderWrapper.java b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/AppenderWrapper.java
new file mode 100644
index 0000000..eb39fe7
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/AppenderWrapper.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.bridge;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.Layout;
+import org.apache.log4j.helpers.AppenderAttachableImpl;
+import org.apache.log4j.spi.AppenderAttachable;
+import org.apache.log4j.spi.ErrorHandler;
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.filter.AbstractFilterable;
+import org.apache.logging.log4j.status.StatusLogger;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+
+/**
+ * Holds a Log4j 2 Appender in an empty Log4j 1 Appender so it can be extracted when constructing the configuration.
+ * Allows a Log4j 1 Appender to reference a Log4j 2 Appender.
+ */
+public class AppenderWrapper extends AppenderAttachableImpl implements Appender {
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+    private final org.apache.logging.log4j.core.Appender appender;
+
+    public AppenderWrapper(org.apache.logging.log4j.core.Appender appender) {
+        this.appender = appender;
+    }
+
+    public org.apache.logging.log4j.core.Appender getAppender() {
+        return appender;
+    }
+
+    @Override
+    public void addFilter(Filter newFilter) {
+        if (appender instanceof AbstractFilterable) {
+            if (newFilter instanceof FilterWrapper) {
+                ((AbstractFilterable) appender).addFilter(((FilterWrapper) newFilter).getFilter());
+            } else {
+                ((AbstractFilterable) appender).addFilter(new FilterAdapter(newFilter));
+            }
+        } else {
+            LOGGER.warn("Unable to add filter to appender {}, it does not support filters", appender.getName());
+        }
+    }
+
+    @Override
+    public Filter getFilter() {
+        return null;
+    }
+
+    @Override
+    public void clearFilters() {
+
+    }
+
+    @Override
+    public void close() {
+        // Not supported with Log4j 2.
+    }
+
+    @Override
+    public void doAppend(LoggingEvent event) {
+        if (event instanceof LogEventAdapter) {
+            appender.append(((LogEventAdapter) event).getEvent());
+        }
+    }
+
+    @Override
+    public String getName() {
+        return appender.getName();
+    }
+
+    @Override
+    public void setErrorHandler(ErrorHandler errorHandler) {
+        appender.setHandler(new ErrorHandlerAdapter(errorHandler));
+    }
+
+    @Override
+    public ErrorHandler getErrorHandler() {
+        return ((ErrorHandlerAdapter)appender.getHandler()).getHandler();
+    }
+
+    @Override
+    public void setLayout(Layout layout) {
+        // Log4j 2 doesn't support this.
+    }
+
+    @Override
+    public Layout getLayout() {
+        return new LayoutWrapper(appender.getLayout());
+    }
+
+    @Override
+    public void setName(String name) {
+        // Log4j 2 doesn't support this.
+    }
+
+    @Override
+    public boolean requiresLayout() {
+        return false;
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/ErrorHandlerAdapter.java b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/ErrorHandlerAdapter.java
new file mode 100644
index 0000000..1f166a2
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/ErrorHandlerAdapter.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.bridge;
+
+import org.apache.log4j.spi.ErrorHandler;
+import org.apache.logging.log4j.core.LogEvent;
+
+/**
+ * Makes a Log4j 1 ErrorHandler usable by a Log4j 2 Appender.
+ */
+public class ErrorHandlerAdapter implements org.apache.logging.log4j.core.ErrorHandler {
+
+    private final ErrorHandler errorHandler;
+
+    public ErrorHandlerAdapter(ErrorHandler errorHandler) {
+        this.errorHandler = errorHandler;
+    }
+
+    public ErrorHandler getHandler() {
+        return errorHandler;
+    }
+
+    @Override
+    public void error(String msg) {
+        errorHandler.error(msg);
+    }
+
+    @Override
+    public void error(String msg, Throwable t) {
+        if (t instanceof Exception) {
+            errorHandler.error(msg, (Exception) t, 0);
+        } else {
+            errorHandler.error(msg);
+        }
+    }
+
+    @Override
+    public void error(String msg, LogEvent event, Throwable t) {
+        if (t == null || t instanceof Exception) {
+            errorHandler.error(msg, (Exception) t, 0, new LogEventAdapter(event));
+        } else {
+            errorHandler.error(msg);
+        }
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/FilterAdapter.java b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/FilterAdapter.java
new file mode 100644
index 0000000..2dff272
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/FilterAdapter.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.bridge;
+
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.filter.AbstractFilter;
+
+/**
+ * Binds a Log4j 1.x Filter with Log4j 2.
+ */
+public class FilterAdapter extends AbstractFilter {
+
+    private final Filter filter;
+
+    public FilterAdapter(Filter filter) {
+        this.filter = filter;
+    }
+
+    @Override
+    public void start() {
+        filter.activateOptions();
+    }
+
+    @Override
+    public Result filter(LogEvent event) {
+        LoggingEvent loggingEvent = new LogEventAdapter(event);
+        Filter next = filter;
+        while (next != null) {
+            switch (filter.decide(loggingEvent)) {
+                case Filter.ACCEPT:
+                    return Result.ACCEPT;
+                case Filter.DENY:
+                    return Result.DENY;
+                default:
+            }
+            next = filter.getNext();
+        }
+        return Result.NEUTRAL;
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/FilterWrapper.java b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/FilterWrapper.java
new file mode 100644
index 0000000..b2855cd
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/FilterWrapper.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.bridge;
+
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.spi.LoggingEvent;
+
+/**
+ * This acts as a container for Log4j 2 Filters to be attached to Log4j 1 components. However, the Log4j 2
+ * Filters will always be called directly so this class just acts as a container.
+ */
+public class FilterWrapper extends Filter {
+
+    private final org.apache.logging.log4j.core.Filter filter;
+
+    public FilterWrapper(org.apache.logging.log4j.core.Filter filter) {
+        this.filter = filter;
+    }
+
+    public org.apache.logging.log4j.core.Filter getFilter() {
+        return filter;
+    }
+
+    /**
+     * This method is never called.
+     * @param event The LoggingEvent to decide upon.
+     * @return 0
+     */
+    @Override
+    public int decide(LoggingEvent event) {
+        return 0;
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/LayoutAdapter.java b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/LayoutAdapter.java
new file mode 100644
index 0000000..5494c92
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/LayoutAdapter.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.bridge;
+
+import org.apache.log4j.Layout;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.layout.ByteBufferDestination;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Class Description goes here.
+ */
+public class LayoutAdapter implements org.apache.logging.log4j.core.Layout<String> {
+    private Layout layout;
+
+    public LayoutAdapter(Layout layout) {
+        this.layout = layout;
+    }
+
+
+    @Override
+    public byte[] getFooter() {
+        return layout.getFooter() == null ? null : layout.getFooter().getBytes();
+    }
+
+    @Override
+    public byte[] getHeader() {
+        return layout.getHeader() == null ? null : layout.getHeader().getBytes();
+    }
+
+    @Override
+    public byte[] toByteArray(LogEvent event) {
+        String result = layout.format(new LogEventAdapter(event));
+        return result == null ? null : result.getBytes();
+    }
+
+    @Override
+    public String toSerializable(LogEvent event) {
+        return layout.format(new LogEventAdapter(event));
+    }
+
+    @Override
+    public String getContentType() {
+        return layout.getContentType();
+    }
+
+    @Override
+    public Map<String, String> getContentFormat() {
+        return new HashMap<>();
+    }
+
+    @Override
+    public void encode(LogEvent event, ByteBufferDestination destination) {
+        final byte[] data = toByteArray(event);
+        destination.writeBytes(data, 0, data.length);
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/LayoutWrapper.java b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/LayoutWrapper.java
new file mode 100644
index 0000000..fc1e72f
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/LayoutWrapper.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.bridge;
+
+
+import org.apache.log4j.Layout;
+import org.apache.log4j.spi.LoggingEvent;
+
+
+/**
+ * Bridge between the Log4j 1 Layout and a Log4j 2 Layout.
+ */
+public class LayoutWrapper extends Layout {
+
+    private final org.apache.logging.log4j.core.Layout<?> layout;
+
+    public LayoutWrapper(org.apache.logging.log4j.core.Layout<?> layout) {
+        this.layout = layout;
+    }
+
+    @Override
+    public String format(LoggingEvent event) {
+        return layout.toSerializable(((LogEventAdapter)event).getEvent()).toString();
+    }
+
+    @Override
+    public boolean ignoresThrowable() {
+        return false;
+    }
+
+    public org.apache.logging.log4j.core.Layout<?> getLayout() {
+        return this.layout;
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/LogEventAdapter.java b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/LogEventAdapter.java
new file mode 100644
index 0000000..9de0476
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/LogEventAdapter.java
@@ -0,0 +1,226 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.bridge;
+
+import org.apache.log4j.Category;
+import org.apache.log4j.Level;
+import org.apache.log4j.spi.LocationInfo;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.log4j.spi.ThrowableInformation;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.util.Loader;
+import org.apache.logging.log4j.core.util.Throwables;
+import org.apache.logging.log4j.spi.StandardLevel;
+import org.apache.logging.log4j.status.StatusLogger;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Converts a Log4j 2 LogEvent into the components needed by a Log4j 1.x LoggingEvent.
+ * This class requires Log4j 2.
+ */
+public class LogEventAdapter extends LoggingEvent {
+
+    private static final long JVM_START_TIME = initStartTime();
+
+    private final LogEvent event;
+
+    public LogEventAdapter(LogEvent event) {
+        this.event = event;
+    }
+
+    /**
+     * Returns the time when the application started, in milliseconds
+     * elapsed since 01.01.1970.
+     */
+    public static long getStartTime() {
+        return JVM_START_TIME;
+    }
+
+    /**
+     * Returns the result of {@code ManagementFactory.getRuntimeMXBean().getStartTime()},
+     * or the current system time if JMX is not available.
+     */
+    private static long initStartTime() {
+        // We'd like to call ManagementFactory.getRuntimeMXBean().getStartTime(),
+        // but Google App Engine throws a java.lang.NoClassDefFoundError
+        // "java.lang.management.ManagementFactory is a restricted class".
+        // The reflection is necessary because without it, Google App Engine
+        // will refuse to initialize this class.
+        try {
+            final Class<?> factoryClass = Loader.loadSystemClass("java.lang.management.ManagementFactory");
+            final Method getRuntimeMXBean = factoryClass.getMethod("getRuntimeMXBean");
+            final Object runtimeMXBean = getRuntimeMXBean.invoke(null);
+
+            final Class<?> runtimeMXBeanClass = Loader.loadSystemClass("java.lang.management.RuntimeMXBean");
+            final Method getStartTime = runtimeMXBeanClass.getMethod("getStartTime");
+            return (Long) getStartTime.invoke(runtimeMXBean);
+        } catch (final Throwable t) {
+            StatusLogger.getLogger().error("Unable to call ManagementFactory.getRuntimeMXBean().getStartTime(), "
+                    + "using system time for OnStartupTriggeringPolicy", t);
+            // We have little option but to declare "now" as the beginning of time.
+            return System.currentTimeMillis();
+        }
+    }
+
+    public LogEvent getEvent() {
+        return this.event;
+    }
+
+    /**
+     * Set the location information for this logging event. The collected
+     * information is cached for future use.
+     */
+    @Override
+    public LocationInfo getLocationInformation() {
+        return new LocationInfo(event.getSource());
+    }
+
+    /**
+     * Return the level of this event. Use this form instead of directly
+     * accessing the <code>level</code> field.
+     */
+    @Override
+    public Level getLevel() {
+        switch (StandardLevel.getStandardLevel(event.getLevel().intLevel())) {
+            case TRACE:
+                return Level.TRACE;
+            case DEBUG:
+                return Level.DEBUG;
+            case INFO:
+                return Level.INFO;
+            case WARN:
+                return Level.WARN;
+            case FATAL:
+                return Level.FATAL;
+            case OFF:
+                return Level.OFF;
+            case ALL:
+                return Level.ALL;
+            default:
+                return Level.ERROR;
+        }
+    }
+
+    /**
+     * Return the name of the logger. Use this form instead of directly
+     * accessing the <code>categoryName</code> field.
+     */
+    @Override
+    public String getLoggerName() {
+        return event.getLoggerName();
+    }
+
+    /**
+     * Gets the logger of the event.
+     */
+    @Override
+    public Category getLogger() {
+        return Category.getInstance(event.getLoggerName());
+    }
+
+    /*
+     Return the message for this logging event.
+    */
+    @Override
+    public Object getMessage() {
+        return event.getMessage();
+    }
+
+    /*
+     * This method returns the NDC for this event.
+     */
+    @Override
+    public String getNDC() {
+        return event.getContextStack().toString();
+    }
+
+    /*
+     Returns the the context corresponding to the <code>key</code> parameter.
+     */
+    @Override
+    public Object getMDC(String key) {
+        if (event.getContextData() != null) {
+            return event.getContextData().getValue(key);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Obtain a copy of this thread's MDC prior to serialization or
+     * asynchronous logging.
+     */
+    @Override
+    public void getMDCCopy() {
+    }
+
+    @Override
+    public String getRenderedMessage() {
+        return event.getMessage().getFormattedMessage();
+    }
+
+    @Override
+    public String getThreadName() {
+        return event.getThreadName();
+    }
+
+    /**
+     * Returns the throwable information contained within this
+     * event. May be <code>null</code> if there is no such information.
+     *
+     * <p>Note that the {@link Throwable} object contained within a
+     * {@link ThrowableInformation} does not survive serialization.
+     *
+     * @since 1.1
+     */
+    @Override
+    public ThrowableInformation getThrowableInformation() {
+        if (event.getThrown() != null) {
+            return new ThrowableInformation(event.getThrown());
+        }
+        return null;
+    }
+
+    /**
+     * Return this event's throwable's string[] representaion.
+     */
+    @Override
+    public String[] getThrowableStrRep() {
+        if (event.getThrown() != null) {
+            return Throwables.toStringList(event.getThrown()).toArray(new String[0]);
+        }
+        return null;
+    }
+
+    @Override
+    public String getProperty(final String key) {
+        return event.getContextData().getValue(key);
+    }
+
+    @Override
+    public Set getPropertyKeySet() {
+        return event.getContextData().toMap().keySet();
+    }
+
+    @Override
+    public Map getProperties() {
+        return event.getContextData().toMap();
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/LogEventWrapper.java b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/LogEventWrapper.java
new file mode 100644
index 0000000..1e46e12
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/LogEventWrapper.java
@@ -0,0 +1,216 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.bridge;
+
+import org.apache.log4j.NDC;
+import org.apache.log4j.helpers.OptionConverter;
+import org.apache.log4j.spi.LocationInfo;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.ThreadContext;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.impl.ThrowableProxy;
+import org.apache.logging.log4j.core.time.Instant;
+import org.apache.logging.log4j.core.time.MutableInstant;
+import org.apache.logging.log4j.message.Message;
+import org.apache.logging.log4j.message.SimpleMessage;
+import org.apache.logging.log4j.spi.MutableThreadContextStack;
+import org.apache.logging.log4j.util.BiConsumer;
+import org.apache.logging.log4j.util.ReadOnlyStringMap;
+import org.apache.logging.log4j.util.TriConsumer;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Exposes a Log4j 1 logging event as a Log4j 2 LogEvent.
+ */
+public class LogEventWrapper implements LogEvent {
+
+    private final LoggingEvent event;
+    private final ContextDataMap contextData;
+    private final MutableThreadContextStack contextStack;
+    private volatile Thread thread;
+
+    public LogEventWrapper(LoggingEvent event) {
+        this.event = event;
+        this.contextData = new ContextDataMap(event.getProperties());
+        this.contextStack = new MutableThreadContextStack(NDC.cloneStack());
+    }
+
+    @Override
+    public LogEvent toImmutable() {
+        return null;
+    }
+
+    @Override
+    public ReadOnlyStringMap getContextData() {
+        return contextData;
+    }
+
+    @Override
+    public ThreadContext.ContextStack getContextStack() {
+        return contextStack;
+    }
+
+    @Override
+    public String getLoggerFqcn() {
+        return null;
+    }
+
+    @Override
+    public Level getLevel() {
+        return OptionConverter.convertLevel(event.getLevel());
+    }
+
+    @Override
+    public String getLoggerName() {
+        return event.getLoggerName();
+    }
+
+    @Override
+    public Marker getMarker() {
+        return null;
+    }
+
+    @Override
+    public Message getMessage() {
+        return new SimpleMessage(event.getRenderedMessage());
+    }
+
+    @Override
+    public long getTimeMillis() {
+        return event.getTimeStamp();
+    }
+
+    @Override
+    public Instant getInstant() {
+        MutableInstant mutable = new MutableInstant();
+        mutable.initFromEpochMilli(event.getTimeStamp(), 0);
+        return mutable;
+    }
+
+    @Override
+    public StackTraceElement getSource() {
+        LocationInfo info = event.getLocationInformation();
+        return new StackTraceElement(info.getClassName(), info.getMethodName(), info.getFileName(),
+                Integer.parseInt(info.getLineNumber()));
+    }
+
+    @Override
+    public String getThreadName() {
+        return event.getThreadName();
+    }
+
+    @Override
+    public long getThreadId() {
+        Thread thread = getThread();
+        return thread != null ? thread.getId() : 0;
+    }
+
+    @Override
+    public int getThreadPriority() {
+            Thread thread = getThread();
+            return thread != null ? thread.getPriority() : 0;
+    }
+
+    private Thread getThread() {
+        if (thread == null) {
+            for (Thread thread : Thread.getAllStackTraces().keySet()) {
+                if (thread.getName().equals(event.getThreadName())) {
+                    this.thread = thread;
+                    return thread;
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public Throwable getThrown() {
+        if (event.getThrowableInformation() != null) {
+            return event.getThrowableInformation().getThrowable();
+        }
+        return null;
+    }
+
+    @Override
+    public ThrowableProxy getThrownProxy() {
+        return null;
+    }
+
+    @Override
+    public boolean isEndOfBatch() {
+        return false;
+    }
+
+    @Override
+    public boolean isIncludeLocation() {
+        return false;
+    }
+
+    @Override
+    public void setEndOfBatch(boolean endOfBatch) {
+
+    }
+
+    @Override
+    public void setIncludeLocation(boolean locationRequired) {
+
+    }
+
+    @Override
+    public long getNanoTime() {
+        return 0;
+    }
+
+
+    private static class ContextDataMap extends HashMap<String, String> implements ReadOnlyStringMap {
+
+        ContextDataMap(Map<String, String> map) {
+            if (map != null) {
+                super.putAll(map);
+            }
+        }
+
+        @Override
+        public Map<String, String> toMap() {
+            return this;
+        }
+
+        @Override
+        public boolean containsKey(String key) {
+            return super.containsKey(key);
+        }
+
+        @Override
+        public <V> void forEach(BiConsumer<String, ? super V> action) {
+            super.forEach((k,v) -> action.accept(k, (V) v));
+        }
+
+        @Override
+        public <V, S> void forEach(TriConsumer<String, ? super V, S> action, S state) {
+            super.forEach((k,v) -> action.accept(k, (V) v, state));
+        }
+
+        @Override
+        public <V> V getValue(String key) {
+            return (V) super.get(key);
+        }
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/RewritePolicyAdapter.java b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/RewritePolicyAdapter.java
new file mode 100644
index 0000000..cf0b42b
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/RewritePolicyAdapter.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.bridge;
+
+import org.apache.log4j.rewrite.RewritePolicy;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.logging.log4j.core.LogEvent;
+
+
+/**
+ * Binds a Log4j 1.x RewritePolicy to Log4j 2.
+ */
+public class RewritePolicyAdapter implements org.apache.logging.log4j.core.appender.rewrite.RewritePolicy {
+
+    private final RewritePolicy policy;
+
+    /**
+     * Constructor.
+     */
+    public RewritePolicyAdapter(RewritePolicy policy) {
+        this.policy = policy;
+    }
+
+    @Override
+    public LogEvent rewrite(LogEvent source) {
+        LoggingEvent event = policy.rewrite(new LogEventAdapter(source));
+        return event instanceof LogEventAdapter ? ((LogEventAdapter) event).getEvent() : new LogEventWrapper(event);
+    }
+
+    public RewritePolicy getPolicy() {
+        return this.policy;
+    }
+
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/RewritePolicyWrapper.java b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/RewritePolicyWrapper.java
new file mode 100644
index 0000000..e0994e1
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/RewritePolicyWrapper.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.bridge;
+
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.log4j.rewrite.RewritePolicy;
+
+/**
+ * Binds a Log4j 2 RewritePolicy to Log4j 1.
+ */
+public class RewritePolicyWrapper implements RewritePolicy {
+
+    private final org.apache.logging.log4j.core.appender.rewrite.RewritePolicy policy;
+
+    public RewritePolicyWrapper(org.apache.logging.log4j.core.appender.rewrite.RewritePolicy policy) {
+        this.policy = policy;
+    }
+
+    @Override
+    public LoggingEvent rewrite(LoggingEvent source) {
+        LogEvent event = source instanceof LogEventAdapter ? ((LogEventAdapter) source).getEvent() :
+                new LogEventWrapper(source);
+        return new LogEventAdapter(policy.rewrite(event));
+    }
+
+    public org.apache.logging.log4j.core.appender.rewrite.RewritePolicy getPolicy() {
+        return policy;
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/AbstractBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/AbstractBuilder.java
new file mode 100644
index 0000000..0448ed2
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/AbstractBuilder.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.builders;
+
+import org.apache.log4j.bridge.FilterAdapter;
+import org.apache.log4j.bridge.FilterWrapper;
+import org.apache.log4j.helpers.OptionConverter;
+import org.apache.log4j.spi.Filter;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.filter.CompositeFilter;
+import org.apache.logging.log4j.core.filter.ThresholdFilter;
+import org.apache.logging.log4j.status.StatusLogger;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * Base class for Log4j 1 component builders.
+ */
+public abstract class AbstractBuilder {
+
+    private static Logger LOGGER = StatusLogger.getLogger();
+    protected static final String FILE_PARAM = "File";
+    protected static final String APPEND_PARAM = "Append";
+    protected static final String BUFFERED_IO_PARAM = "BufferedIO";
+    protected static final String BUFFER_SIZE_PARAM = "BufferSize";
+    protected static final String MAX_SIZE_PARAM = "MaxFileSize";
+    protected static final String MAX_BACKUP_INDEX = "MaxBackupIndex";
+    protected static final String RELATIVE = "RELATIVE";
+
+    private final String prefix;
+    private final Properties props;
+
+    public AbstractBuilder() {
+        this.prefix = null;
+        this.props = new Properties();
+    }
+
+    public AbstractBuilder(String prefix, Properties props) {
+        this.prefix = prefix + ".";
+        this.props = props;
+    }
+
+    public String getProperty(String key) {
+        return props.getProperty(prefix + key);
+    }
+
+    public String getProperty(String key, String defaultValue) {
+        return props.getProperty(prefix + key, defaultValue);
+    }
+
+    public boolean getBooleanProperty(String key) {
+        return Boolean.parseBoolean(props.getProperty(prefix + key, Boolean.FALSE.toString()));
+    }
+
+    public int getIntegerProperty(String key, int defaultValue) {
+        String value = props.getProperty(key);
+        try {
+            if (value != null) {
+                return Integer.parseInt(value);
+            }
+        } catch (Exception ex) {
+            LOGGER.warn("Error converting value {} of {} to an integer: {}", value, key, ex.getMessage());
+        }
+        return defaultValue;
+    }
+
+    public Properties getProperties() {
+        return props;
+    }
+
+
+    protected org.apache.logging.log4j.core.Filter buildFilters(String level, Filter filter) {
+        if (level != null && filter != null) {
+            List<org.apache.logging.log4j.core.Filter> filterList = new ArrayList<>();
+            org.apache.logging.log4j.core.Filter thresholdFilter =
+                    ThresholdFilter.createFilter(OptionConverter.convertLevel(level, Level.TRACE),
+                            org.apache.logging.log4j.core.Filter.Result.NEUTRAL,
+                            org.apache.logging.log4j.core.Filter.Result.DENY);
+            filterList.add(thresholdFilter);
+            Filter f = filter;
+            while (f != null) {
+                if (filter instanceof FilterWrapper) {
+                    filterList.add(((FilterWrapper) f).getFilter());
+                } else {
+                    filterList.add(new FilterAdapter(f));
+                }
+                f = f.next;
+            }
+            return CompositeFilter.createFilters(filterList.toArray(new org.apache.logging.log4j.core.Filter[0]));
+        } else if (level != null) {
+            return ThresholdFilter.createFilter(OptionConverter.convertLevel(level, Level.TRACE),
+                    org.apache.logging.log4j.core.Filter.Result.NEUTRAL,
+                    org.apache.logging.log4j.core.Filter.Result.DENY);
+        } else if (filter != null) {
+            if (filter instanceof FilterWrapper) {
+                return ((FilterWrapper) filter).getFilter();
+            } else {
+                return new FilterAdapter(filter);
+            }
+        }
+        return null;
+    }
+}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/BooleanHolder.java
similarity index 69%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-1.2-api/src/main/java/org/apache/log4j/builders/BooleanHolder.java
index 13aaf9c..16e46d3 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/BooleanHolder.java
@@ -14,17 +14,20 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
+package org.apache.log4j.builders;
 
-import org.junit.Test;
+/**
+ * Holds Boolean values created inside of a Lambda expression.
+ */
+public class BooleanHolder extends Holder<Boolean> {
+    public BooleanHolder() {
+        super(Boolean.FALSE);
+    }
 
-import static org.junit.Assert.*;
-
-public class ProcessIdUtilTest {
-
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
+    @Override
+    public void set(Boolean value) {
+        if (value != null) {
+            super.set(value);
+        }
     }
 }
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/BuilderManager.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/BuilderManager.java
new file mode 100644
index 0000000..3319bf0
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/BuilderManager.java
@@ -0,0 +1,175 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.builders;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.Layout;
+import org.apache.log4j.builders.appender.AppenderBuilder;
+import org.apache.log4j.builders.filter.FilterBuilder;
+import org.apache.log4j.builders.layout.LayoutBuilder;
+import org.apache.log4j.builders.rewrite.RewritePolicyBuilder;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.rewrite.RewritePolicy;
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.xml.XmlConfiguration;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.plugins.util.PluginManager;
+import org.apache.logging.log4j.plugins.util.PluginType;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.LoaderUtil;
+import org.w3c.dom.Element;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ *
+ */
+public class BuilderManager {
+
+    public static final String CATEGORY = "Log4j Builder";
+    private static final Logger LOGGER = StatusLogger.getLogger();
+    private final Map<String, PluginType<?>> plugins;
+    private static Class<?>[] constructorParams = new Class[] { String.class, Properties.class};
+
+    public BuilderManager() {
+        final PluginManager manager = new PluginManager(CATEGORY);
+        manager.collectPlugins();
+        plugins = manager.getPlugins();
+    }
+
+    public Appender parseAppender(String className, Element appenderElement, XmlConfiguration config) {
+        PluginType<?> plugin = plugins.get(className.toLowerCase());
+        if (plugin != null) {
+            try {
+                @SuppressWarnings("unchecked")
+                AppenderBuilder builder = (AppenderBuilder) LoaderUtil.newInstanceOf(plugin.getPluginClass());
+                return builder.parseAppender(appenderElement, config);
+            } catch (InstantiationException | IllegalAccessException | InvocationTargetException ex) {
+                LOGGER.warn("Unable to load plugin: {} due to: {}", plugin.getKey(), ex.getMessage());
+            }
+        }
+        return null;
+    }
+
+    public Appender parseAppender(String name, String className, String prefix, String layoutPrefix,
+            String filterPrefix, Properties props, PropertiesConfiguration config) {
+        PluginType<?> plugin = plugins.get(className.toLowerCase());
+        if (plugin != null) {
+            AppenderBuilder builder = createBuilder(plugin, prefix, props);
+            if (builder != null) {
+                return builder.parseAppender(name, prefix, layoutPrefix, filterPrefix, props, config);
+            }
+        }
+        return null;
+    }
+
+    public Filter parseFilter(String className, Element filterElement, XmlConfiguration config) {
+        PluginType<?> plugin = plugins.get(className.toLowerCase());
+        if (plugin != null) {
+            try {
+                @SuppressWarnings("unchecked")
+                FilterBuilder builder = (FilterBuilder) LoaderUtil.newInstanceOf(plugin.getPluginClass());
+                return builder.parseFilter(filterElement, config);
+            } catch (InstantiationException | IllegalAccessException | InvocationTargetException ex) {
+                LOGGER.warn("Unable to load plugin: {} due to: {}", plugin.getKey(), ex.getMessage());
+            }
+        }
+        return null;
+    }
+
+    public Filter parseFilter(String className, String filterPrefix, Properties props, PropertiesConfiguration config) {
+        PluginType<?> plugin = plugins.get(className.toLowerCase());
+        if (plugin != null) {
+            FilterBuilder builder = createBuilder(plugin, filterPrefix, props);
+            if (builder != null) {
+                return builder.parseFilter(config);
+            }
+        }
+        return null;
+    }
+
+    public Layout parseLayout(String className, Element layoutElement, XmlConfiguration config) {
+        PluginType<?> plugin = plugins.get(className.toLowerCase());
+        if (plugin != null) {
+            try {
+                @SuppressWarnings("unchecked")
+                LayoutBuilder builder = (LayoutBuilder) LoaderUtil.newInstanceOf(plugin.getPluginClass());
+                return builder.parseLayout(layoutElement, config);
+            } catch (InstantiationException | IllegalAccessException | InvocationTargetException ex) {
+                LOGGER.warn("Unable to load plugin: {} due to: {}", plugin.getKey(), ex.getMessage());
+            }
+        }
+        return null;
+    }
+    public Layout parseLayout(String className, String layoutPrefix, Properties props, PropertiesConfiguration config) {
+        PluginType<?> plugin = plugins.get(className.toLowerCase());
+        if (plugin != null) {
+            LayoutBuilder builder = createBuilder(plugin, layoutPrefix, props);
+            if (builder != null) {
+                return builder.parseLayout(config);
+            }
+        }
+        return null;
+    }
+
+    public RewritePolicy parseRewritePolicy(String className, Element rewriteElement, XmlConfiguration config) {
+        PluginType<?> plugin = plugins.get(className.toLowerCase());
+        if (plugin != null) {
+            try {
+                @SuppressWarnings("unchecked")
+                RewritePolicyBuilder builder = (RewritePolicyBuilder) LoaderUtil.newInstanceOf(plugin.getPluginClass());
+                return builder.parseRewritePolicy(rewriteElement, config);
+            } catch (InstantiationException | IllegalAccessException | InvocationTargetException ex) {
+                LOGGER.warn("Unable to load plugin: {} due to: {}", plugin.getKey(), ex.getMessage());
+            }
+        }
+        return null;
+    }
+    public RewritePolicy parseRewritePolicy(String className, String policyPrefix, Properties props, PropertiesConfiguration config) {
+        PluginType<?> plugin = plugins.get(className.toLowerCase());
+        if (plugin != null) {
+            RewritePolicyBuilder builder = createBuilder(plugin, policyPrefix, props);
+            if (builder != null) {
+                return builder.parseRewritePolicy(config);
+            }
+        }
+        return null;
+    }
+
+    private <T extends AbstractBuilder> T createBuilder(PluginType<?> plugin, String prefix, Properties props) {
+        try {
+            Class<?> clazz = plugin.getPluginClass();
+            if (AbstractBuilder.class.isAssignableFrom(clazz)) {
+                @SuppressWarnings("unchecked")
+                Constructor<T> constructor =
+                        (Constructor<T>) clazz.getConstructor(constructorParams);
+                return constructor.newInstance(prefix, props);
+            } else {
+                @SuppressWarnings("unchecked")
+                T builder = (T) LoaderUtil.newInstanceOf(clazz);
+                return builder;
+            }
+        } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException ex) {
+            LOGGER.warn("Unable to load plugin: {} due to: {}", plugin.getKey(), ex.getMessage());
+            return null;
+        }
+    }
+
+}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/Holder.java
similarity index 67%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-1.2-api/src/main/java/org/apache/log4j/builders/Holder.java
index 13aaf9c..b9ce2bf 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/Holder.java
@@ -14,17 +14,26 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
+package org.apache.log4j.builders;
 
-import org.junit.Test;
+/**
+ * Provides a place to hold values generated inside of a Lambda expression.
+ */
+public class Holder<T> {
+    private T value;
 
-import static org.junit.Assert.*;
+    public Holder() {
+    }
 
-public class ProcessIdUtilTest {
+    public Holder(T defaultValue) {
+        this.value = defaultValue;
+    }
 
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
+    public void set(T value) {
+        this.value = value;
+    }
+
+    public T get() {
+        return value;
     }
 }
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/AppenderBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/AppenderBuilder.java
new file mode 100644
index 0000000..bb7ff93
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/AppenderBuilder.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.builders.appender;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.xml.XmlConfiguration;
+import org.w3c.dom.Element;
+
+import java.util.Properties;
+
+/**
+ * Define an Appender Builder.
+ */
+public interface AppenderBuilder {
+
+    Appender parseAppender(Element element, XmlConfiguration configuration);
+
+    Appender parseAppender(String name, String appenderPrefix, String layoutPrefix, String filterPrefix,
+            Properties props, PropertiesConfiguration configuration);
+
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/AsyncAppenderBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/AsyncAppenderBuilder.java
new file mode 100644
index 0000000..e60d50b
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/AsyncAppenderBuilder.java
@@ -0,0 +1,168 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.builders.appender;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.bridge.AppenderWrapper;
+import org.apache.log4j.builders.AbstractBuilder;
+import org.apache.log4j.builders.BooleanHolder;
+import org.apache.log4j.builders.Holder;
+import org.apache.log4j.config.Log4j1Configuration;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.helpers.OptionConverter;
+import org.apache.log4j.xml.XmlConfiguration;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.appender.AsyncAppender;
+import org.apache.logging.log4j.core.config.AppenderRef;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.xml.XmlConfiguration.NAME_ATTR;
+import static org.apache.log4j.xml.XmlConfiguration.PARAM_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.VALUE_ATTR;
+import static org.apache.log4j.xml.XmlConfiguration.forEachElement;
+import static org.apache.log4j.config.Log4j1Configuration.APPENDER_REF_TAG;
+import static org.apache.log4j.config.Log4j1Configuration.THRESHOLD_PARAM;
+
+
+/**
+ * Build an Asynch Appender
+ */
+@Plugin(name = "org.apache.log4j.AsyncAppender", category = CATEGORY)
+public class AsyncAppenderBuilder extends AbstractBuilder implements AppenderBuilder {
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+    private static final String BLOCKING_PARAM = "Blocking";
+    private static final String INCLUDE_LOCATION_PARAM = "IncludeLocation";
+
+    public AsyncAppenderBuilder() {
+    }
+
+    public AsyncAppenderBuilder(String prefix, Properties props) {
+        super(prefix, props);
+    }
+
+    @Override
+    public Appender parseAppender(final Element appenderElement, final XmlConfiguration config) {
+        String name = appenderElement.getAttribute(NAME_ATTR);
+        Holder<List<String>> appenderRefs = new Holder<>(new ArrayList<>());
+        Holder<Boolean> blocking = new BooleanHolder();
+        Holder<Boolean> includeLocation = new BooleanHolder();
+        Holder<String> level = new Holder<>("trace");
+        Holder<Integer> bufferSize = new Holder<>(1024);
+        forEachElement(appenderElement.getChildNodes(), (currentElement) -> {
+            switch (currentElement.getTagName()) {
+                case APPENDER_REF_TAG:
+                    Appender appender = config.findAppenderByReference(currentElement);
+                    if (appender != null) {
+                        appenderRefs.get().add(appender.getName());
+                    }
+                    break;
+                case PARAM_TAG: {
+                    switch (currentElement.getAttribute(NAME_ATTR)) {
+                        case BUFFER_SIZE_PARAM: {
+                            String value = currentElement.getAttribute(VALUE_ATTR);
+                            if (value == null) {
+                                LOGGER.warn("No value supplied for BufferSize parameter. Defaulting to 1024.");
+                            } else {
+                                bufferSize.set(Integer.parseInt(value));
+                            }
+                            break;
+                        }
+                        case BLOCKING_PARAM: {
+                            String value = currentElement.getAttribute(VALUE_ATTR);
+                            if (value == null) {
+                                LOGGER.warn("No value supplied for Blocking parameter. Defaulting to false.");
+                            } else {
+                                blocking.set(Boolean.parseBoolean(value));
+                            }
+                            break;
+                        }
+                        case INCLUDE_LOCATION_PARAM: {
+                            String value = currentElement.getAttribute(VALUE_ATTR);
+                            if (value == null) {
+                                LOGGER.warn("No value supplied for IncludeLocation parameter. Defaulting to false.");
+                            } else {
+                                includeLocation.set(Boolean.parseBoolean(value));
+                            }
+                            break;
+                        }
+                        case THRESHOLD_PARAM: {
+                            String value = currentElement.getAttribute(VALUE_ATTR);
+                            if (value == null) {
+                                LOGGER.warn("No value supplied for Threshold parameter, ignoring.");
+                            } else {
+                                level.set(value);
+                            }
+                            break;
+                        }
+                    }
+                    break;
+                }
+            }
+        });
+        return createAppender(name, level.get(), appenderRefs.get().toArray(new String[0]), blocking.get(),
+                bufferSize.get(), includeLocation.get(), config);
+    }
+
+    @Override
+    public Appender parseAppender(final String name, final String appenderPrefix, final String layoutPrefix,
+            final String filterPrefix, final Properties props, final PropertiesConfiguration configuration) {
+        String appenderRef = getProperty(APPENDER_REF_TAG);
+        boolean blocking = getBooleanProperty(BLOCKING_PARAM);
+        boolean includeLocation = getBooleanProperty(INCLUDE_LOCATION_PARAM);
+        String level = getProperty(THRESHOLD_PARAM);
+        int bufferSize = getIntegerProperty(BUFFER_SIZE_PARAM, 1024);
+        if (appenderRef == null) {
+            LOGGER.warn("No appender references configured for AsyncAppender {}", name);
+            return null;
+        }
+        Appender appender = configuration.parseAppender(props, appenderRef);
+        if (appender == null) {
+            LOGGER.warn("Cannot locate Appender {}", appenderRef);
+            return null;
+        }
+        return createAppender(name, level, new String[] {appenderRef}, blocking, bufferSize, includeLocation,
+                configuration);
+    }
+
+    private <T extends Log4j1Configuration> Appender createAppender(String name, String level,
+            String[] appenderRefs, boolean blocking, int bufferSize, boolean includeLocation,
+            T configuration) {
+        org.apache.logging.log4j.Level logLevel = OptionConverter.convertLevel(level,
+                org.apache.logging.log4j.Level.TRACE);
+        AppenderRef[] refs = new AppenderRef[appenderRefs.length];
+        int index = 0;
+        for (String appenderRef : appenderRefs) {
+            refs[index++] = AppenderRef.createAppenderRef(appenderRef, logLevel, null);
+        }
+        return new AppenderWrapper(AsyncAppender.newBuilder()
+                .setName(name)
+                .setAppenderRefs(refs)
+                .setBlocking(blocking)
+                .setBufferSize(bufferSize)
+                .setIncludeLocation(includeLocation)
+                .setConfiguration(configuration)
+                .build());
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/ConsoleAppenderBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/ConsoleAppenderBuilder.java
new file mode 100644
index 0000000..119e6fb
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/ConsoleAppenderBuilder.java
@@ -0,0 +1,161 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.builders.appender;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.Layout;
+import org.apache.log4j.bridge.AppenderWrapper;
+import org.apache.log4j.bridge.LayoutAdapter;
+import org.apache.log4j.bridge.LayoutWrapper;
+import org.apache.log4j.builders.AbstractBuilder;
+import org.apache.log4j.builders.Holder;
+import org.apache.log4j.config.Log4j1Configuration;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.xml.XmlConfiguration;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.appender.ConsoleAppender;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.config.Log4j1Configuration.THRESHOLD_PARAM;
+import static org.apache.log4j.xml.XmlConfiguration.FILTER_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.LAYOUT_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.NAME_ATTR;
+import static org.apache.log4j.xml.XmlConfiguration.PARAM_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.VALUE_ATTR;
+import static org.apache.log4j.xml.XmlConfiguration.forEachElement;
+
+/**
+ * Build a Console Appender
+ */
+@Plugin(name = "org.apache.log4j.ConsoleAppender", category = CATEGORY)
+public class ConsoleAppenderBuilder extends AbstractBuilder implements AppenderBuilder {
+    private static final String SYSTEM_OUT = "System.out";
+    private static final String SYSTEM_ERR = "System.err";
+    private static final String TARGET = "target";
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+
+    public ConsoleAppenderBuilder() {
+    }
+
+    public ConsoleAppenderBuilder(String prefix, Properties props) {
+        super(prefix, props);
+    }
+
+    @Override
+    public Appender parseAppender(final Element appenderElement, final XmlConfiguration config) {
+        String name = appenderElement.getAttribute(NAME_ATTR);
+        Holder<String> target = new Holder<>(SYSTEM_OUT);
+        Holder<Layout> layout = new Holder<>();
+        Holder<List<Filter>> filters = new Holder<>(new ArrayList<>());
+        Holder<String> level = new Holder<>();
+        forEachElement(appenderElement.getChildNodes(), (currentElement) -> {
+            switch (currentElement.getTagName()) {
+                case LAYOUT_TAG:
+                    layout.set(config.parseLayout(currentElement));
+                    break;
+                case FILTER_TAG:
+                    filters.get().add(config.parseFilters(currentElement));
+                    break;
+                case PARAM_TAG: {
+                    switch (currentElement.getAttribute(NAME_ATTR)) {
+                        case TARGET: {
+                            String value = currentElement.getAttribute(VALUE_ATTR);
+                            if (value == null) {
+                                LOGGER.warn("No value supplied for target parameter. Defaulting to System.out.");
+                            } else {
+                                switch (value) {
+                                    case SYSTEM_OUT:
+                                        target.set(SYSTEM_OUT);
+                                        break;
+                                    case SYSTEM_ERR:
+                                        target.set(SYSTEM_ERR);
+                                        break;
+                                    default:
+                                        LOGGER.warn("Invalid value \"{}\" for target parameter. Using default of System.out",
+                                                value);
+                                }
+                            }
+                            break;
+                        }
+                        case THRESHOLD_PARAM: {
+                            String value = currentElement.getAttribute(VALUE_ATTR);
+                            if (value == null) {
+                                LOGGER.warn("No value supplied for Threshold parameter, ignoring.");
+                            } else {
+                                level.set(value);
+                            }
+                            break;
+                        }
+                    }
+                    break;
+                }
+            }
+        });
+        Filter head = null;
+        Filter current = null;
+        for (Filter f : filters.get()) {
+            if (head == null) {
+                head = f;
+                current = f;
+            } else {
+                current.next = f;
+                current = f;
+            }
+        }
+        return createAppender(name, layout.get(), head, level.get(), target.get(), config);
+    }
+
+    @Override
+    public Appender parseAppender(final String name, final String appenderPrefix, final String layoutPrefix,
+            final String filterPrefix, final Properties props, final PropertiesConfiguration configuration) {
+        Layout layout = configuration.parseLayout(layoutPrefix, name, props);
+        Filter filter = configuration.parseAppenderFilters(props, filterPrefix, name);
+        String level = getProperty(THRESHOLD_PARAM);
+        String target = getProperty(TARGET);
+        return createAppender(name, layout, filter, level, target, configuration);
+    }
+
+    private <T extends Log4j1Configuration> Appender createAppender(String name, Layout layout, Filter filter,
+            String level, String target, T configuration) {
+        org.apache.logging.log4j.core.Layout<?> consoleLayout = null;
+
+        if (layout instanceof LayoutWrapper) {
+            consoleLayout = ((LayoutWrapper) layout).getLayout();
+        } else if (layout != null) {
+            consoleLayout = new LayoutAdapter(layout);
+        }
+        org.apache.logging.log4j.core.Filter consoleFilter = buildFilters(level, filter);
+        ConsoleAppender.Target consoleTarget = SYSTEM_ERR.equals(target)
+                ? ConsoleAppender.Target.SYSTEM_ERR : ConsoleAppender.Target.SYSTEM_OUT;
+        return new AppenderWrapper(ConsoleAppender.newBuilder()
+                .setName(name)
+                .setTarget(consoleTarget)
+                .setLayout(consoleLayout)
+                .setFilter(consoleFilter)
+                .setConfiguration(configuration)
+                .build());
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/DailyRollingFileAppenderBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/DailyRollingFileAppenderBuilder.java
new file mode 100644
index 0000000..89c2dba
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/DailyRollingFileAppenderBuilder.java
@@ -0,0 +1,190 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.builders.appender;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.Layout;
+import org.apache.log4j.bridge.AppenderWrapper;
+import org.apache.log4j.bridge.LayoutAdapter;
+import org.apache.log4j.bridge.LayoutWrapper;
+import org.apache.log4j.builders.AbstractBuilder;
+import org.apache.log4j.builders.BooleanHolder;
+import org.apache.log4j.builders.Holder;
+import org.apache.log4j.config.Log4j1Configuration;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.xml.XmlConfiguration;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.appender.RollingFileAppender;
+import org.apache.logging.log4j.core.appender.rolling.DefaultRolloverStrategy;
+import org.apache.logging.log4j.core.appender.rolling.RolloverStrategy;
+import org.apache.logging.log4j.core.appender.rolling.TimeBasedTriggeringPolicy;
+import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+
+import java.util.Properties;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.config.Log4j1Configuration.THRESHOLD_PARAM;
+import static org.apache.log4j.xml.XmlConfiguration.FILTER_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.LAYOUT_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.NAME_ATTR;
+import static org.apache.log4j.xml.XmlConfiguration.PARAM_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.VALUE_ATTR;
+import static org.apache.log4j.xml.XmlConfiguration.forEachElement;
+
+
+/**
+ * Build a Daily Rolling File Appender
+ */
+@Plugin(name = "org.apache.log4j.DailyRollingFileAppender", category = CATEGORY)
+public class DailyRollingFileAppenderBuilder extends AbstractBuilder implements AppenderBuilder {
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+
+    public DailyRollingFileAppenderBuilder() {
+    }
+
+    public DailyRollingFileAppenderBuilder(String prefix, Properties props) {
+        super(prefix, props);
+    }
+
+
+    @Override
+    public Appender parseAppender(final Element appenderElement, final XmlConfiguration config) {
+        String name = appenderElement.getAttribute(NAME_ATTR);
+        Holder<Layout> layout = new Holder<>();
+        Holder<Filter> filter = new Holder<>();
+        Holder<String> fileName = new Holder<>();
+        Holder<String> level = new Holder<>();
+        Holder<Boolean> immediateFlush = new BooleanHolder();
+        Holder<Boolean> append = new BooleanHolder();
+        Holder<Boolean> bufferedIo = new BooleanHolder();
+        Holder<Integer> bufferSize = new Holder<>(8192);
+        forEachElement(appenderElement.getChildNodes(), (currentElement) -> {
+            switch (currentElement.getTagName()) {
+                case LAYOUT_TAG:
+                    layout.set(config.parseLayout(currentElement));
+                    break;
+                case FILTER_TAG:
+                    filter.set(config.parseFilters(currentElement));
+                    break;
+                case PARAM_TAG: {
+                    switch (currentElement.getAttribute(NAME_ATTR)) {
+                        case FILE_PARAM:
+                            fileName.set(currentElement.getAttribute(VALUE_ATTR));
+                            break;
+                        case APPEND_PARAM: {
+                            String bool = currentElement.getAttribute(VALUE_ATTR);
+                            if (bool != null) {
+                                append.set(Boolean.parseBoolean(bool));
+                            } else {
+                                LOGGER.warn("No value provided for append parameter");
+                            }
+                            break;
+                        }
+                        case BUFFERED_IO_PARAM: {
+                            String bool = currentElement.getAttribute(VALUE_ATTR);
+                            if (bool != null) {
+                                bufferedIo.set(Boolean.parseBoolean(bool));
+                            } else {
+                                LOGGER.warn("No value provided for bufferedIo parameter");
+                            }
+                            break;
+                        }
+                        case BUFFER_SIZE_PARAM: {
+                            String size = currentElement.getAttribute(VALUE_ATTR);
+                            if (size != null) {
+                                bufferSize.set(Integer.parseInt(size));
+                            } else {
+                                LOGGER.warn("No value provide for bufferSize parameter");
+                            }
+                            break;
+                        }
+                        case THRESHOLD_PARAM: {
+                            String value = currentElement.getAttribute(VALUE_ATTR);
+                            if (value == null) {
+                                LOGGER.warn("No value supplied for Threshold parameter, ignoring.");
+                            } else {
+                                level.set(value);
+                            }
+                            break;
+                        }
+                    }
+                    break;
+                }
+            }
+        });
+        return createAppender(name, layout.get(), filter.get(), fileName.get(), append.get(), immediateFlush.get(),
+                level.get(), bufferedIo.get(), bufferSize.get(), config);
+    }
+
+    @Override
+    public Appender parseAppender(final String name, final String appenderPrefix, final String layoutPrefix,
+            final String filterPrefix, final Properties props, final PropertiesConfiguration configuration) {
+        Layout layout = configuration.parseLayout(layoutPrefix, name, props);
+        Filter filter = configuration.parseAppenderFilters(props, filterPrefix, name);
+        String fileName = getProperty(FILE_PARAM);
+        String level = getProperty(THRESHOLD_PARAM);
+        boolean append = getBooleanProperty(APPEND_PARAM);
+        boolean immediateFlush = false;
+        boolean bufferedIo = getBooleanProperty(BUFFERED_IO_PARAM);
+        int bufferSize = Integer.parseInt(getProperty(BUFFER_SIZE_PARAM, "8192"));
+        return createAppender(name, layout, filter, fileName, append, immediateFlush,
+                level, bufferedIo, bufferSize, configuration);
+    }
+
+    private <T extends Log4j1Configuration> Appender createAppender(final String name, final Layout layout,
+            final Filter filter, final String fileName, final boolean append, boolean immediateFlush,
+            final String level, final boolean bufferedIo, final int bufferSize, final T configuration) {
+
+        org.apache.logging.log4j.core.Layout<?> fileLayout = null;
+        if (bufferedIo) {
+            immediateFlush = true;
+        }
+        if (layout instanceof LayoutWrapper) {
+            fileLayout = ((LayoutWrapper) layout).getLayout();
+        } else if (layout != null) {
+            fileLayout = new LayoutAdapter(layout);
+        }
+        org.apache.logging.log4j.core.Filter fileFilter = buildFilters(level, filter);
+        if (fileName == null) {
+            LOGGER.warn("Unable to create File Appender, no file name provided");
+            return null;
+        }
+        String filePattern = fileName +"%d{yyy-MM-dd}";
+        TriggeringPolicy policy = TimeBasedTriggeringPolicy.newBuilder().setModulate(true).build();
+        RolloverStrategy strategy = DefaultRolloverStrategy.newBuilder()
+                .setConfig(configuration)
+                .setMax(Integer.toString(Integer.MAX_VALUE))
+                .build();
+        return new AppenderWrapper(RollingFileAppender.newBuilder()
+                .setName(name)
+                .setConfiguration(configuration)
+                .setLayout(fileLayout)
+                .setFilter(fileFilter)
+                .setFileName(fileName)
+                .setBufferSize(bufferSize)
+                .setImmediateFlush(immediateFlush)
+                .setFilePattern(filePattern)
+                .setPolicy(policy)
+                .setStrategy(strategy)
+                .build());
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/FileAppenderBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/FileAppenderBuilder.java
new file mode 100644
index 0000000..8b7f467
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/FileAppenderBuilder.java
@@ -0,0 +1,178 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.builders.appender;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.Layout;
+import org.apache.log4j.bridge.AppenderWrapper;
+import org.apache.log4j.bridge.LayoutAdapter;
+import org.apache.log4j.bridge.LayoutWrapper;
+import org.apache.log4j.builders.AbstractBuilder;
+import org.apache.log4j.builders.BooleanHolder;
+import org.apache.log4j.builders.Holder;
+import org.apache.log4j.config.Log4j1Configuration;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.xml.XmlConfiguration;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.appender.FileAppender;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+
+import java.util.Properties;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.config.Log4j1Configuration.THRESHOLD_PARAM;
+import static org.apache.log4j.xml.XmlConfiguration.FILTER_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.LAYOUT_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.PARAM_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.forEachElement;
+import static org.apache.log4j.xml.XmlConfiguration.NAME_ATTR;
+import static org.apache.log4j.xml.XmlConfiguration.VALUE_ATTR;
+
+/**
+ * Build a File Appender
+ */
+@Plugin(name = "org.apache.log4j.FileAppender", category = CATEGORY)
+public class FileAppenderBuilder extends AbstractBuilder implements AppenderBuilder {
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+
+    public FileAppenderBuilder() {
+    }
+
+    public FileAppenderBuilder(String prefix, Properties props) {
+        super(prefix, props);
+    }
+
+    @Override
+    public Appender parseAppender(Element appenderElement, XmlConfiguration config) {
+        String name = appenderElement.getAttribute(NAME_ATTR);
+        Holder<Layout> layout = new Holder<>();
+        Holder<Filter> filter = new Holder<>();
+        Holder<String> fileName = new Holder<>();
+        Holder<String> level = new Holder<>();
+        Holder<Boolean> immediateFlush = new BooleanHolder();
+        Holder<Boolean> append = new BooleanHolder();
+        Holder<Boolean> bufferedIo = new BooleanHolder();
+        Holder<Integer> bufferSize = new Holder<>(8192);
+        forEachElement(appenderElement.getChildNodes(), (currentElement) -> {
+            switch (currentElement.getTagName()) {
+                case LAYOUT_TAG:
+                    layout.set(config.parseLayout(currentElement));
+                    break;
+                case FILTER_TAG:
+                    filter.set(config.parseFilters(currentElement));
+                    break;
+                case PARAM_TAG: {
+                    switch (currentElement.getAttribute(NAME_ATTR)) {
+                        case FILE_PARAM:
+                            fileName.set(currentElement.getAttribute(VALUE_ATTR));
+                            break;
+                        case APPEND_PARAM: {
+                            String bool = currentElement.getAttribute(VALUE_ATTR);
+                            if (bool != null) {
+                                append.set(Boolean.parseBoolean(bool));
+                            } else {
+                                LOGGER.warn("No value provided for append parameter");
+                            }
+                            break;
+                        }
+                        case BUFFERED_IO_PARAM: {
+                            String bool = currentElement.getAttribute(VALUE_ATTR);
+                            if (bool != null) {
+                                bufferedIo.set(Boolean.parseBoolean(bool));
+                            } else {
+                                LOGGER.warn("No value provided for bufferedIo parameter");
+                            }
+                            break;
+                        }
+                        case BUFFER_SIZE_PARAM: {
+                            String size = currentElement.getAttribute(VALUE_ATTR);
+                            if (size != null) {
+                                bufferSize.set(Integer.parseInt(size));
+                            } else {
+                                LOGGER.warn("No value provide for bufferSize parameter");
+                            }
+                            break;
+                        }
+                        case THRESHOLD_PARAM: {
+                            String value = currentElement.getAttribute(VALUE_ATTR);
+                            if (value == null) {
+                                LOGGER.warn("No value supplied for Threshold parameter, ignoring.");
+                            } else {
+                                level.set(value);
+                            }
+                            break;
+                        }
+                    }
+                    break;
+                }
+            }
+        });
+
+        return createAppender(name, config, layout.get(), filter.get(), fileName.get(), level.get(),
+                immediateFlush.get(), append.get(), bufferedIo.get(), bufferSize.get());
+    }
+
+
+    @Override
+    public Appender parseAppender(final String name, final String appenderPrefix, final String layoutPrefix,
+            final String filterPrefix, final Properties props, final PropertiesConfiguration configuration) {
+        Layout layout = configuration.parseLayout(layoutPrefix, name, props);
+        Filter filter = configuration.parseAppenderFilters(props, filterPrefix, name);
+        String level = getProperty(THRESHOLD_PARAM);
+        String fileName = getProperty(FILE_PARAM);
+        boolean append = getBooleanProperty(APPEND_PARAM);
+        boolean immediateFlush = false;
+        boolean bufferedIo = getBooleanProperty(BUFFERED_IO_PARAM);
+        int bufferSize = Integer.parseInt(getProperty(BUFFER_SIZE_PARAM, "8192"));
+        return createAppender(name, configuration, layout, filter, fileName, level, immediateFlush,
+                append, bufferedIo, bufferSize);
+    }
+
+    private Appender createAppender(final String name, final Log4j1Configuration configuration, final Layout layout,
+            final Filter filter, final String fileName, String level, boolean immediateFlush, final boolean append,
+            final boolean bufferedIo, final int bufferSize) {
+        org.apache.logging.log4j.core.Layout<?> fileLayout = null;
+        if (bufferedIo) {
+            immediateFlush = true;
+        }
+        if (layout instanceof LayoutWrapper) {
+            fileLayout = ((LayoutWrapper) layout).getLayout();
+        } else if (layout != null) {
+            fileLayout = new LayoutAdapter(layout);
+        }
+        org.apache.logging.log4j.core.Filter fileFilter = buildFilters(level, filter);
+        if (fileName == null) {
+            LOGGER.warn("Unable to create File Appender, no file name provided");
+            return null;
+        }
+        return new AppenderWrapper(FileAppender.newBuilder()
+                .setName(name)
+                .setConfiguration(configuration)
+                .setLayout(fileLayout)
+                .setFilter(fileFilter)
+                .setFileName(fileName)
+                .setImmediateFlush(immediateFlush)
+                .setAppend(append)
+                .setBufferedIo(bufferedIo)
+                .setBufferSize(bufferSize)
+                .build());
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/NullAppenderBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/NullAppenderBuilder.java
new file mode 100644
index 0000000..07f2fd5
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/NullAppenderBuilder.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.builders.appender;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.bridge.AppenderWrapper;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.xml.XmlConfiguration;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.appender.NullAppender;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+
+import java.util.Properties;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+
+/**
+ * Build a Null Appender
+ */
+@Plugin(name = "org.apache.log4j.varia.NullAppender", category = CATEGORY)
+public class NullAppenderBuilder implements AppenderBuilder {
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+
+    @Override
+    public Appender parseAppender(Element appenderElement, XmlConfiguration config) {
+        String name = appenderElement.getAttribute("name");
+        return new AppenderWrapper(NullAppender.createAppender(name));
+    }
+
+
+    @Override
+    public Appender parseAppender(final String name, final String appenderPrefix, final String layoutPrefix,
+            final String filterPrefix, final Properties props, final PropertiesConfiguration configuration) {
+        return new AppenderWrapper(NullAppender.createAppender(name));
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/RewriteAppenderBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/RewriteAppenderBuilder.java
new file mode 100644
index 0000000..37ac70f
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/RewriteAppenderBuilder.java
@@ -0,0 +1,152 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.builders.appender;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.bridge.AppenderWrapper;
+import org.apache.log4j.bridge.RewritePolicyAdapter;
+import org.apache.log4j.bridge.RewritePolicyWrapper;
+import org.apache.log4j.builders.AbstractBuilder;
+import org.apache.log4j.builders.Holder;
+import org.apache.log4j.config.Log4j1Configuration;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.helpers.OptionConverter;
+import org.apache.log4j.rewrite.RewritePolicy;
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.xml.XmlConfiguration;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.appender.rewrite.RewriteAppender;
+import org.apache.logging.log4j.core.config.AppenderRef;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.config.Log4j1Configuration.APPENDER_REF_TAG;
+import static org.apache.log4j.config.Log4j1Configuration.THRESHOLD_PARAM;
+import static org.apache.log4j.xml.XmlConfiguration.FILTER_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.NAME_ATTR;
+import static org.apache.log4j.xml.XmlConfiguration.PARAM_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.VALUE_ATTR;
+import static org.apache.log4j.xml.XmlConfiguration.forEachElement;
+
+
+/**
+ * Build an Asynch Appender
+ */
+@Plugin(name = "org.apache.log4j.rewrite.RewriteAppender", category = CATEGORY)
+public class RewriteAppenderBuilder extends AbstractBuilder implements AppenderBuilder {
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+    private static final String REWRITE_POLICY_TAG = "rewritePolicy";
+
+    public RewriteAppenderBuilder() {
+    }
+
+    public RewriteAppenderBuilder(String prefix, Properties props) {
+        super(prefix, props);
+    }
+
+    @Override
+    public Appender parseAppender(final Element appenderElement, final XmlConfiguration config) {
+        String name = appenderElement.getAttribute(NAME_ATTR);
+        Holder<List<String>> appenderRefs = new Holder<>(new ArrayList<>());
+        Holder<RewritePolicy> rewritePolicyHolder = new Holder<>();
+        Holder<String> level = new Holder<>();
+        Holder<Filter> filter = new Holder<>();
+        forEachElement(appenderElement.getChildNodes(), (currentElement) -> {
+            switch (currentElement.getTagName()) {
+                case APPENDER_REF_TAG:
+                    Appender appender = config.findAppenderByReference(currentElement);
+                    if (appender != null) {
+                        appenderRefs.get().add(appender.getName());
+                    }
+                    break;
+                case REWRITE_POLICY_TAG: {
+                    RewritePolicy policy = config.parseRewritePolicy(currentElement);
+                    if (policy != null) {
+                        rewritePolicyHolder.set(policy);
+                    }
+                    break;
+                }
+                case FILTER_TAG: {
+                    filter.set(config.parseFilters(currentElement));
+                    break;
+                }
+                case PARAM_TAG: {
+                    if (currentElement.getAttribute(NAME_ATTR).equalsIgnoreCase(THRESHOLD_PARAM)) {
+                        String value = currentElement.getAttribute(VALUE_ATTR);
+                        if (value == null) {
+                            LOGGER.warn("No value supplied for Threshold parameter, ignoring.");
+                        } else {
+                            level.set(value);
+                        }
+                    }
+                    break;
+                }
+            }
+        });
+        return createAppender(name, level.get(), appenderRefs.get().toArray(new String[0]), rewritePolicyHolder.get(),
+                filter.get(), config);
+    }
+
+    @Override
+    public Appender parseAppender(final String name, final String appenderPrefix, final String layoutPrefix,
+            final String filterPrefix, final Properties props, final PropertiesConfiguration configuration) {
+        String appenderRef = getProperty(APPENDER_REF_TAG);
+        Filter filter = configuration.parseAppenderFilters(props, filterPrefix, name);
+        String policyPrefix = appenderPrefix + ".rewritePolicy";
+        String className = getProperty(policyPrefix);
+        RewritePolicy policy = configuration.getBuilderManager().parseRewritePolicy(className, policyPrefix,
+                props, configuration);
+        String level = getProperty(THRESHOLD_PARAM);
+        if (appenderRef == null) {
+            LOGGER.warn("No appender references configured for AsyncAppender {}", name);
+            return null;
+        }
+        Appender appender = configuration.parseAppender(props, appenderRef);
+        if (appender == null) {
+            LOGGER.warn("Cannot locate Appender {}", appenderRef);
+            return null;
+        }
+        return createAppender(name, level, new String[] {appenderRef}, policy, filter, configuration);
+    }
+
+    private <T extends Log4j1Configuration> Appender createAppender(String name, String level,
+            String[] appenderRefs, RewritePolicy policy, Filter filter, T configuration) {
+        org.apache.logging.log4j.Level logLevel = OptionConverter.convertLevel(level,
+                org.apache.logging.log4j.Level.TRACE);
+        AppenderRef[] refs = new AppenderRef[appenderRefs.length];
+        int index = 0;
+        for (String appenderRef : appenderRefs) {
+            refs[index++] = AppenderRef.createAppenderRef(appenderRef, logLevel, null);
+        }
+        org.apache.logging.log4j.core.Filter rewriteFilter = buildFilters(level, filter);
+        org.apache.logging.log4j.core.appender.rewrite.RewritePolicy rewritePolicy;
+        if (policy instanceof RewritePolicyWrapper) {
+            rewritePolicy = ((RewritePolicyWrapper) policy).getPolicy();
+        } else {
+            rewritePolicy = new RewritePolicyAdapter(policy);
+        }
+        return new AppenderWrapper(RewriteAppender.createAppender(name, true, refs, configuration,
+                rewritePolicy, rewriteFilter));
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/RollingFileAppenderBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/RollingFileAppenderBuilder.java
new file mode 100644
index 0000000..bac9425
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/RollingFileAppenderBuilder.java
@@ -0,0 +1,213 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.builders.appender;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.Layout;
+import org.apache.log4j.bridge.AppenderWrapper;
+import org.apache.log4j.bridge.LayoutAdapter;
+import org.apache.log4j.bridge.LayoutWrapper;
+import org.apache.log4j.builders.AbstractBuilder;
+import org.apache.log4j.builders.BooleanHolder;
+import org.apache.log4j.builders.Holder;
+import org.apache.log4j.config.Log4j1Configuration;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.xml.XmlConfiguration;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.appender.RollingFileAppender;
+import org.apache.logging.log4j.core.appender.rolling.CompositeTriggeringPolicy;
+import org.apache.logging.log4j.core.appender.rolling.DefaultRolloverStrategy;
+import org.apache.logging.log4j.core.appender.rolling.RolloverStrategy;
+import org.apache.logging.log4j.core.appender.rolling.SizeBasedTriggeringPolicy;
+import org.apache.logging.log4j.core.appender.rolling.TimeBasedTriggeringPolicy;
+import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+
+import java.util.Properties;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.config.Log4j1Configuration.THRESHOLD_PARAM;
+import static org.apache.log4j.xml.XmlConfiguration.FILTER_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.LAYOUT_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.NAME_ATTR;
+import static org.apache.log4j.xml.XmlConfiguration.PARAM_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.VALUE_ATTR;
+import static org.apache.log4j.xml.XmlConfiguration.forEachElement;
+
+
+/**
+ * Build a File Appender
+ */
+@Plugin(name = "org.apache.log4j.RollingFileAppender", category = CATEGORY)
+public class RollingFileAppenderBuilder extends AbstractBuilder implements AppenderBuilder {
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+
+    public RollingFileAppenderBuilder() {
+    }
+
+    public RollingFileAppenderBuilder(String prefix, Properties props) {
+        super(prefix, props);
+    }
+
+    @Override
+    public Appender parseAppender(Element appenderElement, XmlConfiguration config) {
+        String name = appenderElement.getAttribute(NAME_ATTR);
+        Holder<Layout> layout = new Holder<>();
+        Holder<Filter> filter = new Holder<>();
+        Holder<String> fileName = new Holder<>();
+        Holder<Boolean> immediateFlush = new BooleanHolder();
+        Holder<Boolean> append = new BooleanHolder();
+        Holder<Boolean> bufferedIo = new BooleanHolder();
+        Holder<Integer> bufferSize = new Holder<>(8192);
+        Holder<String> maxSize = new Holder<>();
+        Holder<String> maxBackups = new Holder<>();
+        Holder<String> level = new Holder<>();
+        forEachElement(appenderElement.getChildNodes(), (currentElement) -> {
+            switch (currentElement.getTagName()) {
+                case LAYOUT_TAG:
+                    layout.set(config.parseLayout(currentElement));
+                    break;
+                case FILTER_TAG:
+                    filter.set(config.parseFilters(currentElement));
+                    break;
+                case PARAM_TAG: {
+                    switch (currentElement.getAttribute(NAME_ATTR)) {
+                        case FILE_PARAM:
+                            fileName.set(currentElement.getAttribute(VALUE_ATTR));
+                            break;
+                        case APPEND_PARAM: {
+                            String bool = currentElement.getAttribute(VALUE_ATTR);
+                            if (bool != null) {
+                                append.set(Boolean.parseBoolean(bool));
+                            } else {
+                                LOGGER.warn("No value provided for append parameter");
+                            }
+                            break;
+                        }
+                        case BUFFERED_IO_PARAM: {
+                            String bool = currentElement.getAttribute(VALUE_ATTR);
+                            if (bool != null) {
+                                bufferedIo.set(Boolean.parseBoolean(bool));
+                            } else {
+                                LOGGER.warn("No value provided for bufferedIo parameter");
+                            }
+                            break;
+                        }
+                        case BUFFER_SIZE_PARAM: {
+                            String size = currentElement.getAttribute(VALUE_ATTR);
+                            if (size != null) {
+                                bufferSize.set(Integer.parseInt(size));
+                            } else {
+                                LOGGER.warn("No value provide for bufferSize parameter");
+                            }
+                            break;
+                        }
+                        case MAX_BACKUP_INDEX: {
+                            String size = currentElement.getAttribute(VALUE_ATTR);
+                            if (size != null) {
+                                maxBackups.set(size);
+                            } else {
+                                LOGGER.warn("No value provide for maxBackupIndex parameter");
+                            }
+                            break;
+                        }
+                        case MAX_SIZE_PARAM: {
+                            String size = currentElement.getAttribute(VALUE_ATTR);
+                            if (size != null) {
+                                maxSize.set(size);
+                            } else {
+                                LOGGER.warn("No value provide for bufferSize parameter");
+                            }
+                            break;
+                        }
+                        case THRESHOLD_PARAM: {
+                            String value = currentElement.getAttribute(VALUE_ATTR);
+                            if (value == null) {
+                                LOGGER.warn("No value supplied for Threshold parameter, ignoring.");
+                            } else {
+                                level.set(value);
+                            }
+                            break;
+                        }
+                    }
+                    break;
+                }
+            }
+        });
+        return createAppender(name, config, layout.get(), filter.get(), bufferedIo.get(), immediateFlush.get(),
+                fileName.get(), level.get(), maxSize.get(), maxBackups.get());
+    }
+
+
+    @Override
+    public Appender parseAppender(final String name, final String appenderPrefix, final String layoutPrefix,
+            final String filterPrefix, final Properties props, final PropertiesConfiguration configuration) {
+        Layout layout = configuration.parseLayout(layoutPrefix, name, props);
+        Filter filter = configuration.parseAppenderFilters(props, filterPrefix, name);
+        String fileName = getProperty(FILE_PARAM);
+        String level = getProperty(THRESHOLD_PARAM);
+        boolean immediateFlush = false;
+        boolean bufferedIo = getBooleanProperty(BUFFERED_IO_PARAM);
+        String maxSize = getProperty(MAX_SIZE_PARAM);
+        String maxBackups = getProperty(MAX_BACKUP_INDEX);
+        return createAppender(name, configuration, layout, filter, bufferedIo, immediateFlush, fileName, level, maxSize,
+                maxBackups);
+    }
+
+    private Appender createAppender(final String name, final Log4j1Configuration config, final Layout layout,
+            final Filter filter, final boolean bufferedIo, boolean immediateFlush, final String fileName,
+            final String level, final String maxSize, final String maxBackups) {
+        org.apache.logging.log4j.core.Layout<?> fileLayout = null;
+        if (bufferedIo) {
+            immediateFlush = true;
+        }
+        if (layout instanceof LayoutWrapper) {
+            fileLayout = ((LayoutWrapper) layout).getLayout();
+        } else if (layout != null) {
+            fileLayout = new LayoutAdapter(layout);
+        }
+        org.apache.logging.log4j.core.Filter fileFilter = buildFilters(level, filter);
+        if (fileName == null) {
+            LOGGER.warn("Unable to create File Appender, no file name provided");
+            return null;
+        }
+        String filePattern = fileName +"%d{yyy-MM-dd}";
+        TriggeringPolicy timePolicy = TimeBasedTriggeringPolicy.newBuilder().setModulate(true).build();
+        SizeBasedTriggeringPolicy sizePolicy = SizeBasedTriggeringPolicy.createPolicy(maxSize);
+        CompositeTriggeringPolicy policy = CompositeTriggeringPolicy.createPolicy(sizePolicy, timePolicy);
+        RolloverStrategy strategy = DefaultRolloverStrategy.newBuilder()
+                .setConfig(config)
+                .setMax(maxBackups)
+                .build();
+        return new AppenderWrapper(RollingFileAppender.newBuilder()
+                .setName(name)
+                .setConfiguration(config)
+                .setLayout(fileLayout)
+                .setFilter(fileFilter)
+                .setBufferedIo(bufferedIo)
+                .setImmediateFlush(immediateFlush)
+                .setFileName(fileName)
+                .setFilePattern(filePattern)
+                .setPolicy(policy)
+                .setStrategy(strategy)
+                .build());
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/SyslogAppenderBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/SyslogAppenderBuilder.java
new file mode 100644
index 0000000..c281ea9
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/SyslogAppenderBuilder.java
@@ -0,0 +1,173 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.builders.appender;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.Layout;
+import org.apache.log4j.bridge.AppenderWrapper;
+import org.apache.log4j.bridge.LayoutAdapter;
+import org.apache.log4j.bridge.LayoutWrapper;
+import org.apache.log4j.builders.AbstractBuilder;
+import org.apache.log4j.builders.Holder;
+import org.apache.log4j.config.Log4j1Configuration;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.xml.XmlConfiguration;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.appender.SyslogAppender;
+import org.apache.logging.log4j.core.layout.SyslogLayout;
+import org.apache.logging.log4j.core.net.Facility;
+import org.apache.logging.log4j.core.net.Protocol;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+
+import java.util.Properties;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.config.Log4j1Configuration.THRESHOLD_PARAM;
+import static org.apache.log4j.xml.XmlConfiguration.FILTER_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.LAYOUT_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.NAME_ATTR;
+import static org.apache.log4j.xml.XmlConfiguration.PARAM_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.VALUE_ATTR;
+import static org.apache.log4j.xml.XmlConfiguration.forEachElement;
+
+/**
+ * Build a File Appender
+ */
+@Plugin(name = "org.apache.log4j.net.SyslogAppender", category = CATEGORY)
+public class SyslogAppenderBuilder extends AbstractBuilder implements AppenderBuilder {
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+    private static final String FACILITY_PARAM = "Facility";
+    private static final String SYSLOG_HOST_PARAM = "SyslogHost";
+    private static int SYSLOG_PORT = 512;
+
+    public SyslogAppenderBuilder() {
+    }
+
+    public SyslogAppenderBuilder(String prefix, Properties props) {
+        super(prefix, props);
+    }
+
+    @Override
+    public Appender parseAppender(Element appenderElement, XmlConfiguration config) {
+        String name = appenderElement.getAttribute(NAME_ATTR);
+        Holder<Layout> layout = new Holder<>();
+        Holder<Filter> filter = new Holder<>();
+        Holder<String> facility = new Holder<>();
+        Holder<String> level = new Holder<>();
+        Holder<String> host = new Holder<>();
+        forEachElement(appenderElement.getChildNodes(), (currentElement) -> {
+            switch (currentElement.getTagName()) {
+                case LAYOUT_TAG:
+                    layout.set(config.parseLayout(currentElement));
+                    break;
+                case FILTER_TAG:
+                    filter.set(config.parseFilters(currentElement));
+                    break;
+                case PARAM_TAG: {
+                    switch (currentElement.getAttribute(NAME_ATTR)) {
+                        case SYSLOG_HOST_PARAM: {
+                            host.set(currentElement.getAttribute(VALUE_ATTR));
+                            break;
+                        }
+                        case FACILITY_PARAM:
+                            facility.set(currentElement.getAttribute(VALUE_ATTR));
+                            break;
+                        case THRESHOLD_PARAM: {
+                            String value = currentElement.getAttribute(VALUE_ATTR);
+                            if (value == null) {
+                                LOGGER.warn("No value supplied for Threshold parameter, ignoring.");
+                            } else {
+                                level.set(value);
+                            }
+                            break;
+                        }
+                    }
+                    break;
+                }
+            }
+        });
+
+        return createAppender(name, config, layout.get(), facility.get(), filter.get(), host.get(), level.get());
+    }
+
+
+    @Override
+    public Appender parseAppender(final String name, final String appenderPrefix, final String layoutPrefix,
+            final String filterPrefix, final Properties props, final PropertiesConfiguration configuration) {
+        Filter filter = configuration.parseAppenderFilters(props, filterPrefix, name);
+        Layout layout = configuration.parseLayout(layoutPrefix, name, props);
+        String level = getProperty(THRESHOLD_PARAM);
+        String facility = getProperty(FACILITY_PARAM, "LOCAL0");
+        String syslogHost = getProperty(SYSLOG_HOST_PARAM, "localhost:514");
+
+        return createAppender(name, configuration, layout, facility, filter, syslogHost, level);
+    }
+
+    private Appender createAppender(final String name, final Log4j1Configuration configuration, Layout layout,
+            String facility, final Filter filter, final String syslogHost, final String level) {
+        Holder<String> host = new Holder<>();
+        Holder<Integer> port = new Holder<>();
+        resolveSyslogHost(syslogHost, host, port);
+        org.apache.logging.log4j.core.Layout appenderLayout;
+        if (layout instanceof LayoutWrapper) {
+            appenderLayout = ((LayoutWrapper) layout).getLayout();
+        } else if (layout != null) {
+            appenderLayout = new LayoutAdapter(layout);
+        } else {
+            appenderLayout = SyslogLayout.newBuilder()
+                    .setFacility(Facility.toFacility(facility))
+                    .setConfiguration(configuration)
+                    .build();
+        }
+
+        org.apache.logging.log4j.core.Filter fileFilter = buildFilters(level, filter);
+        return new AppenderWrapper(SyslogAppender.newBuilder()
+                .setName(name)
+                .setConfiguration(configuration)
+                .setLayout(appenderLayout)
+                .setFilter(fileFilter)
+                .setPort(port.get())
+                .setProtocol(Protocol.TCP)
+                .setHost(host.get())
+                .build());
+    }
+
+    private void resolveSyslogHost(String syslogHost, Holder<String> host, Holder<Integer> port) {
+        int urlPort = -1;
+
+        //
+        //  If not an unbracketed IPv6 address then
+        //      parse as a URL
+        //
+        String[] parts = syslogHost.split(":");
+        if (parts.length == 1) {
+            host.set(parts[0]);
+            port.set(SYSLOG_PORT);
+        } else if (parts.length == 2) {
+            host.set(parts[0]);
+            port.set(Integer.parseInt(parts[1]));
+        } else {
+            LOGGER.warn("Invalid syslogHost setting: {}. Using default", syslogHost);
+            host.set("localhost");
+            port.set(SYSLOG_PORT);
+        }
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/filter/DenyAllFilterBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/filter/DenyAllFilterBuilder.java
new file mode 100644
index 0000000..f15d6e5
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/filter/DenyAllFilterBuilder.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.builders.filter;
+
+import org.apache.log4j.bridge.FilterWrapper;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.xml.XmlConfiguration;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.core.filter.DenyAllFilter;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+
+/**
+ * Build a Pattern Layout
+ */
+@Plugin(name = "org.apache.log4j.varia.DenyAllFilter", category = CATEGORY)
+public class DenyAllFilterBuilder implements FilterBuilder {
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+
+    @Override
+    public Filter parseFilter(Element filterElement, XmlConfiguration config) {
+        return new FilterWrapper(DenyAllFilter.newBuilder().build());
+    }
+
+    @Override
+    public Filter parseFilter(PropertiesConfiguration config) {
+        return new FilterWrapper(DenyAllFilter.newBuilder().build());
+    }
+}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/filter/FilterBuilder.java
similarity index 66%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-1.2-api/src/main/java/org/apache/log4j/builders/filter/FilterBuilder.java
index 13aaf9c..f26e7cb 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/filter/FilterBuilder.java
@@ -14,17 +14,20 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
+package org.apache.log4j.builders.filter;
 
-import org.junit.Test;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.xml.XmlConfiguration;
+import org.w3c.dom.Element;
 
-import static org.junit.Assert.*;
+/**
+ * Define a Filter Builder.
+ */
+public interface FilterBuilder {
 
-public class ProcessIdUtilTest {
+    Filter parseFilter(Element element, XmlConfiguration config);
 
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
-    }
+    Filter parseFilter(PropertiesConfiguration config);
+
 }
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/filter/LevelMatchFilterBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/filter/LevelMatchFilterBuilder.java
new file mode 100644
index 0000000..5b1e435
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/filter/LevelMatchFilterBuilder.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.builders.filter;
+
+import org.apache.log4j.bridge.FilterWrapper;
+import org.apache.log4j.builders.AbstractBuilder;
+import org.apache.log4j.builders.BooleanHolder;
+import org.apache.log4j.builders.Holder;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.xml.XmlConfiguration;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.core.filter.LevelMatchFilter;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+
+import java.util.Properties;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.xml.XmlConfiguration.*;
+import static org.apache.log4j.xml.XmlConfiguration.VALUE_ATTR;
+
+/**
+ * Build a Level match failter.
+ */
+@Plugin(name = "org.apache.log4j.varia.LevelMatchFilter", category = CATEGORY)
+public class LevelMatchFilterBuilder extends AbstractBuilder implements FilterBuilder {
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+    private static final String LEVEL = "LevelToMatch";
+    private static final String ACCEPT_ON_MATCH = "AcceptOnMatch";
+
+    public LevelMatchFilterBuilder() {
+    }
+
+    public LevelMatchFilterBuilder(String prefix, Properties props) {
+        super(prefix, props);
+    }
+
+    @Override
+    public Filter parseFilter(Element filterElement, XmlConfiguration config) {
+        final Holder<String> level = new Holder<>();
+        final Holder<Boolean> acceptOnMatch = new BooleanHolder();
+        forEachElement(filterElement.getElementsByTagName("param"), (currentElement) -> {
+            if (currentElement.getTagName().equals("param")) {
+                switch (currentElement.getAttribute(NAME_ATTR)) {
+                    case LEVEL:
+                        level.set(currentElement.getAttribute(VALUE_ATTR));
+                        break;
+                    case ACCEPT_ON_MATCH:
+                        acceptOnMatch.set(Boolean.parseBoolean(currentElement.getAttribute(VALUE_ATTR)));
+                        break;
+                }
+            }
+        });
+        return createFilter(level.get(), acceptOnMatch.get());
+    }
+
+    @Override
+    public Filter parseFilter(PropertiesConfiguration config) {
+        String level = getProperty(LEVEL);
+        boolean acceptOnMatch = getBooleanProperty(ACCEPT_ON_MATCH);
+        return createFilter(level, acceptOnMatch);
+    }
+
+    private Filter createFilter(String level, boolean acceptOnMatch) {
+        Level lvl = Level.ERROR;
+        if (level != null) {
+            lvl = Level.toLevel(level, Level.ERROR);
+        }
+        org.apache.logging.log4j.core.Filter.Result onMatch = acceptOnMatch
+                ? org.apache.logging.log4j.core.Filter.Result.ACCEPT
+                : org.apache.logging.log4j.core.Filter.Result.DENY;
+        return new FilterWrapper(LevelMatchFilter.newBuilder()
+                .setLevel(lvl)
+                .setOnMatch(onMatch)
+                .setOnMismatch(org.apache.logging.log4j.core.Filter.Result.NEUTRAL)
+                .build());
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/filter/LevelRangeFilterBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/filter/LevelRangeFilterBuilder.java
new file mode 100644
index 0000000..ca2c70f
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/filter/LevelRangeFilterBuilder.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.builders.filter;
+
+import org.apache.log4j.bridge.FilterWrapper;
+import org.apache.log4j.builders.AbstractBuilder;
+import org.apache.log4j.builders.BooleanHolder;
+import org.apache.log4j.builders.Holder;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.xml.XmlConfiguration;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.core.filter.LevelRangeFilter;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+
+
+import java.util.Properties;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.xml.XmlConfiguration.*;
+
+/**
+ * Build a Level match failter.
+ */
+@Plugin(name = "org.apache.log4j.varia.LevelRangeFilter", category = CATEGORY)
+public class LevelRangeFilterBuilder extends AbstractBuilder implements FilterBuilder {
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+    private static final String LEVEL_MAX = "LevelMax";
+    private static final String LEVEL_MIN = "LevelMin";
+    private static final String ACCEPT_ON_MATCH = "AcceptOnMatch";
+
+    public LevelRangeFilterBuilder() {
+    }
+
+    public LevelRangeFilterBuilder(String prefix, Properties props) {
+        super(prefix, props);
+    }
+
+    @Override
+    public Filter parseFilter(Element filterElement, XmlConfiguration config) {
+        final Holder<String> levelMax = new Holder<>();
+        final Holder<String> levelMin = new Holder<>();
+        final Holder<Boolean> acceptOnMatch = new BooleanHolder();
+        forEachElement(filterElement.getElementsByTagName("param"), (currentElement) -> {
+            if (currentElement.getTagName().equals("param")) {
+                switch (currentElement.getAttribute(NAME_ATTR)) {
+                    case LEVEL_MAX:
+                        levelMax.set(currentElement.getAttribute(VALUE_ATTR));
+                        break;
+                    case LEVEL_MIN:
+                        levelMax.set(currentElement.getAttribute(VALUE_ATTR));
+                        break;
+                    case ACCEPT_ON_MATCH:
+                        acceptOnMatch.set(Boolean.parseBoolean(currentElement.getAttribute(VALUE_ATTR)));
+                        break;
+                }
+            }
+        });
+        return createFilter(levelMax.get(), levelMin.get(), acceptOnMatch.get());
+    }
+
+    @Override
+    public Filter parseFilter(PropertiesConfiguration config) {
+        String levelMax = getProperty(LEVEL_MAX);
+        String levelMin = getProperty(LEVEL_MIN);
+        boolean acceptOnMatch = getBooleanProperty(ACCEPT_ON_MATCH);
+        return createFilter(levelMax, levelMin, acceptOnMatch);
+    }
+
+    private Filter createFilter(String levelMax, String levelMin, boolean acceptOnMatch) {
+        Level max = Level.FATAL;
+        Level min = Level.TRACE;
+        if (levelMax != null) {
+            max = Level.toLevel(levelMax, Level.FATAL);
+        }
+        if (levelMin != null) {
+            min = Level.toLevel(levelMin, Level.DEBUG);
+        }
+        org.apache.logging.log4j.core.Filter.Result onMatch = acceptOnMatch
+                ? org.apache.logging.log4j.core.Filter.Result.ACCEPT
+                : org.apache.logging.log4j.core.Filter.Result.NEUTRAL;
+
+        return new FilterWrapper(LevelRangeFilter.createFilter(min, max, onMatch,
+                org.apache.logging.log4j.core.Filter.Result.DENY));
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/filter/StringMatchFilterBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/filter/StringMatchFilterBuilder.java
new file mode 100644
index 0000000..f81dbdc
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/filter/StringMatchFilterBuilder.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.builders.filter;
+
+import org.apache.log4j.bridge.FilterWrapper;
+import org.apache.log4j.builders.AbstractBuilder;
+import org.apache.log4j.builders.BooleanHolder;
+import org.apache.log4j.builders.Holder;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.xml.XmlConfiguration;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.core.filter.StringMatchFilter;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+
+import java.util.Properties;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.xml.XmlConfiguration.*;
+
+/**
+ * Build a String match filter.
+ */
+@Plugin(name = "org.apache.log4j.varia.StringMatchFilter", category = CATEGORY)
+public class StringMatchFilterBuilder extends AbstractBuilder implements FilterBuilder {
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+    private static final String STRING_TO_MATCH = "StringToMatch";
+    private static final String ACCEPT_ON_MATCH = "AcceptOnMatch";
+
+    @Override
+    public Filter parseFilter(Element filterElement, XmlConfiguration config) {
+        final Holder<Boolean> acceptOnMatch = new BooleanHolder();
+        final Holder<String> text = new Holder<>();
+        forEachElement(filterElement.getElementsByTagName("param"), (currentElement) -> {
+            if (currentElement.getTagName().equals("param")) {
+                switch (currentElement.getAttribute(NAME_ATTR)) {
+                    case STRING_TO_MATCH:
+                        text.set(currentElement.getAttribute(VALUE_ATTR));
+                        break;
+                    case ACCEPT_ON_MATCH:
+                        acceptOnMatch.set(Boolean.parseBoolean(currentElement.getAttribute(VALUE_ATTR)));
+                        break;
+
+                }
+            }
+        });
+        return createFilter(text.get(), acceptOnMatch.get());
+    }
+
+    @Override
+    public Filter parseFilter(PropertiesConfiguration config) {
+        String text = getProperty(STRING_TO_MATCH);
+        boolean acceptOnMatch = getBooleanProperty(ACCEPT_ON_MATCH);
+        return createFilter(text, acceptOnMatch);
+    }
+
+    private Filter createFilter(String text, boolean acceptOnMatch) {
+        if (text == null) {
+            LOGGER.warn("No text provided for StringMatchFilter");
+            return null;
+        }
+        org.apache.logging.log4j.core.Filter.Result onMatch = acceptOnMatch
+                ? org.apache.logging.log4j.core.Filter.Result.ACCEPT
+                : org.apache.logging.log4j.core.Filter.Result.DENY;
+        return new FilterWrapper(StringMatchFilter.newBuilder()
+                .setMatchString(text)
+                .setOnMatch(onMatch)
+                .setOnMismatch(org.apache.logging.log4j.core.Filter.Result.NEUTRAL)
+                .build());
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/HtmlLayoutBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/HtmlLayoutBuilder.java
new file mode 100644
index 0000000..423350e
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/HtmlLayoutBuilder.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.builders.layout;
+
+import org.apache.log4j.Layout;
+import org.apache.log4j.bridge.LayoutWrapper;
+import org.apache.log4j.builders.AbstractBuilder;
+import org.apache.log4j.builders.BooleanHolder;
+import org.apache.log4j.builders.Holder;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.xml.XmlConfiguration;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.core.layout.HtmlLayout;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+
+import java.util.Properties;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.xml.XmlConfiguration.*;
+
+/**
+ * Build a Pattern Layout
+ */
+@Plugin(name = "org.apache.log4j.HTMLLayout", category = CATEGORY)
+public class HtmlLayoutBuilder extends AbstractBuilder implements LayoutBuilder {
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+
+    private static final String TITLE = "Title";
+    private static final String LOCATION_INFO = "LocationInfo";
+
+    public HtmlLayoutBuilder() {
+    }
+
+    public HtmlLayoutBuilder(String prefix, Properties props) {
+        super(prefix, props);
+    }
+
+
+    @Override
+    public Layout parseLayout(Element layoutElement, XmlConfiguration config) {
+        final Holder<String> title = new Holder<>();
+        final Holder<Boolean> locationInfo = new BooleanHolder();
+        forEachElement(layoutElement.getElementsByTagName("param"), (currentElement) -> {
+            if (currentElement.getTagName().equals(PARAM_TAG)) {
+                if (TITLE.equalsIgnoreCase(currentElement.getAttribute("name"))) {
+                    title.set(currentElement.getAttribute("value"));
+                } else if (LOCATION_INFO.equalsIgnoreCase(currentElement.getAttribute("name"))) {
+                    locationInfo.set(Boolean.parseBoolean(currentElement.getAttribute("value")));
+                }
+            }
+        });
+        return createLayout(title.get(), locationInfo.get());
+    }
+
+    @Override
+    public Layout parseLayout(PropertiesConfiguration config) {
+        String title = getProperty(TITLE);
+        boolean locationInfo = getBooleanProperty(LOCATION_INFO);
+        return createLayout(title, locationInfo);
+    }
+
+    private Layout createLayout(String title, boolean locationInfo) {
+        return new LayoutWrapper(HtmlLayout.newBuilder()
+                .setTitle(title)
+                .setLocationInfo(locationInfo)
+                .build());
+    }
+}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/LayoutBuilder.java
similarity index 66%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/LayoutBuilder.java
index 13aaf9c..4f28284 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/LayoutBuilder.java
@@ -14,17 +14,19 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
+package org.apache.log4j.builders.layout;
 
-import org.junit.Test;
+import org.apache.log4j.Layout;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.xml.XmlConfiguration;
+import org.w3c.dom.Element;
 
-import static org.junit.Assert.*;
+/**
+ * Define a Layout Builder.
+ */
+public interface LayoutBuilder {
 
-public class ProcessIdUtilTest {
+    Layout parseLayout(Element element, XmlConfiguration config);
 
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
-    }
+    Layout parseLayout(PropertiesConfiguration config);
 }
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/PatternLayoutBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/PatternLayoutBuilder.java
new file mode 100644
index 0000000..1849768
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/PatternLayoutBuilder.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.builders.layout;
+
+import org.apache.log4j.Layout;
+import org.apache.log4j.bridge.LayoutWrapper;
+import org.apache.log4j.builders.AbstractBuilder;
+import org.apache.log4j.config.Log4j1Configuration;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.xml.XmlConfiguration;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.config.plugins.PluginAliases;
+import org.apache.logging.log4j.core.layout.PatternLayout;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import java.util.Properties;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.xml.XmlConfiguration.PARAM_TAG;
+
+/**
+ * Build a Pattern Layout
+ */
+@Plugin(name = "org.apache.log4j.PatternLayout", category = CATEGORY)
+@PluginAliases("org.apache.log4j.EnhancedPatternLayout")
+public class PatternLayoutBuilder extends AbstractBuilder implements LayoutBuilder {
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+    private static final String PATTERN = "ConversionPattern";
+
+    public PatternLayoutBuilder() {
+    }
+
+    public PatternLayoutBuilder(String prefix, Properties props) {
+        super(prefix, props);
+    }
+
+    @Override
+    public Layout parseLayout(final Element layoutElement, final XmlConfiguration config) {
+        NodeList params = layoutElement.getElementsByTagName("param");
+        final int length = params.getLength();
+        String pattern = null;
+        for (int index = 0; index < length; ++ index) {
+            Node currentNode = params.item(index);
+            if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
+                Element currentElement = (Element) currentNode;
+                if (currentElement.getTagName().equals(PARAM_TAG)) {
+                    if (PATTERN.equalsIgnoreCase(currentElement.getAttribute("name"))) {
+                        pattern = currentElement.getAttribute("value");
+                        break;
+                    }
+                }
+            }
+        }
+        return createLayout(pattern, config);
+    }
+
+    @Override
+    public Layout parseLayout(final PropertiesConfiguration config) {
+        String pattern = getProperty(PATTERN);
+        return createLayout(pattern, config);
+    }
+
+    private Layout createLayout(String pattern, final Log4j1Configuration config) {
+        if (pattern == null) {
+            LOGGER.info("No pattern provided for pattern layout, using default pattern");
+            pattern = PatternLayout.DEFAULT_CONVERSION_PATTERN;
+        }
+        return new LayoutWrapper(PatternLayout.newBuilder()
+                .setPattern(pattern
+                        // Log4j 2's %x (NDC) is not compatible with Log4j 1's
+                        // %x
+                        // Log4j 1: "foo bar baz"
+                        // Log4j 2: "[foo, bar, baz]"
+                        // Use %ndc to get the Log4j 1 format
+                        .replace("%x", "%ndc")
+
+                        // Log4j 2's %X (MDC) is not compatible with Log4j 1's
+                        // %X
+                        // Log4j 1: "{{foo,bar}{hoo,boo}}"
+                        // Log4j 2: "{foo=bar,hoo=boo}"
+                        // Use %properties to get the Log4j 1 format
+                        .replace("%X", "%properties"))
+                .setConfiguration(config)
+                .build());
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/SimpleLayoutBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/SimpleLayoutBuilder.java
new file mode 100644
index 0000000..d35beba
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/SimpleLayoutBuilder.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.builders.layout;
+
+import org.apache.log4j.Layout;
+import org.apache.log4j.bridge.LayoutWrapper;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.xml.XmlConfiguration;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.core.layout.PatternLayout;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+
+import java.util.Properties;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+
+/**
+ * Build a Pattern Layout
+ */
+@Plugin(name = "org.apache.log4j.SimpleLayout", category = CATEGORY)
+public class SimpleLayoutBuilder implements LayoutBuilder {
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+
+    @Override
+    public Layout parseLayout(Element layoutElement, XmlConfiguration config) {
+        return new LayoutWrapper(PatternLayout.newBuilder()
+                .setPattern("%level - %m%n")
+                .setConfiguration(config)
+                .build());
+    }
+
+    @Override
+    public Layout parseLayout(PropertiesConfiguration config) {
+        return new LayoutWrapper(PatternLayout.newBuilder()
+                .setPattern("%level - %m%n")
+                .setConfiguration(config)
+                .build());
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/TTCCLayoutBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/TTCCLayoutBuilder.java
new file mode 100644
index 0000000..2641ea2
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/TTCCLayoutBuilder.java
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.builders.layout;
+
+import org.apache.log4j.Layout;
+import org.apache.log4j.bridge.LayoutWrapper;
+import org.apache.log4j.builders.AbstractBuilder;
+import org.apache.log4j.builders.BooleanHolder;
+import org.apache.log4j.builders.Holder;
+import org.apache.log4j.config.Log4j1Configuration;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.xml.XmlConfiguration;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.layout.PatternLayout;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+
+import java.util.Properties;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.xml.XmlConfiguration.*;
+
+/**
+ * Build a Pattern Layout
+ */
+@Plugin(name = "org.apache.log4j.TTCCLayout", category = CATEGORY)
+public class TTCCLayoutBuilder extends AbstractBuilder implements LayoutBuilder {
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+
+    private static final String THREAD_PRINTING_PARAM = "ThreadPrinting";
+    private static final String CATEGORY_PREFIXING_PARAM = "CategoryPrefixing";
+    private static final String CONTEXT_PRINTING_PARAM = "ContextPrinting";
+    private static final String DATE_FORMAT_PARAM = "DateFormat";
+    private static final String TIMEZONE_FORMAT = "TimeZone";
+
+    public TTCCLayoutBuilder() {
+    }
+
+    public TTCCLayoutBuilder(String prefix, Properties props) {
+        super(prefix, props);
+    }
+
+    @Override
+    public Layout parseLayout(Element layoutElement, XmlConfiguration config) {
+        final Holder<Boolean> threadPrinting = new BooleanHolder();
+        final Holder<Boolean> categoryPrefixing = new BooleanHolder();
+        final Holder<Boolean> contextPrinting = new BooleanHolder();
+        final Holder<String> dateFormat = new Holder<>();
+        final Holder<String> timezone = new Holder<>();
+        forEachElement(layoutElement.getElementsByTagName("param"), (currentElement) -> {
+            if (currentElement.getTagName().equals(PARAM_TAG)) {
+                switch (currentElement.getAttribute(NAME_ATTR)) {
+                    case THREAD_PRINTING_PARAM:
+                        threadPrinting.set(Boolean.parseBoolean(currentElement.getAttribute(VALUE_ATTR)));
+                        break;
+                    case CATEGORY_PREFIXING_PARAM:
+                        categoryPrefixing.set(Boolean.parseBoolean(currentElement.getAttribute(VALUE_ATTR)));
+                        break;
+                    case CONTEXT_PRINTING_PARAM:
+                        contextPrinting.set(Boolean.parseBoolean(currentElement.getAttribute(VALUE_ATTR)));
+                        break;
+                    case DATE_FORMAT_PARAM:
+                        dateFormat.set(currentElement.getAttribute(VALUE_ATTR));
+                        break;
+                    case TIMEZONE_FORMAT:
+                        timezone.set(currentElement.getAttribute(VALUE_ATTR));
+                        break;
+                }
+            }
+        });
+        return createLayout(threadPrinting.get(), categoryPrefixing.get(), contextPrinting.get(),
+                dateFormat.get(), timezone.get(), config);
+    }
+
+    @Override
+    public Layout parseLayout(PropertiesConfiguration config) {
+        boolean threadPrinting = getBooleanProperty(THREAD_PRINTING_PARAM);
+        boolean categoryPrefixing = getBooleanProperty(CATEGORY_PREFIXING_PARAM);
+        boolean contextPrinting = getBooleanProperty(CONTEXT_PRINTING_PARAM);
+        String dateFormat = getProperty(DATE_FORMAT_PARAM);
+        String timezone = getProperty(TIMEZONE_FORMAT);
+
+        return createLayout(threadPrinting, categoryPrefixing, contextPrinting,
+                dateFormat, timezone, config);
+    }
+
+    private Layout createLayout(boolean threadPrinting, boolean categoryPrefixing, boolean contextPrinting,
+            String dateFormat, String timezone, Log4j1Configuration config) {
+        StringBuilder sb = new StringBuilder();
+        if (dateFormat != null) {
+            if (RELATIVE.equalsIgnoreCase(dateFormat)) {
+                sb.append("%r ");
+            } else {
+                sb.append("%d{").append(dateFormat).append("}");
+                if (timezone != null) {
+                    sb.append("{").append(timezone).append("}");
+                }
+                sb.append(" ");
+            }
+        }
+        if (threadPrinting) {
+            sb.append("[%t] ");
+        }
+        sb.append("%p ");
+        if (categoryPrefixing) {
+            sb.append("%c ");
+        }
+        if (contextPrinting) {
+            sb.append("%notEmpty{%ndc }");
+        }
+        sb.append("- %m%n");
+        return new LayoutWrapper(PatternLayout.newBuilder()
+                .setPattern(sb.toString())
+                .setConfiguration(config)
+                .build());
+    }
+}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/rewrite/RewritePolicyBuilder.java
similarity index 63%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-1.2-api/src/main/java/org/apache/log4j/builders/rewrite/RewritePolicyBuilder.java
index 13aaf9c..5ca196a 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/rewrite/RewritePolicyBuilder.java
@@ -14,17 +14,19 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
+package org.apache.log4j.builders.rewrite;
 
-import org.junit.Test;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.rewrite.RewritePolicy;
+import org.apache.log4j.xml.XmlConfiguration;
+import org.w3c.dom.Element;
 
-import static org.junit.Assert.*;
+/**
+ * Define a RewritePolicy Builder.
+ */
+public interface RewritePolicyBuilder {
 
-public class ProcessIdUtilTest {
+    RewritePolicy parseRewritePolicy(Element element, XmlConfiguration config);
 
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
-    }
+    RewritePolicy parseRewritePolicy(PropertiesConfiguration config);
 }
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1Configuration.java b/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1Configuration.java
new file mode 100644
index 0000000..9236006
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1Configuration.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.config;
+
+import org.apache.log4j.builders.BuilderManager;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.AbstractConfiguration;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.ConfigurationSource;
+import org.apache.logging.log4j.core.config.Reconfigurable;
+
+/**
+ * Base Configuration for Log4j 1.
+ */
+public class Log4j1Configuration extends AbstractConfiguration implements Reconfigurable {
+
+    public static final String MONITOR_INTERVAL = "log4j1.monitorInterval";
+    public static final String APPENDER_REF_TAG = "appender-ref";
+    public static final String THRESHOLD_PARAM = "Threshold";
+
+    public static final String INHERITED = "inherited";
+
+    public static final String NULL = "null";
+
+    protected final BuilderManager manager;
+
+    public Log4j1Configuration(final LoggerContext loggerContext, final ConfigurationSource source,
+            int monitorIntervalSeconds) {
+        super(loggerContext, source);
+        manager = new BuilderManager();
+        initializeWatchers(this, source, monitorIntervalSeconds);
+    }
+
+    public BuilderManager getBuilderManager() {
+        return manager;
+    }
+
+    /**
+     * Initialize the configuration.
+     */
+    @Override
+    public void initialize() {
+        getStrSubstitutor().setConfiguration(this);
+        super.getScheduler().start();
+        doConfigure();
+        setState(State.INITIALIZED);
+        LOGGER.debug("Configuration {} initialized", this);
+    }
+
+    @Override
+    public Configuration reconfigure() {
+        return null;
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfiguration.java b/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfiguration.java
new file mode 100644
index 0000000..2f7ac58
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfiguration.java
@@ -0,0 +1,589 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.config;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.Layout;
+import org.apache.log4j.LogManager;
+import org.apache.log4j.PatternLayout;
+import org.apache.log4j.bridge.AppenderAdapter;
+import org.apache.log4j.bridge.AppenderWrapper;
+import org.apache.log4j.builders.BuilderManager;
+import org.apache.log4j.helpers.OptionConverter;
+import org.apache.log4j.spi.ErrorHandler;
+import org.apache.log4j.spi.Filter;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.ConfigurationSource;
+import org.apache.logging.log4j.core.config.LoggerConfig;
+import org.apache.logging.log4j.core.config.status.StatusConfiguration;
+import org.apache.logging.log4j.core.filter.AbstractFilterable;
+import org.apache.logging.log4j.util.LoaderUtil;
+
+import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.SortedMap;
+import java.util.StringTokenizer;
+import java.util.TreeMap;
+
+/**
+ * Construct a configuration based on Log4j 1 properties.
+ */
+public class PropertiesConfiguration  extends Log4j1Configuration {
+
+    private static final String CATEGORY_PREFIX = "log4j.category.";
+    private static final String LOGGER_PREFIX = "log4j.logger.";
+    private static final String ADDITIVITY_PREFIX = "log4j.additivity.";
+    private static final String ROOT_CATEGORY_PREFIX = "log4j.rootCategory";
+    private static final String ROOT_LOGGER_PREFIX = "log4j.rootLogger";
+    private static final String APPENDER_PREFIX = "log4j.appender.";
+    private static final String LOGGER_REF	= "logger-ref";
+    private static final String ROOT_REF		= "root-ref";
+    private static final String APPENDER_REF_TAG = "appender-ref";
+    public static final long DEFAULT_DELAY = 60000;
+    public static final String DEBUG_KEY="log4j.debug";
+
+    private static final String INTERNAL_ROOT_NAME = "root";
+
+    private final Map<String, Appender> registry;
+
+    /**
+     * No argument constructor.
+     */
+    public PropertiesConfiguration(final LoggerContext loggerContext, final ConfigurationSource source,
+            int monitorIntervalSeconds) {
+        super(loggerContext, source, monitorIntervalSeconds);
+        registry = new HashMap<>();
+    }
+
+    public void doConfigure() {
+        InputStream is = getConfigurationSource().getInputStream();
+        Properties props = new Properties();
+        try {
+            props.load(is);
+        } catch (Exception e) {
+            LOGGER.error("Could not read configuration file [{}].", getConfigurationSource().toString(), e);
+            return;
+        }
+        // If we reach here, then the config file is alright.
+        doConfigure(props);
+    }
+
+    /**
+     * Read configuration from a file. <b>The existing configuration is
+     * not cleared nor reset.</b> If you require a different behavior,
+     * then call {@link  LogManager#resetConfiguration
+     * resetConfiguration} method before calling
+     * <code>doConfigure</code>.
+     *
+     * <p>The configuration file consists of statements in the format
+     * <code>key=value</code>. The syntax of different configuration
+     * elements are discussed below.
+     *
+     * <p>The level value can consist of the string values OFF, FATAL,
+     * ERROR, WARN, INFO, DEBUG, ALL or a <em>custom level</em> value. A
+     * custom level value can be specified in the form
+     * level#classname. By default the repository-wide threshold is set
+     * to the lowest possible value, namely the level <code>ALL</code>.
+     * </p>
+     *
+     *
+     * <h3>Appender configuration</h3>
+     *
+     * <p>Appender configuration syntax is:
+     * <pre>
+     * # For appender named <i>appenderName</i>, set its class.
+     * # Note: The appender name can contain dots.
+     * log4j.appender.appenderName=fully.qualified.name.of.appender.class
+     *
+     * # Set appender specific options.
+     * log4j.appender.appenderName.option1=value1
+     * ...
+     * log4j.appender.appenderName.optionN=valueN
+     * </pre>
+     * <p>
+     * For each named appender you can configure its {@link Layout}. The
+     * syntax for configuring an appender's layout is:
+     * <pre>
+     * log4j.appender.appenderName.layout=fully.qualified.name.of.layout.class
+     * log4j.appender.appenderName.layout.option1=value1
+     * ....
+     * log4j.appender.appenderName.layout.optionN=valueN
+     * </pre>
+     * <p>
+     * The syntax for adding {@link Filter}s to an appender is:
+     * <pre>
+     * log4j.appender.appenderName.filter.ID=fully.qualified.name.of.filter.class
+     * log4j.appender.appenderName.filter.ID.option1=value1
+     * ...
+     * log4j.appender.appenderName.filter.ID.optionN=valueN
+     * </pre>
+     * The first line defines the class name of the filter identified by ID;
+     * subsequent lines with the same ID specify filter option - value
+     * pairs. Multiple filters are added to the appender in the lexicographic
+     * order of IDs.
+     * <p>
+     * The syntax for adding an {@link ErrorHandler} to an appender is:
+     * <pre>
+     * log4j.appender.appenderName.errorhandler=fully.qualified.name.of.errorhandler.class
+     * log4j.appender.appenderName.errorhandler.appender-ref=appenderName
+     * log4j.appender.appenderName.errorhandler.option1=value1
+     * ...
+     * log4j.appender.appenderName.errorhandler.optionN=valueN
+     * </pre>
+     *
+     * <h3>Configuring loggers</h3>
+     *
+     * <p>The syntax for configuring the root logger is:
+     * <pre>
+     * log4j.rootLogger=[level], appenderName, appenderName, ...
+     * </pre>
+     *
+     * <p>This syntax means that an optional <em>level</em> can be
+     * supplied followed by appender names separated by commas.
+     *
+     * <p>The level value can consist of the string values OFF, FATAL,
+     * ERROR, WARN, INFO, DEBUG, ALL or a <em>custom level</em> value. A
+     * custom level value can be specified in the form
+     * <code>level#classname</code>.
+     *
+     * <p>If a level value is specified, then the root level is set
+     * to the corresponding level.  If no level value is specified,
+     * then the root level remains untouched.
+     *
+     * <p>The root logger can be assigned multiple appenders.
+     *
+     * <p>Each <i>appenderName</i> (separated by commas) will be added to
+     * the root logger. The named appender is defined using the
+     * appender syntax defined above.
+     *
+     * <p>For non-root categories the syntax is almost the same:
+     * <pre>
+     * log4j.logger.logger_name=[level|INHERITED|NULL], appenderName, appenderName, ...
+     * </pre>
+     *
+     * <p>The meaning of the optional level value is discussed above
+     * in relation to the root logger. In addition however, the value
+     * INHERITED can be specified meaning that the named logger should
+     * inherit its level from the logger hierarchy.
+     *
+     * <p>If no level value is supplied, then the level of the
+     * named logger remains untouched.
+     *
+     * <p>By default categories inherit their level from the
+     * hierarchy. However, if you set the level of a logger and later
+     * decide that that logger should inherit its level, then you should
+     * specify INHERITED as the value for the level value. NULL is a
+     * synonym for INHERITED.
+     *
+     * <p>Similar to the root logger syntax, each <i>appenderName</i>
+     * (separated by commas) will be attached to the named logger.
+     *
+     * <p>See the <a href="../../../../manual.html#additivity">appender
+     * additivity rule</a> in the user manual for the meaning of the
+     * <code>additivity</code> flag.
+     *
+     *
+     * # Set options for appender named "A1".
+     * # Appender "A1" will be a SyslogAppender
+     * log4j.appender.A1=org.apache.log4j.net.SyslogAppender
+     *
+     * # The syslog daemon resides on www.abc.net
+     * log4j.appender.A1.SyslogHost=www.abc.net
+     *
+     * # A1's layout is a PatternLayout, using the conversion pattern
+     * # <b>%r %-5p %c{2} %M.%L %x - %m\n</b>. Thus, the log output will
+     * # include # the relative time since the start of the application in
+     * # milliseconds, followed by the level of the log request,
+     * # followed by the two rightmost components of the logger name,
+     * # followed by the callers method name, followed by the line number,
+     * # the nested diagnostic context and finally the message itself.
+     * # Refer to the documentation of {@link PatternLayout} for further information
+     * # on the syntax of the ConversionPattern key.
+     * log4j.appender.A1.layout=org.apache.log4j.PatternLayout
+     * log4j.appender.A1.layout.ConversionPattern=%-4r %-5p %c{2} %M.%L %x - %m\n
+     *
+     * # Set options for appender named "A2"
+     * # A2 should be a RollingFileAppender, with maximum file size of 10 MB
+     * # using at most one backup file. A2's layout is TTCC, using the
+     * # ISO8061 date format with context printing enabled.
+     * log4j.appender.A2=org.apache.log4j.RollingFileAppender
+     * log4j.appender.A2.MaxFileSize=10MB
+     * log4j.appender.A2.MaxBackupIndex=1
+     * log4j.appender.A2.layout=org.apache.log4j.TTCCLayout
+     * log4j.appender.A2.layout.ContextPrinting=enabled
+     * log4j.appender.A2.layout.DateFormat=ISO8601
+     *
+     * # Root logger set to DEBUG using the A2 appender defined above.
+     * log4j.rootLogger=DEBUG, A2
+     *
+     * # Logger definitions:
+     * # The SECURITY logger inherits is level from root. However, it's output
+     * # will go to A1 appender defined above. It's additivity is non-cumulative.
+     * log4j.logger.SECURITY=INHERIT, A1
+     * log4j.additivity.SECURITY=false
+     *
+     * # Only warnings or above will be logged for the logger "SECURITY.access".
+     * # Output will go to A1.
+     * log4j.logger.SECURITY.access=WARN
+     *
+     *
+     * # The logger "class.of.the.day" inherits its level from the
+     * # logger hierarchy.  Output will go to the appender's of the root
+     * # logger, A2 in this case.
+     * log4j.logger.class.of.the.day=INHERIT
+     * </pre>
+     *
+     * <p>Refer to the <b>setOption</b> method in each Appender and
+     * Layout for class specific options.
+     *
+     * <p>Use the <code>#</code> or <code>!</code> characters at the
+     * beginning of a line for comments.
+     *
+     * <p>
+     */
+    private void doConfigure(Properties properties) {
+        String status = "error";
+        String value = properties.getProperty(DEBUG_KEY);
+        if (value == null) {
+            value = properties.getProperty("log4j.configDebug");
+            if (value != null) {
+                LOGGER.warn("[log4j.configDebug] is deprecated. Use [log4j.debug] instead.");
+            }
+        }
+
+        if (value != null) {
+            status = OptionConverter.toBoolean(value, false) ? "debug" : "error";
+        }
+
+        final StatusConfiguration statusConfig = new StatusConfiguration().setStatus(status);
+        statusConfig.initialize();
+
+        configureRoot(properties);
+        parseLoggers(properties);
+
+        LOGGER.debug("Finished configuring.");
+    }
+
+    // --------------------------------------------------------------------------
+    // Internal stuff
+    // --------------------------------------------------------------------------
+
+    private void configureRoot(Properties props) {
+        String effectiveFrefix = ROOT_LOGGER_PREFIX;
+        String value = OptionConverter.findAndSubst(ROOT_LOGGER_PREFIX, props);
+
+        if (value == null) {
+            value = OptionConverter.findAndSubst(ROOT_CATEGORY_PREFIX, props);
+            effectiveFrefix = ROOT_CATEGORY_PREFIX;
+        }
+
+        if (value == null) {
+            LOGGER.debug("Could not find root logger information. Is this OK?");
+        } else {
+            LoggerConfig root = getRootLogger();
+            parseLogger(props, root, effectiveFrefix, INTERNAL_ROOT_NAME, value);
+        }
+    }
+
+    /**
+     * Parse non-root elements, such non-root categories and renderers.
+     */
+    private void parseLoggers(Properties props) {
+        Enumeration enumeration = props.propertyNames();
+        while (enumeration.hasMoreElements()) {
+            String key = (String) enumeration.nextElement();
+            if (key.startsWith(CATEGORY_PREFIX) || key.startsWith(LOGGER_PREFIX)) {
+                String loggerName = null;
+                if (key.startsWith(CATEGORY_PREFIX)) {
+                    loggerName = key.substring(CATEGORY_PREFIX.length());
+                } else if (key.startsWith(LOGGER_PREFIX)) {
+                    loggerName = key.substring(LOGGER_PREFIX.length());
+                }
+                String value = OptionConverter.findAndSubst(key, props);
+                LoggerConfig loggerConfig = getLogger(loggerName);
+                if (loggerConfig == null) {
+                    boolean additivity = getAdditivityForLogger(props, loggerName);
+                    loggerConfig = new LoggerConfig(loggerName, org.apache.logging.log4j.Level.ERROR, additivity);
+                    addLogger(loggerName, loggerConfig);
+                }
+                parseLogger(props, loggerConfig, key, loggerName, value);
+            }
+        }
+    }
+
+    /**
+     * Parse the additivity option for a non-root category.
+     */
+    private boolean getAdditivityForLogger(Properties props, String loggerName) {
+        boolean additivity = true;
+        String key = ADDITIVITY_PREFIX + loggerName;
+        String value = OptionConverter.findAndSubst(key, props);
+        LOGGER.debug("Handling {}=[{}]", key, value);
+        // touch additivity only if necessary
+        if ((value != null) && (!value.equals(""))) {
+            additivity = OptionConverter.toBoolean(value, true);
+        }
+        return additivity;
+    }
+
+    /**
+     * This method must work for the root category as well.
+     */
+    private void parseLogger(Properties props, LoggerConfig logger, String optionKey, String loggerName, String value) {
+
+        LOGGER.debug("Parsing for [{}] with value=[{}].", loggerName, value);
+        // We must skip over ',' but not white space
+        StringTokenizer st = new StringTokenizer(value, ",");
+
+        // If value is not in the form ", appender.." or "", then we should set the level of the logger.
+
+        if (!(value.startsWith(",") || value.equals(""))) {
+
+            // just to be on the safe side...
+            if (!st.hasMoreTokens()) {
+                return;
+            }
+
+            String levelStr = st.nextToken();
+            LOGGER.debug("Level token is [{}].", levelStr);
+
+            org.apache.logging.log4j.Level level = levelStr == null ? org.apache.logging.log4j.Level.ERROR :
+                    OptionConverter.convertLevel(levelStr, org.apache.logging.log4j.Level.DEBUG);
+            logger.setLevel(level);
+            LOGGER.debug("Logger {} level set to {}", loggerName, level);
+        }
+
+        Appender appender;
+        String appenderName;
+        while (st.hasMoreTokens()) {
+            appenderName = st.nextToken().trim();
+            if (appenderName == null || appenderName.equals(",")) {
+                continue;
+            }
+            LOGGER.debug("Parsing appender named \"{}\".", appenderName);
+            appender = parseAppender(props, appenderName);
+            if (appender != null) {
+                LOGGER.debug("Adding appender named [{}] to loggerConfig [{}].", appenderName,
+                        logger.getName());
+                logger.addAppender(getAppender(appenderName), null, null);
+            } else {
+                LOGGER.debug("Appender named [{}}] not found.", appenderName);
+            }
+        }
+    }
+
+    public Appender parseAppender(Properties props, String appenderName) {
+        Appender appender = registry.get(appenderName);
+        if ((appender != null)) {
+            LOGGER.debug("Appender \"" + appenderName + "\" was already parsed.");
+            return appender;
+        }
+        // Appender was not previously initialized.
+        final String prefix = APPENDER_PREFIX + appenderName;
+        final String layoutPrefix = prefix + ".layout";
+        final String filterPrefix = APPENDER_PREFIX + appenderName + ".filter.";
+        String className = OptionConverter.findAndSubst(prefix, props);
+        appender = manager.parseAppender(appenderName, className, prefix, layoutPrefix, filterPrefix, props, this);
+        if (appender == null) {
+            appender = buildAppender(appenderName, className, prefix, layoutPrefix, filterPrefix, props);
+        } else {
+            registry.put(appenderName, appender);
+            if (appender instanceof AppenderWrapper) {
+                addAppender(((AppenderWrapper) appender).getAppender());
+            } else {
+                addAppender(new AppenderAdapter(appender).getAdapter());
+            }
+        }
+        return appender;
+    }
+
+    private Appender buildAppender(final String appenderName, final String className, final String prefix,
+            final String layoutPrefix, final String filterPrefix, final Properties props) {
+        Appender appender = newInstanceOf(className, "Appender");
+        if (appender == null) {
+            return null;
+        }
+        appender.setName(appenderName);
+        appender.setLayout(parseLayout(layoutPrefix, appenderName, props));
+        final String errorHandlerPrefix = prefix + ".errorhandler";
+        String errorHandlerClass = OptionConverter.findAndSubst(errorHandlerPrefix, props);
+        if (errorHandlerClass != null) {
+            ErrorHandler eh = parseErrorHandler(props, errorHandlerPrefix, errorHandlerClass, appender);
+            if (eh != null) {
+                appender.setErrorHandler(eh);
+            }
+        }
+        parseAppenderFilters(props, filterPrefix, appenderName);
+        String[] keys = new String[] {
+                layoutPrefix,
+        };
+        addProperties(appender, keys, props, prefix);
+        if (appender instanceof AppenderWrapper) {
+            addAppender(((AppenderWrapper) appender).getAppender());
+        } else {
+            addAppender(new AppenderAdapter(appender).getAdapter());
+        }
+        registry.put(appenderName, appender);
+        return appender;
+    }
+
+    public Layout parseLayout(String layoutPrefix, String appenderName, Properties props) {
+        String layoutClass = OptionConverter.findAndSubst(layoutPrefix, props);
+        if (layoutClass == null) {
+            return null;
+        }
+        Layout layout = manager.parseLayout(layoutClass, layoutPrefix, props, this);
+        if (layout == null) {
+            layout = buildLayout(layoutPrefix, layoutClass, appenderName, props);
+        }
+        return layout;
+    }
+
+    private Layout buildLayout(String layoutPrefix, String className, String appenderName, Properties props) {
+        Layout layout = newInstanceOf(className, "Layout");
+        if (layout == null) {
+            return null;
+        }
+        LOGGER.debug("Parsing layout options for \"{}\".", appenderName);
+        PropertySetter.setProperties(layout, props, layoutPrefix + ".");
+        LOGGER.debug("End of parsing for \"{}\".", appenderName);
+        return layout;
+    }
+
+    public ErrorHandler parseErrorHandler(final Properties props, final String errorHandlerPrefix,
+            final String errorHandlerClass, final Appender appender) {
+        ErrorHandler eh = newInstanceOf(errorHandlerClass, "ErrorHandler");
+        final String[] keys = new String[] {
+                errorHandlerPrefix + "." + ROOT_REF,
+                errorHandlerPrefix + "." + LOGGER_REF,
+                errorHandlerPrefix + "." + APPENDER_REF_TAG
+        };
+        addProperties(eh, keys, props, errorHandlerPrefix);
+        return eh;
+    }
+
+    public void addProperties(final Object obj, final String[] keys, final Properties props, final String prefix) {
+        final Properties edited = new Properties();
+        props.stringPropertyNames().stream().filter((name) -> {
+            if (name.startsWith(prefix)) {
+                for (String key : keys) {
+                    if (name.equals(key)) {
+                        return false;
+                    }
+                }
+                return true;
+            }
+            return false;
+        }).forEach((name) -> edited.put(name, props.getProperty(name)));
+        PropertySetter.setProperties(obj, edited, prefix + ".");
+    }
+
+
+    public Filter parseAppenderFilters(Properties props, String filterPrefix, String appenderName) {
+        // extract filters and filter options from props into a hashtable mapping
+        // the property name defining the filter class to a list of pre-parsed
+        // name-value pairs associated to that filter
+        int fIdx = filterPrefix.length();
+        SortedMap<String, List<NameValue>> filters = new TreeMap<>();
+        Enumeration e = props.keys();
+        String name = "";
+        while (e.hasMoreElements()) {
+            String key = (String) e.nextElement();
+            if (key.startsWith(filterPrefix)) {
+                int dotIdx = key.indexOf('.', fIdx);
+                String filterKey = key;
+                if (dotIdx != -1) {
+                    filterKey = key.substring(0, dotIdx);
+                    name = key.substring(dotIdx + 1);
+                }
+                List<NameValue> filterOpts = filters.computeIfAbsent(filterKey, k -> new ArrayList<>());
+                if (dotIdx != -1) {
+                    String value = OptionConverter.findAndSubst(key, props);
+                    filterOpts.add(new NameValue(name, value));
+                }
+            }
+        }
+
+        Filter head = null;
+        Filter next = null;
+        for (Map.Entry<String, List<NameValue>> entry : filters.entrySet()) {
+            String clazz = props.getProperty(entry.getKey());
+            Filter filter = null;
+            if (clazz != null) {
+                filter = manager.parseFilter(clazz, filterPrefix, props, this);
+                if (filter == null) {
+                    LOGGER.debug("Filter key: [{}] class: [{}] props: {}", entry.getKey(), clazz, entry.getValue());
+                    filter = buildFilter(clazz, appenderName, entry.getValue());
+                }
+            }
+            if (filter != null) {
+                if (head != null) {
+                    head = filter;
+                    next = filter;
+                } else {
+                    next.setNext(filter);
+                    next = filter;
+                }
+            }
+        }
+        return head;
+    }
+
+    private Filter buildFilter(String className, String appenderName, List<NameValue> props) {
+        Filter filter = newInstanceOf(className, "Filter");
+        if (filter != null) {
+            PropertySetter propSetter = new PropertySetter(filter);
+            for (NameValue property : props) {
+                propSetter.setProperty(property.key, property.value);
+            }
+            propSetter.activate();
+        }
+        return filter;
+    }
+
+
+    private static <T> T newInstanceOf(String className, String type) {
+        try {
+            return LoaderUtil.newInstanceOf(className);
+        } catch (ClassNotFoundException | IllegalAccessException | NoSuchMethodException |
+                InstantiationException | InvocationTargetException ex) {
+            LOGGER.error("Unable to create {} {} due to {}:{}", type,  className,
+                    ex.getClass().getSimpleName(), ex.getMessage());
+            return null;
+        }
+    }
+
+    private static class NameValue {
+        String key, value;
+
+        NameValue(String key, String value) {
+            this.key = key;
+            this.value = value;
+        }
+
+        public String toString() {
+            return key + "=" + value;
+        }
+    }
+
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfigurationFactory.java b/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfigurationFactory.java
new file mode 100644
index 0000000..465eaa1
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfigurationFactory.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.config;
+
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.config.ConfigurationSource;
+import org.apache.logging.log4j.core.config.Order;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.util.PropertiesUtil;
+
+/**
+ * Configures Log4j from a log4j 1 format properties file.
+ */
+@Plugin(name = "Log4j1PropertiesConfigurationFactory", category = ConfigurationFactory.CATEGORY)
+@Order(2)
+public class PropertiesConfigurationFactory extends ConfigurationFactory {
+
+
+    /**
+     * File name prefix for test configurations.
+     */
+    protected static final String TEST_PREFIX = "log4j-test";
+
+    /**
+     * File name prefix for standard configurations.
+     */
+    protected static final String DEFAULT_PREFIX = "log4j";
+
+    @Override
+    protected String[] getSupportedTypes() {
+        if (!PropertiesUtil.getProperties().getBooleanProperty(ConfigurationFactory.LOG4J1_EXPERIMENTAL, Boolean.FALSE)) {
+            return null;
+        }
+        return new String[] {".properties"};
+    }
+
+    @Override
+    public Configuration getConfiguration(LoggerContext loggerContext, ConfigurationSource source) {
+        int interval = PropertiesUtil.getProperties().getIntegerProperty(Log4j1Configuration.MONITOR_INTERVAL, 0);
+        return new PropertiesConfiguration(loggerContext, source, interval);
+    }
+
+    @Override
+    protected String getTestPrefix() {
+        return TEST_PREFIX;
+    }
+
+    @Override
+    protected String getDefaultPrefix() {
+        return DEFAULT_PREFIX;
+    }
+
+    @Override
+    protected String getVersion() {
+        return LOG4J1_VERSION;
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertySetter.java b/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertySetter.java
index 342024a..5982278 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertySetter.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertySetter.java
@@ -1,47 +1,156 @@
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
+ * 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 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
+ * 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.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
+
+// Contributors:  Georg Lundesgaard
+
 package org.apache.log4j.config;
 
+import org.apache.log4j.Appender;
+import org.apache.log4j.Level;
+import org.apache.log4j.Priority;
+import org.apache.log4j.spi.ErrorHandler;
+import org.apache.log4j.spi.OptionHandler;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.util.OptionConverter;
+import org.apache.logging.log4j.status.StatusLogger;
+
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
 import java.beans.PropertyDescriptor;
+import java.io.InterruptedIOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.util.Properties;
 
 /**
+ * General purpose Object property setter. Clients repeatedly invokes
+ * {@link #setProperty setProperty(name,value)} in order to invoke setters
+ * on the Object specified in the constructor. This class relies on the
+ * JavaBeans {@link Introspector} to analyze the given Object Class using
+ * reflection.
  *
- * @since 1.1
+ * <p>Usage:
+ * <pre>
+ * PropertySetter ps = new PropertySetter(anObject);
+ * ps.set("name", "Joe");
+ * ps.set("age", "32");
+ * ps.set("isMale", "true");
+ * </pre>
+ * will cause the invocations anObject.setName("Joe"), anObject.setAge(32),
+ * and setMale(true) if such methods exist with those signatures.
+ * Otherwise an {@link IntrospectionException} are thrown.
  */
 public class PropertySetter {
+    private static Logger LOGGER = StatusLogger.getLogger();
+    protected Object obj;
+    protected PropertyDescriptor[] props;
 
     /**
      * Create a new PropertySetter for the specified Object. This is done
-     * in preparation for invoking {@link #setProperty} one or more times.
+     * in prepartion for invoking {@link #setProperty} one or more times.
      *
-     * @param obj  the object for which to set properties
+     * @param obj the object for which to set properties
      */
-    public PropertySetter(final Object obj) {
+    public PropertySetter(Object obj) {
+        this.obj = obj;
     }
 
+    /**
+     * Set the properties of an object passed as a parameter in one
+     * go. The <code>properties</code> are parsed relative to a
+     * <code>prefix</code>.
+     *
+     * @param obj        The object to configure.
+     * @param properties A java.util.Properties containing keys and values.
+     * @param prefix     Only keys having the specified prefix will be set.
+     */
+    public static void setProperties(Object obj, Properties properties, String prefix) {
+        new PropertySetter(obj).setProperties(properties, prefix);
+    }
 
     /**
-     * Set the properties for the object that match the <code>prefix</code> passed as parameter.
-     *
-     * @param properties The properties
-     * @param prefix The prefix
+     * Uses JavaBeans {@link Introspector} to computer setters of object to be
+     * configured.
      */
-    public void setProperties(final Properties properties, final String prefix) {
+    protected void introspect() {
+        try {
+            BeanInfo bi = Introspector.getBeanInfo(obj.getClass());
+            props = bi.getPropertyDescriptors();
+        } catch (IntrospectionException ex) {
+            LOGGER.error("Failed to introspect {}: {}", obj, ex.getMessage());
+            props = new PropertyDescriptor[0];
+        }
+    }
+
+    /**
+     * Set the properites for the object that match the
+     * <code>prefix</code> passed as parameter.
+     */
+    public void setProperties(Properties properties, String prefix) {
+        int len = prefix.length();
+
+        for (String key : properties.stringPropertyNames()) {
+
+            // handle only properties that start with the desired frefix.
+            if (key.startsWith(prefix)) {
+
+
+                // ignore key if it contains dots after the prefix
+                if (key.indexOf('.', len + 1) > 0) {
+                    continue;
+                }
+
+                String value = OptionConverter.findAndSubst(key, properties);
+                key = key.substring(len);
+                if (("layout".equals(key) || "errorhandler".equals(key)) && obj instanceof Appender) {
+                    continue;
+                }
+                //
+                //   if the property type is an OptionHandler
+                //     (for example, triggeringPolicy of org.apache.log4j.rolling.RollingFileAppender)
+                PropertyDescriptor prop = getPropertyDescriptor(Introspector.decapitalize(key));
+                if (prop != null
+                        && OptionHandler.class.isAssignableFrom(prop.getPropertyType())
+                        && prop.getWriteMethod() != null) {
+                    OptionHandler opt = (OptionHandler)
+                            OptionConverter.instantiateByKey(properties, prefix + key,
+                                    prop.getPropertyType(),
+                                    null);
+                    PropertySetter setter = new PropertySetter(opt);
+                    setter.setProperties(properties, prefix + key + ".");
+                    try {
+                        prop.getWriteMethod().invoke(this.obj, opt);
+                    } catch (InvocationTargetException ex) {
+                        if (ex.getTargetException() instanceof InterruptedException
+                                || ex.getTargetException() instanceof InterruptedIOException) {
+                            Thread.currentThread().interrupt();
+                        }
+                        LOGGER.warn("Failed to set property [{}] to value \"{}\".", key, value, ex);
+                    } catch (IllegalAccessException | RuntimeException ex) {
+                        LOGGER.warn("Failed to set property [{}] to value \"{}\".", key, value, ex);
+                    }
+                    continue;
+                }
+
+                setProperty(key, value);
+            }
+        }
+        activate();
     }
 
     /**
@@ -56,33 +165,123 @@
      * to an int using new Integer(value). If the setter expects a boolean,
      * the conversion is by new Boolean(value).
      *
-     * @param name    name of the property
-     * @param value   String value of the property
+     * @param name  name of the property
+     * @param value String value of the property
      */
-    public void setProperty(final String name, final String value) {
+    public void setProperty(String name, String value) {
+        if (value == null) {
+            return;
+        }
+
+        name = Introspector.decapitalize(name);
+        PropertyDescriptor prop = getPropertyDescriptor(name);
+
+        //LOGGER.debug("---------Key: "+name+", type="+prop.getPropertyType());
+
+        if (prop == null) {
+            LOGGER.warn("No such property [" + name + "] in " +
+                    obj.getClass().getName() + ".");
+        } else {
+            try {
+                setProperty(prop, name, value);
+            } catch (PropertySetterException ex) {
+                LOGGER.warn("Failed to set property [{}] to value \"{}\".", name, value, ex.rootCause);
+            }
+        }
     }
 
     /**
      * Set the named property given a {@link PropertyDescriptor}.
      *
-     * @param prop A PropertyDescriptor describing the characteristics of the property to set.
-     * @param name The named of the property to set.
+     * @param prop  A PropertyDescriptor describing the characteristics
+     *              of the property to set.
+     * @param name  The named of the property to set.
      * @param value The value of the property.
-     * @throws PropertySetterException (Never actually throws this exception. Kept for historical purposes.)
      */
-    public void setProperty(final PropertyDescriptor prop, final String name, final String value)
-        throws PropertySetterException {
+    public void setProperty(PropertyDescriptor prop, String name, String value)
+            throws PropertySetterException {
+        Method setter = prop.getWriteMethod();
+        if (setter == null) {
+            throw new PropertySetterException("No setter for property [" + name + "].");
+        }
+        Class[] paramTypes = setter.getParameterTypes();
+        if (paramTypes.length != 1) {
+            throw new PropertySetterException("#params for setter != 1");
+        }
+
+        Object arg;
+        try {
+            arg = convertArg(value, paramTypes[0]);
+        } catch (Throwable t) {
+            throw new PropertySetterException("Conversion to type [" + paramTypes[0] +
+                    "] failed. Reason: " + t);
+        }
+        if (arg == null) {
+            throw new PropertySetterException(
+                    "Conversion to type [" + paramTypes[0] + "] failed.");
+        }
+        LOGGER.debug("Setting property [" + name + "] to [" + arg + "].");
+        try {
+            setter.invoke(obj, arg);
+        } catch (InvocationTargetException ex) {
+            if (ex.getTargetException() instanceof InterruptedException
+                    || ex.getTargetException() instanceof InterruptedIOException) {
+                Thread.currentThread().interrupt();
+            }
+            throw new PropertySetterException(ex);
+        } catch (IllegalAccessException | RuntimeException ex) {
+            throw new PropertySetterException(ex);
+        }
     }
 
+
     /**
-     * Set the properties of an object passed as a parameter in one
-     * go. The <code>properties</code> are parsed relative to a
-     * <code>prefix</code>.
-     *
-     * @param obj The object to configure.
-     * @param properties A java.util.Properties containing keys and values.
-     * @param prefix Only keys having the specified prefix will be set.
+     * Convert <code>val</code> a String parameter to an object of a
+     * given type.
      */
-    public static void setProperties(final Object obj, final Properties properties, final String prefix) {
+    protected Object convertArg(String val, Class type) {
+        if (val == null) {
+            return null;
+        }
+
+        String v = val.trim();
+        if (String.class.isAssignableFrom(type)) {
+            return val;
+        } else if (Integer.TYPE.isAssignableFrom(type)) {
+            return Integer.parseInt(v);
+        } else if (Long.TYPE.isAssignableFrom(type)) {
+            return Long.parseLong(v);
+        } else if (Boolean.TYPE.isAssignableFrom(type)) {
+            if ("true".equalsIgnoreCase(v)) {
+                return Boolean.TRUE;
+            } else if ("false".equalsIgnoreCase(v)) {
+                return Boolean.FALSE;
+            }
+        } else if (Priority.class.isAssignableFrom(type)) {
+            return org.apache.log4j.helpers.OptionConverter.toLevel(v, Level.DEBUG);
+        } else if (ErrorHandler.class.isAssignableFrom(type)) {
+            return OptionConverter.instantiateByClassName(v,
+                    ErrorHandler.class, null);
+        }
+        return null;
+    }
+
+
+    protected PropertyDescriptor getPropertyDescriptor(String name) {
+        if (props == null) {
+            introspect();
+        }
+        for (PropertyDescriptor prop : props) {
+            if (name.equals(prop.getName())) {
+                return prop;
+            }
+        }
+        return null;
+    }
+
+    public void activate() {
+        if (obj instanceof OptionHandler) {
+            ((OptionHandler) obj).activateOptions();
+        }
     }
 }
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/helpers/AppenderAttachableImpl.java b/log4j-1.2-api/src/main/java/org/apache/log4j/helpers/AppenderAttachableImpl.java
new file mode 100644
index 0000000..e9e35f9
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/helpers/AppenderAttachableImpl.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.helpers;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.spi.AppenderAttachable;
+import org.apache.log4j.spi.LoggingEvent;
+
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * Allows Classes to attach Appenders.
+ */
+public class AppenderAttachableImpl implements AppenderAttachable {
+
+    private final ConcurrentMap<String, Appender> appenders = new ConcurrentHashMap<>();
+
+    @Override
+    public void addAppender(Appender newAppender) {
+        if (newAppender != null) {
+            appenders.put(newAppender.getName(), newAppender);
+        }
+    }
+
+    @Override
+    public Enumeration getAllAppenders() {
+        return Collections.enumeration(appenders.values());
+    }
+
+    @Override
+    public Appender getAppender(String name) {
+        return appenders.get(name);
+    }
+
+    @Override
+    public boolean isAttached(Appender appender) {
+        return appenders.containsValue(appender);
+    }
+
+    @Override
+    public void removeAllAppenders() {
+        appenders.clear();
+    }
+
+    @Override
+    public void removeAppender(Appender appender) {
+        appenders.remove(appender.getName(), appender);
+    }
+
+    @Override
+    public void removeAppender(String name) {
+        appenders.remove(name);
+    }
+
+    /**
+     * Call the <code>doAppend</code> method on all attached appenders.
+     */
+    public int appendLoopOnAppenders(LoggingEvent event) {
+        for (Appender appender : appenders.values()) {
+            appender.doAppend(event);
+        }
+        return appenders.size();
+    }
+
+    public void close() {
+        for (Appender appender : appenders.values()) {
+            appender.close();
+        }
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/helpers/OptionConverter.java b/log4j-1.2-api/src/main/java/org/apache/log4j/helpers/OptionConverter.java
new file mode 100644
index 0000000..5f910fa
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/helpers/OptionConverter.java
@@ -0,0 +1,414 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.helpers;
+
+import org.apache.log4j.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.spi.StandardLevel;
+import org.apache.logging.log4j.util.LoaderUtil;
+
+import java.io.InterruptedIOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Properties;
+
+/**
+ * A convenience class to convert property values to specific types.
+ */
+public class OptionConverter {
+    
+    static String DELIM_START = "${";
+    static char DELIM_STOP = '}';
+    static int DELIM_START_LEN = 2;
+    static int DELIM_STOP_LEN = 1;
+    private static final Logger LOGGER = LogManager.getLogger(OptionConverter.class);
+    private static final CharMap[] charMap = new CharMap[] {
+        new CharMap('n', '\n'),
+        new CharMap('r', '\r'),
+        new CharMap('t', '\t'),
+        new CharMap('f', '\f'),
+        new CharMap('\b', '\b'),
+        new CharMap('\"', '\"'),
+        new CharMap('\'', '\''),
+        new CharMap('\\', '\\')    
+    };
+
+    /**
+     * OptionConverter is a static class.
+     */
+    private OptionConverter() {
+    }
+
+    public static String[] concatanateArrays(String[] l, String[] r) {
+        int len = l.length + r.length;
+        String[] a = new String[len];
+
+        System.arraycopy(l, 0, a, 0, l.length);
+        System.arraycopy(r, 0, a, l.length, r.length);
+
+        return a;
+    }
+
+    public static String convertSpecialChars(String s) {
+        char c;
+        int len = s.length();
+        StringBuilder sbuf = new StringBuilder(len);
+
+        int i = 0;
+        while (i < len) {
+            c = s.charAt(i++);
+            if (c == '\\') {
+                c = s.charAt(i++);
+                for (CharMap entry : charMap) {
+                    if (entry.key == c) {
+                        c = entry.replacement;
+                    }
+                }
+            }
+            sbuf.append(c);
+        }
+        return sbuf.toString();
+    }
+
+
+    /**
+     * Very similar to <code>System.getProperty</code> except
+     * that the {@link SecurityException} is hidden.
+     *
+     * @param key The key to search for.
+     * @param def The default value to return.
+     * @return the string value of the system property, or the default
+     * value if there is no property with that key.
+     * @since 1.1
+     */
+    public static String getSystemProperty(String key, String def) {
+        try {
+            return System.getProperty(key, def);
+        } catch (Throwable e) { // MS-Java throws com.ms.security.SecurityExceptionEx
+            LOGGER.debug("Was not allowed to read system property \"{}\".", key);
+            return def;
+        }
+    }
+
+    /**
+     * If <code>value</code> is "true", then <code>true</code> is
+     * returned. If <code>value</code> is "false", then
+     * <code>true</code> is returned. Otherwise, <code>default</code> is
+     * returned.
+     *
+     * <p>Case of value is unimportant.
+     */
+    public static boolean toBoolean(String value, boolean dEfault) {
+        if (value == null) {
+            return dEfault;
+        }
+        String trimmedVal = value.trim();
+        if ("true".equalsIgnoreCase(trimmedVal)) {
+            return true;
+        }
+        if ("false".equalsIgnoreCase(trimmedVal)) {
+            return false;
+        }
+        return dEfault;
+    }
+
+    /**
+     * Converts a standard or custom priority level to a Level
+     * object.  <p> If <code>value</code> is of form
+     * "level#classname", then the specified class' toLevel method
+     * is called to process the specified level string; if no '#'
+     * character is present, then the default {@link org.apache.log4j.Level}
+     * class is used to process the level value.
+     *
+     * <p>As a special case, if the <code>value</code> parameter is
+     * equal to the string "NULL", then the value <code>null</code> will
+     * be returned.
+     *
+     * <p> If any error occurs while converting the value to a level,
+     * the <code>defaultValue</code> parameter, which may be
+     * <code>null</code>, is returned.
+     *
+     * <p> Case of <code>value</code> is insignificant for the level level, but is
+     * significant for the class name part, if present.
+     *
+     * @since 1.1
+     */
+    public static Level toLevel(String value, Level defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+
+        value = value.trim();
+
+        int hashIndex = value.indexOf('#');
+        if (hashIndex == -1) {
+            if ("NULL".equalsIgnoreCase(value)) {
+                return null;
+            } else {
+                // no class name specified : use standard Level class
+                return Level.toLevel(value, defaultValue);
+            }
+        }
+
+        Level result = defaultValue;
+
+        String clazz = value.substring(hashIndex + 1);
+        String levelName = value.substring(0, hashIndex);
+
+        // This is degenerate case but you never know.
+        if ("NULL".equalsIgnoreCase(levelName)) {
+            return null;
+        }
+
+        LOGGER.debug("toLevel" + ":class=[" + clazz + "]"
+                + ":pri=[" + levelName + "]");
+
+        try {
+            Class customLevel = LoaderUtil.loadClass(clazz);
+
+            // get a ref to the specified class' static method
+            // toLevel(String, org.apache.log4j.Level)
+            Class[] paramTypes = new Class[]{String.class,
+                    org.apache.log4j.Level.class
+            };
+            java.lang.reflect.Method toLevelMethod =
+                    customLevel.getMethod("toLevel", paramTypes);
+
+            // now call the toLevel method, passing level string + default
+            Object[] params = new Object[]{levelName, defaultValue};
+            Object o = toLevelMethod.invoke(null, params);
+
+            result = (Level) o;
+        } catch (ClassNotFoundException e) {
+            LOGGER.warn("custom level class [" + clazz + "] not found.");
+        } catch (NoSuchMethodException e) {
+            LOGGER.warn("custom level class [" + clazz + "]"
+                    + " does not have a class function toLevel(String, Level)", e);
+        } catch (java.lang.reflect.InvocationTargetException e) {
+            if (e.getTargetException() instanceof InterruptedException
+                    || e.getTargetException() instanceof InterruptedIOException) {
+                Thread.currentThread().interrupt();
+            }
+            LOGGER.warn("custom level class [" + clazz + "]"
+                    + " could not be instantiated", e);
+        } catch (ClassCastException e) {
+            LOGGER.warn("class [" + clazz
+                    + "] is not a subclass of org.apache.log4j.Level", e);
+        } catch (IllegalAccessException e) {
+            LOGGER.warn("class [" + clazz +
+                    "] cannot be instantiated due to access restrictions", e);
+        } catch (RuntimeException e) {
+            LOGGER.warn("class [" + clazz + "], level [" + levelName +
+                    "] conversion failed.", e);
+        }
+        return result;
+    }
+
+    /**
+     * Instantiate an object given a class name. Check that the
+     * <code>className</code> is a subclass of
+     * <code>superClass</code>. If that test fails or the object could
+     * not be instantiated, then <code>defaultValue</code> is returned.
+     *
+     * @param className    The fully qualified class name of the object to instantiate.
+     * @param superClass   The class to which the new object should belong.
+     * @param defaultValue The object to return in case of non-fulfillment
+     */
+    public static Object instantiateByClassName(String className, Class<?> superClass,
+            Object defaultValue) {
+        if (className != null) {
+            try {
+                Object obj = LoaderUtil.newInstanceOf(className);
+                if (!superClass.isAssignableFrom(obj.getClass())) {
+                    LOGGER.error("A \"{}\" object is not assignable to a \"{}\" variable", className,
+                            superClass.getName());
+                    return defaultValue;
+                }
+                return obj;
+            } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException
+                    | InstantiationException | InvocationTargetException e) {
+                LOGGER.error("Could not instantiate class [" + className + "].", e);
+            }
+        }
+        return defaultValue;
+    }
+
+
+    /**
+     * Perform variable substitution in string <code>val</code> from the
+     * values of keys found in the system propeties.
+     *
+     * <p>The variable substitution delimeters are <b>${</b> and <b>}</b>.
+     *
+     * <p>For example, if the System properties contains "key=value", then
+     * the call
+     * <pre>
+     * String s = OptionConverter.substituteVars("Value of key is ${key}.");
+     * </pre>
+     * <p>
+     * will set the variable <code>s</code> to "Value of key is value.".
+     *
+     * <p>If no value could be found for the specified key, then the
+     * <code>props</code> parameter is searched, if the value could not
+     * be found there, then substitution defaults to the empty string.
+     *
+     * <p>For example, if system propeties contains no value for the key
+     * "inexistentKey", then the call
+     *
+     * <pre>
+     * String s = OptionConverter.subsVars("Value of inexistentKey is [${inexistentKey}]");
+     * </pre>
+     * will set <code>s</code> to "Value of inexistentKey is []"
+     *
+     * <p>An {@link IllegalArgumentException} is thrown if
+     * <code>val</code> contains a start delimeter "${" which is not
+     * balanced by a stop delimeter "}". </p>
+     *
+     * <p><b>Author</b> Avy Sharell</a></p>
+     *
+     * @param val The string on which variable substitution is performed.
+     * @throws IllegalArgumentException if <code>val</code> is malformed.
+     */
+    public static String substVars(String val, Properties props) throws IllegalArgumentException {
+
+        StringBuilder sbuf = new StringBuilder();
+
+        int i = 0;
+        int j, k;
+
+        while (true) {
+            j = val.indexOf(DELIM_START, i);
+            if (j == -1) {
+                // no more variables
+                if (i == 0) { // this is a simple string
+                    return val;
+                } else { // add the tail string which contails no variables and return the result.
+                    sbuf.append(val.substring(i, val.length()));
+                    return sbuf.toString();
+                }
+            } else {
+                sbuf.append(val.substring(i, j));
+                k = val.indexOf(DELIM_STOP, j);
+                if (k == -1) {
+                    throw new IllegalArgumentException('"' + val +
+                            "\" has no closing brace. Opening brace at position " + j
+                            + '.');
+                } else {
+                    j += DELIM_START_LEN;
+                    String key = val.substring(j, k);
+                    // first try in System properties
+                    String replacement = getSystemProperty(key, null);
+                    // then try props parameter
+                    if (replacement == null && props != null) {
+                        replacement = props.getProperty(key);
+                    }
+
+                    if (replacement != null) {
+                        // Do variable substitution on the replacement string
+                        // such that we can solve "Hello ${x2}" as "Hello p1"
+                        // the where the properties are
+                        // x1=p1
+                        // x2=${x1}
+                        String recursiveReplacement = substVars(replacement, props);
+                        sbuf.append(recursiveReplacement);
+                    }
+                    i = k + DELIM_STOP_LEN;
+                }
+            }
+        }
+    }
+
+    public static org.apache.logging.log4j.Level convertLevel(String level,
+            org.apache.logging.log4j.Level defaultLevel) {
+        Level l = toLevel(level, null);
+        return l != null ? convertLevel(l) : defaultLevel;
+    }
+
+    public static  org.apache.logging.log4j.Level convertLevel(Level level) {
+        if (level == null) {
+            return org.apache.logging.log4j.Level.ERROR;
+        }
+        if (level.isGreaterOrEqual(Level.FATAL)) {
+            return org.apache.logging.log4j.Level.FATAL;
+        } else if (level.isGreaterOrEqual(Level.ERROR)) {
+            return org.apache.logging.log4j.Level.ERROR;
+        } else if (level.isGreaterOrEqual(Level.WARN)) {
+            return org.apache.logging.log4j.Level.WARN;
+        } else if (level.isGreaterOrEqual(Level.INFO)) {
+            return org.apache.logging.log4j.Level.INFO;
+        } else if (level.isGreaterOrEqual(Level.DEBUG)) {
+            return org.apache.logging.log4j.Level.DEBUG;
+        } else if (level.isGreaterOrEqual(Level.TRACE)) {
+            return org.apache.logging.log4j.Level.TRACE;
+        }
+        return org.apache.logging.log4j.Level.ALL;
+    }
+
+    public static Level convertLevel(org.apache.logging.log4j.Level level) {
+        if (level == null) {
+            return Level.ERROR;
+        }
+        switch (level.getStandardLevel()) {
+            case FATAL:
+                return Level.FATAL;
+            case WARN:
+                return Level.WARN;
+            case INFO:
+                return Level.INFO;
+            case DEBUG:
+                return Level.DEBUG;
+            case TRACE:
+                return Level.TRACE;
+            case ALL:
+                return Level.ALL;
+            case OFF:
+                return Level.OFF;
+            default:
+                return Level.ERROR;
+        }
+    }
+
+    /**
+     * Find the value corresponding to <code>key</code> in
+     * <code>props</code>. Then perform variable substitution on the
+     * found value.
+     */
+    public static String findAndSubst(String key, Properties props) {
+        String value = props.getProperty(key);
+        if (value == null) {
+            return null;
+        }
+
+        try {
+            return substVars(value, props);
+        } catch (IllegalArgumentException e) {
+            LOGGER.error("Bad option value [{}].", value, e);
+            return value;
+        }
+    }
+    
+    private static class CharMap {
+        final char key;
+        final char replacement;
+        
+        public CharMap(char key, char replacement) {
+            this.key = key;
+            this.replacement = replacement;
+        }
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/helpers/QuietWriter.java b/log4j-1.2-api/src/main/java/org/apache/log4j/helpers/QuietWriter.java
new file mode 100644
index 0000000..1779019
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/helpers/QuietWriter.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.helpers;
+
+import org.apache.log4j.spi.ErrorCode;
+import org.apache.log4j.spi.ErrorHandler;
+
+import java.io.FilterWriter;
+import java.io.Writer;
+
+
+/**
+ * QuietWriter does not throw exceptions when things go
+ * wrong. Instead, it delegates error handling to its {@link ErrorHandler}.
+ */
+public class QuietWriter extends FilterWriter {
+
+    protected ErrorHandler errorHandler;
+
+    public QuietWriter(Writer writer, ErrorHandler errorHandler) {
+        super(writer);
+        setErrorHandler(errorHandler);
+    }
+
+    public void write(String string) {
+        if (string != null) {
+            try {
+                out.write(string);
+            } catch (Exception e) {
+                errorHandler.error("Failed to write [" + string + "].", e,
+                        ErrorCode.WRITE_FAILURE);
+            }
+        }
+    }
+
+    public void flush() {
+        try {
+            out.flush();
+        } catch (Exception e) {
+            errorHandler.error("Failed to flush writer,", e,
+                    ErrorCode.FLUSH_FAILURE);
+        }
+    }
+
+
+    public void setErrorHandler(ErrorHandler eh) {
+        if (eh == null) {
+            // This is a programming error on the part of the enclosing appender.
+            throw new IllegalArgumentException("Attempted to set null ErrorHandler.");
+        } else {
+            this.errorHandler = eh;
+        }
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/layout/Log4j1XmlLayout.java b/log4j-1.2-api/src/main/java/org/apache/log4j/layout/Log4j1XmlLayout.java
index 8d23307..899ebb6 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/layout/Log4j1XmlLayout.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/layout/Log4j1XmlLayout.java
@@ -48,8 +48,8 @@
     @PluginFactory
     public static Log4j1XmlLayout createLayout(
             // @formatter:off
-            @PluginAttribute(value = "locationInfo") final boolean locationInfo,
-            @PluginAttribute(value = "properties") final boolean properties
+            @PluginAttribute final boolean locationInfo,
+            @PluginAttribute final boolean properties
             // @formatter:on
     ) {
         return new Log4j1XmlLayout(locationInfo, properties);
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-1.2-api/src/main/java/org/apache/log4j/or/ObjectRenderer.java
similarity index 68%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-1.2-api/src/main/java/org/apache/log4j/or/ObjectRenderer.java
index 13aaf9c..f3fed18 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/or/ObjectRenderer.java
@@ -14,17 +14,14 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
+package org.apache.log4j.or;
 
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-public class ProcessIdUtilTest {
-
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
-    }
+/**
+ * Converts objects to Strings.
+ */
+public interface ObjectRenderer {
+    /**
+     * Render the object passed as parameter as a String.
+     */
+	 String doRender(Object o);
 }
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-1.2-api/src/main/java/org/apache/log4j/or/RendererSupport.java
similarity index 69%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-1.2-api/src/main/java/org/apache/log4j/or/RendererSupport.java
index 13aaf9c..9b8728d 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/or/RendererSupport.java
@@ -14,17 +14,13 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
+package org.apache.log4j.or;
 
-import org.junit.Test;
+import java.util.Map;
 
-import static org.junit.Assert.*;
-
-public class ProcessIdUtilTest {
-
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
-    }
+/**
+ * Interface that indicates the Renderer Map is available. This interface differs
+ */
+public interface RendererSupport {
+    Map<Class<?>, ObjectRenderer> getRendererMap();
 }
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/or/ThreadGroupRenderer.java b/log4j-1.2-api/src/main/java/org/apache/log4j/or/ThreadGroupRenderer.java
new file mode 100644
index 0000000..08233bf
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/or/ThreadGroupRenderer.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.or;
+
+import org.apache.log4j.Layout;
+
+/**
+ */
+public class ThreadGroupRenderer implements ObjectRenderer {
+
+    public
+    String  doRender(Object obj) {
+        if(obj instanceof ThreadGroup) {
+            StringBuilder sb = new StringBuilder();
+            ThreadGroup threadGroup = (ThreadGroup) obj;
+            sb.append("java.lang.ThreadGroup[name=");
+            sb.append(threadGroup.getName());
+            sb.append(", maxpri=");
+            sb.append(threadGroup.getMaxPriority());
+            sb.append("]");
+            Thread[] threads = new Thread[threadGroup.activeCount()];
+            threadGroup.enumerate(threads);
+            for (Thread thread : threads) {
+                sb.append(Layout.LINE_SEP);
+                sb.append("   Thread=[");
+                sb.append(thread.getName());
+                sb.append(",");
+                sb.append(thread.getPriority());
+                sb.append(",");
+                sb.append(thread.isDaemon());
+                sb.append("]");
+            }
+            return sb.toString();
+        } else {
+            try {
+                // this is the best we can do
+                return obj.toString();
+            } catch(Exception ex) {
+                return ex.toString();
+            }
+        }
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/rewrite/MapRewritePolicy.java b/log4j-1.2-api/src/main/java/org/apache/log4j/rewrite/MapRewritePolicy.java
new file mode 100644
index 0000000..4f53583
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/rewrite/MapRewritePolicy.java
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.rewrite;
+
+import org.apache.log4j.bridge.LogEventAdapter;
+import org.apache.log4j.helpers.OptionConverter;
+import org.apache.log4j.spi.LocationInfo;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.impl.Log4jLogEvent;
+import org.apache.logging.log4j.message.MapMessage;
+import org.apache.logging.log4j.message.Message;
+import org.apache.logging.log4j.message.SimpleMessage;
+import org.apache.logging.log4j.util.SortedArrayStringMap;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This policy rewrites events where the message of the
+ * original event implements java.util.Map.
+ * All other events are passed through unmodified.
+ * If the map contains a "message" entry, the value will be
+ * used as the message for the rewritten event.  The rewritten
+ * event will have a property set that is the combination of the
+ * original property set and the other members of the message map.
+ * If both the original property set and the message map
+ * contain the same entry, the value from the message map
+ * will overwrite the original property set.
+ * <p>
+ * The combination of the RewriteAppender and this policy
+ * performs the same actions as the MapFilter from log4j 1.3.
+ */
+public class MapRewritePolicy implements RewritePolicy {
+    /**
+     * {@inheritDoc}
+     */
+    public LoggingEvent rewrite(final LoggingEvent source) {
+        Object msg = source.getMessage();
+        if (msg instanceof MapMessage || msg instanceof Map) {
+            Map<String, String> props = source.getProperties() != null ? new HashMap<>(source.getProperties())
+                    : new HashMap<>();
+            @SuppressWarnings("unchecked")
+            Map<String, Object> eventProps = msg instanceof Map ? (Map) msg : ((MapMessage) msg).getData();
+            //
+            //   if the map sent in the logging request
+            //      has "message" entry, use that as the message body
+            //      otherwise, use the entire map.
+            //
+            Message newMessage = null;
+            Object newMsg = eventProps.get("message");
+            if (newMsg != null) {
+                newMessage = new SimpleMessage(newMsg.toString());
+                for (Map.Entry<String, Object> entry : eventProps.entrySet()) {
+                    if (!("message".equals(entry.getKey()))) {
+                        props.put(entry.getKey(), entry.getValue().toString());
+                    }
+                }
+            } else {
+                return source;
+            }
+
+            LogEvent event;
+            if (source instanceof LogEventAdapter) {
+                event = new Log4jLogEvent.Builder(((LogEventAdapter) source).getEvent())
+                        .setMessage(newMessage)
+                        .setContextData(new SortedArrayStringMap(props))
+                        .build();
+            } else {
+                LocationInfo info = source.getLocationInformation();
+                StackTraceElement element = new StackTraceElement(info.getClassName(), info.getMethodName(),
+                        info.getFileName(), Integer.parseInt(info.getLineNumber()));
+                Thread thread = getThread(source.getThreadName());
+                long threadId = thread != null ? thread.getId() : 0;
+                int threadPriority = thread != null ? thread.getPriority() : 0;
+                event = Log4jLogEvent.newBuilder()
+                        .setContextData(new SortedArrayStringMap(props))
+                        .setLevel(OptionConverter.convertLevel(source.getLevel()))
+                        .setLoggerFqcn(source.getFQNOfLoggerClass())
+                        .setMarker(null)
+                        .setMessage(newMessage)
+                        .setSource(element)
+                        .setLoggerName(source.getLoggerName())
+                        .setThreadName(source.getThreadName())
+                        .setThreadId(threadId)
+                        .setThreadPriority(threadPriority)
+                        .setThrown(source.getThrowableInformation().getThrowable())
+                        .setTimeMillis(source.getTimeStamp())
+                        .setNanoTime(0)
+                        .setThrownProxy(null)
+                        .build();
+            }
+            return new LogEventAdapter(event);
+        } else {
+            return source;
+        }
+
+    }
+
+    private Thread getThread(String name) {
+        for (Thread thread : Thread.getAllStackTraces().keySet()) {
+            if (thread.getName().equals(name)) {
+                return thread;
+            }
+        }
+        return null;
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/rewrite/PropertyRewritePolicy.java b/log4j-1.2-api/src/main/java/org/apache/log4j/rewrite/PropertyRewritePolicy.java
new file mode 100644
index 0000000..b822a99
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/rewrite/PropertyRewritePolicy.java
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.rewrite;
+
+import org.apache.log4j.bridge.LogEventAdapter;
+import org.apache.log4j.helpers.OptionConverter;
+import org.apache.log4j.spi.LocationInfo;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.impl.Log4jLogEvent;
+import org.apache.logging.log4j.message.SimpleMessage;
+import org.apache.logging.log4j.util.SortedArrayStringMap;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+/**
+ * This policy rewrites events by adding
+ * a user-specified list of properties to the event.
+ * Existing properties are not modified.
+ * <p>
+ * The combination of the RewriteAppender and this policy
+ * performs the same actions as the PropertyFilter from log4j 1.3.
+ */
+
+public class PropertyRewritePolicy implements RewritePolicy {
+    private Map<String, String> properties = Collections.EMPTY_MAP;
+
+    public PropertyRewritePolicy() {
+    }
+
+    /**
+     * Set a string representing the property name/value pairs.
+     * <p>
+     * Form: propname1=propvalue1,propname2=propvalue2
+     *
+     * @param props
+     */
+    public void setProperties(String props) {
+        Map hashTable = new HashMap();
+        StringTokenizer pairs = new StringTokenizer(props, ",");
+        while (pairs.hasMoreTokens()) {
+            StringTokenizer entry = new StringTokenizer(pairs.nextToken(), "=");
+            hashTable.put(entry.nextElement().toString().trim(), entry.nextElement().toString().trim());
+        }
+        synchronized (this) {
+            properties = hashTable;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public LoggingEvent rewrite(final LoggingEvent source) {
+        if (!properties.isEmpty()) {
+            Map<String, String> rewriteProps = source.getProperties() != null ? new HashMap<>(source.getProperties())
+                    : new HashMap<>();
+            for (Map.Entry<String, String> entry : properties.entrySet()) {
+                if (!rewriteProps.containsKey(entry.getKey())) {
+                    rewriteProps.put(entry.getKey(), entry.getValue());
+                }
+            }
+            LogEvent event;
+            if (source instanceof LogEventAdapter) {
+                event = new Log4jLogEvent.Builder(((LogEventAdapter) source).getEvent())
+                        .setContextData(new SortedArrayStringMap(rewriteProps))
+                        .build();
+            } else {
+                LocationInfo info = source.getLocationInformation();
+                StackTraceElement element = new StackTraceElement(info.getClassName(), info.getMethodName(),
+                        info.getFileName(), Integer.parseInt(info.getLineNumber()));
+                Thread thread = getThread(source.getThreadName());
+                long threadId = thread != null ? thread.getId() : 0;
+                int threadPriority = thread != null ? thread.getPriority() : 0;
+                event = Log4jLogEvent.newBuilder()
+                        .setContextData(new SortedArrayStringMap(rewriteProps))
+                        .setLevel(OptionConverter.convertLevel(source.getLevel()))
+                        .setLoggerFqcn(source.getFQNOfLoggerClass())
+                        .setMarker(null)
+                        .setMessage(new SimpleMessage(source.getRenderedMessage()))
+                        .setSource(element)
+                        .setLoggerName(source.getLoggerName())
+                        .setThreadName(source.getThreadName())
+                        .setThreadId(threadId)
+                        .setThreadPriority(threadPriority)
+                        .setThrown(source.getThrowableInformation().getThrowable())
+                        .setTimeMillis(source.getTimeStamp())
+                        .setNanoTime(0)
+                        .setThrownProxy(null)
+                        .build();
+            }
+            return new LogEventAdapter(event);
+        }
+        return source;
+    }
+
+    private Thread getThread(String name) {
+        for (Thread thread : Thread.getAllStackTraces().keySet()) {
+            if (thread.getName().equals(name)) {
+                return thread;
+            }
+        }
+        return null;
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/rewrite/RewritePolicy.java b/log4j-1.2-api/src/main/java/org/apache/log4j/rewrite/RewritePolicy.java
new file mode 100644
index 0000000..9570218
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/rewrite/RewritePolicy.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.rewrite;
+
+import org.apache.log4j.spi.LoggingEvent;
+
+/**
+ * This interface is implemented to provide a rewrite
+ * strategy for RewriteAppender.  RewriteAppender will
+ * call the rewrite method with a source logging event.
+ * The strategy may return that event, create a new event
+ * or return null to suppress the logging request.
+ */
+public interface RewritePolicy {
+    /**
+     * Rewrite a logging event.
+     * @param source a logging event that may be returned or
+     * used to create a new logging event.
+     * @return a logging event or null to suppress processing.
+     */
+    LoggingEvent rewrite(final LoggingEvent source);
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/spi/AppenderAttachable.java b/log4j-1.2-api/src/main/java/org/apache/log4j/spi/AppenderAttachable.java
new file mode 100644
index 0000000..fd464a2
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/spi/AppenderAttachable.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.spi;
+
+import org.apache.log4j.Appender;
+
+import java.util.Enumeration;
+
+/**
+ * Interface for attaching appenders to objects.
+ */
+public interface AppenderAttachable {
+
+    /**
+     * Add an appender.
+     */
+    void addAppender(Appender newAppender);
+
+    /**
+     * Get all previously added appenders as an Enumeration.
+     */
+    Enumeration getAllAppenders();
+
+    /**
+     * Get an appender by name.
+     */
+    Appender getAppender(String name);
+
+
+    /**
+     * Returns <code>true</code> if the specified appender is in list of
+     * attached attached, <code>false</code> otherwise.
+     *
+     * @since 1.2
+     */
+    boolean isAttached(Appender appender);
+
+    /**
+     * Remove all previously added appenders.
+     */
+    void removeAllAppenders();
+
+
+    /**
+     * Remove the appender passed as parameter from the list of appenders.
+     */
+    void removeAppender(Appender appender);
+
+
+    /**
+     * Remove the appender with the name passed as parameter from the
+     * list of appenders.
+     */
+    void removeAppender(String name);
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/spi/Configurator.java b/log4j-1.2-api/src/main/java/org/apache/log4j/spi/Configurator.java
new file mode 100644
index 0000000..b418db8
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/spi/Configurator.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.spi;
+
+import java.io.InputStream;
+import java.net.URL;
+
+import org.apache.logging.log4j.core.LoggerContext;
+
+/**
+ * Log4j 1.x Configurator interface.
+ */
+public interface Configurator {
+
+    public static final String INHERITED = "inherited";
+
+    public static final String NULL = "null";
+
+
+    /**
+     Interpret a resource pointed by a InputStream and set up log4j accordingly.
+
+     The configuration is done relative to the <code>hierarchy</code>
+     parameter.
+
+     @param inputStream The InputStream to parse
+
+     @since 1.2.17
+     */
+    void doConfigure(InputStream inputStream, final LoggerContext loggerContext);
+
+    /**
+     Interpret a resource pointed by a URL and set up log4j accordingly.
+
+     The configuration is done relative to the <code>hierarchy</code>
+     parameter.
+
+     @param url The URL to parse
+     */
+    void doConfigure(URL url, final LoggerContext loggerContext);
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/spi/ErrorCode.java b/log4j-1.2-api/src/main/java/org/apache/log4j/spi/ErrorCode.java
new file mode 100644
index 0000000..7fbbf95
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/spi/ErrorCode.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.spi;
+
+
+/**
+   This interface defines commonly encoutered error codes.
+ */
+public interface ErrorCode {
+
+  public final int GENERIC_FAILURE = 0;
+  public final int WRITE_FAILURE = 1;
+  public final int FLUSH_FAILURE = 2;
+  public final int CLOSE_FAILURE = 3;
+  public final int FILE_OPEN_FAILURE = 4;
+  public final int MISSING_LAYOUT = 5;
+  public final int ADDRESS_PARSE_FAILURE = 6;
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/spi/Filter.java b/log4j-1.2-api/src/main/java/org/apache/log4j/spi/Filter.java
index 9bba50c..997398b 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/spi/Filter.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/spi/Filter.java
@@ -16,10 +16,24 @@
  */
 package org.apache.log4j.spi;
 
+import org.apache.log4j.bridge.FilterAdapter;
+
 /**
  * @since 0.9.0
  */
 public abstract class Filter {
+    private final FilterAdapter adapter;
+
+    public Filter() {
+        FilterAdapter filterAdapter = null;
+        try {
+            Class.forName("org.apache.logging.log4j.core.Filter");
+            filterAdapter = new FilterAdapter(this);
+        } catch(ClassNotFoundException ex) {
+            // Ignore the exception. Log4j Core is not present.
+        }
+        this.adapter = filterAdapter;
+    }
 
     /**
      * The log event must be dropped immediately without consulting
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/spi/LocationInfo.java b/log4j-1.2-api/src/main/java/org/apache/log4j/spi/LocationInfo.java
new file mode 100644
index 0000000..2102802
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/spi/LocationInfo.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.spi;
+
+/**
+ The internal representation of caller location information.
+
+ @since 0.8.3
+ */
+public class LocationInfo implements java.io.Serializable {
+
+    private final StackTraceElement element;
+
+    public String fullInfo;
+
+    public LocationInfo(StackTraceElement element) {
+        this.element = element;
+    }
+
+    /**
+     When location information is not available the constant
+     <code>NA</code> is returned. Current value of this string
+     constant is <b>?</b>.  */
+    public final static String NA = "?";
+
+    static final long serialVersionUID = -1325822038990805636L;
+
+
+    /**
+     Return the fully qualified class name of the caller making the
+     logging request.
+     */
+    public
+    String getClassName() {
+        return element.getClassName();
+    }
+
+    /**
+     Return the file name of the caller.
+     */
+    public
+    String getFileName() {
+        return element.getFileName();
+    }
+
+    /**
+     Returns the line number of the caller.
+     */
+    public
+    String getLineNumber() {
+        return Integer.toString(element.getLineNumber());
+    }
+
+    /**
+     Returns the method name of the caller.
+     */
+    public
+    String getMethodName() {
+        return element.getMethodName();
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/spi/LoggingEvent.java b/log4j-1.2-api/src/main/java/org/apache/log4j/spi/LoggingEvent.java
index 5f4b172..d7755a2 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/spi/LoggingEvent.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/spi/LoggingEvent.java
@@ -16,8 +16,147 @@
  */
 package org.apache.log4j.spi;
 
+import org.apache.log4j.Category;
+import org.apache.log4j.Level;
+import org.apache.log4j.bridge.LogEventAdapter;
+
+import java.util.Map;
+import java.util.Set;
+
 /**
- *  No-op version of Log4j 1.2 LoggingEvent.
+ *  No-op version of Log4j 1.2 LoggingEvent. This class is not directly used by Log4j 1.x clients but is used by
+ *  the Log4j 2 LogEvent adapter to be compatible with Log4j 1.x components.
  */
 public class LoggingEvent {
+
+    /**
+     Set the location information for this logging event. The collected
+     information is cached for future use.
+     */
+    public LocationInfo getLocationInformation() {
+        return null;
+    }
+
+    /**
+     * Return the level of this event. Use this form instead of directly
+     * accessing the <code>level</code> field.  */
+    public Level getLevel() {
+        return null;
+    }
+
+    /**
+     * Return the name of the logger. Use this form instead of directly
+     * accessing the <code>categoryName</code> field.
+     */
+    public String getLoggerName() {
+        return null;
+    }
+
+    public String getFQNOfLoggerClass() {
+        return null;
+    }
+
+    public final long getTimeStamp() {
+        return 0;
+    }
+
+    /**
+     * Gets the logger of the event.
+     * Use should be restricted to cloning events.
+     * @since 1.2.15
+     */
+    public Category getLogger() {
+        return null;
+    }
+
+    /**
+     Return the message for this logging event.
+
+     <p>Before serialization, the returned object is the message
+     passed by the user to generate the logging event. After
+     serialization, the returned value equals the String form of the
+     message possibly after object rendering.
+
+     @since 1.1 */
+    public
+    Object getMessage() {
+        return null;
+    }
+
+    public
+    String getNDC() {
+        return null;
+    }
+
+    public
+    Object getMDC(String key) {
+        return null;
+    }
+
+    /**
+     Obtain a copy of this thread's MDC prior to serialization or
+     asynchronous logging.
+     */
+    public
+    void getMDCCopy() {
+    }
+
+    public
+    String getRenderedMessage() {
+        return null;
+    }
+
+    /**
+     Returns the time when the application started, in milliseconds
+     elapsed since 01.01.1970.  */
+    public static long getStartTime() {
+        return LogEventAdapter.getStartTime();
+    }
+
+    public
+    String getThreadName() {
+        return null;
+    }
+
+    /**
+     Returns the throwable information contained within this
+     event. May be <code>null</code> if there is no such information.
+
+     <p>Note that the {@link Throwable} object contained within a
+     {@link ThrowableInformation} does not survive serialization.
+
+     @since 1.1 */
+    public
+    ThrowableInformation getThrowableInformation() {
+        return null;
+    }
+
+    /**
+     Return this event's throwable's string[] representaion.
+     */
+    public
+    String[] getThrowableStrRep() {
+        return null;
+    }
+
+    public void setProperty(final String propName,
+            final String propValue) {
+
+    }
+
+    public String getProperty(final String key) {
+        return null;
+    }
+
+    public Set getPropertyKeySet() {
+        return null;
+    }
+
+    public Map getProperties() {
+        return null;
+    }
+
+    public Object removeProperty(String propName) {
+        return null;
+    }
 }
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/spi/ThrowableInformation.java b/log4j-1.2-api/src/main/java/org/apache/log4j/spi/ThrowableInformation.java
new file mode 100644
index 0000000..5a9ace5
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/spi/ThrowableInformation.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.spi;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.List;
+
+import org.apache.logging.log4j.core.util.Throwables;
+
+/**
+ * Class Description goes here.
+ */
+public class ThrowableInformation implements java.io.Serializable {
+
+    static final long serialVersionUID = -4748765566864322735L;
+
+    private transient Throwable throwable;
+    private Method toStringList;
+
+    @SuppressWarnings("unchecked")
+    public
+    ThrowableInformation(Throwable throwable) {
+        this.throwable = throwable;
+        Method method = null;
+        try {
+            Class throwables = Class.forName("org.apache.logging.log4j.core.util.Throwables");
+            method = throwables.getMethod("toStringList", Throwable.class);
+        } catch (ClassNotFoundException | NoSuchMethodException ex) {
+            // Ignore the exception if Log4j-core is not present.
+        }
+        this.toStringList = method;
+    }
+
+    public
+    Throwable getThrowable() {
+        return throwable;
+    }
+
+    public synchronized String[] getThrowableStrRep() {
+        if (toStringList != null && throwable != null) {
+            try {
+                @SuppressWarnings("unchecked")
+                List<String> elements = (List<String>) toStringList.invoke(null, throwable);
+                if (elements != null) {
+                    return elements.toArray(new String[0]);
+                }
+            } catch (IllegalAccessException | InvocationTargetException ex) {
+                // Ignore the exception.
+            }
+        }
+        return null;
+    }
+}
+
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/xml/Log4jEntityResolver.java b/log4j-1.2-api/src/main/java/org/apache/log4j/xml/Log4jEntityResolver.java
new file mode 100644
index 0000000..edda022
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/xml/Log4jEntityResolver.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.xml;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+/**
+ * An {@link EntityResolver} specifically designed to return
+ * <code>log4j.dtd</code> which is embedded within the log4j jar
+ * file.
+ */
+public class Log4jEntityResolver implements EntityResolver {
+    private static final Logger LOGGER = StatusLogger.getLogger();
+    private static final String PUBLIC_ID = "-//APACHE//DTD LOG4J 1.2//EN";
+
+    public InputSource resolveEntity(String publicId, String systemId) {
+        if (systemId.endsWith("log4j.dtd") || PUBLIC_ID.equals(publicId)) {
+            Class clazz = getClass();
+            InputStream in = clazz.getResourceAsStream("/org/apache/log4j/xml/log4j.dtd");
+            if (in == null) {
+                LOGGER.warn("Could not find [log4j.dtd] using [{}] class loader, parsed without DTD.",
+                        clazz.getClassLoader());
+                in = new ByteArrayInputStream(new byte[0]);
+            }
+            return new InputSource(in);
+        } else {
+            return null;
+        }
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/xml/UnrecognizedElementHandler.java b/log4j-1.2-api/src/main/java/org/apache/log4j/xml/UnrecognizedElementHandler.java
new file mode 100644
index 0000000..463d5d9
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/xml/UnrecognizedElementHandler.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.xml;
+
+import org.w3c.dom.Element;
+import java.util.Properties;
+
+/**
+ * When implemented by an object configured by DOMConfigurator,
+ * the handle method will be called when an unrecognized child
+ * element is encountered.  Unrecognized child elements of
+ * the log4j:configuration element will be dispatched to
+ * the logger repository if it supports this interface.
+ *
+ * @since 1.2.15
+ */
+public interface UnrecognizedElementHandler {
+    /**
+     * Called to inform a configured object when
+     * an unrecognized child element is encountered.
+     * @param element element, may not be null.
+     * @param props properties in force, may be null.
+     * @return true if configured object recognized the element
+     * @throws Exception throw an exception to prevent activation
+     * of the configured object.
+     */
+    boolean parseUnrecognizedElement(Element element, Properties props) throws Exception;
+}
\ No newline at end of file
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfiguration.java b/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfiguration.java
new file mode 100644
index 0000000..a37f140
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfiguration.java
@@ -0,0 +1,780 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.xml;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.Layout;
+import org.apache.log4j.Level;
+import org.apache.log4j.bridge.AppenderAdapter;
+import org.apache.log4j.bridge.AppenderWrapper;
+import org.apache.log4j.config.Log4j1Configuration;
+import org.apache.log4j.config.PropertySetter;
+import org.apache.log4j.helpers.OptionConverter;
+import org.apache.log4j.rewrite.RewritePolicy;
+import org.apache.log4j.spi.AppenderAttachable;
+import org.apache.log4j.spi.ErrorHandler;
+import org.apache.log4j.spi.Filter;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.ConfigurationSource;
+import org.apache.logging.log4j.core.config.LoggerConfig;
+import org.apache.logging.log4j.core.config.status.StatusConfiguration;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.LoaderUtil;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.FactoryConfigurationError;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.function.Consumer;
+
+/**
+ * Class Description goes here.
+ */
+public class XmlConfiguration extends Log4j1Configuration {
+
+    private static final org.apache.logging.log4j.Logger LOGGER = StatusLogger.getLogger();
+
+    private static final String CONFIGURATION_TAG = "log4j:configuration";
+    private static final String OLD_CONFIGURATION_TAG = "configuration";
+    private static final String RENDERER_TAG = "renderer";
+    private static final String APPENDER_TAG = "appender";
+    public  static final String PARAM_TAG = "param";
+    public static final String LAYOUT_TAG = "layout";
+    private static final String CATEGORY = "category";
+    private static final String LOGGER_ELEMENT = "logger";
+    private static final String CATEGORY_FACTORY_TAG = "categoryFactory";
+    private static final String LOGGER_FACTORY_TAG = "loggerFactory";
+    public static final String NAME_ATTR = "name";
+    private static final String CLASS_ATTR = "class";
+    public static final String VALUE_ATTR = "value";
+    private static final String ROOT_TAG = "root";
+    private static final String LEVEL_TAG = "level";
+    private static final String PRIORITY_TAG = "priority";
+    public static final String FILTER_TAG = "filter";
+    private static final String ERROR_HANDLER_TAG = "errorHandler";
+    public static final String REF_ATTR = "ref";
+    private static final String ADDITIVITY_ATTR = "additivity";
+    private static final String CONFIG_DEBUG_ATTR = "configDebug";
+    private static final String INTERNAL_DEBUG_ATTR = "debug";
+    private static final String EMPTY_STR = "";
+    private static final Class[] ONE_STRING_PARAM = new Class[]{String.class};
+    private static final String dbfKey = "javax.xml.parsers.DocumentBuilderFactory";
+    private static final String THROWABLE_RENDERER_TAG = "throwableRenderer";
+
+    public static final long DEFAULT_DELAY = 60000;
+    /**
+     * File name prefix for test configurations.
+     */
+    protected static final String TEST_PREFIX = "log4j-test";
+
+    /**
+     * File name prefix for standard configurations.
+     */
+    protected static final String DEFAULT_PREFIX = "log4j";
+
+    // key: appenderName, value: appender
+    private Map<String, Appender> appenderMap;
+
+    private Properties props = null;
+
+    public XmlConfiguration(final LoggerContext loggerContext, final ConfigurationSource source,
+            int monitorIntervalSeconds) {
+        super(loggerContext, source, monitorIntervalSeconds);
+        appenderMap = new HashMap<>();
+    }
+
+    public void addAppenderIfAbsent(Appender appender) {
+        appenderMap.putIfAbsent(appender.getName(), appender);
+    }
+
+    /**
+     * Configure log4j by reading in a log4j.dtd compliant XML
+     * configuration file.
+     */
+    @Override
+    public void doConfigure() throws FactoryConfigurationError {
+        ConfigurationSource source = getConfigurationSource();
+        ParseAction action = new ParseAction() {
+            public Document parse(final DocumentBuilder parser) throws SAXException, IOException {
+                InputSource inputSource = new InputSource(source.getInputStream());
+                inputSource.setSystemId("dummy://log4j.dtd");
+                return parser.parse(inputSource);
+            }
+
+            public String toString() {
+                return getConfigurationSource().getLocation();
+            }
+        };
+        doConfigure(action);
+    }
+
+    private void doConfigure(final ParseAction action) throws FactoryConfigurationError {
+        DocumentBuilderFactory dbf;
+        try {
+            LOGGER.debug("System property is : {}", OptionConverter.getSystemProperty(dbfKey, null));
+            dbf = DocumentBuilderFactory.newInstance();
+            LOGGER.debug("Standard DocumentBuilderFactory search succeded.");
+            LOGGER.debug("DocumentBuilderFactory is: " + dbf.getClass().getName());
+        } catch (FactoryConfigurationError fce) {
+            Exception e = fce.getException();
+            LOGGER.debug("Could not instantiate a DocumentBuilderFactory.", e);
+            throw fce;
+        }
+
+        try {
+            dbf.setValidating(true);
+
+            DocumentBuilder docBuilder = dbf.newDocumentBuilder();
+
+            docBuilder.setErrorHandler(new SAXErrorHandler());
+            docBuilder.setEntityResolver(new Log4jEntityResolver());
+
+            Document doc = action.parse(docBuilder);
+            parse(doc.getDocumentElement());
+        } catch (Exception e) {
+            if (e instanceof InterruptedException || e instanceof InterruptedIOException) {
+                Thread.currentThread().interrupt();
+            }
+            // I know this is miserable...
+            LOGGER.error("Could not parse " + action.toString() + ".", e);
+        }
+    }
+
+    /**
+     * Delegates unrecognized content to created instance if it supports UnrecognizedElementParser.
+     *
+     * @param instance instance, may be null.
+     * @param element  element, may not be null.
+     * @param props    properties
+     * @throws IOException thrown if configuration of owner object should be abandoned.
+     */
+    private void parseUnrecognizedElement(final Object instance, final Element element,
+            final Properties props) throws Exception {
+        boolean recognized = false;
+        if (instance instanceof UnrecognizedElementHandler) {
+            recognized = ((UnrecognizedElementHandler) instance).parseUnrecognizedElement(
+                    element, props);
+        }
+        if (!recognized) {
+            LOGGER.warn("Unrecognized element {}", element.getNodeName());
+        }
+    }
+
+    /**
+     * Delegates unrecognized content to created instance if
+     * it supports UnrecognizedElementParser and catches and
+     * logs any exception.
+     *
+     * @param instance instance, may be null.
+     * @param element  element, may not be null.
+     * @param props    properties
+     * @since 1.2.15
+     */
+    private void quietParseUnrecognizedElement(final Object instance,
+            final Element element,
+            final Properties props) {
+        try {
+            parseUnrecognizedElement(instance, element, props);
+        } catch (Exception ex) {
+            if (ex instanceof InterruptedException || ex instanceof InterruptedIOException) {
+                Thread.currentThread().interrupt();
+            }
+            LOGGER.error("Error in extension content: ", ex);
+        }
+    }
+
+    /**
+     * Substitutes property value for any references in expression.
+     *
+     * @param value value from configuration file, may contain
+     *              literal text, property references or both
+     * @param props properties.
+     * @return evaluated expression, may still contain expressions
+     * if unable to expand.
+     */
+    public String subst(final String value, final Properties props) {
+        try {
+            return OptionConverter.substVars(value, props);
+        } catch (IllegalArgumentException e) {
+            LOGGER.warn("Could not perform variable substitution.", e);
+            return value;
+        }
+    }
+
+    /**
+     * Sets a parameter based from configuration file content.
+     *
+     * @param elem       param element, may not be null.
+     * @param propSetter property setter, may not be null.
+     * @param props      properties
+     * @since 1.2.15
+     */
+    public void setParameter(final Element elem, final PropertySetter propSetter, final Properties props) {
+        String name = subst(elem.getAttribute("name"), props);
+        String value = (elem.getAttribute("value"));
+        value = subst(OptionConverter.convertSpecialChars(value), props);
+        propSetter.setProperty(name, value);
+    }
+
+    /**
+     * Creates an object and processes any nested param elements
+     * but does not call activateOptions.  If the class also supports
+     * UnrecognizedElementParser, the parseUnrecognizedElement method
+     * will be call for any child elements other than param.
+     *
+     * @param element       element, may not be null.
+     * @param props         properties
+     * @param expectedClass interface or class expected to be implemented
+     *                      by created class
+     * @return created class or null.
+     * @throws Exception thrown if the contain object should be abandoned.
+     * @since 1.2.15
+     */
+    public Object parseElement(final Element element, final Properties props,
+            @SuppressWarnings("rawtypes") final Class expectedClass) throws Exception {
+        String clazz = subst(element.getAttribute("class"), props);
+        Object instance = OptionConverter.instantiateByClassName(clazz,
+                expectedClass, null);
+
+        if (instance != null) {
+            PropertySetter propSetter = new PropertySetter(instance);
+            NodeList children = element.getChildNodes();
+            final int length = children.getLength();
+
+            for (int loop = 0; loop < length; loop++) {
+                Node currentNode = children.item(loop);
+                if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
+                    Element currentElement = (Element) currentNode;
+                    String tagName = currentElement.getTagName();
+                    if (tagName.equals("param")) {
+                        setParameter(currentElement, propSetter, props);
+                    } else {
+                        parseUnrecognizedElement(instance, currentElement, props);
+                    }
+                }
+            }
+            return instance;
+        }
+        return null;
+    }
+
+    /**
+     * Used internally to parse appenders by IDREF name.
+     */
+    private Appender findAppenderByName(Document doc, String appenderName) {
+        Appender appender = appenderMap.get(appenderName);
+
+        if (appender != null) {
+            return appender;
+        } else {
+            // Doesn't work on DOM Level 1 :
+            // Element element = doc.getElementById(appenderName);
+
+            // Endre's hack:
+            Element element = null;
+            NodeList list = doc.getElementsByTagName("appender");
+            for (int t = 0; t < list.getLength(); t++) {
+                Node node = list.item(t);
+                NamedNodeMap map = node.getAttributes();
+                Node attrNode = map.getNamedItem("name");
+                if (appenderName.equals(attrNode.getNodeValue())) {
+                    element = (Element) node;
+                    break;
+                }
+            }
+            // Hack finished.
+
+            if (element == null) {
+
+                LOGGER.error("No appender named [{}] could be found.", appenderName);
+                return null;
+            } else {
+                appender = parseAppender(element);
+                if (appender != null) {
+                    appenderMap.put(appenderName, appender);
+                }
+                return appender;
+            }
+        }
+    }
+
+    /**
+     * Used internally to parse appenders by IDREF element.
+     */
+    public Appender findAppenderByReference(Element appenderRef) {
+        String appenderName = subst(appenderRef.getAttribute(REF_ATTR));
+        Document doc = appenderRef.getOwnerDocument();
+        return findAppenderByName(doc, appenderName);
+    }
+
+    /**
+     * Used internally to parse an appender element.
+     */
+    public Appender parseAppender(Element appenderElement) {
+        String className = subst(appenderElement.getAttribute(CLASS_ATTR));
+        LOGGER.debug("Class name: [" + className + ']');
+        Appender appender = manager.parseAppender(className, appenderElement, this);
+        if (appender == null) {
+            appender = buildAppender(className, appenderElement);
+        }
+        return appender;
+    }
+
+    private Appender buildAppender(String className, Element appenderElement) {
+        try {
+            Appender appender = LoaderUtil.newInstanceOf(className);
+            PropertySetter propSetter = new PropertySetter(appender);
+
+            appender.setName(subst(appenderElement.getAttribute(NAME_ATTR)));
+            forEachElement(appenderElement.getChildNodes(), (currentElement) -> {
+                // Parse appender parameters
+                switch (currentElement.getTagName()) {
+                    case PARAM_TAG:
+                        setParameter(currentElement, propSetter);
+                        break;
+                    case LAYOUT_TAG:
+                        appender.setLayout(parseLayout(currentElement));
+                        break;
+                    case FILTER_TAG:
+                        Filter filter = parseFilters(currentElement);
+                        if (filter != null) {
+                            LOGGER.debug("Adding filter of type [{}] to appender named [{}]",
+                                    filter.getClass(), appender.getName());
+                            appender.addFilter(filter);
+                        }
+                        break;
+                    case ERROR_HANDLER_TAG:
+                        parseErrorHandler(currentElement, appender);
+                        break;
+                    case APPENDER_REF_TAG:
+                        String refName = subst(currentElement.getAttribute(REF_ATTR));
+                        if (appender instanceof AppenderAttachable) {
+                            AppenderAttachable aa = (AppenderAttachable) appender;
+                            Appender child = findAppenderByReference(currentElement);
+                            LOGGER.debug("Attaching appender named [{}] to appender named [{}].", refName,
+                                    appender.getName());
+                            aa.addAppender(child);
+                        } else {
+                            LOGGER.error("Requesting attachment of appender named [{}] to appender named [{}}]"
+                                            + "which does not implement org.apache.log4j.spi.AppenderAttachable.",
+                                    refName, appender.getName());
+                        }
+                        break;
+                    default:
+                        try {
+                            parseUnrecognizedElement(appender, currentElement, props);
+                        } catch (Exception ex) {
+                            throw new ConsumerException(ex);
+                        }
+                }
+            });
+            propSetter.activate();
+            return appender;
+        } catch (ConsumerException ex) {
+            Throwable t = ex.getCause();
+            if (t instanceof InterruptedException || t instanceof InterruptedIOException) {
+                Thread.currentThread().interrupt();
+            }
+            LOGGER.error("Could not create an Appender. Reported error follows.", t);
+        } catch (Exception oops) {
+            if (oops instanceof InterruptedException || oops instanceof InterruptedIOException) {
+                Thread.currentThread().interrupt();
+            }
+            LOGGER.error("Could not create an Appender. Reported error follows.", oops);
+        }
+        return null;
+    }
+
+
+    public RewritePolicy parseRewritePolicy(Element rewritePolicyElement) {
+
+        String className = subst(rewritePolicyElement.getAttribute(CLASS_ATTR));
+        LOGGER.debug("Class name: [" + className + ']');
+        RewritePolicy policy = manager.parseRewritePolicy(className, rewritePolicyElement, this);
+        if (policy == null) {
+            policy = buildRewritePolicy(className, rewritePolicyElement);
+        }
+        return policy;
+    }
+
+    private RewritePolicy buildRewritePolicy(String className, Element element) {
+        try {
+            RewritePolicy policy = LoaderUtil.newInstanceOf(className);
+            PropertySetter propSetter = new PropertySetter(policy);
+
+            forEachElement(element.getChildNodes(), (currentElement) -> {
+                if (currentElement.getTagName().equalsIgnoreCase(PARAM_TAG)) {
+                    setParameter(currentElement, propSetter);
+                }
+            });
+            propSetter.activate();
+            return policy;
+        } catch (ConsumerException ex) {
+            Throwable t = ex.getCause();
+            if (t instanceof InterruptedException || t instanceof InterruptedIOException) {
+                Thread.currentThread().interrupt();
+            }
+            LOGGER.error("Could not create an RewritePolicy. Reported error follows.", t);
+        } catch (Exception oops) {
+            if (oops instanceof InterruptedException || oops instanceof InterruptedIOException) {
+                Thread.currentThread().interrupt();
+            }
+            LOGGER.error("Could not create an RewritePolicy. Reported error follows.", oops);
+        }
+        return null;
+    }
+
+    /**
+     * Used internally to parse an {@link ErrorHandler} element.
+     */
+    private void parseErrorHandler(Element element, Appender appender) {
+        ErrorHandler eh = (ErrorHandler) OptionConverter.instantiateByClassName(
+                subst(element.getAttribute(CLASS_ATTR)),
+                ErrorHandler.class,
+                null);
+
+        if (eh != null) {
+            eh.setAppender(appender);
+
+            PropertySetter propSetter = new PropertySetter(eh);
+            forEachElement(element.getChildNodes(), (currentElement) -> {
+                String tagName = currentElement.getTagName();
+                if (tagName.equals(PARAM_TAG)) {
+                    setParameter(currentElement, propSetter);
+                }
+            });
+            propSetter.activate();
+            appender.setErrorHandler(eh);
+        }
+    }
+
+    /**
+     * Used internally to parse a filter element.
+     */
+    public Filter parseFilters(Element filterElement) {
+        String className = subst(filterElement.getAttribute(CLASS_ATTR));
+        LOGGER.debug("Class name: [" + className + ']');
+        Filter filter = manager.parseFilter(className, filterElement, this);
+        if (filter == null) {
+            PropertySetter propSetter = new PropertySetter(filter);
+            forEachElement(filterElement.getChildNodes(), (currentElement) -> {
+                String tagName = currentElement.getTagName();
+                if (tagName.equals(PARAM_TAG)) {
+                    setParameter(currentElement, propSetter);
+                } else {
+                    quietParseUnrecognizedElement(filter, currentElement, props);
+                }
+            });
+            propSetter.activate();
+        }
+        return filter;
+    }
+
+    /**
+     * Used internally to parse an category element.
+     */
+    private void parseCategory(Element loggerElement) {
+        // Create a new org.apache.log4j.Category object from the <category> element.
+        String catName = subst(loggerElement.getAttribute(NAME_ATTR));
+        boolean additivity = OptionConverter.toBoolean(subst(loggerElement.getAttribute(ADDITIVITY_ATTR)), true);
+        LoggerConfig loggerConfig = getLogger(catName);
+        if (loggerConfig == null) {
+            loggerConfig = new LoggerConfig(catName, org.apache.logging.log4j.Level.ERROR, additivity);
+            addLogger(catName, loggerConfig);
+        } else {
+            loggerConfig.setAdditive(additivity);
+        }
+        parseChildrenOfLoggerElement(loggerElement, loggerConfig, false);
+    }
+
+    /**
+     * Used internally to parse the roor category element.
+     */
+    private void parseRoot(Element rootElement) {
+        LoggerConfig root = getRootLogger();
+        parseChildrenOfLoggerElement(rootElement, root, true);
+    }
+
+    /**
+     * Used internally to parse the children of a LoggerConfig element.
+     */
+    private void parseChildrenOfLoggerElement(Element catElement, LoggerConfig loggerConfig, boolean isRoot) {
+
+        final PropertySetter propSetter = new PropertySetter(loggerConfig);
+        loggerConfig.getAppenderRefs().clear();
+        forEachElement(catElement.getChildNodes(), (currentElement) -> {
+            switch (currentElement.getTagName()) {
+                case APPENDER_REF_TAG: {
+                    Appender appender = findAppenderByReference(currentElement);
+                    String refName = subst(currentElement.getAttribute(REF_ATTR));
+                    if (appender != null) {
+                        LOGGER.debug("Adding appender named [{}] to loggerConfig [{}].", refName,
+                                loggerConfig.getName());
+                        loggerConfig.addAppender(getAppender(refName), null, null);
+                    } else {
+                        LOGGER.debug("Appender named [{}}] not found.", refName);
+                    }
+                    break;
+                }
+                case LEVEL_TAG: case PRIORITY_TAG: {
+                    parseLevel(currentElement, loggerConfig, isRoot);
+                    break;
+                }
+                case PARAM_TAG: {
+                    setParameter(currentElement, propSetter);
+                    break;
+                }
+                default: {
+                    quietParseUnrecognizedElement(loggerConfig, currentElement, props);
+                }
+            }
+        });
+        propSetter.activate();
+    }
+
+    /**
+     * Used internally to parse a layout element.
+     */
+    public Layout parseLayout(Element layoutElement) {
+        String className = subst(layoutElement.getAttribute(CLASS_ATTR));
+        LOGGER.debug("Parsing layout of class: \"{}\"", className);
+        Layout layout = manager.parseLayout(className, layoutElement, this);
+        if (layout == null) {
+            layout = buildLayout(className, layoutElement);
+        }
+        return layout;
+    }
+
+    private Layout buildLayout(String className, Element layout_element) {
+        try {
+            Layout layout = LoaderUtil.newInstanceOf(className);
+            PropertySetter propSetter = new PropertySetter(layout);
+            forEachElement(layout_element.getChildNodes(), (currentElement) -> {
+                String tagName = currentElement.getTagName();
+                if (tagName.equals(PARAM_TAG)) {
+                    setParameter(currentElement, propSetter);
+                } else {
+                    try {
+                        parseUnrecognizedElement(layout, currentElement, props);
+                    } catch (Exception ex) {
+                        throw new ConsumerException(ex);
+                    }
+                }
+            });
+
+            propSetter.activate();
+            return layout;
+        } catch (ConsumerException ce) {
+            Throwable cause = ce.getCause();
+            if (cause instanceof InterruptedException || cause instanceof InterruptedIOException) {
+                Thread.currentThread().interrupt();
+            }
+            LOGGER.error("Could not create the Layout. Reported error follows.", cause);
+        } catch (Exception oops) {
+            if (oops instanceof InterruptedException || oops instanceof InterruptedIOException) {
+                Thread.currentThread().interrupt();
+            }
+            LOGGER.error("Could not create the Layout. Reported error follows.", oops);
+        }
+        return null;
+    }
+
+    /**
+     * Used internally to parse a level  element.
+     */
+    private void parseLevel(Element element, LoggerConfig logger, boolean isRoot) {
+        String catName = logger.getName();
+        if (isRoot) {
+            catName = "root";
+        }
+
+        String priStr = subst(element.getAttribute(VALUE_ATTR));
+        LOGGER.debug("Level value for {} is [{}}].", catName, priStr);
+
+        if (INHERITED.equalsIgnoreCase(priStr) || NULL.equalsIgnoreCase(priStr)) {
+            if (isRoot) {
+                LOGGER.error("Root level cannot be inherited. Ignoring directive.");
+            } else {
+                logger.setLevel(null);
+            }
+        } else {
+            String className = subst(element.getAttribute(CLASS_ATTR));
+            if (EMPTY_STR.equals(className)) {
+                logger.setLevel(OptionConverter.convertLevel(priStr, org.apache.logging.log4j.Level.DEBUG));
+            } else {
+                LOGGER.debug("Desired Level sub-class: [{}]", className);
+                try {
+                    Class<?> clazz = LoaderUtil.loadClass(className);
+                    Method toLevelMethod = clazz.getMethod("toLevel", ONE_STRING_PARAM);
+                    Level pri = (Level) toLevelMethod.invoke(null, new Object[]{priStr});
+                    logger.setLevel(OptionConverter.convertLevel(pri));
+                } catch (Exception oops) {
+                    if (oops instanceof InterruptedException || oops instanceof InterruptedIOException) {
+                        Thread.currentThread().interrupt();
+                    }
+                    LOGGER.error("Could not create level [" + priStr +
+                            "]. Reported error follows.", oops);
+                    return;
+                }
+            }
+        }
+        LOGGER.debug("{} level set to {}", catName,  logger.getLevel());
+    }
+
+    private void setParameter(Element elem, PropertySetter propSetter) {
+        String name = subst(elem.getAttribute(NAME_ATTR));
+        String value = (elem.getAttribute(VALUE_ATTR));
+        value = subst(OptionConverter.convertSpecialChars(value));
+        propSetter.setProperty(name, value);
+    }
+
+    /**
+     * Used internally to configure the log4j framework by parsing a DOM
+     * tree of XML elements based on <a
+     * href="doc-files/log4j.dtd">log4j.dtd</a>.
+     */
+    private void parse(Element element) {
+        String rootElementName = element.getTagName();
+
+        if (!rootElementName.equals(CONFIGURATION_TAG)) {
+            if (rootElementName.equals(OLD_CONFIGURATION_TAG)) {
+                LOGGER.warn("The <" + OLD_CONFIGURATION_TAG +
+                        "> element has been deprecated.");
+                LOGGER.warn("Use the <" + CONFIGURATION_TAG + "> element instead.");
+            } else {
+                LOGGER.error("DOM element is - not a <" + CONFIGURATION_TAG + "> element.");
+                return;
+            }
+        }
+
+
+        String debugAttrib = subst(element.getAttribute(INTERNAL_DEBUG_ATTR));
+
+        LOGGER.debug("debug attribute= \"" + debugAttrib + "\".");
+        // if the log4j.dtd is not specified in the XML file, then the
+        // "debug" attribute is returned as the empty string.
+        String status = "error";
+        if (!debugAttrib.equals("") && !debugAttrib.equals("null")) {
+            status = OptionConverter.toBoolean(debugAttrib, true) ? "debug" : "error";
+
+        } else {
+            LOGGER.debug("Ignoring " + INTERNAL_DEBUG_ATTR + " attribute.");
+        }
+
+        String confDebug = subst(element.getAttribute(CONFIG_DEBUG_ATTR));
+        if (!confDebug.equals("") && !confDebug.equals("null")) {
+            LOGGER.warn("The \"" + CONFIG_DEBUG_ATTR + "\" attribute is deprecated.");
+            LOGGER.warn("Use the \"" + INTERNAL_DEBUG_ATTR + "\" attribute instead.");
+            status = OptionConverter.toBoolean(confDebug, true) ? "debug" : "error";
+        }
+
+        final StatusConfiguration statusConfig = new StatusConfiguration().setStatus(status);
+        statusConfig.initialize();
+
+        forEachElement(element.getChildNodes(), (currentElement) -> {
+            switch (currentElement.getTagName()) {
+                case CATEGORY: case LOGGER_ELEMENT:
+                    parseCategory(currentElement);
+                    break;
+                case ROOT_TAG:
+                    parseRoot(currentElement);
+                    break;
+                case RENDERER_TAG:
+                    LOGGER.warn("Renderers are not supported by Log4j 2 and will be ignored.");
+                    break;
+                case THROWABLE_RENDERER_TAG:
+                    LOGGER.warn("Throwable Renderers are not supported by Log4j 2 and will be ignored.");
+                    break;
+                case CATEGORY_FACTORY_TAG: case LOGGER_FACTORY_TAG:
+                    LOGGER.warn("Log4j 1 Logger factories are not supported by Log4j 2 and will be ignored.");
+                    break;
+                case APPENDER_TAG:
+                    Appender appender = parseAppender(currentElement);
+                    appenderMap.put(appender.getName(), appender);
+                    if (appender instanceof AppenderWrapper) {
+                        addAppender(((AppenderWrapper) appender).getAppender());
+                    } else {
+                        addAppender(new AppenderAdapter(appender).getAdapter());
+                    }
+                    break;
+                default:
+                    quietParseUnrecognizedElement(null, currentElement, props);
+            }
+        });
+    }
+
+    private String subst(final String value) {
+        return getStrSubstitutor().replace(value);
+    }
+
+    public static void forEachElement(NodeList list, Consumer<Element> consumer) {
+        final int length = list.getLength();
+        for (int loop = 0; loop < length; loop++) {
+            Node currentNode = list.item(loop);
+
+            if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
+                Element currentElement = (Element) currentNode;
+                consumer.accept(currentElement);
+            }
+        }
+    }
+
+    private interface ParseAction {
+        Document parse(final DocumentBuilder parser) throws SAXException, IOException;
+    }
+
+    private static class SAXErrorHandler implements org.xml.sax.ErrorHandler {
+        private static final org.apache.logging.log4j.Logger LOGGER = StatusLogger.getLogger();
+
+        public void error(final SAXParseException ex) {
+            emitMessage("Continuable parsing error ", ex);
+        }
+
+        public void fatalError(final SAXParseException ex) {
+            emitMessage("Fatal parsing error ", ex);
+        }
+
+        public void warning(final SAXParseException ex) {
+            emitMessage("Parsing warning ", ex);
+        }
+
+        private static void emitMessage(final String msg, final SAXParseException ex) {
+            LOGGER.warn("{} {} and column {}", msg, ex.getLineNumber(), ex.getColumnNumber());
+            LOGGER.warn(ex.getMessage(), ex.getException());
+        }
+    }
+
+    private static class ConsumerException extends RuntimeException {
+
+        ConsumerException(Exception ex) {
+            super(ex);
+        }
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfigurationFactory.java b/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfigurationFactory.java
new file mode 100644
index 0000000..04b596e
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfigurationFactory.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.xml;
+
+import org.apache.log4j.config.Log4j1Configuration;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.config.ConfigurationSource;
+import org.apache.logging.log4j.core.config.Order;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.PropertiesUtil;
+
+/**
+ * Constructs a Configuration usable in Log4j 2 from a Log4j 1 configuration file.
+ */
+@Plugin(name = "Log4j1XmlConfigurationFactory", category = ConfigurationFactory.CATEGORY)
+@Order(2)
+public class XmlConfigurationFactory extends ConfigurationFactory {
+    private static final org.apache.logging.log4j.Logger LOGGER = StatusLogger.getLogger();
+
+    /**
+     * File name prefix for test configurations.
+     */
+    protected static final String TEST_PREFIX = "log4j-test";
+
+    /**
+     * File name prefix for standard configurations.
+     */
+    protected static final String DEFAULT_PREFIX = "log4j";
+
+    @Override
+    protected String[] getSupportedTypes() {
+        if (!PropertiesUtil.getProperties().getBooleanProperty(ConfigurationFactory.LOG4J1_EXPERIMENTAL, Boolean.FALSE)) {
+            return null;
+        }
+        return new String[] {".xml"};
+    }
+
+    @Override
+    public Configuration getConfiguration(LoggerContext loggerContext, ConfigurationSource source) {
+        int interval = PropertiesUtil.getProperties().getIntegerProperty(Log4j1Configuration.MONITOR_INTERVAL, 0);
+        return new XmlConfiguration(loggerContext, source, interval);
+    }
+
+    @Override
+    protected String getTestPrefix() {
+        return TEST_PREFIX;
+    }
+
+    @Override
+    protected String getDefaultPrefix() {
+        return DEFAULT_PREFIX;
+    }
+
+    @Override
+    protected String getVersion() {
+        return LOG4J1_VERSION;
+    }
+}
diff --git a/log4j-1.2-api/src/main/resources/org/apache/log4j/xml/log4j.dtd b/log4j-1.2-api/src/main/resources/org/apache/log4j/xml/log4j.dtd
new file mode 100644
index 0000000..f8e433a
--- /dev/null
+++ b/log4j-1.2-api/src/main/resources/org/apache/log4j/xml/log4j.dtd
@@ -0,0 +1,237 @@
+<?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.
+-->
+
+<!-- Authors: Chris Taylor, Ceki Gulcu. -->
+
+<!-- Version: 1.2 -->
+
+<!-- A configuration element consists of optional renderer
+elements,appender elements, categories and an optional root
+element. -->
+
+<!ELEMENT log4j:configuration (renderer*, throwableRenderer?,
+                               appender*,plugin*, (category|logger)*,root?,
+                               (categoryFactory|loggerFactory)?)>
+
+<!-- The "threshold" attribute takes a level value below which -->
+<!-- all logging statements are disabled. -->
+
+<!-- Setting the "debug" enable the printing of internal log4j logging   -->
+<!-- statements.                                                         -->
+
+<!-- By default, debug attribute is "null", meaning that we not do touch -->
+<!-- internal log4j logging settings. The "null" value for the threshold -->
+<!-- attribute can be misleading. The threshold field of a repository	 -->
+<!-- cannot be set to null. The "null" value for the threshold attribute -->
+<!-- simply means don't touch the threshold field, the threshold field   --> 
+<!-- keeps its old value.                                                -->
+     
+<!ATTLIST log4j:configuration
+  xmlns:log4j              CDATA #FIXED "http://jakarta.apache.org/log4j/" 
+  threshold                (all|trace|debug|info|warn|error|fatal|off|null) "null"
+  debug                    (true|false|null)  "null"
+  reset                    (true|false) "false"
+>
+
+<!-- renderer elements allow the user to customize the conversion of  -->
+<!-- message objects to String.                                       -->
+
+<!ELEMENT renderer EMPTY>
+<!ATTLIST renderer
+  renderedClass  CDATA #REQUIRED
+  renderingClass CDATA #REQUIRED
+>
+
+<!--  throwableRenderer allows the user to customize the conversion
+         of exceptions to a string representation.  -->
+<!ELEMENT throwableRenderer (param*)>
+<!ATTLIST throwableRenderer
+  class  CDATA #REQUIRED
+>
+
+
+<!-- Appenders must have a name and a class. -->
+<!-- Appenders may contain an error handler, a layout, optional parameters -->
+<!-- and filters. They may also reference (or include) other appenders. -->
+<!ELEMENT appender (errorHandler?, param*,
+      rollingPolicy?, triggeringPolicy?, connectionSource?,
+      layout?, filter*, appender-ref*)>
+<!ATTLIST appender
+  name 		CDATA 	#REQUIRED
+  class 	CDATA	#REQUIRED
+>
+
+<!ELEMENT layout (param*)>
+<!ATTLIST layout
+  class		CDATA	#REQUIRED
+>
+
+<!ELEMENT filter (param*)>
+<!ATTLIST filter
+  class		CDATA	#REQUIRED
+>
+
+<!-- ErrorHandlers can be of any class. They can admit any number of -->
+<!-- parameters. -->
+
+<!ELEMENT errorHandler (param*, root-ref?, logger-ref*,  appender-ref?)> 
+<!ATTLIST errorHandler
+   class        CDATA   #REQUIRED 
+>
+
+<!ELEMENT root-ref EMPTY>
+
+<!ELEMENT logger-ref EMPTY>
+<!ATTLIST logger-ref
+  ref CDATA #REQUIRED
+>
+
+<!ELEMENT param EMPTY>
+<!ATTLIST param
+  name		CDATA   #REQUIRED
+  value		CDATA	#REQUIRED
+>
+
+
+<!-- The priority class is org.apache.log4j.Level by default -->
+<!ELEMENT priority (param*)>
+<!ATTLIST priority
+  class   CDATA	#IMPLIED
+  value	  CDATA #REQUIRED
+>
+
+<!-- The level class is org.apache.log4j.Level by default -->
+<!ELEMENT level (param*)>
+<!ATTLIST level
+  class   CDATA	#IMPLIED
+  value	  CDATA #REQUIRED
+>
+
+
+<!-- If no level element is specified, then the configurator MUST not -->
+<!-- touch the level of the named category. -->
+<!ELEMENT category (param*,(priority|level)?,appender-ref*)>
+<!ATTLIST category
+  class         CDATA   #IMPLIED
+  name		CDATA	#REQUIRED
+  additivity	(true|false) "true"  
+>
+
+<!-- If no level element is specified, then the configurator MUST not -->
+<!-- touch the level of the named logger. -->
+<!ELEMENT logger (param*,level?,appender-ref*)>
+<!ATTLIST logger
+  class         CDATA   #IMPLIED
+  name		CDATA	#REQUIRED
+  additivity	(true|false) "true"  
+>
+
+
+<!ELEMENT categoryFactory (param*)>
+<!ATTLIST categoryFactory 
+   class        CDATA #REQUIRED>
+
+<!ELEMENT loggerFactory (param*)>
+<!ATTLIST loggerFactory
+   class        CDATA #REQUIRED>
+
+<!ELEMENT appender-ref EMPTY>
+<!ATTLIST appender-ref
+  ref CDATA #REQUIRED
+>
+
+<!-- plugins must have a name and class and can have optional parameters -->
+<!ELEMENT plugin (param*, connectionSource?)>
+<!ATTLIST plugin
+  name 		CDATA 	   #REQUIRED
+  class 	CDATA  #REQUIRED
+>
+
+<!ELEMENT connectionSource (dataSource?, param*)>
+<!ATTLIST connectionSource
+  class        CDATA  #REQUIRED
+>
+
+<!ELEMENT dataSource (param*)>
+<!ATTLIST dataSource
+  class        CDATA  #REQUIRED
+>
+
+<!ELEMENT triggeringPolicy ((param|filter)*)>
+<!ATTLIST triggeringPolicy
+  name 		CDATA  #IMPLIED
+  class 	CDATA  #REQUIRED
+>
+
+<!ELEMENT rollingPolicy (param*)>
+<!ATTLIST rollingPolicy
+  name 		CDATA  #IMPLIED
+  class 	CDATA  #REQUIRED
+>
+
+
+<!-- If no priority element is specified, then the configurator MUST not -->
+<!-- touch the priority of root. -->
+<!-- The root category always exists and cannot be subclassed. -->
+<!ELEMENT root (param*, (priority|level)?, appender-ref*)>
+
+
+<!-- ==================================================================== -->
+<!--                       A logging event                                -->
+<!-- ==================================================================== -->
+<!ELEMENT log4j:eventSet (log4j:event*)>
+<!ATTLIST log4j:eventSet
+  xmlns:log4j             CDATA #FIXED "http://jakarta.apache.org/log4j/" 
+  version                (1.1|1.2) "1.2" 
+  includesLocationInfo   (true|false) "true"
+>
+
+
+
+<!ELEMENT log4j:event (log4j:message, log4j:NDC?, log4j:throwable?, 
+                       log4j:locationInfo?, log4j:properties?) >
+
+<!-- The timestamp format is application dependent. -->
+<!ATTLIST log4j:event
+    logger     CDATA #REQUIRED
+    level      CDATA #REQUIRED
+    thread     CDATA #REQUIRED
+    timestamp  CDATA #REQUIRED
+    time       CDATA #IMPLIED
+>
+
+<!ELEMENT log4j:message (#PCDATA)>
+<!ELEMENT log4j:NDC (#PCDATA)>
+
+<!ELEMENT log4j:throwable (#PCDATA)>
+
+<!ELEMENT log4j:locationInfo EMPTY>
+<!ATTLIST log4j:locationInfo
+  class  CDATA	#REQUIRED
+  method CDATA	#REQUIRED
+  file   CDATA	#REQUIRED
+  line   CDATA	#REQUIRED
+>
+
+<!ELEMENT log4j:properties (log4j:data*)>
+
+<!ELEMENT log4j:data EMPTY>
+<!ATTLIST log4j:data
+  name   CDATA	#REQUIRED
+  value  CDATA	#REQUIRED
+>
diff --git a/log4j-1.2-api/src/site/markdown/index.md b/log4j-1.2-api/src/site/markdown/index.md
index 01d5a76..696e0bb 100644
--- a/log4j-1.2-api/src/site/markdown/index.md
+++ b/log4j-1.2-api/src/site/markdown/index.md
@@ -18,8 +18,7 @@
 
 # Log4j 1.2 Bridge
 
-The Log4j 1.2 Bridge allows applications coded to use Log4j 1.2 API to use
-Log4j 2 instead.
+The Log4j 1.2 Bridge allows applications coded to use Log4j 1.2 API to use Log4j 2 instead.
 
 ## Requirements
 
@@ -37,7 +36,7 @@
 | BasicConfigurator.configure() | NoOp               | Reconfigures Log4j 2                 |
 
 If log4j-core is not present location information will not be accurate in calls using the Log4j 1.2 API. The config
-package which attempts tp convert Log4j 1.x configurations to Log4j 2 is not supported without Log4j 2.  
+package which attempts tp convert Log4j 1.x configurations to Log4j 2 is not supported without Log4j 2.    
 
 For more information, see [Runtime Dependencies](../runtime-dependencies.html).
 
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/Appender.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/Appender.java
new file mode 100644
index 0000000..de89cce
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/Appender.java
@@ -0,0 +1,143 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j;
+
+import org.apache.log4j.spi.ErrorHandler;
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.spi.LoggingEvent;
+
+/**
+ * Implement this interface for your own strategies for outputting log
+ * statements.
+ */
+public interface Appender {
+
+    /**
+     * Add a filter to the end of the filter list.
+     * @param newFilter The filter to add.
+     *
+     * @since 0.9.0
+     */
+    void addFilter(Filter newFilter);
+
+    /**
+     * Returns the head Filter. The Filters are organized in a linked list
+     * and so all Filters on this Appender are available through the result.
+     *
+     * @return the head Filter or null, if no Filters are present
+     * @since 1.1
+     */
+    Filter getFilter();
+
+    /**
+     * Clear the list of filters by removing all the filters in it.
+     *
+     * @since 0.9.0
+     */
+    void clearFilters();
+
+    /**
+     * Release any resources allocated within the appender such as file
+     * handles, network connections, etc.
+     * <p>
+     * It is a programming error to append to a closed appender.
+     * </p>
+     *
+     * @since 0.8.4
+     */
+    void close();
+
+    /**
+     * Log in <code>Appender</code> specific way. When appropriate,
+     * Loggers will call the <code>doAppend</code> method of appender
+     * implementations in order to log.
+     * @param event The LoggingEvent.
+     */
+    void doAppend(LoggingEvent event);
+
+
+    /**
+     * Get the name of this appender.
+     *
+     * @return name, may be null.
+     */
+    String getName();
+
+
+    /**
+     * Set the {@link ErrorHandler} for this appender.
+     * @param errorHandler The error handler.
+     *
+     * @since 0.9.0
+     */
+    void setErrorHandler(ErrorHandler errorHandler);
+
+    /**
+     * Returns the {@link ErrorHandler} for this appender.
+     * @return The error handler.
+     *
+     * @since 1.1
+     */
+    ErrorHandler getErrorHandler();
+
+    /**
+     * Set the {@link Layout} for this appender.
+     * @param layout The Layout.
+     *
+     * @since 0.8.1
+     */
+    void setLayout(Layout layout);
+
+    /**
+     * Returns this appenders layout.
+     * @return the Layout.
+     *
+     * @since 1.1
+     */
+    Layout getLayout();
+
+
+    /**
+     * Set the name of this appender. The name is used by other
+     * components to identify this appender.
+     * @param name The appender name.
+     *
+     * @since 0.8.1
+     */
+    void setName(String name);
+
+    /**
+     * Configurators call this method to determine if the appender
+     * requires a layout. If this method returns {@code true},
+     * meaning that layout is required, then the configurator will
+     * configure an layout using the configuration information at its
+     * disposal.  If this method returns {@code false}, meaning that
+     * a layout is not required, then layout configuration will be
+     * skipped even if there is available layout configuration
+     * information at the disposal of the configurator..
+     * <p>
+     * In the rather exceptional case, where the appender
+     * implementation admits a layout but can also work without it, then
+     * the appender should return {@code true}.
+     * </p>
+     * @return true if a Layout is required.
+     *
+     * @since 0.8.4
+     */
+    boolean requiresLayout();
+}
+
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/AppenderSkeleton.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/AppenderSkeleton.java
new file mode 100644
index 0000000..1353dae
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/AppenderSkeleton.java
@@ -0,0 +1,177 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j;
+
+import org.apache.log4j.spi.ErrorHandler;
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.log4j.spi.OptionHandler;
+
+/**
+ * The base class for Appenders in Log4j 1. Appenders constructed using this are ignored in Log4j 2.
+ */
+public abstract class AppenderSkeleton implements Appender, OptionHandler {
+
+    protected Layout layout;
+
+    protected String name;
+
+    protected Priority threshold;
+
+    protected ErrorHandler errorHandler = new NoOpErrorHandler();
+
+    protected Filter headFilter;
+
+    protected Filter tailFilter;
+
+    protected boolean closed = false;
+
+    /**
+     * Create new instance.
+     */
+    public AppenderSkeleton() {
+        super();
+    }
+
+    protected AppenderSkeleton(final boolean isActive) {
+        super();
+    }
+
+    @Override
+    public void activateOptions() {
+    }
+
+    @Override
+    public void addFilter(final Filter newFilter) {
+        if(headFilter == null) {
+            headFilter = tailFilter = newFilter;
+        } else {
+            tailFilter.setNext(newFilter);
+            tailFilter = newFilter;
+        }
+    }
+
+    protected abstract void append(LoggingEvent event);
+
+    @Override
+    public void clearFilters() {
+        headFilter = tailFilter = null;
+    }
+
+    @Override
+    public void finalize() {
+    }
+
+    @Override
+    public ErrorHandler getErrorHandler() {
+        return this.errorHandler;
+    }
+
+    @Override
+    public Filter getFilter() {
+        return headFilter;
+    }
+
+    public final Filter getFirstFilter() {
+        return headFilter;
+    }
+
+    @Override
+    public Layout getLayout() {
+        return layout;
+    }
+
+    @Override
+    public final String getName() {
+        return this.name;
+    }
+
+    public Priority getThreshold() {
+        return threshold;
+    }
+
+    public boolean isAsSevereAsThreshold(final Priority priority) {
+        return ((threshold == null) || priority.isGreaterOrEqual(threshold));
+    }
+
+    /**
+     * This method is never going to be called in Log4j 2 so there isn't much point in having any code in it.
+     * @param event The LoggingEvent.
+     */
+    @Override
+    public void doAppend(final LoggingEvent event) {
+        append(event);
+    }
+
+    /**
+     * Set the {@link ErrorHandler} for this Appender.
+     *
+     * @since 0.9.0
+     */
+    @Override
+    public synchronized void setErrorHandler(final ErrorHandler eh) {
+        if (eh != null) {
+            this.errorHandler = eh;
+        }
+    }
+
+    @Override
+    public void setLayout(final Layout layout) {
+        this.layout = layout;
+    }
+
+    @Override
+    public void setName(final String name) {
+        this.name = name;
+    }
+
+    public void setThreshold(final Priority threshold) {
+        this.threshold = threshold;
+    }
+
+    public static class NoOpErrorHandler implements ErrorHandler {
+        @Override
+        public void setLogger(final Logger logger) {
+
+        }
+
+        @Override
+        public void error(final String message, final Exception e, final int errorCode) {
+
+        }
+
+        @Override
+        public void error(final String message) {
+
+        }
+
+        @Override
+        public void error(final String message, final Exception e, final int errorCode, final LoggingEvent event) {
+
+        }
+
+        @Override
+        public void setAppender(final Appender appender) {
+
+        }
+
+        @Override
+        public void setBackupAppender(final Appender appender) {
+
+        }
+    }
+}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/BasicConfigurator.java
similarity index 61%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-1.2-api/src/src/main/java/org/apache/log4j/BasicConfigurator.java
index 13aaf9c..2b7ec7f 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/BasicConfigurator.java
@@ -14,17 +14,32 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
+package org.apache.log4j;
 
-import org.junit.Test;
+/**
+ * Provided for compatibility with Log4j 1.x.
+ */
+public class BasicConfigurator {
 
-import static org.junit.Assert.*;
+    protected BasicConfigurator() {
+    }
 
-public class ProcessIdUtilTest {
+    public static void configure() {
+        LogManager.reconfigure();
+    }
 
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
+    /**
+     * No-op implementation.
+     * @param appender The appender.
+     */
+    public static void configure(final Appender appender) {
+        // no-op
+    }
+
+    /**
+     * No-op implementation.
+     */
+    public static void resetConfiguration() {
+        // no-op
     }
 }
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/Category.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/Category.java
new file mode 100644
index 0000000..e0e5aef
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/Category.java
@@ -0,0 +1,571 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j;
+
+import java.util.Enumeration;
+import java.util.Map;
+import java.util.ResourceBundle;
+import java.util.WeakHashMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.log4j.helpers.NullEnumeration;
+import org.apache.log4j.legacy.core.CategoryUtil;
+import org.apache.log4j.or.ObjectRenderer;
+import org.apache.log4j.or.RendererSupport;
+import org.apache.log4j.spi.LoggerFactory;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.logging.log4j.spi.ExtendedLogger;
+import org.apache.logging.log4j.spi.LoggerContext;
+import org.apache.logging.log4j.message.LocalizedMessage;
+import org.apache.logging.log4j.message.Message;
+import org.apache.logging.log4j.message.ObjectMessage;
+import org.apache.logging.log4j.spi.AbstractLoggerAdapter;
+import org.apache.logging.log4j.util.Strings;
+
+
+/**
+ * Implementation of the Category class for compatibility, despite it having been deprecated a long, long time ago.
+ */
+public class Category {
+
+    private static PrivateAdapter adapter = new PrivateAdapter();
+
+    private static final Map<LoggerContext, ConcurrentMap<String, Logger>> CONTEXT_MAP =
+        new WeakHashMap<>();
+
+    private static final String FQCN = Category.class.getName();
+
+    private static final boolean isCoreAvailable;
+
+    private final Map<Class<?>, ObjectRenderer> rendererMap;
+
+    static {
+        boolean available;
+
+        try {
+            available = Class.forName("org.apache.logging.log4j.core.Logger") != null;
+        } catch (Exception ex) {
+            available = false;
+        }
+        isCoreAvailable = available;
+    }
+
+    /**
+     * Resource bundle for localized messages.
+     */
+    protected ResourceBundle bundle = null;
+
+    private final org.apache.logging.log4j.Logger logger;
+
+    /**
+     * Constructor used by Logger to specify a LoggerContext.
+     * @param context The LoggerContext.
+     * @param name The name of the Logger.
+     */
+    protected Category(final LoggerContext context, final String name) {
+        this.logger = context.getLogger(name);
+        rendererMap = ((RendererSupport) LogManager.getLoggerRepository()).getRendererMap();
+    }
+
+    /**
+     * Constructor exposed by Log4j 1.2.
+     * @param name The name of the Logger.
+     */
+    protected Category(final String name) {
+        this(PrivateManager.getContext(), name);
+    }
+
+    private Category(final org.apache.logging.log4j.Logger logger) {
+        this.logger = logger;
+        rendererMap = ((RendererSupport) LogManager.getLoggerRepository()).getRendererMap();
+    }
+
+    public static Category getInstance(final String name) {
+        return getInstance(PrivateManager.getContext(), name, adapter);
+    }
+
+    static Logger getInstance(final LoggerContext context, final String name) {
+        return getInstance(context, name, adapter);
+    }
+
+    static Logger getInstance(final LoggerContext context, final String name, final LoggerFactory factory) {
+        final ConcurrentMap<String, Logger> loggers = getLoggersMap(context);
+        Logger logger = loggers.get(name);
+        if (logger != null) {
+            return logger;
+        }
+        logger = factory.makeNewLoggerInstance(name);
+        final Logger prev = loggers.putIfAbsent(name, logger);
+        return prev == null ? logger : prev;
+    }
+
+    static Logger getInstance(final LoggerContext context, final String name, final PrivateAdapter factory) {
+        final ConcurrentMap<String, Logger> loggers = getLoggersMap(context);
+        Logger logger = loggers.get(name);
+        if (logger != null) {
+            return logger;
+        }
+        logger = factory.newLogger(name, context);
+        final Logger prev = loggers.putIfAbsent(name, logger);
+        return prev == null ? logger : prev;
+    }
+
+    public static Category getInstance(@SuppressWarnings("rawtypes") final Class clazz) {
+        return getInstance(clazz.getName());
+    }
+
+    static Logger getInstance(final LoggerContext context, @SuppressWarnings("rawtypes") final Class clazz) {
+        return getInstance(context, clazz.getName());
+    }
+
+    public final String getName() {
+        return logger.getName();
+    }
+
+    org.apache.logging.log4j.Logger getLogger() {
+        return logger;
+    }
+
+    public final Category getParent() {
+        if (!isCoreAvailable) {
+            return null;
+        }
+        org.apache.logging.log4j.Logger parent = CategoryUtil.getParent(logger);
+        LoggerContext loggerContext = CategoryUtil.getLoggerContext(logger);
+        if (parent == null || loggerContext == null) {
+            return null;
+        }
+        final ConcurrentMap<String, Logger> loggers = getLoggersMap(loggerContext);
+        final Logger l = loggers.get(parent.getName());
+        return l == null ? new Category(parent) : l;
+    }
+
+    public static Category getRoot() {
+        return getInstance(Strings.EMPTY);
+    }
+
+    static Logger getRoot(final LoggerContext context) {
+        return getInstance(context, Strings.EMPTY);
+    }
+
+    private static ConcurrentMap<String, Logger> getLoggersMap(final LoggerContext context) {
+        synchronized (CONTEXT_MAP) {
+            ConcurrentMap<String, Logger> map = CONTEXT_MAP.get(context);
+            if (map == null) {
+                map = new ConcurrentHashMap<>();
+                CONTEXT_MAP.put(context, map);
+            }
+            return map;
+        }
+    }
+
+    /**
+     Returns all the currently defined categories in the default
+     hierarchy as an {@link java.util.Enumeration Enumeration}.
+
+     <p>The root category is <em>not</em> included in the returned
+     {@link Enumeration}.
+     @return and Enumeration of the Categories.
+
+     @deprecated Please use {@link LogManager#getCurrentLoggers()} instead.
+     */
+    @SuppressWarnings("rawtypes")
+    @Deprecated
+    public static Enumeration getCurrentCategories() {
+        return LogManager.getCurrentLoggers();
+    }
+
+    public final Level getEffectiveLevel() {
+        switch (logger.getLevel().getStandardLevel()) {
+        case ALL:
+            return Level.ALL;
+        case TRACE:
+            return Level.TRACE;
+        case DEBUG:
+            return Level.DEBUG;
+        case INFO:
+            return Level.INFO;
+        case WARN:
+            return Level.WARN;
+        case ERROR:
+            return Level.ERROR;
+        case FATAL:
+            return Level.FATAL;
+        default:
+            // TODO Should this be an IllegalStateException?
+            return Level.OFF;
+        }
+    }
+
+    public final Priority getChainedPriority() {
+        return getEffectiveLevel();
+    }
+
+    public final Level getLevel() {
+        return getEffectiveLevel();
+    }
+
+    public void setLevel(final Level level) {
+        setLevel(level.levelStr);
+    }
+
+    public final Level getPriority() {
+        return getEffectiveLevel();
+    }
+
+    public void setPriority(final Priority priority) {
+        setLevel(priority.levelStr);
+    }
+
+    private void setLevel(final String levelStr) {
+        if (isCoreAvailable) {
+            CategoryUtil.setLevel(logger, org.apache.logging.log4j.Level.toLevel(levelStr));
+        }
+    }
+
+    public void debug(final Object message) {
+        maybeLog(FQCN, org.apache.logging.log4j.Level.DEBUG, message, null);
+    }
+
+    public void debug(final Object message, final Throwable t) {
+        maybeLog(FQCN, org.apache.logging.log4j.Level.DEBUG, message, t);
+    }
+
+    public boolean isDebugEnabled() {
+        return logger.isDebugEnabled();
+    }
+
+    public void error(final Object message) {
+        maybeLog(FQCN, org.apache.logging.log4j.Level.ERROR, message, null);
+    }
+
+    public void error(final Object message, final Throwable t) {
+        maybeLog(FQCN, org.apache.logging.log4j.Level.ERROR, message, t);
+    }
+
+    public boolean isErrorEnabled() {
+        return logger.isErrorEnabled();
+    }
+
+    public void warn(final Object message) {
+        maybeLog(FQCN, org.apache.logging.log4j.Level.WARN, message, null);
+    }
+
+    public void warn(final Object message, final Throwable t) {
+        maybeLog(FQCN, org.apache.logging.log4j.Level.WARN, message, t);
+    }
+
+    public boolean isWarnEnabled() {
+        return logger.isWarnEnabled();
+    }
+
+    public void fatal(final Object message) {
+        maybeLog(FQCN, org.apache.logging.log4j.Level.FATAL, message, null);
+    }
+
+    public void fatal(final Object message, final Throwable t) {
+        maybeLog(FQCN, org.apache.logging.log4j.Level.FATAL, message, t);
+    }
+
+    public boolean isFatalEnabled() {
+        return logger.isFatalEnabled();
+    }
+
+    public void info(final Object message) {
+        maybeLog(FQCN, org.apache.logging.log4j.Level.INFO, message, null);
+    }
+
+    public void info(final Object message, final Throwable t) {
+        maybeLog(FQCN, org.apache.logging.log4j.Level.INFO, message, t);
+    }
+
+    public boolean isInfoEnabled() {
+        return logger.isInfoEnabled();
+    }
+
+    public void trace(final Object message) {
+        maybeLog(FQCN, org.apache.logging.log4j.Level.TRACE, message, null);
+    }
+
+    public void trace(final Object message, final Throwable t) {
+        maybeLog(FQCN, org.apache.logging.log4j.Level.TRACE, message, t);
+    }
+
+    public boolean isTraceEnabled() {
+        return logger.isTraceEnabled();
+    }
+
+    public boolean isEnabledFor(final Priority level) {
+        final org.apache.logging.log4j.Level lvl = org.apache.logging.log4j.Level.toLevel(level.toString());
+        return isEnabledFor(lvl);
+    }
+
+    /**
+     * No-op implementation.
+     * @param appender The Appender to add.
+     */
+    public void addAppender(final Appender appender) {
+    }
+
+    /**
+     * No-op implementation.
+     * @param event The logging event.
+     */
+    public void callAppenders(final LoggingEvent event) {
+    }
+
+    @SuppressWarnings("rawtypes")
+    public Enumeration getAllAppenders() {
+        return NullEnumeration.getInstance();
+    }
+
+    /**
+     * No-op implementation.
+     * @param name The name of the Appender.
+     * @return null.
+     */
+    public Appender getAppender(final String name) {
+        return null;
+    }
+
+    /**
+     Is the appender passed as parameter attached to this category?
+     * @param appender The Appender to add.
+     * @return true if the appender is attached.
+     */
+    public boolean isAttached(final Appender appender) {
+        return false;
+    }
+
+    /**
+     * No-op implementation.
+     */
+    public void removeAllAppenders() {
+    }
+
+    /**
+     * No-op implementation.
+     * @param appender The Appender to remove.
+     */
+    public void removeAppender(final Appender appender) {
+    }
+
+    /**
+     * No-op implementation.
+     * @param name The Appender to remove.
+     */
+    public void removeAppender(final String name) {
+    }
+
+    /**
+     * No-op implementation.
+     */
+    public static void shutdown() {
+    }
+
+    public void forcedLog(final String fqcn, final Priority level, final Object message, final Throwable t) {
+        final org.apache.logging.log4j.Level lvl = org.apache.logging.log4j.Level.toLevel(level.toString());
+        ObjectRenderer renderer = get(message.getClass());
+        final Message msg = message instanceof Message ? (Message) message : renderer != null ?
+            new RenderedMessage(renderer, message) : new ObjectMessage(message);
+        if (logger instanceof ExtendedLogger) {
+            ((ExtendedLogger) logger).logMessage(fqcn, lvl, null, new ObjectMessage(message), t);
+        } else {
+            logger.log(lvl, msg, t);
+        }
+    }
+
+    public boolean exists(final String name) {
+        return PrivateManager.getContext().hasLogger(name);
+    }
+
+    public boolean getAdditivity() {
+        return isCoreAvailable ? CategoryUtil.isAdditive(logger) : false;
+    }
+
+    public void setAdditivity(final boolean additivity) {
+        if (isCoreAvailable) {
+            CategoryUtil.setAdditivity(logger, additivity);
+        }
+    }
+
+    public void setResourceBundle(final ResourceBundle bundle) {
+        this.bundle = bundle;
+    }
+
+    public ResourceBundle getResourceBundle() {
+        if (bundle != null) {
+            return bundle;
+        }
+        String name = logger.getName();
+        if (isCoreAvailable) {
+            LoggerContext ctx = CategoryUtil.getLoggerContext(logger);
+            if (ctx != null) {
+                final ConcurrentMap<String, Logger> loggers = getLoggersMap(ctx);
+                while ((name = getSubName(name)) != null) {
+                    final Logger subLogger = loggers.get(name);
+                    if (subLogger != null) {
+                        final ResourceBundle rb = subLogger.bundle;
+                        if (rb != null) {
+                            return rb;
+                        }
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    private static  String getSubName(final String name) {
+        if (Strings.isEmpty(name)) {
+            return null;
+        }
+        final int i = name.lastIndexOf('.');
+        return i > 0 ? name.substring(0, i) : Strings.EMPTY;
+    }
+
+    /**
+     If <code>assertion</code> parameter is {@code false}, then
+     logs <code>msg</code> as an {@link #error(Object) error} statement.
+
+     <p>The <code>assert</code> method has been renamed to
+     <code>assertLog</code> because <code>assert</code> is a language
+     reserved word in JDK 1.4.
+
+     @param assertion The assertion.
+     @param msg The message to print if <code>assertion</code> is
+     false.
+
+     @since 1.2
+     */
+    public void assertLog(final boolean assertion, final String msg) {
+        if (!assertion) {
+            this.error(msg);
+        }
+    }
+
+    public void l7dlog(final Priority priority, final String key, final Throwable t) {
+        if (isEnabledFor(priority)) {
+            final Message msg = new LocalizedMessage(bundle, key, null);
+            forcedLog(FQCN, priority, msg, t);
+        }
+    }
+
+    public void l7dlog(final Priority priority, final String key, final Object[] params, final Throwable t) {
+        if (isEnabledFor(priority)) {
+            final Message msg = new LocalizedMessage(bundle, key, params);
+            forcedLog(FQCN, priority, msg, t);
+        }
+    }
+
+    public void log(final Priority priority, final Object message, final Throwable t) {
+        if (isEnabledFor(priority)) {
+            final Message msg = new ObjectMessage(message);
+            forcedLog(FQCN, priority, msg, t);
+        }
+    }
+
+    public void log(final Priority priority, final Object message) {
+        if (isEnabledFor(priority)) {
+            final Message msg = new ObjectMessage(message);
+            forcedLog(FQCN, priority, msg, null);
+        }
+    }
+
+    public void log(final String fqcn, final Priority priority, final Object message, final Throwable t) {
+        if (isEnabledFor(priority)) {
+            final Message msg = new ObjectMessage(message);
+            forcedLog(fqcn, priority, msg, t);
+        }
+    }
+
+    private void maybeLog(final String fqcn, final org.apache.logging.log4j.Level level,
+            final Object message, final Throwable throwable) {
+        if (logger.isEnabled(level)) {
+            if (logger instanceof ExtendedLogger) {
+                ((ExtendedLogger) logger).logMessage(fqcn, level, null, new ObjectMessage(message), throwable);
+            } else {
+                logger.log(level, message, throwable);
+            }
+        }
+    }
+
+    private static class PrivateAdapter extends AbstractLoggerAdapter<Logger> {
+
+        @Override
+        protected Logger newLogger(final String name, final org.apache.logging.log4j.spi.LoggerContext context) {
+            return new Logger(context, name);
+        }
+
+        @Override
+        protected org.apache.logging.log4j.spi.LoggerContext getContext() {
+            return PrivateManager.getContext();
+        }
+    }
+
+    /**
+     * Private LogManager.
+     */
+    private static class PrivateManager extends org.apache.logging.log4j.LogManager {
+        private static final String FQCN = Category.class.getName();
+
+        public static LoggerContext getContext() {
+            return getContext(FQCN, false);
+        }
+
+        public static org.apache.logging.log4j.Logger getLogger(final String name) {
+            return getLogger(FQCN, name);
+        }
+    }
+
+    private boolean isEnabledFor(final org.apache.logging.log4j.Level level) {
+        return logger.isEnabled(level);
+    }
+
+    private ObjectRenderer get(Class clazz) {
+        ObjectRenderer renderer = null;
+        for(Class c = clazz; c != null; c = c.getSuperclass()) {
+            renderer = rendererMap.get(c);
+            if (renderer != null) {
+                return renderer;
+            }
+            renderer = searchInterfaces(c);
+            if (renderer != null) {
+                return renderer;
+            }
+        }
+        return null;
+    }
+
+    ObjectRenderer searchInterfaces(Class c) {
+        ObjectRenderer renderer = rendererMap.get(c);
+        if(renderer != null) {
+            return renderer;
+        } else {
+            Class[] ia = c.getInterfaces();
+            for (Class clazz : ia) {
+                renderer = searchInterfaces(clazz);
+                if (renderer != null) {
+                    return renderer;
+                }
+            }
+        }
+        return null;
+    }
+
+}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/ConsoleAppender.java
similarity index 64%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-1.2-api/src/src/main/java/org/apache/log4j/ConsoleAppender.java
index 13aaf9c..605fac7 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/ConsoleAppender.java
@@ -14,17 +14,39 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
+package org.apache.log4j;
 
-import org.junit.Test;
+import org.apache.log4j.spi.LoggingEvent;
 
-import static org.junit.Assert.*;
+/**
+ * Console-appender.
+ */
+public class ConsoleAppender extends AppenderSkeleton
+{
 
-public class ProcessIdUtilTest {
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void close()
+  {
+  }
 
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
-    }
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean requiresLayout()
+  {
+    return false;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected void append(final LoggingEvent theEvent)
+  {
+  }
+
 }
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/Layout.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/Layout.java
new file mode 100644
index 0000000..dbd2291
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/Layout.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j;
+
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.logging.log4j.util.Strings;
+
+/**
+ *
+ */
+public abstract class Layout {
+
+    public final static String LINE_SEP = Strings.LINE_SEPARATOR;
+
+    /** Note that the line.separator property can be looked up even by applets. */
+    public static final int LINE_SEP_LEN = Strings.LINE_SEPARATOR.length();
+
+    /**
+     * Implement this method to create your own layout format.
+     * @param event The LoggingEvent.
+     * @return The formatted LoggingEvent.
+     */
+    public abstract String format(LoggingEvent event);
+
+    /**
+     * Returns the content type output by this layout. The base class
+     * returns "text/plain".
+     * @return the type of content rendered by the Layout.
+     */
+    public String getContentType() {
+        return "text/plain";
+    }
+
+    /**
+     * Returns the header for the layout format. The base class returns
+     * <code>null</code>.
+     * @return The header.
+     */
+    public String getHeader() {
+        return null;
+    }
+
+    /**
+     * Returns the footer for the layout format. The base class returns
+     * <code>null</code>.
+     * @return The footer.
+     */
+    public String getFooter() {
+        return null;
+    }
+
+
+    /**
+     * If the layout handles the throwable object contained within
+     * {@link LoggingEvent}, then the layout should return
+     * {@code false}. Otherwise, if the layout ignores throwable
+     * object, then the layout should return {@code true}.
+     * If ignoresThrowable is true, the appender is responsible for
+     * rendering the throwable.
+     * <p>
+     * The <a href="/log4j/1.2/apidocs/org/apache/log4j/SimpleLayout.html">SimpleLayout</a>,
+     * <a href="/log4j/1.2/apidocs/org/apache/log4j/TTCCLayout.html">TTCCLayout</a>,
+     * <a href="/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html">PatternLayout</a>
+     * all return {@code true}. The
+     * <a href="/log4j/1.2/apidocs/org/apache/log4j/xml/XMLLayout.html">XMLLayout</a>
+     * returns {@code false}.
+     * </p>
+     *
+     * @return true if the Layout ignores Throwables.
+     *
+     * @since 0.8.4
+     */
+    public abstract boolean ignoresThrowable();
+}
+
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/Level.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/Level.java
new file mode 100644
index 0000000..af53154
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/Level.java
@@ -0,0 +1,252 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.util.Locale;
+
+import org.apache.logging.log4j.util.Strings;
+
+/**
+ * Defines the minimum set of levels recognized by the system, that is
+ * <code>OFF</code>, <code>FATAL</code>, <code>ERROR</code>,
+ * <code>WARN</code>, <code>INFO</code>, <code>DEBUG</code>
+ * and <code>ALL</code>.
+ * <p>
+ * The <code>Level</code> class may be subclassed to define a larger
+ * level set.
+ * </p>
+ */
+public class Level extends Priority implements Serializable {
+
+    /**
+     * TRACE level integer value.
+     *
+     * @since 1.2.12
+     */
+    public static final int TRACE_INT = 5000;
+
+    /**
+     * The <code>OFF</code> has the highest possible rank and is
+     * intended to turn off logging.
+     */
+    public static final Level OFF = new Level(OFF_INT, "OFF", 0);
+
+    /**
+     * The <code>FATAL</code> level designates very severe error
+     * events that will presumably lead the application to abort.
+     */
+    public static final Level FATAL = new Level(FATAL_INT, "FATAL", 0);
+
+    /**
+     * The <code>ERROR</code> level designates error events that
+     * might still allow the application to continue running.
+     */
+    public static final Level ERROR = new Level(ERROR_INT, "ERROR", 3);
+
+    /**
+     * The <code>WARN</code> level designates potentially harmful situations.
+     */
+    public static final Level WARN = new Level(WARN_INT, "WARN", 4);
+
+    /**
+     * The <code>INFO</code> level designates informational messages
+     * that highlight the progress of the application at coarse-grained
+     * level.
+     */
+    public static final Level INFO = new Level(INFO_INT, "INFO", 6);
+
+    /**
+     * The <code>DEBUG</code> Level designates fine-grained
+     * informational events that are most useful to debug an
+     * application.
+     */
+    public static final Level DEBUG = new Level(DEBUG_INT, "DEBUG", 7);
+
+    /**
+     * The <code>TRACE</code> Level designates finer-grained
+     * informational events than the <code>DEBUG</code> level.
+     */
+    public static final Level TRACE = new Level(TRACE_INT, "TRACE", 7);
+
+    /**
+     * The <code>ALL</code> has the lowest possible rank and is intended to
+     * turn on all logging.
+     */
+    public static final Level ALL = new Level(ALL_INT, "ALL", 7);
+
+    /**
+     * Serialization version id.
+     */
+    private static final long serialVersionUID = 3491141966387921974L;
+
+    /**
+     * Instantiate a Level object.
+     *
+     * @param level            The logging level.
+     * @param levelStr         The level name.
+     * @param syslogEquivalent The matching syslog level.
+     */
+    protected Level(final int level, final String levelStr, final int syslogEquivalent) {
+        super(level, levelStr, syslogEquivalent);
+    }
+
+
+    /**
+     * Convert the string passed as argument to a level. If the
+     * conversion fails, then this method returns {@link #DEBUG}.
+     *
+     * @param sArg The level name.
+     * @return The Level.
+     */
+    public static Level toLevel(final String sArg) {
+        return toLevel(sArg, Level.DEBUG);
+    }
+
+    /**
+     * Convert an integer passed as argument to a level. If the
+     * conversion fails, then this method returns {@link #DEBUG}.
+     *
+     * @param val The integer value of the Level.
+     * @return The Level.
+     */
+    public static Level toLevel(final int val) {
+        return toLevel(val, Level.DEBUG);
+    }
+
+    /**
+     * Convert an integer passed as argument to a level. If the
+     * conversion fails, then this method returns the specified default.
+     *
+     * @param val          The integer value of the Level.
+     * @param defaultLevel the default level if the integer doesn't match.
+     * @return The matching Level.
+     */
+    public static Level toLevel(final int val, final Level defaultLevel) {
+        switch (val) {
+            case ALL_INT:
+                return ALL;
+            case DEBUG_INT:
+                return Level.DEBUG;
+            case INFO_INT:
+                return Level.INFO;
+            case WARN_INT:
+                return Level.WARN;
+            case ERROR_INT:
+                return Level.ERROR;
+            case FATAL_INT:
+                return Level.FATAL;
+            case OFF_INT:
+                return OFF;
+            case TRACE_INT:
+                return Level.TRACE;
+            default:
+                return defaultLevel;
+        }
+    }
+
+    /**
+     * Convert the string passed as argument to a level. If the
+     * conversion fails, then this method returns the value of
+     * <code>defaultLevel</code>.
+     * @param sArg The name of the Level.
+     * @param defaultLevel The default Level to use.
+     * @return the matching Level.
+     */
+    public static Level toLevel(final String sArg, final Level defaultLevel) {
+        if (sArg == null) {
+            return defaultLevel;
+        }
+        final String s = sArg.toUpperCase(Locale.ROOT);
+        switch (s) {
+        case "ALL":
+            return Level.ALL;
+        case "DEBUG":
+            return Level.DEBUG;
+        case "INFO":
+            return Level.INFO;
+        case "WARN":
+            return Level.WARN;
+        case "ERROR":
+            return Level.ERROR;
+        case "FATAL":
+            return Level.FATAL;
+        case "OFF":
+            return Level.OFF;
+        case "TRACE":
+            return Level.TRACE;
+        default:
+            return defaultLevel;
+        }
+    }
+
+    /**
+     * Custom deserialization of Level.
+     *
+     * @param s serialization stream.
+     * @throws IOException            if IO exception.
+     * @throws ClassNotFoundException if class not found.
+     */
+    private void readObject(final ObjectInputStream s) throws IOException, ClassNotFoundException {
+        s.defaultReadObject();
+        level = s.readInt();
+        syslogEquivalent = s.readInt();
+        levelStr = s.readUTF();
+        if (levelStr == null) {
+            levelStr = Strings.EMPTY;
+        }
+    }
+
+    /**
+     * Serialize level.
+     *
+     * @param s serialization stream.
+     * @throws IOException if exception during serialization.
+     */
+    private void writeObject(final ObjectOutputStream s) throws IOException {
+        s.defaultWriteObject();
+        s.writeInt(level);
+        s.writeInt(syslogEquivalent);
+        s.writeUTF(levelStr);
+    }
+
+    /**
+     * Resolved deserialized level to one of the stock instances.
+     * May be overridden in classes derived from Level.
+     *
+     * @return resolved object.
+     * @throws ObjectStreamException if exception during resolution.
+     */
+    protected Object readResolve() throws ObjectStreamException {
+        //
+        //  if the deserialized object is exactly an instance of Level
+        //
+        if (getClass() == Level.class) {
+            return toLevel(level);
+        }
+        //
+        //   extension of Level can't substitute stock item
+        //
+        return this;
+    }
+
+}
+
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/LogManager.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/LogManager.java
new file mode 100644
index 0000000..c4966aa
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/LogManager.java
@@ -0,0 +1,251 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j;
+
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.log4j.helpers.NullEnumeration;
+import org.apache.log4j.legacy.core.ContextUtil;
+import org.apache.log4j.or.ObjectRenderer;
+import org.apache.log4j.or.RendererSupport;
+import org.apache.log4j.spi.HierarchyEventListener;
+import org.apache.log4j.spi.LoggerFactory;
+import org.apache.log4j.spi.LoggerRepository;
+import org.apache.log4j.spi.RepositorySelector;
+import org.apache.logging.log4j.spi.LoggerContext;
+import org.apache.logging.log4j.util.Strings;
+
+/**
+ *
+ */
+public final class LogManager {
+
+    /**
+     * @deprecated This variable is for internal use only. It will
+     * become package protected in future versions.
+     * */
+    @Deprecated
+    public static final String DEFAULT_CONFIGURATION_FILE = "log4j.properties";
+
+    /**
+     * @deprecated This variable is for internal use only. It will
+     * become private in future versions.
+     * */
+    @Deprecated
+    public static final String DEFAULT_CONFIGURATION_KEY = "log4j.configuration";
+
+    /**
+     * @deprecated This variable is for internal use only. It will
+     * become private in future versions.
+     * */
+    @Deprecated
+    public static final String CONFIGURATOR_CLASS_KEY = "log4j.configuratorClass";
+
+    /**
+     * @deprecated This variable is for internal use only. It will
+     * become private in future versions.
+     */
+    @Deprecated
+    public static final String DEFAULT_INIT_OVERRIDE_KEY = "log4j.defaultInitOverride";
+
+    static final String DEFAULT_XML_CONFIGURATION_FILE = "log4j.xml";
+
+    private static final LoggerRepository REPOSITORY = new Repository();
+
+    private static final boolean isLog4jCore;
+
+    static {
+        boolean core = false;
+        try {
+            if (Class.forName("org.apache.logging.log4j.core.LoggerContext") != null) {
+                core = true;
+            }
+        } catch (Exception ex) {
+            // Ignore the exception;
+        }
+        isLog4jCore = core;
+    }
+
+    private LogManager() {
+    }
+
+    public static Logger getRootLogger() {
+        return Category.getInstance(PrivateManager.getContext(), Strings.EMPTY);
+    }
+
+    public static Logger getLogger(final String name) {
+        return Category.getInstance(PrivateManager.getContext(), name);
+    }
+
+    public static Logger getLogger(final Class<?> clazz) {
+        return Category.getInstance(PrivateManager.getContext(), clazz.getName());
+    }
+
+    public static Logger getLogger(final String name, final LoggerFactory factory) {
+        return Category.getInstance(PrivateManager.getContext(), name);
+    }
+
+    public static Logger exists(final String name) {
+        final LoggerContext ctx = PrivateManager.getContext();
+        if (!ctx.hasLogger(name)) {
+            return null;
+        }
+        return Logger.getLogger(name);
+    }
+
+    @SuppressWarnings("rawtypes")
+    public static Enumeration getCurrentLoggers() {
+        return NullEnumeration.getInstance();
+    }
+
+    static void reconfigure() {
+        if (isLog4jCore) {
+            final LoggerContext ctx = PrivateManager.getContext();
+            ContextUtil.reconfigure(ctx);
+        }
+    }
+
+    /**
+     * No-op implementation.
+     */
+    public static void shutdown() {
+    }
+
+    /**
+     * No-op implementation.
+     */
+    public static void resetConfiguration() {
+    }
+
+    /**
+     * No-op implementation.
+     * @param selector The RepositorySelector.
+     * @param guard prevents calls at the incorrect time.
+     * @throws IllegalArgumentException if a parameter is invalid.
+     */
+    public static void setRepositorySelector(final RepositorySelector selector, final Object guard)
+        throws IllegalArgumentException {
+    }
+
+    public static LoggerRepository getLoggerRepository() {
+        return REPOSITORY;
+    }
+
+    /**
+     * The Repository.
+     */
+    private static class Repository implements LoggerRepository, RendererSupport {
+
+        private final Map<Class<?>, ObjectRenderer> rendererMap = new HashMap<>();
+
+        @Override
+        public Map<Class<?>, ObjectRenderer> getRendererMap() {
+            return rendererMap;
+        }
+
+        @Override
+        public void addHierarchyEventListener(final HierarchyEventListener listener) {
+
+        }
+
+        @Override
+        public boolean isDisabled(final int level) {
+            return false;
+        }
+
+        @Override
+        public void setThreshold(final Level level) {
+
+        }
+
+        @Override
+        public void setThreshold(final String val) {
+
+        }
+
+        @Override
+        public void emitNoAppenderWarning(final Category cat) {
+
+        }
+
+        @Override
+        public Level getThreshold() {
+            return Level.OFF;
+        }
+
+        @Override
+        public Logger getLogger(final String name) {
+            return Category.getInstance(PrivateManager.getContext(), name);
+        }
+
+        @Override
+        public Logger getLogger(final String name, final LoggerFactory factory) {
+            return Category.getInstance(PrivateManager.getContext(), name);
+        }
+
+        @Override
+        public Logger getRootLogger() {
+            return Category.getRoot(PrivateManager.getContext());
+        }
+
+        @Override
+        public Logger exists(final String name) {
+            return LogManager.exists(name);
+        }
+
+        @Override
+        public void shutdown() {
+        }
+
+        @Override
+        @SuppressWarnings("rawtypes")
+        public Enumeration getCurrentLoggers() {
+            return NullEnumeration.getInstance();
+        }
+
+        @Override
+        @SuppressWarnings("rawtypes")
+        public Enumeration getCurrentCategories() {
+            return NullEnumeration.getInstance();
+        }
+
+        @Override
+        public void fireAddAppenderEvent(final Category logger, final Appender appender) {
+        }
+
+        @Override
+        public void resetConfiguration() {
+        }
+    }
+
+    /**
+     * Internal LogManager.
+     */
+    private static class PrivateManager extends org.apache.logging.log4j.LogManager {
+        private static final String FQCN = LogManager.class.getName();
+
+        public static LoggerContext getContext() {
+            return getContext(FQCN, false);
+        }
+
+        public static org.apache.logging.log4j.Logger getLogger(final String name) {
+            return getLogger(FQCN, name);
+        }
+    }
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/Logger.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/Logger.java
new file mode 100644
index 0000000..fe1f26a
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/Logger.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j;
+
+
+import org.apache.log4j.spi.LoggerFactory;
+import org.apache.logging.log4j.spi.LoggerContext;
+
+/**
+ *
+ */
+public class Logger extends Category {
+
+    protected Logger(final String name) {
+        super(PrivateManager.getContext(), name);
+    }
+
+    Logger(final LoggerContext context, final String name) {
+        super(context, name);
+    }
+
+    public static Logger getLogger(final String name) {
+        return Category.getInstance(PrivateManager.getContext(), name);
+    }
+
+    public static Logger getLogger(final Class<?> clazz) {
+        return Category.getInstance(PrivateManager.getContext(), clazz);
+    }
+
+    public static Logger getRootLogger() {
+        return Category.getRoot(PrivateManager.getContext());
+    }
+
+    public static Logger getLogger(final String name, final LoggerFactory factory) {
+        return Category.getInstance(PrivateManager.getContext(), name, factory);
+    }
+
+    /**
+     * Internal Log Manager.
+     */
+    private static class PrivateManager extends org.apache.logging.log4j.LogManager {
+        private static final String FQCN = Logger.class.getName();
+
+        public static LoggerContext getContext() {
+            return getContext(FQCN, false);
+        }
+
+        public static org.apache.logging.log4j.Logger getLogger(final String name) {
+            return getLogger(FQCN, name);
+        }
+    }
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/MDC.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/MDC.java
new file mode 100644
index 0000000..ee7631a
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/MDC.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j;
+
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.apache.logging.log4j.ThreadContext;
+
+/**
+ * This class behaves just like Log4j's MDC would - and so can cause issues with the redeployment of web
+ * applications if the Objects stored in the threads Map cannot be garbage collected.
+ */
+public final class MDC {
+
+
+    private static ThreadLocal<Map<String, Object>> localMap =
+        new InheritableThreadLocal<Map<String, Object>>() {
+            @Override
+            protected Map<String, Object> initialValue() {
+                return new HashMap<>();
+            }
+
+            @Override
+            protected Map<String, Object> childValue(final Map<String, Object> parentValue) {
+                return parentValue == null ? new HashMap<String, Object>() : new HashMap<>(parentValue);
+            }
+        };
+
+    private MDC() {
+    }
+
+
+    public static void put(final String key, final String value) {
+        localMap.get().put(key, value);
+        ThreadContext.put(key, value);
+    }
+
+
+    public static void put(final String key, final Object value) {
+        localMap.get().put(key, value);
+        ThreadContext.put(key, value.toString());
+    }
+
+    public static Object get(final String key) {
+        return localMap.get().get(key);
+    }
+
+    public static void remove(final String key) {
+        localMap.get().remove(key);
+        ThreadContext.remove(key);
+    }
+
+    public static void clear() {
+        localMap.get().clear();
+        ThreadContext.clearMap();
+    }
+
+    public static Hashtable<String, Object> getContext() {
+        return new Hashtable<>(localMap.get());
+    }
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/NDC.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/NDC.java
new file mode 100644
index 0000000..a4e23dc
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/NDC.java
@@ -0,0 +1,207 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j;
+
+import java.util.Stack;
+
+/**
+ *
+ */
+public final class NDC {
+
+    private NDC() {
+    }
+
+    /**
+     * Clear any nested diagnostic information if any. This method is
+     * useful in cases where the same thread can be potentially used
+     * over and over in different unrelated contexts.
+     * <p>
+     * This method is equivalent to calling the {@link #setMaxDepth}
+     * method with a zero <code>maxDepth</code> argument.
+     * </p>
+     */
+    public static void clear() {
+        org.apache.logging.log4j.ThreadContext.clearStack();
+    }
+
+
+    /**
+     * Clone the diagnostic context for the current thread.
+     * <p>
+     * Internally a diagnostic context is represented as a stack.  A
+     * given thread can supply the stack (i.e. diagnostic context) to a
+     * child thread so that the child can inherit the parent thread's
+     * diagnostic context.
+     * </p>
+     * <p>
+     * The child thread uses the {@link #inherit inherit} method to
+     * inherit the parent's diagnostic context.
+     * </p>
+     * @return Stack A clone of the current thread's  diagnostic context.
+     */
+    @SuppressWarnings("rawtypes")
+    public static Stack cloneStack() {
+        final Stack<String> stack = new Stack<>();
+        for (final String element : org.apache.logging.log4j.ThreadContext.cloneStack().asList()) {
+            stack.push(element);
+        }
+        return stack;
+    }
+
+
+    /**
+     * Inherit the diagnostic context of another thread.
+     * <p>
+     * The parent thread can obtain a reference to its diagnostic
+     * context using the {@link #cloneStack} method.  It should
+     * communicate this information to its child so that it may inherit
+     * the parent's diagnostic context.
+     * </p>
+     * <p>
+     * The parent's diagnostic context is cloned before being
+     * inherited. In other words, once inherited, the two diagnostic
+     * contexts can be managed independently.
+     * </p>
+     * <p>
+     * In java, a child thread cannot obtain a reference to its
+     * parent, unless it is directly handed the reference. Consequently,
+     * there is no client-transparent way of inheriting diagnostic
+     * contexts. Do you know any solution to this problem?
+     * </p>
+     * @param stack The diagnostic context of the parent thread.
+     */
+    public static void inherit(final Stack<String> stack) {
+        org.apache.logging.log4j.ThreadContext.setStack(stack);
+    }
+
+
+    /**
+     * <strong style="color:#FF4040">Never use this method directly.</strong>
+     *
+     * @return The string value of the specified key.
+     */
+    public static String get() {
+        return org.apache.logging.log4j.ThreadContext.peek();
+    }
+
+    /**
+     * Get the current nesting depth of this diagnostic context.
+     * @return int The number of elements in the call stack.
+     * @see #setMaxDepth
+     */
+    public static int getDepth() {
+        return org.apache.logging.log4j.ThreadContext.getDepth();
+    }
+
+    /**
+     * Clients should call this method before leaving a diagnostic
+     * context.
+     * <p>
+     * The returned value is the value that was pushed last. If no
+     * context is available, then the empty string "" is returned.
+     * </p>
+     * @return String The innermost diagnostic context.
+     */
+    public static String pop() {
+        return org.apache.logging.log4j.ThreadContext.pop();
+    }
+
+    /**
+     * Looks at the last diagnostic context at the top of this NDC
+     * without removing it.
+     * <p>
+     * The returned value is the value that was pushed last. If no
+     * context is available, then the empty string "" is returned.
+     * </p>
+     * @return String The innermost diagnostic context.
+     */
+    public static String peek() {
+        return org.apache.logging.log4j.ThreadContext.peek();
+    }
+
+    /**
+     * Push new diagnostic context information for the current thread.
+     * <p>
+     * The contents of the <code>message</code> parameter is
+     * determined solely by the client.
+     * </p>
+     * @param message The new diagnostic context information.
+     */
+    public static void push(final String message) {
+        org.apache.logging.log4j.ThreadContext.push(message);
+    }
+
+    /**
+     * Remove the diagnostic context for this thread.
+     * <p>
+     * Each thread that created a diagnostic context by calling
+     * {@link #push} should call this method before exiting. Otherwise,
+     * the memory used by the <b>thread</b> cannot be reclaimed by the
+     * VM.
+     * </p>
+     * <p>
+     * As this is such an important problem in heavy duty systems and
+     * because it is difficult to always guarantee that the remove
+     * method is called before exiting a thread, this method has been
+     * augmented to lazily remove references to dead threads. In
+     * practice, this means that you can be a little sloppy and
+     * occasionally forget to call {@code remove} before exiting a
+     * thread. However, you must call <code>remove</code> sometime. If
+     * you never call it, then your application is sure to run out of
+     * memory.
+     * </p>
+     */
+    public static void remove() {
+        org.apache.logging.log4j.ThreadContext.removeStack();
+    }
+
+    /**
+     * Set maximum depth of this diagnostic context. If the current
+     * depth is smaller or equal to <code>maxDepth</code>, then no
+     * action is taken.
+     * <p>
+     * This method is a convenient alternative to multiple {@link
+     * #pop} calls. Moreover, it is often the case that at the end of
+     * complex call sequences, the depth of the NDC is
+     * unpredictable. The <code>setMaxDepth</code> method circumvents
+     * this problem.
+     * </p>
+     * <p>
+     * For example, the combination
+     * </p>
+     * <pre>
+     * void foo() {
+     * &nbsp;  int depth = NDC.getDepth();
+     *
+     * &nbsp;  ... complex sequence of calls
+     *
+     * &nbsp;  NDC.setMaxDepth(depth);
+     * }
+     * </pre>
+     * <p>
+     * ensures that between the entry and exit of foo the depth of the
+     * diagnostic stack is conserved.
+     * </p>
+     *
+     * @see #getDepth
+     * @param maxDepth The maximum depth of the stack.
+     */
+    public static void setMaxDepth(final int maxDepth) {
+        org.apache.logging.log4j.ThreadContext.trim(maxDepth);
+    }
+}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/PatternLayout.java
similarity index 66%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-1.2-api/src/src/main/java/org/apache/log4j/PatternLayout.java
index 13aaf9c..c2e1251 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/PatternLayout.java
@@ -14,17 +14,27 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
+package org.apache.log4j;
 
-import org.junit.Test;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.logging.log4j.util.Strings;
 
-import static org.junit.Assert.*;
+/**
+ *
+ */
+public class PatternLayout extends Layout {
 
-public class ProcessIdUtilTest {
+    public PatternLayout(final String pattern) {
 
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
+    }
+
+    @Override
+    public String format(final LoggingEvent event) {
+        return Strings.EMPTY;
+    }
+
+    @Override
+    public boolean ignoresThrowable() {
+        return true;
     }
 }
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/Priority.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/Priority.java
new file mode 100644
index 0000000..8f6eee9
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/Priority.java
@@ -0,0 +1,239 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j;
+
+/**
+ * <em style="color:#A44">Refrain from using this class directly, use
+ * the {@link Level} class instead.</em>
+ */
+public class Priority {
+
+    /**
+     * The <code>OFF</code> has the highest possible rank and is
+     * intended to turn off logging.
+     */
+    public static final int OFF_INT = Integer.MAX_VALUE;
+    /**
+     * The <code>FATAL</code> level designates very severe error
+     * events that will presumably lead the application to abort.
+     */
+    public static final int FATAL_INT = 50000;
+    /**
+     * The <code>ERROR</code> level designates error events that
+     * might still allow the application to continue running.
+     */
+    public static final int ERROR_INT = 40000;
+    /**
+     * The <code>WARN</code> level designates potentially harmful situations.
+     */
+    public static final int WARN_INT = 30000;
+    /**
+     * The <code>INFO</code> level designates informational messages
+     * that highlight the progress of the application at coarse-grained
+     * level.
+     */
+    public static final int INFO_INT = 20000;
+    /**
+     * The <code>DEBUG</code> Level designates fine-grained
+     * informational events that are most useful to debug an
+     * application.
+     */
+    public static final int DEBUG_INT = 10000;
+    //public final static int FINE_INT = DEBUG_INT;
+    /**
+     * The <code>ALL</code> has the lowest possible rank and is intended to
+     * turn on all logging.
+     */
+    public static final int ALL_INT = Integer.MIN_VALUE;
+
+    /**
+     * @deprecated Use {@link Level#FATAL} instead.
+     */
+    @Deprecated
+    public static final Priority FATAL = new Level(FATAL_INT, "FATAL", 0);
+
+    /**
+     * @deprecated Use {@link Level#ERROR} instead.
+     */
+    @Deprecated
+    public static final Priority ERROR = new Level(ERROR_INT, "ERROR", 3);
+
+    /**
+     * @deprecated Use {@link Level#WARN} instead.
+     */
+    @Deprecated
+    public static final Priority WARN = new Level(WARN_INT, "WARN", 4);
+
+    /**
+     * @deprecated Use {@link Level#INFO} instead.
+     */
+    @Deprecated
+    public static final Priority INFO = new Level(INFO_INT, "INFO", 6);
+
+    /**
+     * @deprecated Use {@link Level#DEBUG} instead.
+     */
+    @Deprecated
+    public static final Priority DEBUG = new Level(DEBUG_INT, "DEBUG", 7);
+
+    /*
+     * These variables should be private but were not in Log4j 1.2 so are left the same way here.
+     */
+    transient int level;
+    transient String levelStr;
+    transient int syslogEquivalent;
+
+    /**
+     * Default constructor for deserialization.
+     */
+    protected Priority() {
+        level = DEBUG_INT;
+        levelStr = "DEBUG";
+        syslogEquivalent = 7;
+    }
+
+    /**
+     * Instantiate a level object.
+     * @param level The level value.
+     * @param levelStr The level name.
+     * @param syslogEquivalent The equivalent syslog value.
+     */
+    protected Priority(final int level, final String levelStr, final int syslogEquivalent) {
+        this.level = level;
+        this.levelStr = levelStr;
+        this.syslogEquivalent = syslogEquivalent;
+    }
+
+    /**
+     * Two priorities are equal if their level fields are equal.
+     * @param o The Object to check.
+     * @return true if the objects are equal, false otherwise.
+     *
+     * @since 1.2
+     */
+    @Override
+    public boolean equals(final Object o) {
+        if (o instanceof Priority) {
+            final Priority r = (Priority) o;
+            return this.level == r.level;
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return this.level;
+    }
+
+    /**
+     * Returns the syslog equivalent of this priority as an integer.
+     * @return The equivalent syslog value.
+     */
+    public
+    final int getSyslogEquivalent() {
+        return syslogEquivalent;
+    }
+
+
+    /**
+     * Returns {@code true} if this level has a higher or equal
+     * level than the level passed as argument, {@code false}
+     * otherwise.
+     * <p>
+     * You should think twice before overriding the default
+     * implementation of <code>isGreaterOrEqual</code> method.
+     * </p>
+     * @param r The Priority to check.
+     * @return true if the current level is greater or equal to the specified Priority.
+     */
+    public boolean isGreaterOrEqual(final Priority r) {
+        return level >= r.level;
+    }
+
+    /**
+     * Returns all possible priorities as an array of Level objects in
+     * descending order.
+     * @return An array of all possible Priorities.
+     *
+     * @deprecated This method will be removed with no replacement.
+     */
+    @Deprecated
+    public static Priority[] getAllPossiblePriorities() {
+        return new Priority[]{Priority.FATAL, Priority.ERROR, Level.WARN,
+            Priority.INFO, Priority.DEBUG};
+    }
+
+
+    /**
+     * Returns the string representation of this priority.
+     * @return The name of the Priority.
+     */
+    @Override
+    public final String toString() {
+        return levelStr;
+    }
+
+    /**
+     * Returns the integer representation of this level.
+     * @return The integer value of this level.
+     */
+    public final int toInt() {
+        return level;
+    }
+
+    /**
+     * @param sArg The name of the Priority.
+     * @return The Priority matching the name.
+     * @deprecated Please use the {@link Level#toLevel(String)} method instead.
+     */
+    @Deprecated
+    public static Priority toPriority(final String sArg) {
+        return Level.toLevel(sArg);
+    }
+
+    /**
+     * @param val The value of the Priority.
+     * @return The Priority matching the value.
+     * @deprecated Please use the {@link Level#toLevel(int)} method instead.
+     */
+    @Deprecated
+    public static Priority toPriority(final int val) {
+        return toPriority(val, Priority.DEBUG);
+    }
+
+    /**
+     * @param val The value of the Priority.
+     * @param defaultPriority The default Priority to use if the value is invalid.
+     * @return The Priority matching the value or the default Priority if no match is found.
+     * @deprecated Please use the {@link Level#toLevel(int, Level)} method instead.
+     */
+    @Deprecated
+    public static Priority toPriority(final int val, final Priority defaultPriority) {
+        return Level.toLevel(val, (Level) defaultPriority);
+    }
+
+    /**
+     * @param sArg The name of the Priority.
+     * @param defaultPriority The default Priority to use if the name is not found.
+     * @return The Priority matching the name or the default Priority if no match is found.
+     * @deprecated Please use the {@link Level#toLevel(String, Level)} method instead.
+     */
+    @Deprecated
+    public static Priority toPriority(final String sArg, final Priority defaultPriority) {
+        return Level.toLevel(sArg, (Level) defaultPriority);
+    }
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/PropertyConfigurator.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/PropertyConfigurator.java
new file mode 100644
index 0000000..0fe1fe0
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/PropertyConfigurator.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Properties;
+
+import org.apache.log4j.spi.LoggerRepository;
+
+/**
+ * A configurator for properties.
+ */
+public class PropertyConfigurator {
+
+    /**
+     * Read configuration options from configuration file.
+     *
+     * @param configFileName The configuration file
+     * @param hierarchy The hierarchy
+     */
+    public void doConfigure(final String configFileName, final LoggerRepository hierarchy) {
+
+    }
+
+    /**
+     * Read configuration options from <code>properties</code>.
+     *
+     * See {@link #doConfigure(String, LoggerRepository)} for the expected format.
+     *
+     * @param properties The properties
+     * @param hierarchy The hierarchy
+     */
+    public void doConfigure(final Properties properties, final LoggerRepository hierarchy) {
+    }
+
+    /**
+     * Read configuration options from an InputStream.
+     *
+     * @param inputStream The input stream
+     * @param hierarchy The hierarchy
+     */
+    public void doConfigure(final InputStream inputStream, final LoggerRepository hierarchy) {
+    }
+
+    /**
+     * Read configuration options from url <code>configURL</code>.
+     *
+     * @param configURL The configuration URL
+     * @param hierarchy The hierarchy
+     */
+    public void doConfigure(final URL configURL, final LoggerRepository hierarchy) {
+    }
+
+    /**
+     * Read configuration options from configuration file.
+     *
+     * @param configFileName The configuration file.
+     */
+    public static void configure(final String configFileName) {
+    }
+
+    /**
+     * Read configuration options from url <code>configURL</code>.
+     *
+     * @param configURL The configuration URL
+     */
+    public static void configure(final URL configURL) {
+    }
+
+    /**
+     * Reads configuration options from an InputStream.
+     *
+     * @param inputStream The input stream
+     */
+    public static void configure(final InputStream inputStream) {
+    }
+
+    /**
+     * Read configuration options from <code>properties</code>.
+     *
+     * See {@link #doConfigure(String, LoggerRepository)} for the expected format.
+     *
+     * @param properties The properties
+     */
+    public static void configure(final Properties properties) {
+    }
+
+    /**
+     * Like {@link #configureAndWatch(String, long)} except that the
+     * default delay as defined by FileWatchdog.DEFAULT_DELAY is
+     * used.
+     *
+     * @param configFilename A file in key=value format.
+     */
+    public static void configureAndWatch(final String configFilename) {
+    }
+
+    /**
+     * Read the configuration file <code>configFilename</code> if it
+     * exists. Moreover, a thread will be created that will periodically
+     * check if <code>configFilename</code> has been created or
+     * modified. The period is determined by the <code>delay</code>
+     * argument. If a change or file creation is detected, then
+     * <code>configFilename</code> is read to configure log4j.
+     *
+     * @param configFilename A file in key=value format.
+     * @param delay The delay in milliseconds to wait between each check.
+     */
+    public static void configureAndWatch(final String configFilename, final long delay) {
+    }
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/RenderedMessage.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/RenderedMessage.java
new file mode 100644
index 0000000..422a565
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/RenderedMessage.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j;
+
+import org.apache.log4j.or.ObjectRenderer;
+import org.apache.logging.log4j.message.Message;
+
+/**
+ * Implements object rendering for Log4j 1.x compatibility.
+ */
+public class RenderedMessage implements Message {
+
+    private final ObjectRenderer renderer;
+    private final Object object;
+    private String rendered = null;
+
+    public RenderedMessage(ObjectRenderer renderer, Object object) {
+        this.renderer = renderer;
+        this.object = object;
+    }
+
+
+    @Override
+    public String getFormattedMessage() {
+        if (rendered == null) {
+            rendered = renderer.doRender(object);
+        }
+
+        return rendered;
+    }
+
+    @Override
+    public String getFormat() {
+        return getFormattedMessage();
+    }
+
+    @Override
+    public Object[] getParameters() {
+        return null;
+    }
+
+    @Override
+    public Throwable getThrowable() {
+        return null;
+    }
+}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/SimpleLayout.java
similarity index 65%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-1.2-api/src/src/main/java/org/apache/log4j/SimpleLayout.java
index 13aaf9c..c77b9be 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/SimpleLayout.java
@@ -14,17 +14,33 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
+package org.apache.log4j;
 
-import org.junit.Test;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.logging.log4j.util.Strings;
 
-import static org.junit.Assert.*;
+/**
+ * Simple-layout.
+ */
+public class SimpleLayout extends Layout
+{
 
-public class ProcessIdUtilTest {
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String format(final LoggingEvent theEvent)
+  {
+    return Strings.EMPTY;
+  }
 
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
-    }
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean ignoresThrowable()
+  {
+    return true;
+  }
+
 }
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/WriterAppender.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/WriterAppender.java
new file mode 100644
index 0000000..f026bfa
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/WriterAppender.java
@@ -0,0 +1,378 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j;
+
+import org.apache.log4j.helpers.QuietWriter;
+import org.apache.log4j.spi.ErrorHandler;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.logging.log4j.status.StatusLogger;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+
+
+/**
+ * WriterAppender appends log events to a {@link Writer} or an
+ * {@link OutputStream} depending on the user's choice.
+ */
+public class WriterAppender extends AppenderSkeleton {
+    private static final org.apache.logging.log4j.Logger LOGGER = StatusLogger.getLogger();
+
+    /**
+     * Immediate flush means that the underlying writer or output stream
+     * will be flushed at the end of each append operation unless shouldFlush()
+     * is overridden. Immediate
+     * flush is slower but ensures that each append request is actually
+     * written. If <code>immediateFlush</code> is set to
+     * <code>false</code>, then there is a good chance that the last few
+     * logs events are not actually written to persistent media if and
+     * when the application crashes.
+     *
+     * <p>The <code>immediateFlush</code> variable is set to
+     * <code>true</code> by default.
+     */
+    protected boolean immediateFlush = true;
+
+    /**
+     * The encoding to use when writing.  <p>The
+     * <code>encoding</code> variable is set to <code>null</null> by
+     * default which results in the utilization of the system's default
+     * encoding.
+     */
+    protected String encoding;
+
+    /**
+     * This is the {@link QuietWriter quietWriter} where we will write
+     * to.
+     */
+    protected QuietWriter qw;
+
+
+    /**
+     * This default constructor does nothing.
+     */
+    public WriterAppender() {
+    }
+
+    /**
+     * Instantiate a WriterAppender and set the output destination to a
+     * new {@link OutputStreamWriter} initialized with <code>os</code>
+     * as its {@link OutputStream}.
+     */
+    public WriterAppender(Layout layout, OutputStream os) {
+        this(layout, new OutputStreamWriter(os));
+    }
+
+    /**
+     * Instantiate a WriterAppender and set the output destination to
+     * <code>writer</code>.
+     *
+     * <p>The <code>writer</code> must have been previously opened by
+     * the user.
+     */
+    public WriterAppender(Layout layout, Writer writer) {
+        this.layout = layout;
+        this.setWriter(writer);
+    }
+
+    /**
+     * Returns value of the <b>ImmediateFlush</b> option.
+     */
+    public boolean getImmediateFlush() {
+        return immediateFlush;
+    }
+
+    /**
+     * If the <b>ImmediateFlush</b> option is set to
+     * <code>true</code>, the appender will flush at the end of each
+     * write. This is the default behavior. If the option is set to
+     * <code>false</code>, then the underlying stream can defer writing
+     * to physical medium to a later time.
+     *
+     * <p>Avoiding the flush operation at the end of each append results in
+     * a performance gain of 10 to 20 percent. However, there is safety
+     * tradeoff involved in skipping flushing. Indeed, when flushing is
+     * skipped, then it is likely that the last few log events will not
+     * be recorded on disk when the application exits. This is a high
+     * price to pay even for a 20% performance gain.
+     */
+    public void setImmediateFlush(boolean value) {
+        immediateFlush = value;
+    }
+
+    /**
+     * Does nothing.
+     */
+    public void activateOptions() {
+    }
+
+
+    /**
+     * This method is called by the {@link AppenderSkeleton#doAppend}
+     * method.
+     *
+     * <p>If the output stream exists and is writable then write a log
+     * statement to the output stream. Otherwise, write a single warning
+     * message to <code>System.err</code>.
+     *
+     * <p>The format of the output will depend on this appender's
+     * layout.
+     */
+    public void append(LoggingEvent event) {
+
+        // Reminder: the nesting of calls is:
+        //
+        //    doAppend()
+        //      - check threshold
+        //      - filter
+        //      - append();
+        //        - checkEntryConditions();
+        //        - subAppend();
+
+        if (!checkEntryConditions()) {
+            return;
+        }
+        subAppend(event);
+    }
+
+    /**
+     * This method determines if there is a sense in attempting to append.
+     *
+     * <p>It checks whether there is a set output target and also if
+     * there is a set layout. If these checks fail, then the boolean
+     * value <code>false</code> is returned.
+     */
+    protected boolean checkEntryConditions() {
+        if (this.closed) {
+            LOGGER.warn("Not allowed to write to a closed appender.");
+            return false;
+        }
+
+        if (this.qw == null) {
+            errorHandler.error("No output stream or file set for the appender named [" + name + "].");
+            return false;
+        }
+
+        if (this.layout == null) {
+            errorHandler.error("No layout set for the appender named [" + name + "].");
+            return false;
+        }
+        return true;
+    }
+
+
+    /**
+     * Close this appender instance. The underlying stream or writer is
+     * also closed.
+     *
+     * <p>Closed appenders cannot be reused.
+     *
+     * @see #setWriter
+     * @since 0.8.4
+     */
+    public
+    synchronized void close() {
+        if (this.closed) {
+            return;
+        }
+        this.closed = true;
+        writeFooter();
+        reset();
+    }
+
+    /**
+     * Close the underlying {@link Writer}.
+     */
+    protected void closeWriter() {
+        if (qw != null) {
+            try {
+                qw.close();
+            } catch (IOException e) {
+                if (e instanceof InterruptedIOException) {
+                    Thread.currentThread().interrupt();
+                }
+                // There is do need to invoke an error handler at this late
+                // stage.
+                LOGGER.error("Could not close " + qw, e);
+            }
+        }
+    }
+
+    /**
+     * Returns an OutputStreamWriter when passed an OutputStream.  The
+     * encoding used will depend on the value of the
+     * <code>encoding</code> property.  If the encoding value is
+     * specified incorrectly the writer will be opened using the default
+     * system encoding (an error message will be printed to the LOGGER.
+     */
+    protected OutputStreamWriter createWriter(OutputStream os) {
+        OutputStreamWriter retval = null;
+
+        String enc = getEncoding();
+        if (enc != null) {
+            try {
+                retval = new OutputStreamWriter(os, enc);
+            } catch (IOException e) {
+                if (e instanceof InterruptedIOException) {
+                    Thread.currentThread().interrupt();
+                }
+                LOGGER.warn("Error initializing output writer.");
+                LOGGER.warn("Unsupported encoding?");
+            }
+        }
+        if (retval == null) {
+            retval = new OutputStreamWriter(os);
+        }
+        return retval;
+    }
+
+    public String getEncoding() {
+        return encoding;
+    }
+
+    public void setEncoding(String value) {
+        encoding = value;
+    }
+
+
+    /**
+     * Set the {@link ErrorHandler} for this WriterAppender and also the
+     * underlying {@link QuietWriter} if any.
+     */
+    public synchronized void setErrorHandler(ErrorHandler eh) {
+        if (eh == null) {
+            LOGGER.warn("You have tried to set a null error-handler.");
+        } else {
+            this.errorHandler = eh;
+            if (this.qw != null) {
+                this.qw.setErrorHandler(eh);
+            }
+        }
+    }
+
+    /**
+     * <p>Sets the Writer where the log output will go. The
+     * specified Writer must be opened by the user and be
+     * writable.
+     *
+     * <p>The <code>java.io.Writer</code> will be closed when the
+     * appender instance is closed.
+     *
+     *
+     * <p><b>WARNING:</b> Logging to an unopened Writer will fail.
+     * <p>
+     *
+     * @param writer An already opened Writer.
+     */
+    public synchronized void setWriter(Writer writer) {
+        reset();
+        this.qw = new QuietWriter(writer, errorHandler);
+        //this.tp = new TracerPrintWriter(qw);
+        writeHeader();
+    }
+
+
+    /**
+     * Actual writing occurs here.
+     *
+     * <p>Most subclasses of <code>WriterAppender</code> will need to
+     * override this method.
+     *
+     * @since 0.9.0
+     */
+    protected void subAppend(LoggingEvent event) {
+        this.qw.write(this.layout.format(event));
+
+        if (layout.ignoresThrowable()) {
+            String[] s = event.getThrowableStrRep();
+            if (s != null) {
+                int len = s.length;
+                for (int i = 0; i < len; i++) {
+                    this.qw.write(s[i]);
+                    this.qw.write(Layout.LINE_SEP);
+                }
+            }
+        }
+
+        if (shouldFlush(event)) {
+            this.qw.flush();
+        }
+    }
+
+
+    /**
+     * The WriterAppender requires a layout. Hence, this method returns
+     * <code>true</code>.
+     */
+    public boolean requiresLayout() {
+        return true;
+    }
+
+    /**
+     * Clear internal references to the writer and other variables.
+     * <p>
+     * Subclasses can override this method for an alternate closing
+     * behavior.
+     */
+    protected void reset() {
+        closeWriter();
+        this.qw = null;
+        //this.tp = null;
+    }
+
+
+    /**
+     * Write a footer as produced by the embedded layout's {@link
+     * Layout#getFooter} method.
+     */
+    protected void writeFooter() {
+        if (layout != null) {
+            String f = layout.getFooter();
+            if (f != null && this.qw != null) {
+                this.qw.write(f);
+                this.qw.flush();
+            }
+        }
+    }
+
+    /**
+     * Write a header as produced by the embedded layout's {@link
+     * Layout#getHeader} method.
+     */
+    protected void writeHeader() {
+        if (layout != null) {
+            String h = layout.getHeader();
+            if (h != null && this.qw != null) {
+                this.qw.write(h);
+            }
+        }
+    }
+
+    /**
+     * Determines whether the writer should be flushed after
+     * this event is written.
+     *
+     * @since 1.2.16
+     */
+    protected boolean shouldFlush(final LoggingEvent event) {
+        return immediateFlush;
+    }
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/bridge/AppenderAdapter.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/bridge/AppenderAdapter.java
new file mode 100644
index 0000000..f2dd2c1
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/bridge/AppenderAdapter.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.bridge;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Appender;
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.appender.AbstractAppender;
+import org.apache.logging.log4j.core.config.Property;
+import org.apache.logging.log4j.core.filter.CompositeFilter;
+
+/**
+ * Binds a Log4j 1.x Appender to Log4j 2.
+ */
+public class AppenderAdapter {
+
+    private final Appender appender;
+    private final Adapter adapter;
+
+    /**
+     * Constructor.
+     */
+    public AppenderAdapter(Appender appender) {
+        this.appender = appender;
+        org.apache.logging.log4j.core.Filter appenderFilter = null;
+        if (appender.getFilter() != null) {
+            if (appender.getFilter().getNext() != null) {
+                org.apache.log4j.spi.Filter filter = appender.getFilter();
+                List<org.apache.logging.log4j.core.Filter> filters = new ArrayList<>();
+                while (filter != null) {
+                    filters.add(new FilterAdapter(filter));
+                    filter = filter.getNext();
+                }
+                appenderFilter = CompositeFilter.createFilters(filters.toArray(new Filter[0]));
+            } else {
+                appenderFilter = new FilterAdapter(appender.getFilter());
+            }
+        }
+        this.adapter = new Adapter(appender.getName(), appenderFilter, null, true, null);
+    }
+
+    public Adapter getAdapter() {
+        return adapter;
+    }
+
+    public class Adapter extends AbstractAppender {
+
+        protected Adapter(final String name, final Filter filter, final Layout<? extends Serializable> layout,
+            final boolean ignoreExceptions, final Property[] properties) {
+            super(name, filter, layout, ignoreExceptions, properties);
+        }
+
+        @Override
+        public void append(LogEvent event) {
+            appender.doAppend(new LogEventAdapter(event));
+        }
+
+        @Override
+        public void stop() {
+            appender.close();
+        }
+
+        public Appender getAppender() {
+            return appender;
+        }
+    }
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/bridge/AppenderWrapper.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/bridge/AppenderWrapper.java
new file mode 100644
index 0000000..f06f909
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/bridge/AppenderWrapper.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.bridge;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.Layout;
+import org.apache.log4j.spi.ErrorHandler;
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.spi.LoggingEvent;
+
+/**
+ * Holds a Log4j 2 Appender in an empty Log4j 1 Appender so it can be extracted when constructing the configuration.
+ * Allows a Log4j 1 Appender to reference a Log4j 2 Appender.
+ */
+public class AppenderWrapper implements Appender {
+
+    private final org.apache.logging.log4j.core.Appender appender;
+
+    public AppenderWrapper(org.apache.logging.log4j.core.Appender appender) {
+        this.appender = appender;
+    }
+
+    public org.apache.logging.log4j.core.Appender getAppender() {
+        return appender;
+    }
+
+    @Override
+    public void addFilter(Filter newFilter) {
+    }
+
+    @Override
+    public Filter getFilter() {
+        return null;
+    }
+
+    @Override
+    public void clearFilters() {
+
+    }
+
+    @Override
+    public void close() {
+        // Not supported with Log4j 2.
+    }
+
+    @Override
+    public void doAppend(LoggingEvent event) {
+        if (event instanceof LogEventAdapter) {
+            appender.append(((LogEventAdapter) event).getEvent());
+        }
+    }
+
+    @Override
+    public String getName() {
+        return appender.getName();
+    }
+
+    @Override
+    public void setErrorHandler(ErrorHandler errorHandler) {
+        appender.setHandler(new ErrorHandlerAdapter(errorHandler));
+    }
+
+    @Override
+    public ErrorHandler getErrorHandler() {
+        return ((ErrorHandlerAdapter)appender.getHandler()).getHandler();
+    }
+
+    @Override
+    public void setLayout(Layout layout) {
+        // Log4j 2 doesn't support this.
+    }
+
+    @Override
+    public Layout getLayout() {
+        return new LayoutWrapper(appender.getLayout());
+    }
+
+    @Override
+    public void setName(String name) {
+        // Log4j 2 doesn't support this.
+    }
+
+    @Override
+    public boolean requiresLayout() {
+        return false;
+    }
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/bridge/ErrorHandlerAdapter.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/bridge/ErrorHandlerAdapter.java
new file mode 100644
index 0000000..1f166a2
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/bridge/ErrorHandlerAdapter.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.bridge;
+
+import org.apache.log4j.spi.ErrorHandler;
+import org.apache.logging.log4j.core.LogEvent;
+
+/**
+ * Makes a Log4j 1 ErrorHandler usable by a Log4j 2 Appender.
+ */
+public class ErrorHandlerAdapter implements org.apache.logging.log4j.core.ErrorHandler {
+
+    private final ErrorHandler errorHandler;
+
+    public ErrorHandlerAdapter(ErrorHandler errorHandler) {
+        this.errorHandler = errorHandler;
+    }
+
+    public ErrorHandler getHandler() {
+        return errorHandler;
+    }
+
+    @Override
+    public void error(String msg) {
+        errorHandler.error(msg);
+    }
+
+    @Override
+    public void error(String msg, Throwable t) {
+        if (t instanceof Exception) {
+            errorHandler.error(msg, (Exception) t, 0);
+        } else {
+            errorHandler.error(msg);
+        }
+    }
+
+    @Override
+    public void error(String msg, LogEvent event, Throwable t) {
+        if (t == null || t instanceof Exception) {
+            errorHandler.error(msg, (Exception) t, 0, new LogEventAdapter(event));
+        } else {
+            errorHandler.error(msg);
+        }
+    }
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/bridge/FilterAdapter.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/bridge/FilterAdapter.java
new file mode 100644
index 0000000..2dff272
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/bridge/FilterAdapter.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.bridge;
+
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.filter.AbstractFilter;
+
+/**
+ * Binds a Log4j 1.x Filter with Log4j 2.
+ */
+public class FilterAdapter extends AbstractFilter {
+
+    private final Filter filter;
+
+    public FilterAdapter(Filter filter) {
+        this.filter = filter;
+    }
+
+    @Override
+    public void start() {
+        filter.activateOptions();
+    }
+
+    @Override
+    public Result filter(LogEvent event) {
+        LoggingEvent loggingEvent = new LogEventAdapter(event);
+        Filter next = filter;
+        while (next != null) {
+            switch (filter.decide(loggingEvent)) {
+                case Filter.ACCEPT:
+                    return Result.ACCEPT;
+                case Filter.DENY:
+                    return Result.DENY;
+                default:
+            }
+            next = filter.getNext();
+        }
+        return Result.NEUTRAL;
+    }
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/bridge/FilterWrapper.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/bridge/FilterWrapper.java
new file mode 100644
index 0000000..b2855cd
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/bridge/FilterWrapper.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.bridge;
+
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.spi.LoggingEvent;
+
+/**
+ * This acts as a container for Log4j 2 Filters to be attached to Log4j 1 components. However, the Log4j 2
+ * Filters will always be called directly so this class just acts as a container.
+ */
+public class FilterWrapper extends Filter {
+
+    private final org.apache.logging.log4j.core.Filter filter;
+
+    public FilterWrapper(org.apache.logging.log4j.core.Filter filter) {
+        this.filter = filter;
+    }
+
+    public org.apache.logging.log4j.core.Filter getFilter() {
+        return filter;
+    }
+
+    /**
+     * This method is never called.
+     * @param event The LoggingEvent to decide upon.
+     * @return 0
+     */
+    @Override
+    public int decide(LoggingEvent event) {
+        return 0;
+    }
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/bridge/LayoutAdapter.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/bridge/LayoutAdapter.java
new file mode 100644
index 0000000..5494c92
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/bridge/LayoutAdapter.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.bridge;
+
+import org.apache.log4j.Layout;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.layout.ByteBufferDestination;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Class Description goes here.
+ */
+public class LayoutAdapter implements org.apache.logging.log4j.core.Layout<String> {
+    private Layout layout;
+
+    public LayoutAdapter(Layout layout) {
+        this.layout = layout;
+    }
+
+
+    @Override
+    public byte[] getFooter() {
+        return layout.getFooter() == null ? null : layout.getFooter().getBytes();
+    }
+
+    @Override
+    public byte[] getHeader() {
+        return layout.getHeader() == null ? null : layout.getHeader().getBytes();
+    }
+
+    @Override
+    public byte[] toByteArray(LogEvent event) {
+        String result = layout.format(new LogEventAdapter(event));
+        return result == null ? null : result.getBytes();
+    }
+
+    @Override
+    public String toSerializable(LogEvent event) {
+        return layout.format(new LogEventAdapter(event));
+    }
+
+    @Override
+    public String getContentType() {
+        return layout.getContentType();
+    }
+
+    @Override
+    public Map<String, String> getContentFormat() {
+        return new HashMap<>();
+    }
+
+    @Override
+    public void encode(LogEvent event, ByteBufferDestination destination) {
+        final byte[] data = toByteArray(event);
+        destination.writeBytes(data, 0, data.length);
+    }
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/bridge/LayoutWrapper.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/bridge/LayoutWrapper.java
new file mode 100644
index 0000000..fc1e72f
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/bridge/LayoutWrapper.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.bridge;
+
+
+import org.apache.log4j.Layout;
+import org.apache.log4j.spi.LoggingEvent;
+
+
+/**
+ * Bridge between the Log4j 1 Layout and a Log4j 2 Layout.
+ */
+public class LayoutWrapper extends Layout {
+
+    private final org.apache.logging.log4j.core.Layout<?> layout;
+
+    public LayoutWrapper(org.apache.logging.log4j.core.Layout<?> layout) {
+        this.layout = layout;
+    }
+
+    @Override
+    public String format(LoggingEvent event) {
+        return layout.toSerializable(((LogEventAdapter)event).getEvent()).toString();
+    }
+
+    @Override
+    public boolean ignoresThrowable() {
+        return false;
+    }
+
+    public org.apache.logging.log4j.core.Layout<?> getLayout() {
+        return this.layout;
+    }
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/bridge/LogEventAdapter.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/bridge/LogEventAdapter.java
new file mode 100644
index 0000000..9ad4d27
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/bridge/LogEventAdapter.java
@@ -0,0 +1,217 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.bridge;
+
+import java.lang.reflect.Method;
+
+import org.apache.log4j.Category;
+import org.apache.log4j.Level;
+import org.apache.log4j.spi.LocationInfo;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.log4j.spi.ThrowableInformation;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.util.Loader;
+import org.apache.logging.log4j.core.util.Throwables;
+import org.apache.logging.log4j.spi.StandardLevel;
+import org.apache.logging.log4j.status.StatusLogger;
+
+/**
+ * Converts a Log4j 2 LogEvent into the components needed by a Log4j 1.x LoggingEvent.
+ * This class requires Log4j 2.
+ */
+public class LogEventAdapter extends LoggingEvent {
+
+    private static final long JVM_START_TIME = initStartTime();
+
+    private final LogEvent event;
+
+    public LogEventAdapter(LogEvent event) {
+        this.event = event;
+    }
+
+    public LogEvent getEvent() {
+        return this.event;
+    }
+
+    /**
+     Set the location information for this logging event. The collected
+     information is cached for future use.
+     */
+    @Override
+    public LocationInfo getLocationInformation() {
+        return new LocationInfo(event.getSource());
+    }
+
+    /**
+     * Return the level of this event. Use this form instead of directly
+     * accessing the <code>level</code> field.  */
+    @Override
+    public Level getLevel() {
+        switch (StandardLevel.getStandardLevel(event.getLevel().intLevel())) {
+            case TRACE:
+                return Level.TRACE;
+            case DEBUG:
+                return Level.DEBUG;
+            case INFO:
+                return Level.INFO;
+            case WARN:
+                return Level.WARN;
+            case ERROR:
+                return Level.ERROR;
+            case FATAL:
+                return Level.FATAL;
+            case OFF:
+                return Level.OFF;
+            case ALL:
+                return Level.ALL;
+            default:
+                return Level.ERROR;
+        }
+    }
+
+    /**
+     * Return the name of the logger. Use this form instead of directly
+     * accessing the <code>categoryName</code> field.
+     */
+    @Override
+    public String getLoggerName() {
+        return event.getLoggerName();
+    }
+
+    /**
+     * Gets the logger of the event.
+     */
+    @Override
+    public Category getLogger() {
+        return Category.getInstance(event.getLoggerName());
+    }
+
+    /*
+     Return the message for this logging event.
+    */
+    @Override
+    public
+    Object getMessage() {
+        return event.getMessage().getFormattedMessage();
+    }
+
+    /*
+     * This method returns the NDC for this event.
+     */
+    @Override
+    public
+    String getNDC() {
+        return event.getContextStack().toString();
+    }
+
+
+    /*
+     Returns the the context corresponding to the <code>key</code> parameter.
+     */
+    @Override
+    public
+    Object getMDC(String key) {
+        if (event.getContextData() != null) {
+            return event.getContextData().getValue(key);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     Obtain a copy of this thread's MDC prior to serialization or
+     asynchronous logging.
+     */
+    @Override
+    public
+    void getMDCCopy() {
+    }
+
+    @Override
+    public
+    String getRenderedMessage() {
+        return event.getMessage().getFormattedMessage();
+    }
+
+    /**
+     Returns the time when the application started, in milliseconds
+     elapsed since 01.01.1970.  */
+    public static long getStartTime() {
+        return JVM_START_TIME;
+    }
+
+    @Override
+    public
+    String getThreadName() {
+        return event.getThreadName();
+    }
+
+    /**
+     Returns the throwable information contained within this
+     event. May be <code>null</code> if there is no such information.
+
+     <p>Note that the {@link Throwable} object contained within a
+     {@link ThrowableInformation} does not survive serialization.
+
+     @since 1.1 */
+    @Override
+    public
+    ThrowableInformation getThrowableInformation() {
+        if (event.getThrown() != null) {
+            return new ThrowableInformation(event.getThrown());
+        }
+        return null;
+    }
+
+    /**
+     Return this event's throwable's string[] representaion.
+     */
+    @Override
+    public
+    String[] getThrowableStrRep() {
+        if (event.getThrown() != null) {
+            return Throwables.toStringList(event.getThrown()).toArray(new String[0]);
+        }
+        return null;
+    }
+
+    /**
+     * Returns the result of {@code ManagementFactory.getRuntimeMXBean().getStartTime()},
+     * or the current system time if JMX is not available.
+     */
+    private static long initStartTime() {
+        // We'd like to call ManagementFactory.getRuntimeMXBean().getStartTime(),
+        // but Google App Engine throws a java.lang.NoClassDefFoundError
+        // "java.lang.management.ManagementFactory is a restricted class".
+        // The reflection is necessary because without it, Google App Engine
+        // will refuse to initialize this class.
+        try {
+            final Class<?> factoryClass = Loader.loadSystemClass("java.lang.management.ManagementFactory");
+            final Method getRuntimeMXBean = factoryClass.getMethod("getRuntimeMXBean");
+            final Object runtimeMXBean = getRuntimeMXBean.invoke(null);
+
+            final Class<?> runtimeMXBeanClass = Loader.loadSystemClass("java.lang.management.RuntimeMXBean");
+            final Method getStartTime = runtimeMXBeanClass.getMethod("getStartTime");
+            return (Long) getStartTime.invoke(runtimeMXBean);
+        } catch (final Throwable t) {
+            StatusLogger.getLogger().error("Unable to call ManagementFactory.getRuntimeMXBean().getStartTime(), "
+                + "using system time for OnStartupTriggeringPolicy", t);
+            // We have little option but to declare "now" as the beginning of time.
+            return System.currentTimeMillis();
+        }
+    }
+}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/BooleanHolder.java
similarity index 69%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/BooleanHolder.java
index 13aaf9c..16e46d3 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/BooleanHolder.java
@@ -14,17 +14,20 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
+package org.apache.log4j.builders;
 
-import org.junit.Test;
+/**
+ * Holds Boolean values created inside of a Lambda expression.
+ */
+public class BooleanHolder extends Holder<Boolean> {
+    public BooleanHolder() {
+        super(Boolean.FALSE);
+    }
 
-import static org.junit.Assert.*;
-
-public class ProcessIdUtilTest {
-
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
+    @Override
+    public void set(Boolean value) {
+        if (value != null) {
+            super.set(value);
+        }
     }
 }
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/BuilderManager.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/BuilderManager.java
new file mode 100644
index 0000000..c677513
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/BuilderManager.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.builders;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.Layout;
+import org.apache.log4j.builders.appender.AppenderBuilder;
+import org.apache.log4j.builders.filter.FilterBuilder;
+import org.apache.log4j.builders.layout.LayoutBuilder;
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.config.plugins.util.PluginManager;
+import org.apache.logging.log4j.core.config.plugins.util.PluginType;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.LoaderUtil;
+import org.w3c.dom.Element;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.Map;
+
+/**
+ *
+ */
+public class BuilderManager {
+
+    public static final String CATEGORY = "Log4j Builder";
+    private static final Logger LOGGER = StatusLogger.getLogger();
+    private final Map<String, PluginType<?>> plugins;
+
+    public BuilderManager() {
+        final PluginManager manager = new PluginManager(CATEGORY);
+        manager.collectPlugins();
+        plugins = manager.getPlugins();
+    }
+
+    public Appender parseAppender(String className, Element appenderElement, XmlConfigurationFactory factory) {
+        PluginType<?> plugin = plugins.get(className.toLowerCase());
+        if (plugin != null) {
+            try {
+                @SuppressWarnings("unchecked")
+                AppenderBuilder builder = (AppenderBuilder) LoaderUtil.newInstanceOf(plugin.getPluginClass());
+                return builder.parseAppender(appenderElement, factory);
+            } catch (InstantiationException | IllegalAccessException | InvocationTargetException ex) {
+                LOGGER.warn("Unable to load plugin: {} due to: {}", plugin.getKey(), ex.getMessage());
+            }
+        }
+        return null;
+    }
+
+    public Filter parseFilter(String className, Element filterElement, XmlConfigurationFactory factory) {
+        PluginType<?> plugin = plugins.get(className.toLowerCase());
+        if (plugin != null) {
+            try {
+                @SuppressWarnings("unchecked")
+                FilterBuilder builder = (FilterBuilder) LoaderUtil.newInstanceOf(plugin.getPluginClass());
+                return builder.parseFilter(filterElement, factory);
+            } catch (InstantiationException | IllegalAccessException | InvocationTargetException ex) {
+                LOGGER.warn("Unable to load plugin: {} due to: {}", plugin.getKey(), ex.getMessage());
+            }
+        }
+        return null;
+    }
+
+
+    public Layout parseLayout(String className, Element layoutElement, XmlConfigurationFactory factory) {
+        PluginType<?> plugin = plugins.get(className.toLowerCase());
+        if (plugin != null) {
+            try {
+                @SuppressWarnings("unchecked")
+                LayoutBuilder builder = (LayoutBuilder) LoaderUtil.newInstanceOf(plugin.getPluginClass());
+                return builder.parseLayout(layoutElement, factory);
+            } catch (InstantiationException | IllegalAccessException | InvocationTargetException ex) {
+                LOGGER.warn("Unable to load plugin: {} due to: {}", plugin.getKey(), ex.getMessage());
+            }
+        }
+        return null;
+    }
+
+}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/Holder.java
similarity index 67%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/Holder.java
index 13aaf9c..b9ce2bf 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/Holder.java
@@ -14,17 +14,26 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
+package org.apache.log4j.builders;
 
-import org.junit.Test;
+/**
+ * Provides a place to hold values generated inside of a Lambda expression.
+ */
+public class Holder<T> {
+    private T value;
 
-import static org.junit.Assert.*;
+    public Holder() {
+    }
 
-public class ProcessIdUtilTest {
+    public Holder(T defaultValue) {
+        this.value = defaultValue;
+    }
 
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
+    public void set(T value) {
+        this.value = value;
+    }
+
+    public T get() {
+        return value;
     }
 }
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/appender/AppenderBuilder.java
similarity index 65%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/appender/AppenderBuilder.java
index 13aaf9c..2b72efd 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/appender/AppenderBuilder.java
@@ -14,17 +14,20 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
+package org.apache.log4j.builders.appender;
 
-import org.junit.Test;
+import org.apache.log4j.Appender;
+import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.w3c.dom.Element;
 
-import static org.junit.Assert.*;
+import java.util.function.BiFunction;
 
-public class ProcessIdUtilTest {
+/**
+ * Define an Appender Builder.
+ */
+public interface AppenderBuilder {
 
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
-    }
+    Appender parseAppender(Element element, XmlConfigurationFactory factory);
+
 }
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/appender/ConsoleAppenderBuilder.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/appender/ConsoleAppenderBuilder.java
new file mode 100644
index 0000000..bfb7ff8
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/appender/ConsoleAppenderBuilder.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.builders.appender;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.Layout;
+import org.apache.log4j.bridge.AppenderWrapper;
+import org.apache.log4j.bridge.FilterAdapter;
+import org.apache.log4j.bridge.FilterWrapper;
+import org.apache.log4j.bridge.LayoutAdapter;
+import org.apache.log4j.bridge.LayoutWrapper;
+import org.apache.log4j.builders.Holder;
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.appender.ConsoleAppender;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.xml.XmlConfigurationFactory.*;
+
+/**
+ * Build a Console Appender
+ */
+@Plugin(name = "org.apache.log4j.ConsoleAppender", category = CATEGORY)
+public class ConsoleAppenderBuilder implements AppenderBuilder {
+    private static final String SYSTEM_OUT = "System.out";
+    private static final String SYSTEM_ERR = "System.err";
+    private static final String TARGET = "target";
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+
+    @Override
+    public Appender parseAppender(Element appenderElement, XmlConfigurationFactory factory) {
+        String name = appenderElement.getAttribute(XmlConfigurationFactory.NAME_ATTR);
+        Holder<String> target = new Holder<>(SYSTEM_OUT);
+        Holder<Layout> layout = new Holder<>();
+        Holder<Filter> filter = new Holder<>();
+        forEachElement(appenderElement.getChildNodes(), (currentElement) -> {
+            switch (currentElement.getTagName()) {
+                case LAYOUT_TAG:
+                    layout.set(factory.parseLayout(currentElement));
+                    break;
+                case FILTER_TAG:
+                    filter.set(factory.parseFilters(currentElement));
+                    break;
+                case PARAM_TAG: {
+                    if (currentElement.getAttribute(NAME_ATTR).equalsIgnoreCase(TARGET)) {
+                        String value = currentElement.getAttribute(VALUE_ATTR);
+                        if (value == null) {
+                            LOGGER.warn("No value supplied for target parameter. Defaulting to System.out.");
+                        } else {
+                            switch (value) {
+                                case SYSTEM_OUT:
+                                    target.set(SYSTEM_OUT);
+                                    break;
+                                case SYSTEM_ERR:
+                                    target.set(SYSTEM_ERR);
+                                    break;
+                                default:
+                                    LOGGER.warn("Invalid value \"{}\" for target parameter. Using default of System.out",
+                                            value);
+                            }
+                        }
+                    }
+                    break;
+                }
+            }
+        });
+        org.apache.logging.log4j.core.Layout<?> consoleLayout = null;
+        org.apache.logging.log4j.core.Filter consoleFilter = null;
+
+        if (layout.get() instanceof LayoutWrapper) {
+            consoleLayout = ((LayoutWrapper) layout.get()).getLayout();
+        } else if (layout.get() != null) {
+            consoleLayout = new LayoutAdapter(layout.get());
+        }
+        if (filter.get() != null) {
+            if (filter.get() instanceof FilterWrapper) {
+                consoleFilter = ((FilterWrapper) filter.get()).getFilter();
+            } else {
+                consoleFilter = new FilterAdapter(filter.get());
+            }
+        }
+        ConsoleAppender.Target consoleTarget = SYSTEM_ERR.equals(target.get())
+                ? ConsoleAppender.Target.SYSTEM_ERR : ConsoleAppender.Target.SYSTEM_OUT;
+        return new AppenderWrapper(ConsoleAppender.newBuilder()
+                .setName(name)
+                .setTarget(consoleTarget)
+                .setLayout(consoleLayout)
+                .setFilter(consoleFilter)
+                .setConfiguration(factory.getConfiguration())
+                .build());
+    }
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/appender/DailyRollingFileAppenderBuilder.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/appender/DailyRollingFileAppenderBuilder.java
new file mode 100644
index 0000000..878020f
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/appender/DailyRollingFileAppenderBuilder.java
@@ -0,0 +1,146 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.builders.appender;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.Layout;
+import org.apache.log4j.bridge.AppenderWrapper;
+import org.apache.log4j.bridge.FilterAdapter;
+import org.apache.log4j.bridge.FilterWrapper;
+import org.apache.log4j.bridge.LayoutAdapter;
+import org.apache.log4j.bridge.LayoutWrapper;
+import org.apache.log4j.builders.BooleanHolder;
+import org.apache.log4j.builders.Holder;
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.appender.FileAppender;
+import org.apache.logging.log4j.core.appender.RollingFileAppender;
+import org.apache.logging.log4j.core.appender.rolling.DefaultRolloverStrategy;
+import org.apache.logging.log4j.core.appender.rolling.RolloverStrategy;
+import org.apache.logging.log4j.core.appender.rolling.TimeBasedTriggeringPolicy;
+import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.xml.XmlConfigurationFactory.*;
+
+/**
+ * Build a Daily Rolling File Appender
+ */
+@Plugin(name = "org.apache.log4j.DailyRollingFileAppender", category = CATEGORY)
+public class DailyRollingFileAppenderBuilder implements AppenderBuilder {
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+
+    @Override
+    public Appender parseAppender(Element appenderElement, XmlConfigurationFactory factory) {
+        String name = appenderElement.getAttribute(NAME_ATTR);
+        Holder<Layout> layout = new Holder<>();
+        Holder<Filter> filter = new Holder<>();
+        Holder<String> fileName = new Holder<>();
+        Holder<Boolean> immediateFlush = new BooleanHolder();
+        Holder<Boolean> append = new BooleanHolder();
+        Holder<Boolean> bufferedIo = new BooleanHolder();
+        Holder<Integer> bufferSize = new Holder<>(8192);
+        forEachElement(appenderElement.getChildNodes(), (currentElement) -> {
+            switch (currentElement.getTagName()) {
+                case LAYOUT_TAG:
+                    layout.set(factory.parseLayout(currentElement));
+                    break;
+                case FILTER_TAG:
+                    filter.set(factory.parseFilters(currentElement));
+                    break;
+                case PARAM_TAG: {
+                    switch (currentElement.getAttribute(NAME_ATTR).toLowerCase()) {
+                        case FILE_PARAM:
+                            fileName.set(currentElement.getAttribute(VALUE_ATTR));
+                            break;
+                        case APPEND_PARAM: {
+                            String bool = currentElement.getAttribute(VALUE_ATTR);
+                            if (bool != null) {
+                                append.set(Boolean.parseBoolean(bool));
+                            } else {
+                                LOGGER.warn("No value provided for append parameter");
+                            }
+                            break;
+                        }
+                        case BUFFERED_IO_PARAM: {
+                            String bool = currentElement.getAttribute(VALUE_ATTR);
+                            if (bool != null) {
+                                bufferedIo.set(Boolean.parseBoolean(bool));
+                            } else {
+                                LOGGER.warn("No value provided for bufferedIo parameter");
+                            }
+                            break;
+                        }
+                        case BUFFER_SIZE_PARAM:
+                            String size = currentElement.getAttribute(VALUE_ATTR);
+                            if (size != null) {
+                                bufferSize.set(Integer.parseInt(size));
+                            } else {
+                                LOGGER.warn("No value provide for bufferSize parameter");
+                            }
+                            break;
+                    }
+                    break;
+                }
+            }
+        });
+
+        org.apache.logging.log4j.core.Layout<?> fileLayout = null;
+        org.apache.logging.log4j.core.Filter fileFilter = null;
+        if (bufferedIo.get()) {
+            immediateFlush.set(Boolean.TRUE);
+        }
+        if (layout.get() instanceof LayoutWrapper) {
+            fileLayout = ((LayoutWrapper) layout.get()).getLayout();
+        } else if (layout.get() != null) {
+            fileLayout = new LayoutAdapter(layout.get());
+        }
+        if (filter.get() != null) {
+            if (filter.get() instanceof FilterWrapper) {
+                fileFilter = ((FilterWrapper) filter.get()).getFilter();
+            } else {
+                fileFilter = new FilterAdapter(filter.get());
+            }
+        }
+        if (fileName.get() == null) {
+            LOGGER.warn("Unable to create File Appender, no file name provided");
+            return null;
+        }
+        String filePattern = fileName.get() +"%d{yyy-MM-dd}";
+        TriggeringPolicy policy = TimeBasedTriggeringPolicy.newBuilder().withModulate(true).build();
+        RolloverStrategy strategy = DefaultRolloverStrategy.newBuilder()
+                .withConfig(factory.getConfiguration())
+                .withMax(Integer.toString(Integer.MAX_VALUE))
+                .build();
+        return new AppenderWrapper(RollingFileAppender.newBuilder()
+                .setName(name)
+                .setConfiguration(factory.getConfiguration())
+                .setLayout(fileLayout)
+                .setFilter(fileFilter)
+                .withFileName(fileName.get())
+                .withImmediateFlush(immediateFlush.get())
+                .withFilePattern(filePattern)
+                .withPolicy(policy)
+                .withStrategy(strategy)
+                .build());
+    }
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/appender/FileAppenderBuilder.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/appender/FileAppenderBuilder.java
new file mode 100644
index 0000000..4224c5d
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/appender/FileAppenderBuilder.java
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.builders.appender;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.Layout;
+import org.apache.log4j.bridge.AppenderWrapper;
+import org.apache.log4j.bridge.FilterAdapter;
+import org.apache.log4j.bridge.FilterWrapper;
+import org.apache.log4j.bridge.LayoutAdapter;
+import org.apache.log4j.bridge.LayoutWrapper;
+import org.apache.log4j.builders.BooleanHolder;
+import org.apache.log4j.builders.Holder;
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.appender.FileAppender;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.xml.XmlConfigurationFactory.*;
+
+/**
+ * Build a File Appender
+ */
+@Plugin(name = "org.apache.log4j.FileAppender", category = CATEGORY)
+public class FileAppenderBuilder implements AppenderBuilder {
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+
+    @Override
+    public Appender parseAppender(Element appenderElement, XmlConfigurationFactory factory) {
+        String name = appenderElement.getAttribute(NAME_ATTR);
+        Holder<Layout> layout = new Holder<>();
+        Holder<Filter> filter = new Holder<>();
+        Holder<String> fileName = new Holder<>();
+        Holder<Boolean> immediateFlush = new BooleanHolder();
+        Holder<Boolean> append = new BooleanHolder();
+        Holder<Boolean> bufferedIo = new BooleanHolder();
+        Holder<Integer> bufferSize = new Holder<>(8192);
+        forEachElement(appenderElement.getChildNodes(), (currentElement) -> {
+            switch (currentElement.getTagName()) {
+                case LAYOUT_TAG:
+                    layout.set(factory.parseLayout(currentElement));
+                    break;
+                case FILTER_TAG:
+                    filter.set(factory.parseFilters(currentElement));
+                    break;
+                case PARAM_TAG: {
+                    switch (currentElement.getAttribute(NAME_ATTR).toLowerCase()) {
+                        case FILE_PARAM:
+                            fileName.set(currentElement.getAttribute(VALUE_ATTR));
+                            break;
+                        case APPEND_PARAM: {
+                            String bool = currentElement.getAttribute(VALUE_ATTR);
+                            if (bool != null) {
+                                append.set(Boolean.parseBoolean(bool));
+                            } else {
+                                LOGGER.warn("No value provided for append parameter");
+                            }
+                            break;
+                        }
+                        case BUFFERED_IO_PARAM: {
+                            String bool = currentElement.getAttribute(VALUE_ATTR);
+                            if (bool != null) {
+                                bufferedIo.set(Boolean.parseBoolean(bool));
+                            } else {
+                                LOGGER.warn("No value provided for bufferedIo parameter");
+                            }
+                            break;
+                        }
+                        case BUFFER_SIZE_PARAM:
+                            String size = currentElement.getAttribute(VALUE_ATTR);
+                            if (size != null) {
+                                bufferSize.set(Integer.parseInt(size));
+                            } else {
+                                LOGGER.warn("No value provide for bufferSize parameter");
+                            }
+                            break;
+                    }
+                    break;
+                }
+            }
+        });
+
+        org.apache.logging.log4j.core.Layout<?> fileLayout = null;
+        org.apache.logging.log4j.core.Filter fileFilter = null;
+        if (bufferedIo.get()) {
+            immediateFlush.set(Boolean.TRUE);
+        }
+        if (layout.get() instanceof LayoutWrapper) {
+            fileLayout = ((LayoutWrapper) layout.get()).getLayout();
+        } else if (layout.get() != null) {
+            fileLayout = new LayoutAdapter(layout.get());
+        }
+        if (filter.get() != null) {
+            if (filter.get() instanceof FilterWrapper) {
+                fileFilter = ((FilterWrapper) filter.get()).getFilter();
+            } else {
+                fileFilter = new FilterAdapter(filter.get());
+            }
+        }
+        if (fileName.get() == null) {
+            LOGGER.warn("Unable to create File Appender, no file name provided");
+            return null;
+        }
+        return new AppenderWrapper(FileAppender.newBuilder()
+                .setName(name)
+                .setConfiguration(factory.getConfiguration())
+                .setLayout(fileLayout)
+                .setFilter(fileFilter)
+                .withFileName(fileName.get())
+                .withImmediateFlush(immediateFlush.get())
+                .withAppend(append.get())
+                .withBufferedIo(bufferedIo.get())
+                .withBufferSize(bufferSize.get())
+                .build());
+    }
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/appender/NullAppenderBuilder.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/appender/NullAppenderBuilder.java
new file mode 100644
index 0000000..857203e
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/appender/NullAppenderBuilder.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.builders.appender;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.bridge.AppenderWrapper;
+import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.appender.NullAppender;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+
+/**
+ * Build a Null Appender
+ */
+@Plugin(name = "org.apache.log4j.varia.NullAppender", category = CATEGORY)
+public class NullAppenderBuilder implements AppenderBuilder {
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+
+    @Override
+    public Appender parseAppender(Element appenderElement, XmlConfigurationFactory factory) {
+        String name = appenderElement.getAttribute("name");
+        return new AppenderWrapper(NullAppender.createAppender(name));
+    }
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/appender/RollingFileAppenderBuilder.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/appender/RollingFileAppenderBuilder.java
new file mode 100644
index 0000000..08a5129
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/appender/RollingFileAppenderBuilder.java
@@ -0,0 +1,170 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.builders.appender;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.Layout;
+import org.apache.log4j.bridge.AppenderWrapper;
+import org.apache.log4j.bridge.FilterAdapter;
+import org.apache.log4j.bridge.FilterWrapper;
+import org.apache.log4j.bridge.LayoutAdapter;
+import org.apache.log4j.bridge.LayoutWrapper;
+import org.apache.log4j.builders.BooleanHolder;
+import org.apache.log4j.builders.Holder;
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.appender.RollingFileAppender;
+import org.apache.logging.log4j.core.appender.rolling.CompositeTriggeringPolicy;
+import org.apache.logging.log4j.core.appender.rolling.DefaultRolloverStrategy;
+import org.apache.logging.log4j.core.appender.rolling.RolloverStrategy;
+import org.apache.logging.log4j.core.appender.rolling.SizeBasedTriggeringPolicy;
+import org.apache.logging.log4j.core.appender.rolling.TimeBasedTriggeringPolicy;
+import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.xml.XmlConfigurationFactory.*;
+
+/**
+ * Build a File Appender
+ */
+@Plugin(name = "org.apache.log4j.RollingFileAppender", category = CATEGORY)
+public class RollingFileAppenderBuilder implements AppenderBuilder {
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+
+    @Override
+    public Appender parseAppender(Element appenderElement, XmlConfigurationFactory factory) {
+        String name = appenderElement.getAttribute(NAME_ATTR);
+        Holder<Layout> layout = new Holder<>();
+        Holder<Filter> filter = new Holder<>();
+        Holder<String> fileName = new Holder<>();
+        Holder<Boolean> immediateFlush = new BooleanHolder();
+        Holder<Boolean> append = new BooleanHolder();
+        Holder<Boolean> bufferedIo = new BooleanHolder();
+        Holder<Integer> bufferSize = new Holder<>(8192);
+        Holder<String> maxSize = new Holder<>();
+        Holder<String> maxBackups = new Holder<>();
+        forEachElement(appenderElement.getChildNodes(), (currentElement) -> {
+            switch (currentElement.getTagName()) {
+                case LAYOUT_TAG:
+                    layout.set(factory.parseLayout(currentElement));
+                    break;
+                case FILTER_TAG:
+                    filter.set(factory.parseFilters(currentElement));
+                    break;
+                case PARAM_TAG: {
+                    switch (currentElement.getAttribute(NAME_ATTR).toLowerCase()) {
+                        case FILE_PARAM:
+                            fileName.set(currentElement.getAttribute(VALUE_ATTR));
+                            break;
+                        case APPEND_PARAM: {
+                            String bool = currentElement.getAttribute(VALUE_ATTR);
+                            if (bool != null) {
+                                append.set(Boolean.parseBoolean(bool));
+                            } else {
+                                LOGGER.warn("No value provided for append parameter");
+                            }
+                            break;
+                        }
+                        case BUFFERED_IO_PARAM: {
+                            String bool = currentElement.getAttribute(VALUE_ATTR);
+                            if (bool != null) {
+                                bufferedIo.set(Boolean.parseBoolean(bool));
+                            } else {
+                                LOGGER.warn("No value provided for bufferedIo parameter");
+                            }
+                            break;
+                        }
+                        case BUFFER_SIZE_PARAM: {
+                            String size = currentElement.getAttribute(VALUE_ATTR);
+                            if (size != null) {
+                                bufferSize.set(Integer.parseInt(size));
+                            } else {
+                                LOGGER.warn("No value provide for bufferSize parameter");
+                            }
+                            break;
+                        }
+                        case MAX_BACKUP_INDEX: {
+                            String size = currentElement.getAttribute(VALUE_ATTR);
+                            if (size != null) {
+                                maxBackups.set(size);
+                            } else {
+                                LOGGER.warn("No value provide for maxBackupIndex parameter");
+                            }
+                            break;
+                        }
+                        case MAX_SIZE_PARAM: {
+                            String size = currentElement.getAttribute(VALUE_ATTR);
+                            if (size != null) {
+                                maxSize.set(size);
+                            } else {
+                                LOGGER.warn("No value provide for bufferSize parameter");
+                            }
+                            break;
+                        }
+                    }
+                    break;
+                }
+            }
+        });
+
+        org.apache.logging.log4j.core.Layout<?> fileLayout = null;
+        org.apache.logging.log4j.core.Filter fileFilter = null;
+        if (bufferedIo.get()) {
+            immediateFlush.set(Boolean.TRUE);
+        }
+        if (layout.get() instanceof LayoutWrapper) {
+            fileLayout = ((LayoutWrapper) layout.get()).getLayout();
+        } else if (layout.get() != null) {
+            fileLayout = new LayoutAdapter(layout.get());
+        }
+        if (filter.get() != null) {
+            if (filter.get() instanceof FilterWrapper) {
+                fileFilter = ((FilterWrapper) filter.get()).getFilter();
+            } else {
+                fileFilter = new FilterAdapter(filter.get());
+            }
+        }
+        if (fileName.get() == null) {
+            LOGGER.warn("Unable to create File Appender, no file name provided");
+            return null;
+        }
+        String filePattern = fileName.get() +"%d{yyy-MM-dd}";
+        TriggeringPolicy timePolicy = TimeBasedTriggeringPolicy.newBuilder().withModulate(true).build();
+        SizeBasedTriggeringPolicy sizePolicy = SizeBasedTriggeringPolicy.createPolicy(maxSize.get());
+        CompositeTriggeringPolicy policy = CompositeTriggeringPolicy.createPolicy(sizePolicy, timePolicy);
+        RolloverStrategy strategy = DefaultRolloverStrategy.newBuilder()
+                .withConfig(factory.getConfiguration())
+                .withMax(maxBackups.get())
+                .build();
+        return new AppenderWrapper(RollingFileAppender.newBuilder()
+                .setName(name)
+                .setConfiguration(factory.getConfiguration())
+                .setLayout(fileLayout)
+                .setFilter(fileFilter)
+                .withImmediateFlush(immediateFlush.get())
+                .withFileName(fileName.get())
+                .withFilePattern(filePattern)
+                .withPolicy(policy)
+                .withStrategy(strategy)
+                .build());
+    }
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/filter/DenyAllFilterBuilder.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/filter/DenyAllFilterBuilder.java
new file mode 100644
index 0000000..e942b34
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/filter/DenyAllFilterBuilder.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.builders.filter;
+
+import org.apache.log4j.Layout;
+import org.apache.log4j.bridge.FilterWrapper;
+import org.apache.log4j.bridge.LayoutWrapper;
+import org.apache.log4j.builders.layout.LayoutBuilder;
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.filter.DenyAllFilter;
+import org.apache.logging.log4j.core.layout.PatternLayout;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+
+/**
+ * Build a Pattern Layout
+ */
+@Plugin(name = "org.apache.log4j.varia.DenyAllFilter", category = CATEGORY)
+public class DenyAllFilterBuilder implements FilterBuilder {
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+
+    @Override
+    public Filter parseFilter(Element filterElement, XmlConfigurationFactory factory) {
+        return new FilterWrapper(DenyAllFilter.newBuilder().build());
+    }
+}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/filter/FilterBuilder.java
similarity index 69%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/filter/FilterBuilder.java
index 13aaf9c..fbeaefb 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/filter/FilterBuilder.java
@@ -14,17 +14,17 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
+package org.apache.log4j.builders.filter;
 
-import org.junit.Test;
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.w3c.dom.Element;
 
-import static org.junit.Assert.*;
+/**
+ * Define a Filter Builder.
+ */
+public interface FilterBuilder {
 
-public class ProcessIdUtilTest {
+    Filter parseFilter(Element element, XmlConfigurationFactory factory);
 
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
-    }
 }
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/filter/LevelMatchFilterBuilder.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/filter/LevelMatchFilterBuilder.java
new file mode 100644
index 0000000..b5df7ff
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/filter/LevelMatchFilterBuilder.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.builders.filter;
+
+import org.apache.log4j.bridge.FilterWrapper;
+import org.apache.log4j.builders.BooleanHolder;
+import org.apache.log4j.builders.Holder;
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.filter.LevelMatchFilter;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.xml.XmlConfigurationFactory.*;
+import static org.apache.log4j.xml.XmlConfigurationFactory.VALUE_ATTR;
+
+/**
+ * Build a Level match failter.
+ */
+@Plugin(name = "org.apache.log4j.varia.LevelMatchFilter", category = CATEGORY)
+public class LevelMatchFilterBuilder implements FilterBuilder {
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+    private static final String LEVEL = "level";
+    private static final String ACCEPT_ON_MATCH = "acceptonmatch";
+
+    @Override
+    public Filter parseFilter(Element filterElement, XmlConfigurationFactory factory) {
+        final Holder<String> level = new Holder<>();
+        final Holder<Boolean> acceptOnMatch = new BooleanHolder();
+        forEachElement(filterElement.getElementsByTagName("param"), (currentElement) -> {
+            if (currentElement.getTagName().equals("param")) {
+                switch (currentElement.getAttribute(NAME_ATTR).toLowerCase()) {
+                    case LEVEL:
+                        level.set(currentElement.getAttribute(VALUE_ATTR));
+                        break;
+                    case ACCEPT_ON_MATCH:
+                        acceptOnMatch.set(Boolean.parseBoolean(currentElement.getAttribute(VALUE_ATTR)));
+                        break;
+                }
+            }
+        });
+        Level lvl = Level.ERROR;
+        if (level.get() != null) {
+            lvl = Level.toLevel(level.get(), Level.ERROR);
+        }
+        org.apache.logging.log4j.core.Filter.Result onMatch = acceptOnMatch.get() != null && acceptOnMatch.get()
+                ? org.apache.logging.log4j.core.Filter.Result.ACCEPT
+                : org.apache.logging.log4j.core.Filter.Result.DENY;
+        return new FilterWrapper(LevelMatchFilter.newBuilder()
+                .setLevel(lvl)
+                .setOnMatch(onMatch)
+                .setOnMismatch(org.apache.logging.log4j.core.Filter.Result.NEUTRAL)
+                .build());
+    }
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/filter/LevelRangeFilterBuilder.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/filter/LevelRangeFilterBuilder.java
new file mode 100644
index 0000000..1082245
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/filter/LevelRangeFilterBuilder.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.builders.filter;
+
+import org.apache.log4j.bridge.FilterWrapper;
+import org.apache.log4j.builders.BooleanHolder;
+import org.apache.log4j.builders.Holder;
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.filter.LevelRangeFilter;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.xml.XmlConfigurationFactory.*;
+
+/**
+ * Build a Level match failter.
+ */
+@Plugin(name = "org.apache.log4j.varia.LevelRangeFilter", category = CATEGORY)
+public class LevelRangeFilterBuilder implements FilterBuilder {
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+    private static final String LEVEL_MAX = "levelmax";
+    private static final String LEVEL_MIN = "levelmin";
+    private static final String ACCEPT_ON_MATCH = "acceptonmatch";
+
+    @Override
+    public Filter parseFilter(Element filterElement, XmlConfigurationFactory factory) {
+        final Holder<String> levelMax = new Holder<>();
+        final Holder<String> levelMin = new Holder<>();
+        final Holder<Boolean> acceptOnMatch = new BooleanHolder();
+        forEachElement(filterElement.getElementsByTagName("param"), (currentElement) -> {
+            if (currentElement.getTagName().equals("param")) {
+                switch (currentElement.getAttribute(NAME_ATTR).toLowerCase()) {
+                    case LEVEL_MAX:
+                        levelMax.set(currentElement.getAttribute(VALUE_ATTR));
+                        break;
+                    case LEVEL_MIN:
+                        levelMax.set(currentElement.getAttribute(VALUE_ATTR));
+                        break;
+                    case ACCEPT_ON_MATCH:
+                        acceptOnMatch.set(Boolean.parseBoolean(currentElement.getAttribute(VALUE_ATTR)));
+                        break;
+                }
+            }
+        });
+        Level max = Level.FATAL;
+        Level min = Level.TRACE;
+        if (levelMax.get() != null) {
+            max = Level.toLevel(levelMax.get(), Level.FATAL);
+        }
+        if (levelMin.get() != null) {
+            min = Level.toLevel(levelMin.get(), Level.DEBUG);
+        }
+        org.apache.logging.log4j.core.Filter.Result onMatch = acceptOnMatch.get() != null && acceptOnMatch.get()
+                ? org.apache.logging.log4j.core.Filter.Result.ACCEPT
+                : org.apache.logging.log4j.core.Filter.Result.NEUTRAL;
+
+        return new FilterWrapper(LevelRangeFilter.createFilter(min, max, onMatch,
+                org.apache.logging.log4j.core.Filter.Result.DENY));
+    }
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/filter/StringMatchFilterBuilder.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/filter/StringMatchFilterBuilder.java
new file mode 100644
index 0000000..8e4f71a
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/filter/StringMatchFilterBuilder.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.builders.filter;
+
+import org.apache.log4j.bridge.FilterWrapper;
+import org.apache.log4j.builders.BooleanHolder;
+import org.apache.log4j.builders.Holder;
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.filter.LevelMatchFilter;
+import org.apache.logging.log4j.core.filter.StringMatchFilter;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.xml.XmlConfigurationFactory.*;
+
+/**
+ * Build a String match filter.
+ */
+@Plugin(name = "org.apache.log4j.varia.StringMatchFilter", category = CATEGORY)
+public class StringMatchFilterBuilder implements FilterBuilder {
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+    private static final String STRING_TO_MATCH = "stringtomatch";
+    private static final String ACCEPT_ON_MATCH = "acceptonmatch";
+
+    @Override
+    public Filter parseFilter(Element filterElement, XmlConfigurationFactory factory) {
+        final Holder<Boolean> acceptOnMatch = new BooleanHolder();
+        final Holder<String> text = new Holder<>();
+        forEachElement(filterElement.getElementsByTagName("param"), (currentElement) -> {
+            if (currentElement.getTagName().equals("param")) {
+                switch (currentElement.getAttribute(NAME_ATTR).toLowerCase()) {
+                    case STRING_TO_MATCH:
+                        text.set(currentElement.getAttribute(VALUE_ATTR));
+                        break;
+                    case ACCEPT_ON_MATCH:
+                        acceptOnMatch.set(Boolean.parseBoolean(currentElement.getAttribute(VALUE_ATTR)));
+                        break;
+
+                }
+            }
+        });
+        if (text.get() == null) {
+            LOGGER.warn("No text provided for StringMatchFilter");
+            return null;
+        }
+        org.apache.logging.log4j.core.Filter.Result onMatch = acceptOnMatch.get() != null && acceptOnMatch.get()
+                ? org.apache.logging.log4j.core.Filter.Result.ACCEPT
+                : org.apache.logging.log4j.core.Filter.Result.DENY;
+        return new FilterWrapper(StringMatchFilter.newBuilder()
+                .setMatchString(text.get())
+                .setOnMatch(onMatch)
+                .setOnMismatch(org.apache.logging.log4j.core.Filter.Result.NEUTRAL)
+                .build());
+    }
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/layout/HtmlLayoutBuilder.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/layout/HtmlLayoutBuilder.java
new file mode 100644
index 0000000..78b5f40
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/layout/HtmlLayoutBuilder.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.builders.layout;
+
+import org.apache.log4j.Layout;
+import org.apache.log4j.bridge.LayoutWrapper;
+import org.apache.log4j.builders.BooleanHolder;
+import org.apache.log4j.builders.Holder;
+import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.layout.HtmlLayout;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.xml.XmlConfigurationFactory.*;
+
+/**
+ * Build a Pattern Layout
+ */
+@Plugin(name = "org.apache.log4j.HTMLLayout", category = CATEGORY)
+public class HtmlLayoutBuilder implements LayoutBuilder {
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+
+
+    @Override
+    public Layout parseLayout(Element layoutElement, XmlConfigurationFactory factory) {
+        final Holder<String> title = new Holder<>();
+        final Holder<Boolean> locationInfo = new BooleanHolder();
+        forEachElement(layoutElement.getElementsByTagName("param"), (currentElement) -> {
+            if (currentElement.getTagName().equals("param")) {
+                if ("title".equalsIgnoreCase(currentElement.getAttribute("name"))) {
+                    title.set(currentElement.getAttribute("value"));
+                } else if ("locationInfo".equalsIgnoreCase(currentElement.getAttribute("name"))) {
+                    locationInfo.set(Boolean.parseBoolean(currentElement.getAttribute("value")));
+                }
+            }
+        });
+        return new LayoutWrapper(HtmlLayout.newBuilder()
+                .withTitle(title.get())
+                .withLocationInfo(locationInfo.get())
+                .build());
+    }
+}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/layout/LayoutBuilder.java
similarity index 69%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/layout/LayoutBuilder.java
index 13aaf9c..9dc88f3 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/layout/LayoutBuilder.java
@@ -14,17 +14,17 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
+package org.apache.log4j.builders.layout;
 
-import org.junit.Test;
+import org.apache.log4j.Layout;
+import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.w3c.dom.Element;
 
-import static org.junit.Assert.*;
+/**
+ * Define a Layout Builder.
+ */
+public interface LayoutBuilder {
 
-public class ProcessIdUtilTest {
+    Layout parseLayout(Element element, XmlConfigurationFactory factory);
 
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
-    }
 }
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/layout/PatternLayoutBuilder.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/layout/PatternLayoutBuilder.java
new file mode 100644
index 0000000..b6a1964
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/layout/PatternLayoutBuilder.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.builders.layout;
+
+import org.apache.log4j.Layout;
+import org.apache.log4j.bridge.LayoutWrapper;
+import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginAliases;
+import org.apache.logging.log4j.core.layout.PatternLayout;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+
+/**
+ * Build a Pattern Layout
+ */
+@Plugin(name = "org.apache.log4j.PatternLayout", category = CATEGORY)
+@PluginAliases("org.apache.log4j.EnhancedPatternLayout")
+public class PatternLayoutBuilder implements LayoutBuilder {
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+
+    @Override
+    public Layout parseLayout(Element layoutElement, XmlConfigurationFactory factory) {
+        NodeList params = layoutElement.getElementsByTagName("param");
+        final int length = params.getLength();
+        String pattern = null;
+        for (int index = 0; index < length; ++ index) {
+            Node currentNode = params.item(index);
+            if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
+                Element currentElement = (Element) currentNode;
+                if (currentElement.getTagName().equals("param")) {
+                    if ("conversionPattern".equalsIgnoreCase(currentElement.getAttribute("name"))) {
+                        pattern = currentElement.getAttribute("value")
+                                // Log4j 2's %x (NDC) is not compatible with Log4j 1's
+                                // %x
+                                // Log4j 1: "foo bar baz"
+                                // Log4j 2: "[foo, bar, baz]"
+                                // Use %ndc to get the Log4j 1 format
+                                .replace("%x", "%ndc")
+
+                                // Log4j 2's %X (MDC) is not compatible with Log4j 1's
+                                // %X
+                                // Log4j 1: "{{foo,bar}{hoo,boo}}"
+                                // Log4j 2: "{foo=bar,hoo=boo}"
+                                // Use %properties to get the Log4j 1 format
+                                .replace("%X", "%properties");
+                        break;
+                    }
+                }
+            }
+        }
+        return new LayoutWrapper(PatternLayout.newBuilder()
+                .withPattern(pattern)
+                .withConfiguration(factory.getConfiguration())
+                .build());
+    }
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/layout/SimpleLayoutBuilder.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/layout/SimpleLayoutBuilder.java
new file mode 100644
index 0000000..4f09bc2
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/layout/SimpleLayoutBuilder.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.builders.layout;
+
+import org.apache.log4j.Layout;
+import org.apache.log4j.bridge.LayoutWrapper;
+import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.layout.PatternLayout;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.xml.XmlConfigurationFactory.*;
+
+/**
+ * Build a Pattern Layout
+ */
+@Plugin(name = "org.apache.log4j.SimpleLayout", category = CATEGORY)
+public class SimpleLayoutBuilder implements LayoutBuilder {
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+
+    @Override
+    public Layout parseLayout(Element layoutElement, XmlConfigurationFactory factory) {
+        return new LayoutWrapper(PatternLayout.newBuilder()
+                .withPattern("%level - %m%n")
+                .withConfiguration(factory.getConfiguration())
+                .build());
+    }
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/layout/TTCCLayoutBuilder.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/layout/TTCCLayoutBuilder.java
new file mode 100644
index 0000000..b15d351
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/layout/TTCCLayoutBuilder.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.builders.layout;
+
+import org.apache.log4j.Layout;
+import org.apache.log4j.bridge.LayoutWrapper;
+import org.apache.log4j.builders.BooleanHolder;
+import org.apache.log4j.builders.Holder;
+import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.layout.PatternLayout;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.xml.XmlConfigurationFactory.*;
+
+/**
+ * Build a Pattern Layout
+ */
+@Plugin(name = "org.apache.log4j.TTCCLayout", category = CATEGORY)
+public class TTCCLayoutBuilder implements LayoutBuilder {
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+
+    private static final String THREAD_PRINTING_PARAM = "threadprinting";
+    private static final String CATEGORY_PREFIXING_PARAM = "categoryprefixing";
+    private static final String CONTEXT_PRINTING_PARAM = "contextprinting";
+    private static final String DATE_FORMAT_PARAM = "dateformat";
+    private static final String TIMEZONE_FORMAT = "timezone";
+
+    @Override
+    public Layout parseLayout(Element layoutElement, XmlConfigurationFactory factory) {
+        final Holder<Boolean> threadPrinting = new BooleanHolder();
+        final Holder<Boolean> categoryPrefixing = new BooleanHolder();
+        final Holder<Boolean> contextPrinting = new BooleanHolder();
+        final Holder<String> dateFormat = new Holder<>();
+        final Holder<String> timezone = new Holder<>();
+        forEachElement(layoutElement.getElementsByTagName("param"), (currentElement) -> {
+            if (currentElement.getTagName().equals("param")) {
+                switch (currentElement.getAttribute(NAME_ATTR).toLowerCase()) {
+                    case THREAD_PRINTING_PARAM:
+                        threadPrinting.set(Boolean.parseBoolean(currentElement.getAttribute(VALUE_ATTR)));
+                        break;
+                    case CATEGORY_PREFIXING_PARAM:
+                        categoryPrefixing.set(Boolean.parseBoolean(currentElement.getAttribute(VALUE_ATTR)));
+                        break;
+                    case CONTEXT_PRINTING_PARAM:
+                        contextPrinting.set(Boolean.parseBoolean(currentElement.getAttribute(VALUE_ATTR)));
+                        break;
+                    case DATE_FORMAT_PARAM:
+                        dateFormat.set(currentElement.getAttribute(VALUE_ATTR));
+                        break;
+                    case TIMEZONE_FORMAT:
+                        timezone.set(currentElement.getAttribute(VALUE_ATTR));
+                        break;
+                }
+            }
+        });
+        StringBuilder sb = new StringBuilder();
+        if (dateFormat.get() != null) {
+            if (RELATIVE.equalsIgnoreCase(dateFormat.get())) {
+                sb.append("%r ");
+            } else {
+                sb.append("%d{").append(dateFormat.get()).append("}");
+                if (timezone.get() != null) {
+                    sb.append("{").append(timezone.get()).append("}");
+                }
+                sb.append(" ");
+            }
+        }
+        if (threadPrinting.get()) {
+            sb.append("[%t] ");
+        }
+        sb.append("%p ");
+        if (categoryPrefixing.get()) {
+            sb.append("%c ");
+        }
+        if (contextPrinting.get()) {
+            sb.append("%notEmpty{%ndc }");
+        }
+        sb.append("- %m%n");
+        return new LayoutWrapper(PatternLayout.newBuilder()
+                .withPattern(sb.toString())
+                .withConfiguration(factory.getConfiguration())
+                .build());
+    }
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/layout/XmlLayoutBuilder.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/layout/XmlLayoutBuilder.java
new file mode 100644
index 0000000..5436e5c
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/builders/layout/XmlLayoutBuilder.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.builders.layout;
+
+import org.apache.log4j.Layout;
+import org.apache.log4j.bridge.LayoutWrapper;
+import org.apache.log4j.builders.BooleanHolder;
+import org.apache.log4j.builders.Holder;
+import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.layout.HtmlLayout;
+import org.apache.logging.log4j.core.layout.XmlLayout;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.xml.XmlConfigurationFactory.forEachElement;
+
+/**
+ * Build a Pattern Layout
+ */
+@Plugin(name = "org.apache.log4j.xml.XMLLayout", category = CATEGORY)
+public class XmlLayoutBuilder implements LayoutBuilder {
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+
+
+    @Override
+    public Layout parseLayout(Element layoutElement, XmlConfigurationFactory factory) {
+        final Holder<Boolean> properties = new BooleanHolder();
+        final Holder<Boolean> locationInfo = new BooleanHolder();
+        forEachElement(layoutElement.getElementsByTagName("param"), (currentElement) -> {
+            if ("properties".equalsIgnoreCase(currentElement.getAttribute("name"))) {
+                properties.set(Boolean.parseBoolean(currentElement.getAttribute("value")));
+            } else if ("locationInfo".equalsIgnoreCase(currentElement.getAttribute("name"))) {
+                locationInfo.set(Boolean.parseBoolean(currentElement.getAttribute("value")));
+            }
+        });
+        return new LayoutWrapper(XmlLayout.newBuilder()
+                .setLocationInfo(locationInfo.get())
+                .setProperties(properties.get())
+                .build());
+    }
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/config/InputStreamWrapper.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/config/InputStreamWrapper.java
new file mode 100644
index 0000000..19bf9a9
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/config/InputStreamWrapper.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.config;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+class InputStreamWrapper extends InputStream {
+
+    private final String description;
+    private final InputStream input;
+
+    public InputStreamWrapper(final InputStream input, final String description) {
+        this.input = input;
+        this.description = description;
+    }
+
+    @Override
+    public int available() throws IOException {
+        return input.available();
+    }
+
+    @Override
+    public void close() throws IOException {
+        input.close();
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        return input.equals(obj);
+    }
+
+    @Override
+    public int hashCode() {
+        return input.hashCode();
+    }
+
+    @Override
+    public synchronized void mark(final int readlimit) {
+        input.mark(readlimit);
+    }
+
+    @Override
+    public boolean markSupported() {
+        return input.markSupported();
+    }
+
+    @Override
+    public int read() throws IOException {
+        return input.read();
+    }
+
+    @Override
+    public int read(final byte[] b) throws IOException {
+        return input.read(b);
+    }
+
+    @Override
+    public int read(final byte[] b, final int off, final int len) throws IOException {
+        return input.read(b, off, len);
+    }
+
+    @Override
+    public synchronized void reset() throws IOException {
+        input.reset();
+    }
+
+    @Override
+    public long skip(final long n) throws IOException {
+        return input.skip(n);
+    }
+
+    @Override
+    public String toString() {
+        return getClass().getSimpleName() + " [description=" + description + ", input=" + input + "]";
+    }
+
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/config/Log4j1Configuration.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/config/Log4j1Configuration.java
new file mode 100644
index 0000000..5a6b50d
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/config/Log4j1Configuration.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.config;
+
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.AbstractConfiguration;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.ConfigurationSource;
+import org.apache.logging.log4j.core.config.Node;
+import org.apache.logging.log4j.core.config.Reconfigurable;
+
+/**
+ * Class Description goes here.
+ */
+public class Log4j1Configuration extends AbstractConfiguration implements Reconfigurable {
+
+    public Log4j1Configuration(final LoggerContext loggerContext, final ConfigurationSource source,
+            int monitorIntervalSeconds) {
+        super(loggerContext, source);
+        initializeWatchers(this, source, monitorIntervalSeconds);
+    }
+
+    @Override
+    protected void doConfigure() {
+        super.getScheduler().start();
+
+    }
+
+    /**
+     * Initialize the configuration.
+     */
+    @Override
+    public void initialize() {
+        doConfigure();
+        setState(State.INITIALIZED);
+        LOGGER.debug("Configuration {} initialized", this);
+    }
+
+    @Override
+    public Configuration reconfigure() {
+        return null;
+    }
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/config/Log4j1ConfigurationConverter.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/config/Log4j1ConfigurationConverter.java
new file mode 100644
index 0000000..4475f6a
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/config/Log4j1ConfigurationConverter.java
@@ -0,0 +1,220 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.config;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.logging.log4j.core.config.ConfigurationException;
+import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
+import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
+import org.apache.logging.log4j.core.tools.BasicCommandLineArguments;
+import org.apache.logging.log4j.core.tools.picocli.CommandLine;
+import org.apache.logging.log4j.core.tools.picocli.CommandLine.Command;
+import org.apache.logging.log4j.core.tools.picocli.CommandLine.Option;
+
+/**
+ * Tool for converting a Log4j 1.x properties configuration file to Log4j 2.x XML configuration file.
+ *
+ * <p>
+ * Run with "--help" on the command line.
+ * </p>
+ *
+ * <p>
+ * Example:
+ * </p>
+ *
+ * <pre>
+ * java org.apache.log4j.config.Log4j1ConfigurationConverter --recurse
+ * E:\vcs\git\apache\logging\logging-log4j2\log4j-1.2-api\src\test\resources\config-1.2\hadoop --in log4j.properties --verbose
+ * </pre>
+ */
+public final class Log4j1ConfigurationConverter {
+
+    @Command(name = "Log4j1ConfigurationConverter")
+    public static class CommandLineArguments extends BasicCommandLineArguments implements Runnable {
+
+        @Option(names = { "--failfast", "-f" }, description = "Fails on the first failure in recurse mode.")
+        private boolean failFast;
+
+        @Option(names = { "--in", "-i" }, description = "Specifies the input file.")
+        private Path pathIn;
+
+        @Option(names = { "--out", "-o" }, description = "Specifies the output file.")
+        private Path pathOut;
+
+        @Option(names = { "--recurse", "-r" }, description = "Recurses into this folder looking for the input file")
+        private Path recurseIntoPath;
+
+        @Option(names = { "--verbose", "-v" }, description = "Be verbose.")
+        private boolean verbose;
+
+        public Path getPathIn() {
+            return pathIn;
+        }
+
+        public Path getPathOut() {
+            return pathOut;
+        }
+
+        public Path getRecurseIntoPath() {
+            return recurseIntoPath;
+        }
+
+        public boolean isFailFast() {
+            return failFast;
+        }
+
+        public boolean isVerbose() {
+            return verbose;
+        }
+
+        public void setFailFast(final boolean failFast) {
+            this.failFast = failFast;
+        }
+
+        public void setPathIn(final Path pathIn) {
+            this.pathIn = pathIn;
+        }
+
+        public void setPathOut(final Path pathOut) {
+            this.pathOut = pathOut;
+        }
+
+        public void setRecurseIntoPath(final Path recurseIntoPath) {
+            this.recurseIntoPath = recurseIntoPath;
+        }
+
+        public void setVerbose(final boolean verbose) {
+            this.verbose = verbose;
+        }
+
+        @Override
+        public void run() {
+            if (isHelp()) {
+                CommandLine.usage(this, System.err);
+                return;
+            }
+            new Log4j1ConfigurationConverter(this).run();
+        }
+
+        @Override
+        public String toString() {
+            return "CommandLineArguments [recurseIntoPath=" + recurseIntoPath + ", verbose=" + verbose + ", pathIn="
+                    + pathIn + ", pathOut=" + pathOut + "]";
+        }
+    }
+
+    private static final String FILE_EXT_XML = ".xml";
+
+    public static void main(final String[] args) {
+        CommandLine.run(new CommandLineArguments(), System.err, args);
+    }
+
+    public static Log4j1ConfigurationConverter run(final CommandLineArguments cla) {
+        final Log4j1ConfigurationConverter log4j1ConfigurationConverter = new Log4j1ConfigurationConverter(cla);
+        log4j1ConfigurationConverter.run();
+        return log4j1ConfigurationConverter;
+    }
+
+    private final CommandLineArguments cla;
+
+    private Log4j1ConfigurationConverter(final CommandLineArguments cla) {
+        this.cla = cla;
+    }
+
+    protected void convert(final InputStream input, final OutputStream output) throws IOException {
+        final ConfigurationBuilder<BuiltConfiguration> builder = new Log4j1ConfigurationParser()
+                .buildConfigurationBuilder(input);
+        builder.writeXmlConfiguration(output);
+    }
+
+    InputStream getInputStream() throws IOException {
+        final Path pathIn = cla.getPathIn();
+        return pathIn == null ? System.in : new InputStreamWrapper(Files.newInputStream(pathIn), pathIn.toString());
+    }
+
+    OutputStream getOutputStream() throws IOException {
+        final Path pathOut = cla.getPathOut();
+        return pathOut == null ? System.out : Files.newOutputStream(pathOut);
+    }
+
+    private void run() {
+        if (cla.getRecurseIntoPath() != null) {
+            final AtomicInteger countOKs = new AtomicInteger();
+            final AtomicInteger countFails = new AtomicInteger();
+            try {
+                Files.walkFileTree(cla.getRecurseIntoPath(), new SimpleFileVisitor<Path>() {
+                    @Override
+                    public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs)
+                            throws IOException {
+                        if (cla.getPathIn() == null || file.getFileName().equals(cla.getPathIn())) {
+                            verbose("Reading %s", file);
+                            String newFile = file.getFileName().toString();
+                            final int lastIndex = newFile.lastIndexOf(".");
+                            newFile = lastIndex < 0 ? newFile + FILE_EXT_XML
+                                    : newFile.substring(0, lastIndex) + FILE_EXT_XML;
+                            final Path resolved = file.resolveSibling(newFile);
+                            try (final InputStream input = new InputStreamWrapper(Files.newInputStream(file), file.toString());
+                                    final OutputStream output = Files.newOutputStream(resolved)) {
+                                try {
+                                    convert(input, output);
+                                    countOKs.incrementAndGet();
+                                } catch (ConfigurationException | IOException e) {
+                                    countFails.incrementAndGet();
+                                    if (cla.isFailFast()) {
+                                        throw e;
+                                    }
+                                    e.printStackTrace();
+                                }
+                                verbose("Wrote %s", resolved);
+                            }
+                        }
+                        return FileVisitResult.CONTINUE;
+                    }
+                });
+            } catch (final IOException e) {
+                throw new ConfigurationException(e);
+            } finally {
+                verbose("OK = %,d, Failures = %,d, Total = %,d", countOKs.get(), countFails.get(),
+                        countOKs.get() + countFails.get());
+            }
+        } else {
+            verbose("Reading %s", cla.getPathIn());
+            try (final InputStream input = getInputStream(); final OutputStream output = getOutputStream()) {
+                convert(input, output);
+            } catch (final IOException e) {
+                throw new ConfigurationException(e);
+            }
+            verbose("Wrote %s", cla.getPathOut());
+        }
+    }
+
+    private void verbose(final String template, final Object... args) {
+        if (cla.isVerbose()) {
+            System.err.println(String.format(template, args));
+        }
+    }
+
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/config/Log4j1ConfigurationFactory.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/config/Log4j1ConfigurationFactory.java
new file mode 100644
index 0000000..83f6675
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/config/Log4j1ConfigurationFactory.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.config;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.ConfigurationException;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.config.ConfigurationSource;
+import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
+import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
+
+/**
+ * Experimental ConfigurationFactory for Log4j 1.2 properties configuration files.
+ */
+// TODO
+// @Plugin(name = "Log4j1ConfigurationFactory", category = ConfigurationFactory.CATEGORY)
+//
+// Best Value?
+// @Order(50)
+public class Log4j1ConfigurationFactory extends ConfigurationFactory {
+
+    private static final String[] SUFFIXES = {".properties"};
+
+    @Override
+    public Configuration getConfiguration(final LoggerContext loggerContext, final ConfigurationSource source) {
+        final ConfigurationBuilder<BuiltConfiguration> builder;
+        try (final InputStream configStream = source.getInputStream()) {
+            builder = new Log4j1ConfigurationParser().buildConfigurationBuilder(configStream);
+        } catch (final IOException e) {
+            throw new ConfigurationException("Unable to load " + source, e);
+        }
+        return builder.build();
+    }
+
+    @Override
+    protected String[] getSupportedTypes() {
+        return SUFFIXES;
+    }
+
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/config/Log4j1ConfigurationParser.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/config/Log4j1ConfigurationParser.java
new file mode 100644
index 0000000..112ab42
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/config/Log4j1ConfigurationParser.java
@@ -0,0 +1,446 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.config;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Properties;
+import java.util.TreeMap;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.core.appender.ConsoleAppender;
+import org.apache.logging.log4j.core.appender.FileAppender;
+import org.apache.logging.log4j.core.appender.NullAppender;
+import org.apache.logging.log4j.core.appender.RollingFileAppender;
+import org.apache.logging.log4j.core.config.ConfigurationException;
+import org.apache.logging.log4j.core.config.builder.api.AppenderComponentBuilder;
+import org.apache.logging.log4j.core.config.builder.api.ComponentBuilder;
+import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
+import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory;
+import org.apache.logging.log4j.core.config.builder.api.LayoutComponentBuilder;
+import org.apache.logging.log4j.core.config.builder.api.LoggerComponentBuilder;
+import org.apache.logging.log4j.core.config.builder.api.RootLoggerComponentBuilder;
+import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
+import org.apache.logging.log4j.core.lookup.StrSubstitutor;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.Strings;
+
+/**
+ * Experimental parser for Log4j 1.2 properties configuration files.
+ *
+ * This class is not thread-safe.
+ * 
+ * <p>
+ * From the Log4j 1.2 Javadocs:
+ * </p>
+ * <p>
+ * All option values admit variable substitution. The syntax of variable substitution is similar to that of Unix shells. The string between
+ * an opening "${" and closing "}" is interpreted as a key. The value of the substituted variable can be defined as a system property or in
+ * the configuration file itself. The value of the key is first searched in the system properties, and if not found there, it is then
+ * searched in the configuration file being parsed. The corresponding value replaces the ${variableName} sequence. For example, if java.home
+ * system property is set to /home/xyz, then every occurrence of the sequence ${java.home} will be interpreted as /home/xyz.
+ * </p>
+ */
+public class Log4j1ConfigurationParser {
+
+    private static final String COMMA_DELIMITED_RE = "\\s*,\\s*";
+    private static final String ROOTLOGGER = "rootLogger";
+    private static final String ROOTCATEGORY = "rootCategory";
+    private static final String TRUE = "true";
+    private static final String FALSE = "false";
+
+    private final Properties properties = new Properties();
+    private StrSubstitutor strSubstitutorProperties;
+    private StrSubstitutor strSubstitutorSystem;
+
+    private final ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory
+            .newConfigurationBuilder();
+
+    /**
+     * Parses a Log4j 1.2 properties configuration file in ISO 8859-1 encoding into a ConfigurationBuilder.
+     *
+     * @param input
+     *            InputStream to read from is assumed to be ISO 8859-1, and will not be closed.
+     * @return the populated ConfigurationBuilder, never {@literal null}
+     * @throws IOException
+     *             if unable to read the input
+     * @throws ConfigurationException
+     *             if the input does not contain a valid configuration
+     */
+    public ConfigurationBuilder<BuiltConfiguration> buildConfigurationBuilder(final InputStream input)
+            throws IOException {
+        try {
+            properties.load(input);
+            strSubstitutorProperties = new StrSubstitutor(properties);
+            strSubstitutorSystem = new StrSubstitutor(System.getProperties());
+            final String rootCategoryValue = getLog4jValue(ROOTCATEGORY);
+            final String rootLoggerValue = getLog4jValue(ROOTLOGGER);
+            if (rootCategoryValue == null && rootLoggerValue == null) {
+                // This is not a Log4j 1 properties configuration file.
+                warn("Missing " + ROOTCATEGORY + " or " + ROOTLOGGER + " in " + input);
+                // throw new ConfigurationException(
+                // "Missing " + ROOTCATEGORY + " or " + ROOTLOGGER + " in " + input);
+            }
+            builder.setConfigurationName("Log4j1");
+            // DEBUG
+            final String debugValue = getLog4jValue("debug");
+            if (Boolean.valueOf(debugValue)) {
+                builder.setStatusLevel(Level.DEBUG);
+            }
+            // Root
+            buildRootLogger(getLog4jValue(ROOTCATEGORY));
+            buildRootLogger(getLog4jValue(ROOTLOGGER));
+            // Appenders
+            final Map<String, String> appenderNameToClassName = buildClassToPropertyPrefixMap();
+            for (final Map.Entry<String, String> entry : appenderNameToClassName.entrySet()) {
+                final String appenderName = entry.getKey();
+                final String appenderClass = entry.getValue();
+                buildAppender(appenderName, appenderClass);
+            }
+            // Loggers
+            buildLoggers("log4j.category.");
+            buildLoggers("log4j.logger.");
+            buildProperties();
+            return builder;
+        } catch (final IllegalArgumentException e) {
+            throw new ConfigurationException(e);
+        }
+    }
+
+    private void buildProperties() {
+        for (final Map.Entry<Object, Object> entry : new TreeMap<>(properties).entrySet()) {
+            final String key = entry.getKey().toString();
+            if (!key.startsWith("log4j.") && !key.equals(ROOTCATEGORY) && !key.equals(ROOTLOGGER)) {
+                builder.addProperty(key, Objects.toString(entry.getValue(), Strings.EMPTY));
+            }
+        }
+    }
+
+    private void warn(final String string) {
+        System.err.println(string);
+    }
+
+    private Map<String, String> buildClassToPropertyPrefixMap() {
+        final String prefix = "log4j.appender.";
+        final int preLength = prefix.length();
+        final Map<String, String> map = new HashMap<>();
+        for (final Map.Entry<Object, Object> entry : properties.entrySet()) {
+            final Object keyObj = entry.getKey();
+            if (keyObj != null) {
+                final String key = keyObj.toString();
+                if (key.startsWith(prefix)) {
+                    if (key.indexOf('.', preLength) < 0) {
+                        final String name = key.substring(preLength);
+                        final Object value = entry.getValue();
+                        if (value != null) {
+                            map.put(name, value.toString());
+                        }
+                    }
+                }
+            }
+        }
+        return map;
+    }
+
+    private void buildAppender(final String appenderName, final String appenderClass) {
+        switch (appenderClass) {
+        case "org.apache.log4j.ConsoleAppender":
+            buildConsoleAppender(appenderName);
+            break;
+        case "org.apache.log4j.FileAppender":
+            buildFileAppender(appenderName);
+            break;
+        case "org.apache.log4j.DailyRollingFileAppender":
+            buildDailyRollingFileAppender(appenderName);
+            break;
+        case "org.apache.log4j.RollingFileAppender":
+            buildRollingFileAppender(appenderName);
+            break;
+        case "org.apache.log4j.varia.NullAppender":
+            buildNullAppender(appenderName);
+            break;
+        default:
+            reportWarning("Unknown appender class: " + appenderClass + "; ignoring appender: " + appenderName);
+        }
+    }
+
+    private void buildConsoleAppender(final String appenderName) {
+        final AppenderComponentBuilder appenderBuilder = builder.newAppender(appenderName, ConsoleAppender.PLUGIN_NAME);
+        final String targetValue = getLog4jAppenderValue(appenderName, "Target", "System.out");
+        if (targetValue != null) {
+            final ConsoleAppender.Target target;
+            switch (targetValue) {
+            case "System.out":
+                target = ConsoleAppender.Target.SYSTEM_OUT;
+                break;
+            case "System.err":
+                target = ConsoleAppender.Target.SYSTEM_ERR;
+                break;
+            default:
+                reportWarning("Unknown value for console Target: " + targetValue);
+                target = null;
+            }
+            if (target != null) {
+                appenderBuilder.addAttribute("target", target);
+            }
+        }
+        buildAttribute(appenderName, appenderBuilder, "Follow", "follow");
+        if (FALSE.equalsIgnoreCase(getLog4jAppenderValue(appenderName, "ImmediateFlush"))) {
+            reportWarning("ImmediateFlush=false is not supported on Console appender");
+        }
+        buildAppenderLayout(appenderName, appenderBuilder);
+        builder.add(appenderBuilder);
+    }
+
+    private void buildFileAppender(final String appenderName) {
+        final AppenderComponentBuilder appenderBuilder = builder.newAppender(appenderName, FileAppender.PLUGIN_NAME);
+        buildFileAppender(appenderName, appenderBuilder);
+        builder.add(appenderBuilder);
+    }
+
+    private void buildFileAppender(final String appenderName, final AppenderComponentBuilder appenderBuilder) {
+        buildMandatoryAttribute(appenderName, appenderBuilder, "File", "fileName");
+        buildAttribute(appenderName, appenderBuilder, "Append", "append");
+        buildAttribute(appenderName, appenderBuilder, "BufferedIO", "bufferedIo");
+        buildAttribute(appenderName, appenderBuilder, "BufferSize", "bufferSize");
+        buildAttribute(appenderName, appenderBuilder, "ImmediateFlush", "immediateFlush");
+        buildAppenderLayout(appenderName, appenderBuilder);
+    }
+
+    private void buildDailyRollingFileAppender(final String appenderName) {
+        final AppenderComponentBuilder appenderBuilder = builder.newAppender(appenderName,
+                RollingFileAppender.PLUGIN_NAME);
+        buildFileAppender(appenderName, appenderBuilder);
+        final String fileName = getLog4jAppenderValue(appenderName, "File");
+        final String datePattern = getLog4jAppenderValue(appenderName, "DatePattern", fileName + "'.'yyyy-MM-dd");
+        appenderBuilder.addAttribute("filePattern", fileName + "%d{" + datePattern + "}");
+        final ComponentBuilder<?> triggeringPolicy = builder.newComponent("Policies")
+                .addComponent(builder.newComponent("TimeBasedTriggeringPolicy").addAttribute("modulate", true));
+        appenderBuilder.addComponent(triggeringPolicy);
+        appenderBuilder
+                .addComponent(builder.newComponent("DefaultRolloverStrategy").addAttribute("max", Integer.MAX_VALUE));
+        builder.add(appenderBuilder);
+    }
+
+    private void buildRollingFileAppender(final String appenderName) {
+        final AppenderComponentBuilder appenderBuilder = builder.newAppender(appenderName,
+                RollingFileAppender.PLUGIN_NAME);
+        buildFileAppender(appenderName, appenderBuilder);
+        final String fileName = getLog4jAppenderValue(appenderName, "File");
+        appenderBuilder.addAttribute("filePattern", fileName + ".%i");
+        final String maxFileSizeString = getLog4jAppenderValue(appenderName, "MaxFileSize", "10485760");
+        final String maxBackupIndexString = getLog4jAppenderValue(appenderName, "MaxBackupIndex", "1");
+        final ComponentBuilder<?> triggeringPolicy = builder.newComponent("Policies").addComponent(
+                builder.newComponent("SizeBasedTriggeringPolicy").addAttribute("size", maxFileSizeString));
+        appenderBuilder.addComponent(triggeringPolicy);
+        appenderBuilder.addComponent(
+                builder.newComponent("DefaultRolloverStrategy").addAttribute("max", maxBackupIndexString));
+        builder.add(appenderBuilder);
+    }
+
+    private void buildAttribute(final String componentName, final ComponentBuilder componentBuilder,
+            final String sourceAttributeName, final String targetAttributeName) {
+        final String attributeValue = getLog4jAppenderValue(componentName, sourceAttributeName);
+        if (attributeValue != null) {
+            componentBuilder.addAttribute(targetAttributeName, attributeValue);
+        }
+    }
+
+    private void buildAttributeWithDefault(final String componentName, final ComponentBuilder componentBuilder,
+            final String sourceAttributeName, final String targetAttributeName, final String defaultValue) {
+        final String attributeValue = getLog4jAppenderValue(componentName, sourceAttributeName, defaultValue);
+        componentBuilder.addAttribute(targetAttributeName, attributeValue);
+    }
+
+    private void buildMandatoryAttribute(final String componentName, final ComponentBuilder componentBuilder,
+            final String sourceAttributeName, final String targetAttributeName) {
+        final String attributeValue = getLog4jAppenderValue(componentName, sourceAttributeName);
+        if (attributeValue != null) {
+            componentBuilder.addAttribute(targetAttributeName, attributeValue);
+        } else {
+            reportWarning("Missing " + sourceAttributeName + " for " + componentName);
+        }
+    }
+
+    private void buildNullAppender(final String appenderName) {
+        final AppenderComponentBuilder appenderBuilder = builder.newAppender(appenderName, NullAppender.PLUGIN_NAME);
+        builder.add(appenderBuilder);
+    }
+
+    private void buildAppenderLayout(final String name, final AppenderComponentBuilder appenderBuilder) {
+        final String layoutClass = getLog4jAppenderValue(name, "layout", null);
+        if (layoutClass != null) {
+            switch (layoutClass) {
+            case "org.apache.log4j.PatternLayout":
+            case "org.apache.log4j.EnhancedPatternLayout": {
+                final String pattern = getLog4jAppenderValue(name, "layout.ConversionPattern", null)
+
+                        // Log4j 2's %x (NDC) is not compatible with Log4j 1's
+                        // %x
+                        // Log4j 1: "foo bar baz"
+                        // Log4j 2: "[foo, bar, baz]"
+                        // Use %ndc to get the Log4j 1 format
+                        .replace("%x", "%ndc")
+
+                        // Log4j 2's %X (MDC) is not compatible with Log4j 1's
+                        // %X
+                        // Log4j 1: "{{foo,bar}{hoo,boo}}"
+                        // Log4j 2: "{foo=bar,hoo=boo}"
+                        // Use %properties to get the Log4j 1 format
+                        .replace("%X", "%properties");
+
+                appenderBuilder.add(newPatternLayout(pattern));
+                break;
+            }
+            case "org.apache.log4j.SimpleLayout": {
+                appenderBuilder.add(newPatternLayout("%level - %m%n"));
+                break;
+            }
+            case "org.apache.log4j.TTCCLayout": {
+                String pattern = "%r ";
+                if (Boolean.parseBoolean(getLog4jAppenderValue(name, "layout.ThreadPrinting", TRUE))) {
+                    pattern += "[%t] ";
+                }
+                pattern += "%p ";
+                if (Boolean.parseBoolean(getLog4jAppenderValue(name, "layout.CategoryPrefixing", TRUE))) {
+                    pattern += "%c ";
+                }
+                if (Boolean.parseBoolean(getLog4jAppenderValue(name, "layout.ContextPrinting", TRUE))) {
+                    pattern += "%notEmpty{%ndc }";
+                }
+                pattern += "- %m%n";
+                appenderBuilder.add(newPatternLayout(pattern));
+                break;
+            }
+            case "org.apache.log4j.HTMLLayout": {
+                final LayoutComponentBuilder htmlLayout = builder.newLayout("HtmlLayout");
+                htmlLayout.addAttribute("title", getLog4jAppenderValue(name, "layout.Title", "Log4J Log Messages"));
+                htmlLayout.addAttribute("locationInfo",
+                        Boolean.parseBoolean(getLog4jAppenderValue(name, "layout.LocationInfo", FALSE)));
+                appenderBuilder.add(htmlLayout);
+                break;
+            }
+            case "org.apache.log4j.xml.XMLLayout": {
+                final LayoutComponentBuilder xmlLayout = builder.newLayout("Log4j1XmlLayout");
+                xmlLayout.addAttribute("locationInfo",
+                        Boolean.parseBoolean(getLog4jAppenderValue(name, "layout.LocationInfo", FALSE)));
+                xmlLayout.addAttribute("properties",
+                        Boolean.parseBoolean(getLog4jAppenderValue(name, "layout.Properties", FALSE)));
+                appenderBuilder.add(xmlLayout);
+                break;
+            }
+            default:
+                reportWarning("Unknown layout class: " + layoutClass);
+            }
+        }
+    }
+
+    private LayoutComponentBuilder newPatternLayout(final String pattern) {
+        final LayoutComponentBuilder layoutBuilder = builder.newLayout("PatternLayout");
+        if (pattern != null) {
+            layoutBuilder.addAttribute("pattern", pattern);
+        }
+        return layoutBuilder;
+    }
+
+    private void buildRootLogger(final String rootLoggerValue) {
+        if (rootLoggerValue == null) {
+            return;
+        }
+        final String[] rootLoggerParts = rootLoggerValue.split(COMMA_DELIMITED_RE);
+        final String rootLoggerLevel = getLevelString(rootLoggerParts, Level.ERROR.name());
+        final RootLoggerComponentBuilder loggerBuilder = builder.newRootLogger(rootLoggerLevel);
+        //
+        final String[] sortedAppenderNames = Arrays.copyOfRange(rootLoggerParts, 1, rootLoggerParts.length);
+        Arrays.sort(sortedAppenderNames);
+        for (final String appender : sortedAppenderNames) {
+            loggerBuilder.add(builder.newAppenderRef(appender));
+        }
+        builder.add(loggerBuilder);
+    }
+
+    private String getLevelString(final String[] loggerParts, final String defaultLevel) {
+        return loggerParts.length > 0 ? loggerParts[0] : defaultLevel;
+    }
+
+    private void buildLoggers(final String prefix) {
+        final int preLength = prefix.length();
+        for (final Map.Entry<Object, Object> entry : properties.entrySet()) {
+            final Object keyObj = entry.getKey();
+            if (keyObj != null) {
+                final String key = keyObj.toString();
+                if (key.startsWith(prefix)) {
+                    final String name = key.substring(preLength);
+                    final Object value = entry.getValue();
+                    if (value != null) {
+                        // a Level may be followed by a list of Appender refs.
+                        final String valueStr = value.toString();
+                        final String[] split = valueStr.split(COMMA_DELIMITED_RE);
+                        final String level = getLevelString(split, null);
+                        if (level == null) {
+                            warn("Level is missing for entry " + entry);
+                        } else {
+                            final LoggerComponentBuilder newLogger = builder.newLogger(name, level);
+                            if (split.length > 1) {
+                                // Add Appenders to this logger
+                                final String[] sortedAppenderNames = Arrays.copyOfRange(split, 1, split.length);
+                                Arrays.sort(sortedAppenderNames);
+                                for (final String appenderName : sortedAppenderNames) {
+                                    newLogger.add(builder.newAppenderRef(appenderName));
+                                }
+                            }
+                            builder.add(newLogger);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private String getLog4jAppenderValue(final String appenderName, final String attributeName) {
+        return getProperty("log4j.appender." + appenderName + "." + attributeName);
+    }
+
+    private String getProperty(final String key) {
+        final String value = properties.getProperty(key);
+        final String sysValue = strSubstitutorSystem.replace(value);
+        return strSubstitutorProperties.replace(sysValue);
+    }
+
+    private String getProperty(final String key, final String defaultValue) {
+        final String value = getProperty(key);
+        return value == null ? defaultValue : value;
+    }
+
+    private String getLog4jAppenderValue(final String appenderName, final String attributeName,
+            final String defaultValue) {
+        return getProperty("log4j.appender." + appenderName + "." + attributeName, defaultValue);
+    }
+
+    private String getLog4jValue(final String key) {
+        return getProperty("log4j." + key);
+    }
+
+    private void reportWarning(final String msg) {
+        StatusLogger.getLogger().warn("Log4j 1 configuration parser: " + msg);
+    }
+
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/config/PropertySetter.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/config/PropertySetter.java
new file mode 100644
index 0000000..5982278
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/config/PropertySetter.java
@@ -0,0 +1,287 @@
+/*
+ * 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.
+ */
+
+// Contributors:  Georg Lundesgaard
+
+package org.apache.log4j.config;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.Level;
+import org.apache.log4j.Priority;
+import org.apache.log4j.spi.ErrorHandler;
+import org.apache.log4j.spi.OptionHandler;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.util.OptionConverter;
+import org.apache.logging.log4j.status.StatusLogger;
+
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.io.InterruptedIOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Properties;
+
+/**
+ * General purpose Object property setter. Clients repeatedly invokes
+ * {@link #setProperty setProperty(name,value)} in order to invoke setters
+ * on the Object specified in the constructor. This class relies on the
+ * JavaBeans {@link Introspector} to analyze the given Object Class using
+ * reflection.
+ *
+ * <p>Usage:
+ * <pre>
+ * PropertySetter ps = new PropertySetter(anObject);
+ * ps.set("name", "Joe");
+ * ps.set("age", "32");
+ * ps.set("isMale", "true");
+ * </pre>
+ * will cause the invocations anObject.setName("Joe"), anObject.setAge(32),
+ * and setMale(true) if such methods exist with those signatures.
+ * Otherwise an {@link IntrospectionException} are thrown.
+ */
+public class PropertySetter {
+    private static Logger LOGGER = StatusLogger.getLogger();
+    protected Object obj;
+    protected PropertyDescriptor[] props;
+
+    /**
+     * Create a new PropertySetter for the specified Object. This is done
+     * in prepartion for invoking {@link #setProperty} one or more times.
+     *
+     * @param obj the object for which to set properties
+     */
+    public PropertySetter(Object obj) {
+        this.obj = obj;
+    }
+
+    /**
+     * Set the properties of an object passed as a parameter in one
+     * go. The <code>properties</code> are parsed relative to a
+     * <code>prefix</code>.
+     *
+     * @param obj        The object to configure.
+     * @param properties A java.util.Properties containing keys and values.
+     * @param prefix     Only keys having the specified prefix will be set.
+     */
+    public static void setProperties(Object obj, Properties properties, String prefix) {
+        new PropertySetter(obj).setProperties(properties, prefix);
+    }
+
+    /**
+     * Uses JavaBeans {@link Introspector} to computer setters of object to be
+     * configured.
+     */
+    protected void introspect() {
+        try {
+            BeanInfo bi = Introspector.getBeanInfo(obj.getClass());
+            props = bi.getPropertyDescriptors();
+        } catch (IntrospectionException ex) {
+            LOGGER.error("Failed to introspect {}: {}", obj, ex.getMessage());
+            props = new PropertyDescriptor[0];
+        }
+    }
+
+    /**
+     * Set the properites for the object that match the
+     * <code>prefix</code> passed as parameter.
+     */
+    public void setProperties(Properties properties, String prefix) {
+        int len = prefix.length();
+
+        for (String key : properties.stringPropertyNames()) {
+
+            // handle only properties that start with the desired frefix.
+            if (key.startsWith(prefix)) {
+
+
+                // ignore key if it contains dots after the prefix
+                if (key.indexOf('.', len + 1) > 0) {
+                    continue;
+                }
+
+                String value = OptionConverter.findAndSubst(key, properties);
+                key = key.substring(len);
+                if (("layout".equals(key) || "errorhandler".equals(key)) && obj instanceof Appender) {
+                    continue;
+                }
+                //
+                //   if the property type is an OptionHandler
+                //     (for example, triggeringPolicy of org.apache.log4j.rolling.RollingFileAppender)
+                PropertyDescriptor prop = getPropertyDescriptor(Introspector.decapitalize(key));
+                if (prop != null
+                        && OptionHandler.class.isAssignableFrom(prop.getPropertyType())
+                        && prop.getWriteMethod() != null) {
+                    OptionHandler opt = (OptionHandler)
+                            OptionConverter.instantiateByKey(properties, prefix + key,
+                                    prop.getPropertyType(),
+                                    null);
+                    PropertySetter setter = new PropertySetter(opt);
+                    setter.setProperties(properties, prefix + key + ".");
+                    try {
+                        prop.getWriteMethod().invoke(this.obj, opt);
+                    } catch (InvocationTargetException ex) {
+                        if (ex.getTargetException() instanceof InterruptedException
+                                || ex.getTargetException() instanceof InterruptedIOException) {
+                            Thread.currentThread().interrupt();
+                        }
+                        LOGGER.warn("Failed to set property [{}] to value \"{}\".", key, value, ex);
+                    } catch (IllegalAccessException | RuntimeException ex) {
+                        LOGGER.warn("Failed to set property [{}] to value \"{}\".", key, value, ex);
+                    }
+                    continue;
+                }
+
+                setProperty(key, value);
+            }
+        }
+        activate();
+    }
+
+    /**
+     * Set a property on this PropertySetter's Object. If successful, this
+     * method will invoke a setter method on the underlying Object. The
+     * setter is the one for the specified property name and the value is
+     * determined partly from the setter argument type and partly from the
+     * value specified in the call to this method.
+     *
+     * <p>If the setter expects a String no conversion is necessary.
+     * If it expects an int, then an attempt is made to convert 'value'
+     * to an int using new Integer(value). If the setter expects a boolean,
+     * the conversion is by new Boolean(value).
+     *
+     * @param name  name of the property
+     * @param value String value of the property
+     */
+    public void setProperty(String name, String value) {
+        if (value == null) {
+            return;
+        }
+
+        name = Introspector.decapitalize(name);
+        PropertyDescriptor prop = getPropertyDescriptor(name);
+
+        //LOGGER.debug("---------Key: "+name+", type="+prop.getPropertyType());
+
+        if (prop == null) {
+            LOGGER.warn("No such property [" + name + "] in " +
+                    obj.getClass().getName() + ".");
+        } else {
+            try {
+                setProperty(prop, name, value);
+            } catch (PropertySetterException ex) {
+                LOGGER.warn("Failed to set property [{}] to value \"{}\".", name, value, ex.rootCause);
+            }
+        }
+    }
+
+    /**
+     * Set the named property given a {@link PropertyDescriptor}.
+     *
+     * @param prop  A PropertyDescriptor describing the characteristics
+     *              of the property to set.
+     * @param name  The named of the property to set.
+     * @param value The value of the property.
+     */
+    public void setProperty(PropertyDescriptor prop, String name, String value)
+            throws PropertySetterException {
+        Method setter = prop.getWriteMethod();
+        if (setter == null) {
+            throw new PropertySetterException("No setter for property [" + name + "].");
+        }
+        Class[] paramTypes = setter.getParameterTypes();
+        if (paramTypes.length != 1) {
+            throw new PropertySetterException("#params for setter != 1");
+        }
+
+        Object arg;
+        try {
+            arg = convertArg(value, paramTypes[0]);
+        } catch (Throwable t) {
+            throw new PropertySetterException("Conversion to type [" + paramTypes[0] +
+                    "] failed. Reason: " + t);
+        }
+        if (arg == null) {
+            throw new PropertySetterException(
+                    "Conversion to type [" + paramTypes[0] + "] failed.");
+        }
+        LOGGER.debug("Setting property [" + name + "] to [" + arg + "].");
+        try {
+            setter.invoke(obj, arg);
+        } catch (InvocationTargetException ex) {
+            if (ex.getTargetException() instanceof InterruptedException
+                    || ex.getTargetException() instanceof InterruptedIOException) {
+                Thread.currentThread().interrupt();
+            }
+            throw new PropertySetterException(ex);
+        } catch (IllegalAccessException | RuntimeException ex) {
+            throw new PropertySetterException(ex);
+        }
+    }
+
+
+    /**
+     * Convert <code>val</code> a String parameter to an object of a
+     * given type.
+     */
+    protected Object convertArg(String val, Class type) {
+        if (val == null) {
+            return null;
+        }
+
+        String v = val.trim();
+        if (String.class.isAssignableFrom(type)) {
+            return val;
+        } else if (Integer.TYPE.isAssignableFrom(type)) {
+            return Integer.parseInt(v);
+        } else if (Long.TYPE.isAssignableFrom(type)) {
+            return Long.parseLong(v);
+        } else if (Boolean.TYPE.isAssignableFrom(type)) {
+            if ("true".equalsIgnoreCase(v)) {
+                return Boolean.TRUE;
+            } else if ("false".equalsIgnoreCase(v)) {
+                return Boolean.FALSE;
+            }
+        } else if (Priority.class.isAssignableFrom(type)) {
+            return org.apache.log4j.helpers.OptionConverter.toLevel(v, Level.DEBUG);
+        } else if (ErrorHandler.class.isAssignableFrom(type)) {
+            return OptionConverter.instantiateByClassName(v,
+                    ErrorHandler.class, null);
+        }
+        return null;
+    }
+
+
+    protected PropertyDescriptor getPropertyDescriptor(String name) {
+        if (props == null) {
+            introspect();
+        }
+        for (PropertyDescriptor prop : props) {
+            if (name.equals(prop.getName())) {
+                return prop;
+            }
+        }
+        return null;
+    }
+
+    public void activate() {
+        if (obj instanceof OptionHandler) {
+            ((OptionHandler) obj).activateOptions();
+        }
+    }
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/config/PropertySetterException.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/config/PropertySetterException.java
new file mode 100644
index 0000000..c9dc4cf
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/config/PropertySetterException.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.config;
+
+/**
+ * Thrown when an error is encountered whilst attempting to set a property
+ * using the {@link PropertySetter} utility class.
+ *
+ * @since 1.1
+ */
+public class PropertySetterException extends Exception {
+    private static final long serialVersionUID = -1352613734254235861L;
+
+    /**
+     * The root cause.
+     */
+    protected Throwable rootCause;
+
+    /**
+     * Construct the exception with the given message.
+     *
+     * @param msg The message
+     */
+    public PropertySetterException(final String msg) {
+        super(msg);
+    }
+
+    /**
+     * Construct the exception with the given root cause.
+     *
+     * @param rootCause The root cause
+     */
+    public PropertySetterException(final Throwable rootCause) {
+        super();
+        this.rootCause = rootCause;
+    }
+
+    /**
+     * Returns descriptive text on the cause of this exception.
+     *
+     * @return the descriptive text.
+     */
+    @Override
+    public String getMessage() {
+        String msg = super.getMessage();
+        if (msg == null && rootCause != null) {
+            msg = rootCause.getMessage();
+        }
+        return msg;
+    }
+}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/config/package-info.java
similarity index 68%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-1.2-api/src/src/main/java/org/apache/log4j/config/package-info.java
index 13aaf9c..7f96630 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/config/package-info.java
@@ -14,17 +14,7 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
-
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-public class ProcessIdUtilTest {
-
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
-    }
-}
+/**
+ * Log4j 1.x compatibility layer.
+ */
+package org.apache.log4j.config;
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/helpers/NullEnumeration.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/helpers/NullEnumeration.java
new file mode 100644
index 0000000..d064004
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/helpers/NullEnumeration.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.helpers;
+
+import java.util.Enumeration;
+import java.util.NoSuchElementException;
+
+/**
+ * An always-empty Enumerator.
+ *
+ * @since version 1.0
+ */
+@SuppressWarnings("rawtypes")
+public final class NullEnumeration implements Enumeration {
+    private static final NullEnumeration INSTANCE = new NullEnumeration();
+
+    private NullEnumeration() {
+    }
+
+    public static NullEnumeration getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    public boolean hasMoreElements() {
+        return false;
+    }
+
+    @Override
+    public Object nextElement() {
+        throw new NoSuchElementException();
+    }
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/helpers/OptionConverter.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/helpers/OptionConverter.java
new file mode 100644
index 0000000..8ee0ea5
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/helpers/OptionConverter.java
@@ -0,0 +1,345 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.helpers;
+
+import org.apache.log4j.Level;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.util.LoaderUtil;
+
+import java.io.InterruptedIOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Properties;
+
+/**
+ * A convenience class to convert property values to specific types.
+ */
+public class OptionConverter {
+    
+    static String DELIM_START = "${";
+    static char DELIM_STOP = '}';
+    static int DELIM_START_LEN = 2;
+    static int DELIM_STOP_LEN = 1;
+    private static final Logger LOGGER = LogManager.getLogger(OptionConverter.class);
+    private static final CharMap[] charMap = new CharMap[] {
+        new CharMap('n', '\n'),
+        new CharMap('r', '\r'),
+        new CharMap('t', '\t'),
+        new CharMap('f', '\f'),
+        new CharMap('\b', '\b'),
+        new CharMap('\"', '\"'),
+        new CharMap('\'', '\''),
+        new CharMap('\\', '\\')    
+    };
+
+    /**
+     * OptionConverter is a static class.
+     */
+    private OptionConverter() {
+    }
+
+    public static String[] concatanateArrays(String[] l, String[] r) {
+        int len = l.length + r.length;
+        String[] a = new String[len];
+
+        System.arraycopy(l, 0, a, 0, l.length);
+        System.arraycopy(r, 0, a, l.length, r.length);
+
+        return a;
+    }
+
+    public static String convertSpecialChars(String s) {
+        char c;
+        int len = s.length();
+        StringBuilder sbuf = new StringBuilder(len);
+
+        int i = 0;
+        while (i < len) {
+            c = s.charAt(i++);
+            if (c == '\\') {
+                c = s.charAt(i++);
+                for (CharMap entry : charMap) {
+                    if (entry.key == c) {
+                        c = entry.replacement;
+                    }
+                }
+            }
+            sbuf.append(c);
+        }
+        return sbuf.toString();
+    }
+
+
+    /**
+     * Very similar to <code>System.getProperty</code> except
+     * that the {@link SecurityException} is hidden.
+     *
+     * @param key The key to search for.
+     * @param def The default value to return.
+     * @return the string value of the system property, or the default
+     * value if there is no property with that key.
+     * @since 1.1
+     */
+    public static String getSystemProperty(String key, String def) {
+        try {
+            return System.getProperty(key, def);
+        } catch (Throwable e) { // MS-Java throws com.ms.security.SecurityExceptionEx
+            LOGGER.debug("Was not allowed to read system property \"{}\".", key);
+            return def;
+        }
+    }
+
+    /**
+     * If <code>value</code> is "true", then <code>true</code> is
+     * returned. If <code>value</code> is "false", then
+     * <code>true</code> is returned. Otherwise, <code>default</code> is
+     * returned.
+     *
+     * <p>Case of value is unimportant.
+     */
+    public static boolean toBoolean(String value, boolean dEfault) {
+        if (value == null) {
+            return dEfault;
+        }
+        String trimmedVal = value.trim();
+        if ("true".equalsIgnoreCase(trimmedVal)) {
+            return true;
+        }
+        if ("false".equalsIgnoreCase(trimmedVal)) {
+            return false;
+        }
+        return dEfault;
+    }
+
+    /**
+     * Converts a standard or custom priority level to a Level
+     * object.  <p> If <code>value</code> is of form
+     * "level#classname", then the specified class' toLevel method
+     * is called to process the specified level string; if no '#'
+     * character is present, then the default {@link org.apache.log4j.Level}
+     * class is used to process the level value.
+     *
+     * <p>As a special case, if the <code>value</code> parameter is
+     * equal to the string "NULL", then the value <code>null</code> will
+     * be returned.
+     *
+     * <p> If any error occurs while converting the value to a level,
+     * the <code>defaultValue</code> parameter, which may be
+     * <code>null</code>, is returned.
+     *
+     * <p> Case of <code>value</code> is insignificant for the level level, but is
+     * significant for the class name part, if present.
+     *
+     * @since 1.1
+     */
+    public static Level toLevel(String value, Level defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+
+        value = value.trim();
+
+        int hashIndex = value.indexOf('#');
+        if (hashIndex == -1) {
+            if ("NULL".equalsIgnoreCase(value)) {
+                return null;
+            } else {
+                // no class name specified : use standard Level class
+                return Level.toLevel(value, defaultValue);
+            }
+        }
+
+        Level result = defaultValue;
+
+        String clazz = value.substring(hashIndex + 1);
+        String levelName = value.substring(0, hashIndex);
+
+        // This is degenerate case but you never know.
+        if ("NULL".equalsIgnoreCase(levelName)) {
+            return null;
+        }
+
+        LOGGER.debug("toLevel" + ":class=[" + clazz + "]"
+                + ":pri=[" + levelName + "]");
+
+        try {
+            Class customLevel = LoaderUtil.loadClass(clazz);
+
+            // get a ref to the specified class' static method
+            // toLevel(String, org.apache.log4j.Level)
+            Class[] paramTypes = new Class[]{String.class,
+                    org.apache.log4j.Level.class
+            };
+            java.lang.reflect.Method toLevelMethod =
+                    customLevel.getMethod("toLevel", paramTypes);
+
+            // now call the toLevel method, passing level string + default
+            Object[] params = new Object[]{levelName, defaultValue};
+            Object o = toLevelMethod.invoke(null, params);
+
+            result = (Level) o;
+        } catch (ClassNotFoundException e) {
+            LOGGER.warn("custom level class [" + clazz + "] not found.");
+        } catch (NoSuchMethodException e) {
+            LOGGER.warn("custom level class [" + clazz + "]"
+                    + " does not have a class function toLevel(String, Level)", e);
+        } catch (java.lang.reflect.InvocationTargetException e) {
+            if (e.getTargetException() instanceof InterruptedException
+                    || e.getTargetException() instanceof InterruptedIOException) {
+                Thread.currentThread().interrupt();
+            }
+            LOGGER.warn("custom level class [" + clazz + "]"
+                    + " could not be instantiated", e);
+        } catch (ClassCastException e) {
+            LOGGER.warn("class [" + clazz
+                    + "] is not a subclass of org.apache.log4j.Level", e);
+        } catch (IllegalAccessException e) {
+            LOGGER.warn("class [" + clazz +
+                    "] cannot be instantiated due to access restrictions", e);
+        } catch (RuntimeException e) {
+            LOGGER.warn("class [" + clazz + "], level [" + levelName +
+                    "] conversion failed.", e);
+        }
+        return result;
+    }
+
+    /**
+     * Instantiate an object given a class name. Check that the
+     * <code>className</code> is a subclass of
+     * <code>superClass</code>. If that test fails or the object could
+     * not be instantiated, then <code>defaultValue</code> is returned.
+     *
+     * @param className    The fully qualified class name of the object to instantiate.
+     * @param superClass   The class to which the new object should belong.
+     * @param defaultValue The object to return in case of non-fulfillment
+     */
+    public static Object instantiateByClassName(String className, Class<?> superClass,
+            Object defaultValue) {
+        if (className != null) {
+            try {
+                Object obj = LoaderUtil.newInstanceOf(className);
+                if (!superClass.isAssignableFrom(obj.getClass())) {
+                    LOGGER.error("A \"{}\" object is not assignable to a \"{}\" variable", className,
+                            superClass.getName());
+                    return defaultValue;
+                }
+                return obj;
+            } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException
+                    | InstantiationException | InvocationTargetException e) {
+                LOGGER.error("Could not instantiate class [" + className + "].", e);
+            }
+        }
+        return defaultValue;
+    }
+
+
+    /**
+     * Perform variable substitution in string <code>val</code> from the
+     * values of keys found in the system propeties.
+     *
+     * <p>The variable substitution delimeters are <b>${</b> and <b>}</b>.
+     *
+     * <p>For example, if the System properties contains "key=value", then
+     * the call
+     * <pre>
+     * String s = OptionConverter.substituteVars("Value of key is ${key}.");
+     * </pre>
+     * <p>
+     * will set the variable <code>s</code> to "Value of key is value.".
+     *
+     * <p>If no value could be found for the specified key, then the
+     * <code>props</code> parameter is searched, if the value could not
+     * be found there, then substitution defaults to the empty string.
+     *
+     * <p>For example, if system propeties contains no value for the key
+     * "inexistentKey", then the call
+     *
+     * <pre>
+     * String s = OptionConverter.subsVars("Value of inexistentKey is [${inexistentKey}]");
+     * </pre>
+     * will set <code>s</code> to "Value of inexistentKey is []"
+     *
+     * <p>An {@link IllegalArgumentException} is thrown if
+     * <code>val</code> contains a start delimeter "${" which is not
+     * balanced by a stop delimeter "}". </p>
+     *
+     * <p><b>Author</b> Avy Sharell</a></p>
+     *
+     * @param val The string on which variable substitution is performed.
+     * @throws IllegalArgumentException if <code>val</code> is malformed.
+     */
+    public static String substVars(String val, Properties props) throws IllegalArgumentException {
+
+        StringBuilder sbuf = new StringBuilder();
+
+        int i = 0;
+        int j, k;
+
+        while (true) {
+            j = val.indexOf(DELIM_START, i);
+            if (j == -1) {
+                // no more variables
+                if (i == 0) { // this is a simple string
+                    return val;
+                } else { // add the tail string which contails no variables and return the result.
+                    sbuf.append(val.substring(i, val.length()));
+                    return sbuf.toString();
+                }
+            } else {
+                sbuf.append(val.substring(i, j));
+                k = val.indexOf(DELIM_STOP, j);
+                if (k == -1) {
+                    throw new IllegalArgumentException('"' + val +
+                            "\" has no closing brace. Opening brace at position " + j
+                            + '.');
+                } else {
+                    j += DELIM_START_LEN;
+                    String key = val.substring(j, k);
+                    // first try in System properties
+                    String replacement = getSystemProperty(key, null);
+                    // then try props parameter
+                    if (replacement == null && props != null) {
+                        replacement = props.getProperty(key);
+                    }
+
+                    if (replacement != null) {
+                        // Do variable substitution on the replacement string
+                        // such that we can solve "Hello ${x2}" as "Hello p1"
+                        // the where the properties are
+                        // x1=p1
+                        // x2=${x1}
+                        String recursiveReplacement = substVars(replacement, props);
+                        sbuf.append(recursiveReplacement);
+                    }
+                    i = k + DELIM_STOP_LEN;
+                }
+            }
+        }
+    }
+    
+    private static class CharMap {
+        final char key;
+        final char replacement;
+        
+        public CharMap(char key, char replacement) {
+            this.key = key;
+            this.replacement = replacement;
+        }
+    }
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/helpers/QuietWriter.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/helpers/QuietWriter.java
new file mode 100644
index 0000000..1779019
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/helpers/QuietWriter.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.helpers;
+
+import org.apache.log4j.spi.ErrorCode;
+import org.apache.log4j.spi.ErrorHandler;
+
+import java.io.FilterWriter;
+import java.io.Writer;
+
+
+/**
+ * QuietWriter does not throw exceptions when things go
+ * wrong. Instead, it delegates error handling to its {@link ErrorHandler}.
+ */
+public class QuietWriter extends FilterWriter {
+
+    protected ErrorHandler errorHandler;
+
+    public QuietWriter(Writer writer, ErrorHandler errorHandler) {
+        super(writer);
+        setErrorHandler(errorHandler);
+    }
+
+    public void write(String string) {
+        if (string != null) {
+            try {
+                out.write(string);
+            } catch (Exception e) {
+                errorHandler.error("Failed to write [" + string + "].", e,
+                        ErrorCode.WRITE_FAILURE);
+            }
+        }
+    }
+
+    public void flush() {
+        try {
+            out.flush();
+        } catch (Exception e) {
+            errorHandler.error("Failed to flush writer,", e,
+                    ErrorCode.FLUSH_FAILURE);
+        }
+    }
+
+
+    public void setErrorHandler(ErrorHandler eh) {
+        if (eh == null) {
+            // This is a programming error on the part of the enclosing appender.
+            throw new IllegalArgumentException("Attempted to set null ErrorHandler.");
+        } else {
+            this.errorHandler = eh;
+        }
+    }
+}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/helpers/package-info.java
similarity index 68%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-1.2-api/src/src/main/java/org/apache/log4j/helpers/package-info.java
index 13aaf9c..00d0e12 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/helpers/package-info.java
@@ -14,17 +14,7 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
-
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-public class ProcessIdUtilTest {
-
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
-    }
-}
+/**
+ * Log4j 1.x compatibility layer.
+ */
+package org.apache.log4j.helpers;
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/layout/Log4j1XmlLayout.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/layout/Log4j1XmlLayout.java
new file mode 100644
index 0000000..9522b9e
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/layout/Log4j1XmlLayout.java
@@ -0,0 +1,159 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.layout;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.Node;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
+import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+import org.apache.logging.log4j.core.layout.AbstractStringLayout;
+import org.apache.logging.log4j.core.layout.ByteBufferDestination;
+import org.apache.logging.log4j.core.util.Transform;
+import org.apache.logging.log4j.util.BiConsumer;
+import org.apache.logging.log4j.util.ReadOnlyStringMap;
+import org.apache.logging.log4j.util.Strings;
+
+/**
+ * Port of XMLLayout in Log4j 1.x. Provided for compatibility with existing Log4j 1 configurations.
+ *
+ * Originally developed by Ceki G&uuml;lc&uuml;, Mathias Bogaert.
+ */
+@Plugin(name = "Log4j1XmlLayout", category = Node.CATEGORY, elementType = Layout.ELEMENT_TYPE, printObject = true)
+public final class Log4j1XmlLayout extends AbstractStringLayout {
+
+    private final boolean locationInfo;
+    private final boolean properties;
+
+    @PluginFactory
+    public static Log4j1XmlLayout createLayout(
+            // @formatter:off
+            @PluginAttribute(value = "locationInfo") final boolean locationInfo,
+            @PluginAttribute(value = "properties") final boolean properties
+            // @formatter:on
+    ) {
+        return new Log4j1XmlLayout(locationInfo, properties);
+    }
+
+    private Log4j1XmlLayout(final boolean locationInfo, final boolean properties) {
+        super(StandardCharsets.UTF_8);
+        this.locationInfo = locationInfo;
+        this.properties = properties;
+    }
+
+    public boolean isLocationInfo() {
+        return locationInfo;
+    }
+
+    public boolean isProperties() {
+        return properties;
+    }
+
+    @Override
+    public void encode(final LogEvent event, final ByteBufferDestination destination) {
+        final StringBuilder text = getStringBuilder();
+        formatTo(event, text);
+        getStringBuilderEncoder().encode(text, destination);
+    }
+
+    @Override
+    public String toSerializable(final LogEvent event) {
+        final StringBuilder text = getStringBuilder();
+        formatTo(event, text);
+        return text.toString();
+    }
+
+    private void formatTo(final LogEvent event, final StringBuilder buf) {
+        // We yield to the \r\n heresy.
+
+        buf.append("<log4j:event logger=\"");
+        buf.append(Transform.escapeHtmlTags(event.getLoggerName()));
+        buf.append("\" timestamp=\"");
+        buf.append(event.getTimeMillis());
+        buf.append("\" level=\"");
+        buf.append(Transform.escapeHtmlTags(String.valueOf(event.getLevel())));
+        buf.append("\" thread=\"");
+        buf.append(Transform.escapeHtmlTags(event.getThreadName()));
+        buf.append("\">\r\n");
+
+        buf.append("<log4j:message><![CDATA[");
+        // Append the rendered message. Also make sure to escape any existing CDATA sections.
+        Transform.appendEscapingCData(buf, event.getMessage().getFormattedMessage());
+        buf.append("]]></log4j:message>\r\n");
+
+        final List<String> ndc = event.getContextStack().asList();
+        if (!ndc.isEmpty()) {
+            buf.append("<log4j:NDC><![CDATA[");
+            Transform.appendEscapingCData(buf, Strings.join(ndc, ' '));
+            buf.append("]]></log4j:NDC>\r\n");
+        }
+
+        @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+		final Throwable thrown = event.getThrown();
+        if (thrown != null) {
+            buf.append("<log4j:throwable><![CDATA[");
+            final StringWriter w = new StringWriter();
+            thrown.printStackTrace(new PrintWriter(w));
+            Transform.appendEscapingCData(buf, w.toString());
+            buf.append("]]></log4j:throwable>\r\n");
+        }
+
+        if (locationInfo) {
+            final StackTraceElement source = event.getSource();
+            if (source != null) {
+                buf.append("<log4j:locationInfo class=\"");
+                buf.append(Transform.escapeHtmlTags(source.getClassName()));
+                buf.append("\" method=\"");
+                buf.append(Transform.escapeHtmlTags(source.getMethodName()));
+                buf.append("\" file=\"");
+                buf.append(Transform.escapeHtmlTags(source.getFileName()));
+                buf.append("\" line=\"");
+                buf.append(source.getLineNumber());
+                buf.append("\"/>\r\n");
+            }
+        }
+
+        if (properties) {
+            final ReadOnlyStringMap contextMap = event.getContextData();
+            if (!contextMap.isEmpty()) {
+                buf.append("<log4j:properties>\r\n");
+                contextMap.forEach(new BiConsumer<String, String>() {
+                    @Override
+                    public void accept(final String key, final String val) {
+                        if (val != null) {
+                            buf.append("<log4j:data name=\"");
+                            buf.append(Transform.escapeHtmlTags(key));
+                            buf.append("\" value=\"");
+                            buf.append(Transform.escapeHtmlTags(val));
+                            buf.append("\"/>\r\n");
+                        }
+                    }
+                });
+                buf.append("</log4j:properties>\r\n");
+            }
+        }
+
+        buf.append("</log4j:event>\r\n\r\n");
+    }
+
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/legacy/core/CategoryUtil.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/legacy/core/CategoryUtil.java
new file mode 100644
index 0000000..f9e9f7c
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/legacy/core/CategoryUtil.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.legacy.core;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.spi.LoggerContext;
+
+/**
+ * Provide access to Log4j Core Logger methods.
+ */
+public final class CategoryUtil {
+
+    private CategoryUtil() {
+    }
+
+    public static boolean isAdditive(Logger logger) {
+        if (logger instanceof org.apache.logging.log4j.core.Logger) {
+            return ((org.apache.logging.log4j.core.Logger) logger).isAdditive();
+        }
+        return false;
+    }
+
+    public static void setAdditivity(Logger logger, boolean additivity) {
+        if (logger instanceof org.apache.logging.log4j.core.Logger) {
+            ((org.apache.logging.log4j.core.Logger) logger).setAdditive(additivity);
+        }
+    }
+
+    public static Logger getParent(Logger logger) {
+        if (logger instanceof org.apache.logging.log4j.core.Logger) {
+            return ((org.apache.logging.log4j.core.Logger) logger).getParent();
+
+        }
+        return null;
+    }
+
+    public static LoggerContext getLoggerContext(Logger logger) {
+        if (logger instanceof org.apache.logging.log4j.core.Logger) {
+            return ((org.apache.logging.log4j.core.Logger) logger).getContext();
+        }
+        return null;
+    }
+
+    public static void setLevel(Logger logger, Level level) {
+        if (logger instanceof org.apache.logging.log4j.core.Logger) {
+            ((org.apache.logging.log4j.core.Logger) logger).setLevel(level);
+
+        }
+    }
+}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/legacy/core/ContextUtil.java
similarity index 64%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-1.2-api/src/src/main/java/org/apache/log4j/legacy/core/ContextUtil.java
index 13aaf9c..d3b99fa 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/legacy/core/ContextUtil.java
@@ -14,17 +14,21 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
+package org.apache.log4j.legacy.core;
 
-import org.junit.Test;
+import org.apache.logging.log4j.spi.LoggerContext;
 
-import static org.junit.Assert.*;
+/**
+ * Implements LoggerContext methods specific to log4j-core.
+ */
+public final class ContextUtil {
 
-public class ProcessIdUtilTest {
+    private ContextUtil() {
+    }
 
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
+    public static void reconfigure(LoggerContext ctx) {
+        if (ctx instanceof org.apache.logging.log4j.core.LoggerContext) {
+            ((org.apache.logging.log4j.core.LoggerContext) ctx).reconfigure();
+        }
     }
 }
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/or/ObjectRenderer.java
similarity index 68%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-1.2-api/src/src/main/java/org/apache/log4j/or/ObjectRenderer.java
index 13aaf9c..f3fed18 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/or/ObjectRenderer.java
@@ -14,17 +14,14 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
+package org.apache.log4j.or;
 
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-public class ProcessIdUtilTest {
-
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
-    }
+/**
+ * Converts objects to Strings.
+ */
+public interface ObjectRenderer {
+    /**
+     * Render the object passed as parameter as a String.
+     */
+	 String doRender(Object o);
 }
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/or/RendererSupport.java
similarity index 69%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-1.2-api/src/src/main/java/org/apache/log4j/or/RendererSupport.java
index 13aaf9c..9b8728d 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/or/RendererSupport.java
@@ -14,17 +14,13 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
+package org.apache.log4j.or;
 
-import org.junit.Test;
+import java.util.Map;
 
-import static org.junit.Assert.*;
-
-public class ProcessIdUtilTest {
-
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
-    }
+/**
+ * Interface that indicates the Renderer Map is available. This interface differs
+ */
+public interface RendererSupport {
+    Map<Class<?>, ObjectRenderer> getRendererMap();
 }
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/or/ThreadGroupRenderer.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/or/ThreadGroupRenderer.java
new file mode 100644
index 0000000..08233bf
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/or/ThreadGroupRenderer.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.or;
+
+import org.apache.log4j.Layout;
+
+/**
+ */
+public class ThreadGroupRenderer implements ObjectRenderer {
+
+    public
+    String  doRender(Object obj) {
+        if(obj instanceof ThreadGroup) {
+            StringBuilder sb = new StringBuilder();
+            ThreadGroup threadGroup = (ThreadGroup) obj;
+            sb.append("java.lang.ThreadGroup[name=");
+            sb.append(threadGroup.getName());
+            sb.append(", maxpri=");
+            sb.append(threadGroup.getMaxPriority());
+            sb.append("]");
+            Thread[] threads = new Thread[threadGroup.activeCount()];
+            threadGroup.enumerate(threads);
+            for (Thread thread : threads) {
+                sb.append(Layout.LINE_SEP);
+                sb.append("   Thread=[");
+                sb.append(thread.getName());
+                sb.append(",");
+                sb.append(thread.getPriority());
+                sb.append(",");
+                sb.append(thread.isDaemon());
+                sb.append("]");
+            }
+            return sb.toString();
+        } else {
+            try {
+                // this is the best we can do
+                return obj.toString();
+            } catch(Exception ex) {
+                return ex.toString();
+            }
+        }
+    }
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/or/jms/MessageRenderer.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/or/jms/MessageRenderer.java
new file mode 100644
index 0000000..e6f4b6b
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/or/jms/MessageRenderer.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.or.jms;
+
+import org.apache.log4j.or.ObjectRenderer;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.status.StatusLogger;
+
+import javax.jms.Message;
+import javax.jms.JMSException;
+import javax.jms.DeliveryMode;
+
+/**
+ * Log4j 1.x JMS Message Renderer
+ */
+public class MessageRenderer implements ObjectRenderer {
+    private static final Logger LOGGER = StatusLogger.getLogger();
+    
+    /**
+     Render a {@link javax.jms.Message}.
+     */
+    public
+    String  doRender(Object obj) {
+        if (obj instanceof Message) {
+            StringBuilder sb = new StringBuilder();
+            Message message = (Message) obj;
+            try {
+                sb.append("DeliveryMode=");
+                switch(message.getJMSDeliveryMode()) {
+                    case DeliveryMode.NON_PERSISTENT :
+                        sb.append("NON_PERSISTENT");
+                        break;
+                    case DeliveryMode.PERSISTENT :
+                        sb.append("PERSISTENT");
+                        break;
+                    default: sb.append("UNKNOWN");
+                }
+                sb.append(", CorrelationID=");
+                sb.append(message.getJMSCorrelationID());
+
+                sb.append(", Destination=");
+                sb.append(message.getJMSDestination());
+
+                sb.append(", Expiration=");
+                sb.append(message.getJMSExpiration());
+
+                sb.append(", MessageID=");
+                sb.append(message.getJMSMessageID());
+
+                sb.append(", Priority=");
+                sb.append(message.getJMSPriority());
+
+                sb.append(", Redelivered=");
+                sb.append(message.getJMSRedelivered());
+
+                sb.append(", ReplyTo=");
+                sb.append(message.getJMSReplyTo());
+
+                sb.append(", Timestamp=");
+                sb.append(message.getJMSTimestamp());
+
+                sb.append(", Type=");
+                sb.append(message.getJMSType());
+
+            } catch(JMSException e) {
+                LOGGER.error("Could not parse Message.", e);
+            }
+            return sb.toString();
+        } else {
+            return obj.toString();
+        }
+    }
+}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/package-info.java
similarity index 68%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-1.2-api/src/src/main/java/org/apache/log4j/package-info.java
index 13aaf9c..714c200 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/package-info.java
@@ -14,17 +14,7 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
-
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-public class ProcessIdUtilTest {
-
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
-    }
-}
+/**
+ * Log4j 1.x compatibility layer.
+ */
+package org.apache.log4j;
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/pattern/Log4j1MdcPatternConverter.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/pattern/Log4j1MdcPatternConverter.java
new file mode 100644
index 0000000..b4ae0c5
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/pattern/Log4j1MdcPatternConverter.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.pattern;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.pattern.ConverterKeys;
+import org.apache.logging.log4j.core.pattern.LogEventPatternConverter;
+import org.apache.logging.log4j.core.pattern.PatternConverter;
+import org.apache.logging.log4j.util.TriConsumer;
+
+/**
+ * Able to handle the contents of the LogEvent's MDC and either
+ * output the entire contents of the properties, or to output the value of a specific key
+ * within the property bundle when this pattern converter has the option set.
+ */
+@Plugin(name = "Log4j1MdcPatternConverter", category = PatternConverter.CATEGORY)
+@ConverterKeys({ "properties" })
+public final class Log4j1MdcPatternConverter extends LogEventPatternConverter {
+    /**
+     * Name of property to output.
+     */
+    private final String key;
+
+    /**
+     * Private constructor.
+     *
+     * @param options options, may be null.
+     */
+    private Log4j1MdcPatternConverter(final String[] options) {
+        super(options != null && options.length > 0 ? "Log4j1MDC{" + options[0] + '}' : "Log4j1MDC", "property");
+        if (options != null && options.length > 0) {
+            key = options[0];
+        } else {
+            key = null;
+        }
+    }
+
+    /**
+     * Obtains an instance of PropertiesPatternConverter.
+     *
+     * @param options options, may be null or first element contains name of property to format.
+     * @return instance of PropertiesPatternConverter.
+     */
+    public static Log4j1MdcPatternConverter newInstance(final String[] options) {
+        return new Log4j1MdcPatternConverter(options);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void format(final LogEvent event, final StringBuilder toAppendTo) {
+        if (key == null) {
+            // if there is no additional options, we output every single Key/Value pair for the MDC
+            toAppendTo.append('{');
+            event.getContextData().forEach(APPEND_EACH, toAppendTo);
+            toAppendTo.append('}');
+        } else {
+            // otherwise they just want a single key output
+            final Object val = event.getContextData().getValue(key);
+            if (val != null) {
+                toAppendTo.append(val);
+            }
+        }
+    }
+
+    private static TriConsumer<String, Object, StringBuilder> APPEND_EACH = new TriConsumer<String, Object, StringBuilder>() {
+        @Override
+        public void accept(final String key, final Object value, final StringBuilder toAppendTo) {
+            toAppendTo.append('{').append(key).append(',').append(value).append('}');
+        }
+    };
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/pattern/Log4j1NdcPatternConverter.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/pattern/Log4j1NdcPatternConverter.java
new file mode 100644
index 0000000..405db00
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/pattern/Log4j1NdcPatternConverter.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.pattern;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.pattern.ConverterKeys;
+import org.apache.logging.log4j.core.pattern.LogEventPatternConverter;
+import org.apache.logging.log4j.core.pattern.PatternConverter;
+import org.apache.logging.log4j.util.Strings;
+
+import java.util.List;
+
+
+/**
+ * Returns the event's NDC in a StringBuilder.
+ */
+@Plugin(name = "Log4j1NdcPatternConverter", category = PatternConverter.CATEGORY)
+@ConverterKeys({ "ndc" })
+public final class Log4j1NdcPatternConverter extends LogEventPatternConverter {
+    /**
+     * Singleton.
+     */
+    private static final Log4j1NdcPatternConverter INSTANCE =
+        new Log4j1NdcPatternConverter();
+
+    /**
+     * Private constructor.
+     */
+    private Log4j1NdcPatternConverter() {
+        super("Log4j1NDC", "ndc");
+    }
+
+    /**
+     * Obtains an instance of NdcPatternConverter.
+     *
+     * @param options options, may be null.
+     * @return instance of NdcPatternConverter.
+     */
+    public static Log4j1NdcPatternConverter newInstance(final String[] options) {
+        return INSTANCE;
+    }
+
+    @Override
+    public void format(final LogEvent event, final StringBuilder toAppendTo) {
+        final List<String> ndc = event.getContextStack().asList();
+        toAppendTo.append(Strings.join(ndc, ' '));
+    }
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/AppenderAttachable.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/AppenderAttachable.java
new file mode 100644
index 0000000..fd464a2
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/AppenderAttachable.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.spi;
+
+import org.apache.log4j.Appender;
+
+import java.util.Enumeration;
+
+/**
+ * Interface for attaching appenders to objects.
+ */
+public interface AppenderAttachable {
+
+    /**
+     * Add an appender.
+     */
+    void addAppender(Appender newAppender);
+
+    /**
+     * Get all previously added appenders as an Enumeration.
+     */
+    Enumeration getAllAppenders();
+
+    /**
+     * Get an appender by name.
+     */
+    Appender getAppender(String name);
+
+
+    /**
+     * Returns <code>true</code> if the specified appender is in list of
+     * attached attached, <code>false</code> otherwise.
+     *
+     * @since 1.2
+     */
+    boolean isAttached(Appender appender);
+
+    /**
+     * Remove all previously added appenders.
+     */
+    void removeAllAppenders();
+
+
+    /**
+     * Remove the appender passed as parameter from the list of appenders.
+     */
+    void removeAppender(Appender appender);
+
+
+    /**
+     * Remove the appender with the name passed as parameter from the
+     * list of appenders.
+     */
+    void removeAppender(String name);
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/Configurator.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/Configurator.java
new file mode 100644
index 0000000..b418db8
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/Configurator.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.spi;
+
+import java.io.InputStream;
+import java.net.URL;
+
+import org.apache.logging.log4j.core.LoggerContext;
+
+/**
+ * Log4j 1.x Configurator interface.
+ */
+public interface Configurator {
+
+    public static final String INHERITED = "inherited";
+
+    public static final String NULL = "null";
+
+
+    /**
+     Interpret a resource pointed by a InputStream and set up log4j accordingly.
+
+     The configuration is done relative to the <code>hierarchy</code>
+     parameter.
+
+     @param inputStream The InputStream to parse
+
+     @since 1.2.17
+     */
+    void doConfigure(InputStream inputStream, final LoggerContext loggerContext);
+
+    /**
+     Interpret a resource pointed by a URL and set up log4j accordingly.
+
+     The configuration is done relative to the <code>hierarchy</code>
+     parameter.
+
+     @param url The URL to parse
+     */
+    void doConfigure(URL url, final LoggerContext loggerContext);
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/ErrorCode.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/ErrorCode.java
new file mode 100644
index 0000000..7fbbf95
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/ErrorCode.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.spi;
+
+
+/**
+   This interface defines commonly encoutered error codes.
+ */
+public interface ErrorCode {
+
+  public final int GENERIC_FAILURE = 0;
+  public final int WRITE_FAILURE = 1;
+  public final int FLUSH_FAILURE = 2;
+  public final int CLOSE_FAILURE = 3;
+  public final int FILE_OPEN_FAILURE = 4;
+  public final int MISSING_LAYOUT = 5;
+  public final int ADDRESS_PARSE_FAILURE = 6;
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/ErrorHandler.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/ErrorHandler.java
new file mode 100644
index 0000000..2e64103
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/ErrorHandler.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.spi;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.Logger;
+
+
+/**
+ * Appenders may delegate their error handling to
+ * <code>ErrorHandlers</code>.
+ * <p>
+ * Error handling is a particularly tedious to get right because by
+ * definition errors are hard to predict and to reproduce.
+ * </p>
+ * <p>
+ * Please take the time to contact the author in case you discover
+ * that errors are not properly handled. You are most welcome to
+ * suggest new error handling policies or criticize existing policies.
+ * </p>
+ */
+public interface ErrorHandler {
+
+    /**
+     * Add a reference to a logger to which the failing appender might
+     * be attached to. The failing appender will be searched and
+     * replaced only in the loggers you add through this method.
+     *
+     * @param logger One of the loggers that will be searched for the failing
+     *               appender in view of replacement.
+     * @since 1.2
+     */
+    void setLogger(Logger logger);
+
+
+    /**
+     * Equivalent to the {@link #error(String, Exception, int,
+     * LoggingEvent)} with the the event parameter set to
+     * <code>null</code>.
+     *
+     * @param message   The message associated with the error.
+     * @param e         The Exception that was thrown when the error occurred.
+     * @param errorCode The error code associated with the error.
+     */
+    void error(String message, Exception e, int errorCode);
+
+    /**
+     * This method is normally used to just print the error message
+     * passed as a parameter.
+     *
+     * @param message   The message associated with the error.
+     */
+    void error(String message);
+
+    /**
+     * This method is invoked to handle the error.
+     *
+     * @param message   The message associated with the error.
+     * @param e         The Exception that was thrown when the error occurred.
+     * @param errorCode The error code associated with the error.
+     * @param event     The logging event that the failing appender is asked
+     *                  to log.
+     * @since 1.2
+     */
+    void error(String message, Exception e, int errorCode, LoggingEvent event);
+
+    /**
+     * Set the appender for which errors are handled. This method is
+     * usually called when the error handler is configured.
+     *
+     * @param appender The appender
+     * @since 1.2
+     */
+    void setAppender(Appender appender);
+
+    /**
+     * Set the appender to fallback upon in case of failure.
+     *
+     * @param appender The backup appender
+     * @since 1.2
+     */
+    void setBackupAppender(Appender appender);
+}
+
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/Filter.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/Filter.java
new file mode 100644
index 0000000..997398b
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/Filter.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.spi;
+
+import org.apache.log4j.bridge.FilterAdapter;
+
+/**
+ * @since 0.9.0
+ */
+public abstract class Filter {
+    private final FilterAdapter adapter;
+
+    public Filter() {
+        FilterAdapter filterAdapter = null;
+        try {
+            Class.forName("org.apache.logging.log4j.core.Filter");
+            filterAdapter = new FilterAdapter(this);
+        } catch(ClassNotFoundException ex) {
+            // Ignore the exception. Log4j Core is not present.
+        }
+        this.adapter = filterAdapter;
+    }
+
+    /**
+     * The log event must be dropped immediately without consulting
+     * with the remaining filters, if any, in the chain.
+     */
+    public static final int DENY = -1;
+
+    /**
+     * This filter is neutral with respect to the log event. The
+     * remaining filters, if any, should be consulted for a final decision.
+     */
+    public static final int NEUTRAL = 0;
+
+    /**
+     * The log event must be logged immediately without consulting with
+     * the remaining filters, if any, in the chain.
+     */
+    public static final int ACCEPT = 1;
+
+    /**
+     * Points to the next filter in the filter chain.
+     *
+     * @deprecated As of 1.2.12, use {@link #getNext} and {@link #setNext} instead
+     */
+    @Deprecated
+    public Filter next;
+
+    /**
+     * Usually filters options become active when set. We provide a
+     * default do-nothing implementation for convenience.
+     */
+    public void activateOptions() {
+    }
+
+
+    /**
+     * <p>If the decision is <code>DENY</code>, then the event will be
+     * dropped. If the decision is <code>NEUTRAL</code>, then the next
+     * filter, if any, will be invoked. If the decision is ACCEPT then
+     * the event will be logged without consulting with other filters in
+     * the chain.
+     *
+     * @param event The LoggingEvent to decide upon.
+     * @return decision The decision of the filter.
+     */
+    public abstract int decide(LoggingEvent event);
+
+    /**
+     * Set the next filter pointer.
+     * @param next The next Filter.
+     */
+    public void setNext(final Filter next) {
+        this.next = next;
+    }
+
+    /**
+     * Return the pointer to the next filter.
+     * @return The next Filter.
+     */
+    public Filter getNext() {
+        return next;
+    }
+
+}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/HierarchyEventListener.java
similarity index 69%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/HierarchyEventListener.java
index 13aaf9c..286ba54 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/HierarchyEventListener.java
@@ -14,17 +14,20 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
+package org.apache.log4j.spi;
 
-import org.junit.Test;
+import org.apache.log4j.Appender;
+import org.apache.log4j.Category;
 
-import static org.junit.Assert.*;
+/**
+ Listen to events occurring within a Hierarchy.
 
-public class ProcessIdUtilTest {
+ @since 1.2
 
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
-    }
+ */
+public interface HierarchyEventListener {
+
+    void addAppenderEvent(Category cat, Appender appender);
+
+    void removeAppenderEvent(Category cat, Appender appender);
 }
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/LocationInfo.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/LocationInfo.java
new file mode 100644
index 0000000..2102802
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/LocationInfo.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.spi;
+
+/**
+ The internal representation of caller location information.
+
+ @since 0.8.3
+ */
+public class LocationInfo implements java.io.Serializable {
+
+    private final StackTraceElement element;
+
+    public String fullInfo;
+
+    public LocationInfo(StackTraceElement element) {
+        this.element = element;
+    }
+
+    /**
+     When location information is not available the constant
+     <code>NA</code> is returned. Current value of this string
+     constant is <b>?</b>.  */
+    public final static String NA = "?";
+
+    static final long serialVersionUID = -1325822038990805636L;
+
+
+    /**
+     Return the fully qualified class name of the caller making the
+     logging request.
+     */
+    public
+    String getClassName() {
+        return element.getClassName();
+    }
+
+    /**
+     Return the file name of the caller.
+     */
+    public
+    String getFileName() {
+        return element.getFileName();
+    }
+
+    /**
+     Returns the line number of the caller.
+     */
+    public
+    String getLineNumber() {
+        return Integer.toString(element.getLineNumber());
+    }
+
+    /**
+     Returns the method name of the caller.
+     */
+    public
+    String getMethodName() {
+        return element.getMethodName();
+    }
+}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/LoggerFactory.java
similarity index 69%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/LoggerFactory.java
index 13aaf9c..e2f3708 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/LoggerFactory.java
@@ -14,17 +14,20 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
+package org.apache.log4j.spi;
 
-import org.junit.Test;
+import org.apache.log4j.Logger;
 
-import static org.junit.Assert.*;
+/**
+ *
+ * Implement this interface to create new instances of Logger or a sub-class of Logger.
+ *
+ * <p>
+ * See <code>examples/subclass/MyLogger.java</code> for an example.
+ * </p>
+ */
+public interface LoggerFactory {
 
-public class ProcessIdUtilTest {
+    Logger makeNewLoggerInstance(String name);
 
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
-    }
 }
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/LoggerRepository.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/LoggerRepository.java
new file mode 100644
index 0000000..812280f
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/LoggerRepository.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.spi;
+
+import java.util.Enumeration;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.Category;
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+
+/**
+ * A <code>LoggerRepository</code> is used to create and retrieve <code>Loggers</code>.
+ * <p>
+ * The relation between loggers in a repository depends on the repository but typically loggers are arranged in a named
+ * hierarchy.
+ * </p>
+ * <p>
+ * In addition to the creational methods, a <code>LoggerRepository</code> can be queried for existing loggers, can act
+ * as a point of registry for events related to loggers.
+ * </p>
+ *
+ * @since 1.2
+ */
+public interface LoggerRepository {
+
+    /**
+     * Add a {@link HierarchyEventListener} event to the repository.
+     *
+     * @param listener The listener
+     */
+    void addHierarchyEventListener(HierarchyEventListener listener);
+
+    /**
+     * Returns whether this repository is disabled for a given
+     * level. The answer depends on the repository threshold and the
+     * <code>level</code> parameter. See also {@link #setThreshold}
+     * method.
+     *
+     * @param level The level
+     * @return whether this repository is disabled.
+     */
+    boolean isDisabled(int level);
+
+    /**
+     * Set the repository-wide threshold. All logging requests below the
+     * threshold are immediately dropped. By default, the threshold is
+     * set to <code>Level.ALL</code> which has the lowest possible rank.
+     *
+     * @param level The level
+     */
+    void setThreshold(Level level);
+
+    /**
+     * Another form of {@link #setThreshold(Level)} accepting a string
+     * parameter instead of a <code>Level</code>.
+     *
+     * @param val The threshold value
+     */
+    void setThreshold(String val);
+
+    void emitNoAppenderWarning(Category cat);
+
+    /**
+     * Get the repository-wide threshold. See {@link #setThreshold(Level)} for an explanation.
+     *
+     * @return the level.
+     */
+    Level getThreshold();
+
+    Logger getLogger(String name);
+
+    Logger getLogger(String name, LoggerFactory factory);
+
+    Logger getRootLogger();
+
+    Logger exists(String name);
+
+    void shutdown();
+
+    @SuppressWarnings("rawtypes")
+    Enumeration getCurrentLoggers();
+
+    /**
+     * Deprecated. Please use {@link #getCurrentLoggers} instead.
+     *
+     * @return an enumeration of loggers.
+     */
+    @SuppressWarnings("rawtypes")
+    Enumeration getCurrentCategories();
+
+    void fireAddAppenderEvent(Category logger, Appender appender);
+
+    void resetConfiguration();
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/LoggingEvent.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/LoggingEvent.java
new file mode 100644
index 0000000..e9f57de
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/LoggingEvent.java
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.spi;
+
+import org.apache.log4j.Category;
+import org.apache.log4j.Level;
+import org.apache.log4j.bridge.LogEventAdapter;
+
+/**
+ *  No-op version of Log4j 1.2 LoggingEvent. This class is not directly used by Log4j 1.x clients but is used by
+ *  the Log4j 2 LogEvent adapter to be compatible with Log4j 1.x components.
+ */
+public class LoggingEvent {
+
+    /**
+     Set the location information for this logging event. The collected
+     information is cached for future use.
+     */
+    public LocationInfo getLocationInformation() {
+        return null;
+    }
+
+    /**
+     * Return the level of this event. Use this form instead of directly
+     * accessing the <code>level</code> field.  */
+    public Level getLevel() {
+        return null;
+    }
+
+    /**
+     * Return the name of the logger. Use this form instead of directly
+     * accessing the <code>categoryName</code> field.
+     */
+    public String getLoggerName() {
+        return null;
+    }
+
+    /**
+     * Gets the logger of the event.
+     * Use should be restricted to cloning events.
+     * @since 1.2.15
+     */
+    public Category getLogger() {
+        return null;
+    }
+
+    /**
+     Return the message for this logging event.
+
+     <p>Before serialization, the returned object is the message
+     passed by the user to generate the logging event. After
+     serialization, the returned value equals the String form of the
+     message possibly after object rendering.
+
+     @since 1.1 */
+    public
+    Object getMessage() {
+        return null;
+    }
+
+    public
+    String getNDC() {
+        return null;
+    }
+
+    public
+    Object getMDC(String key) {
+        return null;
+    }
+
+    /**
+     Obtain a copy of this thread's MDC prior to serialization or
+     asynchronous logging.
+     */
+    public
+    void getMDCCopy() {
+    }
+
+    public
+    String getRenderedMessage() {
+        return null;
+    }
+
+    /**
+     Returns the time when the application started, in milliseconds
+     elapsed since 01.01.1970.  */
+    public static long getStartTime() {
+        return LogEventAdapter.getStartTime();
+    }
+
+    public
+    String getThreadName() {
+        return null;
+    }
+
+    /**
+     Returns the throwable information contained within this
+     event. May be <code>null</code> if there is no such information.
+
+     <p>Note that the {@link Throwable} object contained within a
+     {@link ThrowableInformation} does not survive serialization.
+
+     @since 1.1 */
+    public
+    ThrowableInformation getThrowableInformation() {
+        return null;
+    }
+
+    /**
+     Return this event's throwable's string[] representaion.
+     */
+    public
+    String[] getThrowableStrRep() {
+        return null;
+    }
+
+}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/OptionHandler.java
similarity index 69%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/OptionHandler.java
index 13aaf9c..1b855bc 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/OptionHandler.java
@@ -14,17 +14,13 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
+package org.apache.log4j.spi;
 
-import org.junit.Test;
 
-import static org.junit.Assert.*;
+/**
+ * Log4j 1 Interface for dealing with configuration. Ignored in Log4j 2.
+ */
+public interface OptionHandler {
 
-public class ProcessIdUtilTest {
-
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
-    }
+    void activateOptions();
 }
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/RepositorySelector.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/RepositorySelector.java
new file mode 100644
index 0000000..9566659
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/RepositorySelector.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.spi;
+
+/**
+
+ The <code>LogManager</code> uses one (and only one)
+ <code>RepositorySelector</code> implementation to select the
+ {@link org.apache.log4j.spi.LoggerRepository} for a particular application context.
+
+ <p>It is the responsibility of the <code>RepositorySelector</code>
+ implementation to track the application context. Log4j makes no
+ assumptions about the application context or on its management.
+
+ <p>See also {@link org.apache.log4j.LogManager LogManager}.
+
+ @since 1.2
+
+ */
+public interface RepositorySelector {
+
+    /**
+     * Returns a {@link org.apache.log4j.spi.LoggerRepository} depending on the
+     * context. Implementers must make sure that a valid (non-null)
+     * LoggerRepository is returned.
+     * @return a LoggerRepository.
+     */
+    LoggerRepository getLoggerRepository();
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/ThrowableInformation.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/ThrowableInformation.java
new file mode 100644
index 0000000..5a9ace5
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/ThrowableInformation.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.spi;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.List;
+
+import org.apache.logging.log4j.core.util.Throwables;
+
+/**
+ * Class Description goes here.
+ */
+public class ThrowableInformation implements java.io.Serializable {
+
+    static final long serialVersionUID = -4748765566864322735L;
+
+    private transient Throwable throwable;
+    private Method toStringList;
+
+    @SuppressWarnings("unchecked")
+    public
+    ThrowableInformation(Throwable throwable) {
+        this.throwable = throwable;
+        Method method = null;
+        try {
+            Class throwables = Class.forName("org.apache.logging.log4j.core.util.Throwables");
+            method = throwables.getMethod("toStringList", Throwable.class);
+        } catch (ClassNotFoundException | NoSuchMethodException ex) {
+            // Ignore the exception if Log4j-core is not present.
+        }
+        this.toStringList = method;
+    }
+
+    public
+    Throwable getThrowable() {
+        return throwable;
+    }
+
+    public synchronized String[] getThrowableStrRep() {
+        if (toStringList != null && throwable != null) {
+            try {
+                @SuppressWarnings("unchecked")
+                List<String> elements = (List<String>) toStringList.invoke(null, throwable);
+                if (elements != null) {
+                    return elements.toArray(new String[0]);
+                }
+            } catch (IllegalAccessException | InvocationTargetException ex) {
+                // Ignore the exception.
+            }
+        }
+        return null;
+    }
+}
+
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/package-info.java
similarity index 68%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/package-info.java
index 13aaf9c..a7648dc 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/spi/package-info.java
@@ -14,17 +14,7 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
-
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-public class ProcessIdUtilTest {
-
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
-    }
-}
+/**
+ * Log4j 1.x compatibility layer.
+ */
+package org.apache.log4j.spi;
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/xml/DOMConfigurator.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/xml/DOMConfigurator.java
new file mode 100644
index 0000000..04a4555
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/xml/DOMConfigurator.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.xml;
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.net.URL;
+import java.util.Properties;
+
+import javax.xml.parsers.FactoryConfigurationError;
+
+import org.apache.log4j.config.PropertySetter;
+import org.apache.log4j.spi.LoggerRepository;
+import org.w3c.dom.Element;
+
+/**
+ *
+ */
+public class DOMConfigurator {
+
+    public void doConfigure(final String filename, final LoggerRepository repository) {
+    }
+
+    public void doConfigure(final URL url, final LoggerRepository repository) {
+    }
+
+    public void doConfigure(final InputStream inputStream, final LoggerRepository repository)
+        throws FactoryConfigurationError {
+    }
+
+    public void doConfigure(final Reader reader, final LoggerRepository repository)
+        throws FactoryConfigurationError {
+    }
+
+    public void doConfigure(final Element element, final LoggerRepository repository) {
+    }
+
+    public static void configure(final Element element) {
+    }
+
+    public static void configureAndWatch(final String configFilename) {
+    }
+
+    public static void configureAndWatch(final String configFilename, final long delay) {
+    }
+
+    public static void configure(final String filename) throws FactoryConfigurationError {
+    }
+
+    public static void configure(final URL url) throws FactoryConfigurationError {
+    }
+
+    public static String subst(final String value, final Properties props) {
+        return value;
+    }
+
+    public static void setParameter(final Element elem, final PropertySetter propSetter, final Properties props) {
+
+    }
+
+    public static Object parseElement(final Element element, final Properties props,
+                                      @SuppressWarnings("rawtypes") final Class expectedClass)
+        throws Exception {
+        return null;
+    }
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/xml/Log4jEntityResolver.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/xml/Log4jEntityResolver.java
new file mode 100644
index 0000000..edda022
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/xml/Log4jEntityResolver.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.xml;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+/**
+ * An {@link EntityResolver} specifically designed to return
+ * <code>log4j.dtd</code> which is embedded within the log4j jar
+ * file.
+ */
+public class Log4jEntityResolver implements EntityResolver {
+    private static final Logger LOGGER = StatusLogger.getLogger();
+    private static final String PUBLIC_ID = "-//APACHE//DTD LOG4J 1.2//EN";
+
+    public InputSource resolveEntity(String publicId, String systemId) {
+        if (systemId.endsWith("log4j.dtd") || PUBLIC_ID.equals(publicId)) {
+            Class clazz = getClass();
+            InputStream in = clazz.getResourceAsStream("/org/apache/log4j/xml/log4j.dtd");
+            if (in == null) {
+                LOGGER.warn("Could not find [log4j.dtd] using [{}] class loader, parsed without DTD.",
+                        clazz.getClassLoader());
+                in = new ByteArrayInputStream(new byte[0]);
+            }
+            return new InputSource(in);
+        } else {
+            return null;
+        }
+    }
+}
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/xml/UnrecognizedElementHandler.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/xml/UnrecognizedElementHandler.java
new file mode 100644
index 0000000..463d5d9
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/xml/UnrecognizedElementHandler.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.xml;
+
+import org.w3c.dom.Element;
+import java.util.Properties;
+
+/**
+ * When implemented by an object configured by DOMConfigurator,
+ * the handle method will be called when an unrecognized child
+ * element is encountered.  Unrecognized child elements of
+ * the log4j:configuration element will be dispatched to
+ * the logger repository if it supports this interface.
+ *
+ * @since 1.2.15
+ */
+public interface UnrecognizedElementHandler {
+    /**
+     * Called to inform a configured object when
+     * an unrecognized child element is encountered.
+     * @param element element, may not be null.
+     * @param props properties in force, may be null.
+     * @return true if configured object recognized the element
+     * @throws Exception throw an exception to prevent activation
+     * of the configured object.
+     */
+    boolean parseUnrecognizedElement(Element element, Properties props) throws Exception;
+}
\ No newline at end of file
diff --git a/log4j-1.2-api/src/src/main/java/org/apache/log4j/xml/XmlConfigurationFactory.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/xml/XmlConfigurationFactory.java
new file mode 100644
index 0000000..a2f7dc7
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/xml/XmlConfigurationFactory.java
@@ -0,0 +1,926 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.xml;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.Layout;
+import org.apache.log4j.Level;
+import org.apache.log4j.bridge.AppenderAdapter;
+import org.apache.log4j.bridge.AppenderWrapper;
+import org.apache.log4j.bridge.FilterAdapter;
+import org.apache.log4j.bridge.LayoutAdapter;
+import org.apache.log4j.bridge.LayoutWrapper;
+import org.apache.log4j.builders.BuilderManager;
+import org.apache.log4j.config.Log4j1Configuration;
+import org.apache.log4j.config.PropertySetter;
+import org.apache.log4j.helpers.OptionConverter;
+import org.apache.log4j.spi.AppenderAttachable;
+import org.apache.log4j.spi.Configurator;
+import org.apache.log4j.spi.ErrorHandler;
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.spi.LoggerRepository;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.appender.ConsoleAppender;
+import org.apache.logging.log4j.core.appender.FileAppender;
+import org.apache.logging.log4j.core.appender.NullAppender;
+import org.apache.logging.log4j.core.appender.RollingFileAppender;
+import org.apache.logging.log4j.core.appender.rolling.CompositeTriggeringPolicy;
+import org.apache.logging.log4j.core.appender.rolling.DefaultRolloverStrategy;
+import org.apache.logging.log4j.core.appender.rolling.RolloverStrategy;
+import org.apache.logging.log4j.core.appender.rolling.SizeBasedTriggeringPolicy;
+import org.apache.logging.log4j.core.appender.rolling.TimeBasedTriggeringPolicy;
+import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.config.ConfigurationSource;
+import org.apache.logging.log4j.core.config.LoggerConfig;
+import org.apache.logging.log4j.core.config.Order;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.status.StatusConfiguration;
+import org.apache.logging.log4j.core.layout.HtmlLayout;
+import org.apache.logging.log4j.core.layout.PatternLayout;
+import org.apache.logging.log4j.core.layout.XmlLayout;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.LoaderUtil;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.FactoryConfigurationError;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InterruptedIOException;
+import java.io.Reader;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+/**
+ * Constructs a Configuration usable in Log4j 2 from a Log4j 1 configuration file.
+ */
+@Plugin(name = "Log4j1XmlConfigurationFactory", category = ConfigurationFactory.CATEGORY)
+@Order(2)
+public class XmlConfigurationFactory extends ConfigurationFactory implements Configurator {
+    private static final org.apache.logging.log4j.Logger LOGGER = StatusLogger.getLogger();
+
+    private static final String CONFIGURATION_TAG = "log4j:configuration";
+    private static final String OLD_CONFIGURATION_TAG = "configuration";
+    private static final String RENDERER_TAG = "renderer";
+    private static final String APPENDER_TAG = "appender";
+    private static final String APPENDER_REF_TAG = "appender-ref";
+    public  static final String PARAM_TAG = "param";
+    public static final String LAYOUT_TAG = "layout";
+    private static final String CATEGORY = "category";
+    private static final String LOGGER_ELEMENT = "logger";
+    private static final String CATEGORY_FACTORY_TAG = "categoryFactory";
+    private static final String LOGGER_FACTORY_TAG = "loggerFactory";
+    public static final String NAME_ATTR = "name";
+    private static final String CLASS_ATTR = "class";
+    public static final String VALUE_ATTR = "value";
+    private static final String ROOT_TAG = "root";
+    private static final String LEVEL_TAG = "level";
+    private static final String PRIORITY_TAG = "priority";
+    public static final String FILTER_TAG = "filter";
+    private static final String ERROR_HANDLER_TAG = "errorHandler";
+    private static final String REF_ATTR = "ref";
+    private static final String ADDITIVITY_ATTR = "additivity";
+    private static final String CONFIG_DEBUG_ATTR = "configDebug";
+    private static final String INTERNAL_DEBUG_ATTR = "debug";
+    private static final String EMPTY_STR = "";
+    private static final Class[] ONE_STRING_PARAM = new Class[]{String.class};
+    private static final String dbfKey = "javax.xml.parsers.DocumentBuilderFactory";
+    private static final String THROWABLE_RENDERER_TAG = "throwableRenderer";
+    private static final String SYSTEM_OUT = "System.out";
+    private static final String SYSTEM_ERR = "System.err";
+    private static final String THREAD_PRINTING_PARAM = "threadprinting";
+    private static final String CATEGORY_PREFIXING_PARAM = "categoryprefixing";
+    private static final String CONTEXT_PRINTING_PARAM = "contextprinting";
+    private static final String DATE_FORMAT_PARAM = "dateformat";
+    private static final String TIMEZONE_FORMAT = "timezone";
+    public static final String FILE_PARAM = "file";
+    public static final String APPEND_PARAM = "append";
+    public static final String BUFFERED_IO_PARAM = "bufferedio";
+    public static final String BUFFER_SIZE_PARAM = "buffersize";
+    public static final String MAX_SIZE_PARAM = "maxfileSize";
+    public static final String MAX_BACKUP_INDEX = "maxbackupindex";
+    public static final String RELATIVE = "RELATIVE";
+    public static final long DEFAULT_DELAY = 60000;
+    /**
+     * File name prefix for test configurations.
+     */
+    protected static final String TEST_PREFIX = "log4j-test";
+
+    /**
+     * File name prefix for standard configurations.
+     */
+    protected static final String DEFAULT_PREFIX = "log4j";
+
+    private final BuilderManager manager;
+
+    // key: appenderName, value: appender
+    private Map<String, Appender> appenderBag;
+
+    private Properties props = null;
+
+    private final LoggerContext loggerContext;
+    private Log4j1Configuration configuration;
+
+    /**
+     * No argument constructor.
+     */
+    public XmlConfigurationFactory() {
+        appenderBag = new HashMap<>();
+        loggerContext = (LoggerContext) org.apache.logging.log4j.LogManager.getContext(false);
+        manager = new BuilderManager();
+    }
+
+
+    private XmlConfigurationFactory(ConfigurationSource source, int monitorIntervalSeconds) {
+        appenderBag = new HashMap<>();
+        loggerContext = (LoggerContext) org.apache.logging.log4j.LogManager.getContext(false);
+        configuration = new Log4j1Configuration(loggerContext, source, monitorIntervalSeconds);
+        manager = new BuilderManager();
+    }
+
+    @Override
+    protected String[] getSupportedTypes() {
+        return new String[] {".xml"};
+    }
+
+    @Override
+    public Configuration getConfiguration(LoggerContext loggerContext, ConfigurationSource source) {
+        configuration = new Log4j1Configuration(loggerContext, source, 0);
+        doConfigure();
+        return configuration;
+    }
+
+    public Configuration getConfiguration() {
+        return configuration;
+    }
+
+    @Override
+    protected String getTestPrefix() {
+        return TEST_PREFIX;
+    }
+
+    @Override
+    protected String getDefaultPrefix() {
+        return DEFAULT_PREFIX;
+    }
+
+    /**
+     * Delegates unrecognized content to created instance if
+     * it supports UnrecognizedElementParser.
+     *
+     * @param instance instance, may be null.
+     * @param element  element, may not be null.
+     * @param props    properties
+     * @throws IOException thrown if configuration of owner object
+     *                     should be abandoned.
+     * @since 1.2.15
+     */
+    private static void parseUnrecognizedElement(final Object instance, final Element element,
+            final Properties props) throws Exception {
+        boolean recognized = false;
+        if (instance instanceof UnrecognizedElementHandler) {
+            recognized = ((UnrecognizedElementHandler) instance).parseUnrecognizedElement(
+                    element, props);
+        }
+        if (!recognized) {
+            LOGGER.warn("Unrecognized element {}", element.getNodeName());
+        }
+    }
+
+    /**
+     * Delegates unrecognized content to created instance if
+     * it supports UnrecognizedElementParser and catches and
+     * logs any exception.
+     *
+     * @param instance instance, may be null.
+     * @param element  element, may not be null.
+     * @param props    properties
+     * @since 1.2.15
+     */
+    private static void quietParseUnrecognizedElement(final Object instance,
+            final Element element,
+            final Properties props) {
+        try {
+            parseUnrecognizedElement(instance, element, props);
+        } catch (Exception ex) {
+            if (ex instanceof InterruptedException || ex instanceof InterruptedIOException) {
+                Thread.currentThread().interrupt();
+            }
+            LOGGER.error("Error in extension content: ", ex);
+        }
+    }
+
+    /**
+     * Like {@link #configureAndWatch(String, long)} except that the
+     * default delay is used.
+     *
+     * @param configFilename A log4j configuration file in XML format.
+     */
+    public static void configureAndWatch(final String configFilename) {
+        configureAndWatch(configFilename, DEFAULT_DELAY);
+    }
+
+    /**
+     * Read the configuration file <code>configFilename</code> if it
+     * exists. Moreover, a thread will be created that will periodically
+     * check if <code>configFilename</code> has been created or
+     * modified. The period is determined by the <code>delay</code>
+     * argument. If a change or file creation is detected, then
+     * <code>configFilename</code> is read to configure log4j.
+     *
+     * @param configFilename A log4j configuration file in XML format.
+     * @param delay          The delay in milliseconds to wait between each check.
+     */
+    public static void configureAndWatch(final String configFilename, final long delay) {
+        try {
+            File file = new File(configFilename);
+            InputStream is = new FileInputStream(file);
+            ConfigurationSource source = new ConfigurationSource(is, file);
+            int seconds = (int) TimeUnit.MILLISECONDS.toSeconds(delay);
+            XmlConfigurationFactory factory = new XmlConfigurationFactory(source, seconds);
+            factory.doConfigure();
+            org.apache.logging.log4j.core.config.Configurator.reconfigure(factory.getConfiguration());
+
+        } catch (IOException ioe) {
+            LOGGER.error("Unable to process configuration file {} due to {}", configFilename, ioe.getMessage());
+        }
+    }
+
+    /**
+     * A static version of doConfigure(String).
+     */
+    public static void configure(final String filename) throws FactoryConfigurationError {
+        configureAndWatch(filename, 0);
+    }
+
+    /**
+     * A static version of doConfigure(URL).
+     */
+    public static void configure(final URL url) throws FactoryConfigurationError {
+        try {
+            InputStream is = url.openStream();
+            ConfigurationSource source = new ConfigurationSource(is, url);
+            XmlConfigurationFactory factory = new XmlConfigurationFactory(source, 0);
+            factory.doConfigure();
+            org.apache.logging.log4j.core.config.Configurator.reconfigure(factory.getConfiguration());
+        } catch (IOException ioe) {
+            LOGGER.error("Unable to process configuration {} due to {}", url.toString(), ioe.getMessage());
+        }
+    }
+
+    /**
+     * Substitutes property value for any references in expression.
+     *
+     * @param value value from configuration file, may contain
+     *              literal text, property references or both
+     * @param props properties.
+     * @return evaluated expression, may still contain expressions
+     * if unable to expand.
+     */
+    public static String subst(final String value, final Properties props) {
+        try {
+            return OptionConverter.substVars(value, props);
+        } catch (IllegalArgumentException e) {
+            LOGGER.warn("Could not perform variable substitution.", e);
+            return value;
+        }
+    }
+
+    /**
+     * Sets a parameter based from configuration file content.
+     *
+     * @param elem       param element, may not be null.
+     * @param propSetter property setter, may not be null.
+     * @param props      properties
+     * @since 1.2.15
+     */
+    public static void setParameter(final Element elem, final PropertySetter propSetter, final Properties props) {
+        String name = subst(elem.getAttribute("name"), props);
+        String value = (elem.getAttribute("value"));
+        value = subst(OptionConverter.convertSpecialChars(value), props);
+        propSetter.setProperty(name, value);
+    }
+
+    /**
+     * Creates an object and processes any nested param elements
+     * but does not call activateOptions.  If the class also supports
+     * UnrecognizedElementParser, the parseUnrecognizedElement method
+     * will be call for any child elements other than param.
+     *
+     * @param element       element, may not be null.
+     * @param props         properties
+     * @param expectedClass interface or class expected to be implemented
+     *                      by created class
+     * @return created class or null.
+     * @throws Exception thrown if the contain object should be abandoned.
+     * @since 1.2.15
+     */
+    public static Object parseElement(final Element element, final Properties props,
+            @SuppressWarnings("rawtypes") final Class expectedClass) throws Exception {
+        String clazz = subst(element.getAttribute("class"), props);
+        Object instance = OptionConverter.instantiateByClassName(clazz,
+                expectedClass, null);
+
+        if (instance != null) {
+            PropertySetter propSetter = new PropertySetter(instance);
+            NodeList children = element.getChildNodes();
+            final int length = children.getLength();
+
+            for (int loop = 0; loop < length; loop++) {
+                Node currentNode = children.item(loop);
+                if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
+                    Element currentElement = (Element) currentNode;
+                    String tagName = currentElement.getTagName();
+                    if (tagName.equals("param")) {
+                        setParameter(currentElement, propSetter, props);
+                    } else {
+                        parseUnrecognizedElement(instance, currentElement, props);
+                    }
+                }
+            }
+            return instance;
+        }
+        return null;
+    }
+
+    /**
+     * Used internally to parse appenders by IDREF name.
+     */
+    private Appender findAppenderByName(Document doc, String appenderName) {
+        Appender appender = appenderBag.get(appenderName);
+
+        if (appender != null) {
+            return appender;
+        } else {
+            // Doesn't work on DOM Level 1 :
+            // Element element = doc.getElementById(appenderName);
+
+            // Endre's hack:
+            Element element = null;
+            NodeList list = doc.getElementsByTagName("appender");
+            for (int t = 0; t < list.getLength(); t++) {
+                Node node = list.item(t);
+                NamedNodeMap map = node.getAttributes();
+                Node attrNode = map.getNamedItem("name");
+                if (appenderName.equals(attrNode.getNodeValue())) {
+                    element = (Element) node;
+                    break;
+                }
+            }
+            // Hack finished.
+
+            if (element == null) {
+
+                LOGGER.error("No appender named [{}] could be found.", appenderName);
+                return null;
+            } else {
+                appender = parseAppender(element);
+                if (appender != null) {
+                    appenderBag.put(appenderName, appender);
+                }
+                return appender;
+            }
+        }
+    }
+
+    /**
+     * Used internally to parse appenders by IDREF element.
+     */
+    private Appender findAppenderByReference(Element appenderRef) {
+        String appenderName = subst(appenderRef.getAttribute(REF_ATTR));
+        Document doc = appenderRef.getOwnerDocument();
+        return findAppenderByName(doc, appenderName);
+    }
+
+    /**
+     * Used internally to parse an appender element.
+     */
+    private Appender parseAppender(Element appenderElement) {
+        String className = subst(appenderElement.getAttribute(CLASS_ATTR));
+        LOGGER.debug("Class name: [" + className + ']');
+        Appender appender = manager.parseAppender(className, appenderElement, this);
+        if (appender == null) {
+            appender = buildAppender(className, appenderElement);
+        }
+        return appender;
+    }
+
+    private Appender buildAppender(String className, Element appenderElement) {
+            try {
+                Appender appender = LoaderUtil.newInstanceOf(className);
+                PropertySetter propSetter = new PropertySetter(appender);
+
+                appender.setName(subst(appenderElement.getAttribute(NAME_ATTR)));
+                forEachElement(appenderElement.getChildNodes(), (currentElement) -> {
+                    // Parse appender parameters
+                    switch (currentElement.getTagName()) {
+                        case PARAM_TAG:
+                            setParameter(currentElement, propSetter);
+                            break;
+                        case LAYOUT_TAG:
+                            appender.setLayout(parseLayout(currentElement));
+                            break;
+                        case FILTER_TAG:
+                            Filter filter = parseFilters(currentElement);
+                            if (filter != null) {
+                                LOGGER.debug("Adding filter of type [{}] to appender named [{}]",
+                                        filter.getClass(), appender.getName());
+                                appender.addFilter(filter);
+                            }
+                            break;
+                        case ERROR_HANDLER_TAG:
+                            parseErrorHandler(currentElement, appender);
+                            break;
+                        case APPENDER_REF_TAG:
+                            String refName = subst(currentElement.getAttribute(REF_ATTR));
+                            if (appender instanceof AppenderAttachable) {
+                                AppenderAttachable aa = (AppenderAttachable) appender;
+                                Appender child = findAppenderByReference(currentElement);
+                                LOGGER.debug("Attaching appender named [{}] to appender named [{}].", refName,
+                                        appender.getName());
+                                aa.addAppender(child);
+                            } else {
+                                LOGGER.error("Requesting attachment of appender named [{}] to appender named [{}}]"
+                                                + "which does not implement org.apache.log4j.spi.AppenderAttachable.",
+                                        refName, appender.getName());
+                            }
+                            break;
+                        default:
+                            try {
+                                parseUnrecognizedElement(appender, currentElement, props);
+                            } catch (Exception ex) {
+                                throw new ConsumerException(ex);
+                            }
+                    }
+                });
+                propSetter.activate();
+                return appender;
+            } catch (ConsumerException ex) {
+                Throwable t = ex.getCause();
+                if (t instanceof InterruptedException || t instanceof InterruptedIOException) {
+                    Thread.currentThread().interrupt();
+                }
+                LOGGER.error("Could not create an Appender. Reported error follows.", t);
+            } catch (Exception oops) {
+                if (oops instanceof InterruptedException || oops instanceof InterruptedIOException) {
+                    Thread.currentThread().interrupt();
+                }
+                LOGGER.error("Could not create an Appender. Reported error follows.", oops);
+            }
+            return null;
+        }
+
+    /**
+     * Used internally to parse an {@link ErrorHandler} element.
+     */
+    private void parseErrorHandler(Element element, Appender appender) {
+        ErrorHandler eh = (ErrorHandler) OptionConverter.instantiateByClassName(
+                subst(element.getAttribute(CLASS_ATTR)),
+                ErrorHandler.class,
+                null);
+
+        if (eh != null) {
+            eh.setAppender(appender);
+
+            PropertySetter propSetter = new PropertySetter(eh);
+            forEachElement(element.getChildNodes(), (currentElement) -> {
+                String tagName = currentElement.getTagName();
+                if (tagName.equals(PARAM_TAG)) {
+                    setParameter(currentElement, propSetter);
+                }
+            });
+            propSetter.activate();
+            appender.setErrorHandler(eh);
+        }
+    }
+
+    /**
+     * Used internally to parse a filter element.
+     */
+    public Filter parseFilters(Element filterElement) {
+        String className = subst(filterElement.getAttribute(CLASS_ATTR));
+        LOGGER.debug("Class name: [" + className + ']');
+        Filter filter = manager.parseFilter(className, filterElement, this);
+        if (filter == null) {
+            PropertySetter propSetter = new PropertySetter(filter);
+            forEachElement(filterElement.getChildNodes(), (currentElement) -> {
+                String tagName = currentElement.getTagName();
+                if (tagName.equals(PARAM_TAG)) {
+                    setParameter(currentElement, propSetter);
+                } else {
+                    quietParseUnrecognizedElement(filter, currentElement, props);
+                }
+            });
+            propSetter.activate();
+        }
+        return filter;
+    }
+
+    /**
+     * Used internally to parse an category element.
+     */
+    private void parseCategory(Element loggerElement) {
+        // Create a new org.apache.log4j.Category object from the <category> element.
+        String catName = subst(loggerElement.getAttribute(NAME_ATTR));
+        boolean additivity = OptionConverter.toBoolean(subst(loggerElement.getAttribute(ADDITIVITY_ATTR)), true);
+        LoggerConfig loggerConfig = configuration.getLogger(catName);
+        if (loggerConfig == null) {
+            loggerConfig = new LoggerConfig(catName, org.apache.logging.log4j.Level.ERROR, additivity);
+            configuration.addLogger(catName, loggerConfig);
+        } else {
+            loggerConfig.setAdditive(additivity);
+        }
+        parseChildrenOfLoggerElement(loggerElement, loggerConfig, false);
+    }
+
+    /**
+     * Used internally to parse the roor category element.
+     */
+    private void parseRoot(Element rootElement) {
+        LoggerConfig root = configuration.getRootLogger();
+        parseChildrenOfLoggerElement(rootElement, root, true);
+    }
+
+    /**
+     * Used internally to parse the children of a LoggerConfig element.
+     */
+    private void parseChildrenOfLoggerElement(Element catElement, LoggerConfig loggerConfig, boolean isRoot) {
+
+        final PropertySetter propSetter = new PropertySetter(loggerConfig);
+        loggerConfig.getAppenderRefs().clear();
+        forEachElement(catElement.getChildNodes(), (currentElement) -> {
+            switch (currentElement.getTagName()) {
+                case APPENDER_REF_TAG: {
+                    Appender appender = findAppenderByReference(currentElement);
+                    String refName = subst(currentElement.getAttribute(REF_ATTR));
+                    if (appender != null) {
+                        LOGGER.debug("Adding appender named [{}] to loggerConfig [{}].", refName,
+                                loggerConfig.getName());
+                        loggerConfig.addAppender(configuration.getAppender(refName), null, null);
+                    } else {
+                        LOGGER.debug("Appender named [{}}] not found.", refName);
+                    }
+                    break;
+                }
+                case LEVEL_TAG: case PRIORITY_TAG: {
+                    parseLevel(currentElement, loggerConfig, isRoot);
+                    break;
+                }
+                case PARAM_TAG: {
+                    setParameter(currentElement, propSetter);
+                    break;
+                }
+                default: {
+                    quietParseUnrecognizedElement(loggerConfig, currentElement, props);
+                }
+            }
+        });
+        propSetter.activate();
+    }
+
+    /**
+     * Used internally to parse a layout element.
+     */
+    public Layout parseLayout(Element layoutElement) {
+        String className = subst(layoutElement.getAttribute(CLASS_ATTR));
+        LOGGER.debug("Parsing layout of class: \"{}\"", className);
+        Layout layout = manager.parseLayout(className, layoutElement, this);
+        if (layout == null) {
+            layout = buildLayout(className, layoutElement);
+        }
+        return layout;
+    }
+
+    private Layout buildLayout(String className, Element layout_element) {
+        try {
+            Layout layout = LoaderUtil.newInstanceOf(className);
+            PropertySetter propSetter = new PropertySetter(layout);
+            forEachElement(layout_element.getChildNodes(), (currentElement) -> {
+                String tagName = currentElement.getTagName();
+                if (tagName.equals(PARAM_TAG)) {
+                    setParameter(currentElement, propSetter);
+                } else {
+                    try {
+                        parseUnrecognizedElement(layout, currentElement, props);
+                    } catch (Exception ex) {
+                        throw new ConsumerException(ex);
+                    }
+                }
+            });
+
+            propSetter.activate();
+            return layout;
+        } catch (ConsumerException ce) {
+            Throwable cause = ce.getCause();
+            if (cause instanceof InterruptedException || cause instanceof InterruptedIOException) {
+                Thread.currentThread().interrupt();
+            }
+            LOGGER.error("Could not create the Layout. Reported error follows.", cause);
+        } catch (Exception oops) {
+            if (oops instanceof InterruptedException || oops instanceof InterruptedIOException) {
+                Thread.currentThread().interrupt();
+            }
+            LOGGER.error("Could not create the Layout. Reported error follows.", oops);
+        }
+        return null;
+    }
+
+    /**
+     * Used internally to parse a level  element.
+     */
+    private void parseLevel(Element element, LoggerConfig logger, boolean isRoot) {
+        String catName = logger.getName();
+        if (isRoot) {
+            catName = "root";
+        }
+
+        String priStr = subst(element.getAttribute(VALUE_ATTR));
+        LOGGER.debug("Level value for {} is [{}}].", catName, priStr);
+
+        if (INHERITED.equalsIgnoreCase(priStr) || NULL.equalsIgnoreCase(priStr)) {
+            if (isRoot) {
+                LOGGER.error("Root level cannot be inherited. Ignoring directive.");
+            } else {
+                logger.setLevel(null);
+            }
+        } else {
+            String className = subst(element.getAttribute(CLASS_ATTR));
+            if (EMPTY_STR.equals(className)) {
+                logger.setLevel(convertLevel(OptionConverter.toLevel(priStr, Level.DEBUG)));
+            } else {
+                LOGGER.debug("Desired Level sub-class: [{}]", className);
+                try {
+                    Class<?> clazz = LoaderUtil.loadClass(className);
+                    Method toLevelMethod = clazz.getMethod("toLevel", ONE_STRING_PARAM);
+                    Level pri = (Level) toLevelMethod.invoke(null, new Object[]{priStr});
+                    logger.setLevel(convertLevel(pri));
+                } catch (Exception oops) {
+                    if (oops instanceof InterruptedException || oops instanceof InterruptedIOException) {
+                        Thread.currentThread().interrupt();
+                    }
+                    LOGGER.error("Could not create level [" + priStr +
+                            "]. Reported error follows.", oops);
+                    return;
+                }
+            }
+        }
+        LOGGER.debug("{} level set to {}", catName,  logger.getLevel());
+    }
+
+    private void setParameter(Element elem, PropertySetter propSetter) {
+        String name = subst(elem.getAttribute(NAME_ATTR));
+        String value = (elem.getAttribute(VALUE_ATTR));
+        value = subst(OptionConverter.convertSpecialChars(value));
+        propSetter.setProperty(name, value);
+    }
+
+    /**
+     * Configure log4j by reading in a log4j.dtd compliant XML
+     * configuration file.
+     */
+    private void doConfigure() throws FactoryConfigurationError {
+        ConfigurationSource source = configuration.getConfigurationSource();
+        ParseAction action = new ParseAction() {
+            public Document parse(final DocumentBuilder parser) throws SAXException, IOException {
+                InputSource inputSource = new InputSource(source.getInputStream());
+                inputSource.setSystemId("dummy://log4j.dtd");
+                return parser.parse(inputSource);
+            }
+
+            public String toString() {
+                return configuration.getConfigurationSource().getLocation();
+            }
+        };
+        doConfigure(action);
+    }
+
+    private void doConfigure(final ParseAction action) throws FactoryConfigurationError {
+        DocumentBuilderFactory dbf;
+        try {
+            LOGGER.debug("System property is : {}", OptionConverter.getSystemProperty(dbfKey, null));
+            dbf = DocumentBuilderFactory.newInstance();
+            LOGGER.debug("Standard DocumentBuilderFactory search succeded.");
+            LOGGER.debug("DocumentBuilderFactory is: " + dbf.getClass().getName());
+        } catch (FactoryConfigurationError fce) {
+            Exception e = fce.getException();
+            LOGGER.debug("Could not instantiate a DocumentBuilderFactory.", e);
+            throw fce;
+        }
+
+        try {
+            dbf.setValidating(true);
+
+            DocumentBuilder docBuilder = dbf.newDocumentBuilder();
+
+            docBuilder.setErrorHandler(new SAXErrorHandler());
+            docBuilder.setEntityResolver(new Log4jEntityResolver());
+
+            Document doc = action.parse(docBuilder);
+            parse(doc.getDocumentElement());
+        } catch (Exception e) {
+            if (e instanceof InterruptedException || e instanceof InterruptedIOException) {
+                Thread.currentThread().interrupt();
+            }
+            // I know this is miserable...
+            LOGGER.error("Could not parse " + action.toString() + ".", e);
+        }
+    }
+
+    @Override
+    public void doConfigure(InputStream inputStream, LoggerContext loggerContext) {
+        try {
+            ConfigurationSource source = new ConfigurationSource(inputStream);
+            configuration = new Log4j1Configuration(loggerContext, source, 0);
+            doConfigure();
+        } catch (IOException ioe) {
+            LOGGER.error("Unable to process configuration due to {}",  ioe.getMessage());
+        }
+    }
+
+    @Override
+    public void doConfigure(URL url, LoggerContext loggerContext) {
+        try {
+            ConfigurationSource source = new ConfigurationSource(url.openStream(), url);
+            configuration = new Log4j1Configuration(loggerContext, source, 0);
+            doConfigure();
+        } catch (IOException ioe) {
+            LOGGER.error("Unable to process configuration due to {}",  ioe.getMessage());
+        }
+    }
+
+    /**
+     * Used internally to configure the log4j framework by parsing a DOM
+     * tree of XML elements based on <a
+     * href="doc-files/log4j.dtd">log4j.dtd</a>.
+     */
+    private void parse(Element element) {
+        String rootElementName = element.getTagName();
+
+        if (!rootElementName.equals(CONFIGURATION_TAG)) {
+            if (rootElementName.equals(OLD_CONFIGURATION_TAG)) {
+                LOGGER.warn("The <" + OLD_CONFIGURATION_TAG +
+                        "> element has been deprecated.");
+                LOGGER.warn("Use the <" + CONFIGURATION_TAG + "> element instead.");
+            } else {
+                LOGGER.error("DOM element is - not a <" + CONFIGURATION_TAG + "> element.");
+                return;
+            }
+        }
+
+
+        String debugAttrib = subst(element.getAttribute(INTERNAL_DEBUG_ATTR));
+
+        LOGGER.debug("debug attribute= \"" + debugAttrib + "\".");
+        // if the log4j.dtd is not specified in the XML file, then the
+        // "debug" attribute is returned as the empty string.
+        String status = "error";
+        if (!debugAttrib.equals("") && !debugAttrib.equals("null")) {
+            status = OptionConverter.toBoolean(debugAttrib, true) ? "debug" : "error";
+
+        } else {
+            LOGGER.debug("Ignoring " + INTERNAL_DEBUG_ATTR + " attribute.");
+        }
+
+        String confDebug = subst(element.getAttribute(CONFIG_DEBUG_ATTR));
+        if (!confDebug.equals("") && !confDebug.equals("null")) {
+            LOGGER.warn("The \"" + CONFIG_DEBUG_ATTR + "\" attribute is deprecated.");
+            LOGGER.warn("Use the \"" + INTERNAL_DEBUG_ATTR + "\" attribute instead.");
+            status = OptionConverter.toBoolean(confDebug, true) ? "debug" : "error";
+        }
+
+        final StatusConfiguration statusConfig = new StatusConfiguration().withStatus(status);
+        statusConfig.initialize();
+
+        forEachElement(element.getChildNodes(), (currentElement) -> {
+            switch (currentElement.getTagName()) {
+                case CATEGORY: case LOGGER_ELEMENT:
+                    parseCategory(currentElement);
+                    break;
+                case ROOT_TAG:
+                    parseRoot(currentElement);
+                    break;
+                case RENDERER_TAG:
+                    LOGGER.warn("Renderers are not supported by Log4j 2 and will be ignored.");
+                    break;
+                case THROWABLE_RENDERER_TAG:
+                    LOGGER.warn("Throwable Renderers are not supported by Log4j 2 and will be ignored.");
+                    break;
+                case CATEGORY_FACTORY_TAG: case LOGGER_FACTORY_TAG:
+                    LOGGER.warn("Log4j 1 Logger factories are not supported by Log4j 2 and will be ignored.");
+                    break;
+                case APPENDER_TAG:
+                    Appender appender = parseAppender(currentElement);
+                    appenderBag.put(appender.getName(), appender);
+                    if (appender instanceof AppenderWrapper) {
+                        configuration.addAppender(((AppenderWrapper) appender).getAppender());
+                    } else {
+                        configuration.addAppender(new AppenderAdapter(appender).getAdapter());
+                    }
+                    break;
+                default:
+                    quietParseUnrecognizedElement(null, currentElement, props);
+            }
+        });
+    }
+
+    private org.apache.logging.log4j.Level convertLevel(Level level) {
+        if (level == null) {
+            return org.apache.logging.log4j.Level.ERROR;
+        }
+        if (level.isGreaterOrEqual(Level.FATAL)) {
+            return org.apache.logging.log4j.Level.FATAL;
+        } else if (level.isGreaterOrEqual(Level.ERROR)) {
+            return org.apache.logging.log4j.Level.ERROR;
+        } else if (level.isGreaterOrEqual(Level.WARN)) {
+            return org.apache.logging.log4j.Level.WARN;
+        } else if (level.isGreaterOrEqual(Level.INFO)) {
+            return org.apache.logging.log4j.Level.INFO;
+        } else if (level.isGreaterOrEqual(Level.DEBUG)) {
+            return org.apache.logging.log4j.Level.DEBUG;
+        } else if (level.isGreaterOrEqual(Level.TRACE)) {
+            return org.apache.logging.log4j.Level.TRACE;
+        }
+        return org.apache.logging.log4j.Level.ALL;
+    }
+
+    private String subst(final String value) {
+        return configuration.getStrSubstitutor().replace(value);
+    }
+
+    public static void forEachElement(NodeList list, Consumer<Element> consumer) {
+        final int length = list.getLength();
+        for (int loop = 0; loop < length; loop++) {
+            Node currentNode = list.item(loop);
+
+            if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
+                Element currentElement = (Element) currentNode;
+                consumer.accept(currentElement);
+            }
+        }
+    }
+
+    private interface ParseAction {
+        Document parse(final DocumentBuilder parser) throws SAXException, IOException;
+    }
+
+    private static class SAXErrorHandler implements org.xml.sax.ErrorHandler {
+        private static final org.apache.logging.log4j.Logger LOGGER = StatusLogger.getLogger();
+
+        public void error(final SAXParseException ex) {
+            emitMessage("Continuable parsing error ", ex);
+        }
+
+        public void fatalError(final SAXParseException ex) {
+            emitMessage("Fatal parsing error ", ex);
+        }
+
+        public void warning(final SAXParseException ex) {
+            emitMessage("Parsing warning ", ex);
+        }
+
+        private static void emitMessage(final String msg, final SAXParseException ex) {
+            LOGGER.warn("{} {} and column {}", msg, ex.getLineNumber(), ex.getColumnNumber());
+            LOGGER.warn(ex.getMessage(), ex.getException());
+        }
+    }
+
+    private static class ConsumerException extends RuntimeException {
+
+        ConsumerException(Exception ex) {
+            super(ex);
+        }
+    }
+}
+
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-1.2-api/src/src/main/java/org/apache/log4j/xml/package-info.java
similarity index 68%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-1.2-api/src/src/main/java/org/apache/log4j/xml/package-info.java
index 13aaf9c..e3ed0d1 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-1.2-api/src/src/main/java/org/apache/log4j/xml/package-info.java
@@ -14,17 +14,7 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
-
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-public class ProcessIdUtilTest {
-
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
-    }
-}
+/**
+ * Log4j 1.x compatibility layer.
+ */
+package org.apache.log4j.xml;
diff --git a/log4j-1.2-api/src/src/main/resources/org/apache/log4j/xml/log4j.dtd b/log4j-1.2-api/src/src/main/resources/org/apache/log4j/xml/log4j.dtd
new file mode 100644
index 0000000..f8e433a
--- /dev/null
+++ b/log4j-1.2-api/src/src/main/resources/org/apache/log4j/xml/log4j.dtd
@@ -0,0 +1,237 @@
+<?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.
+-->
+
+<!-- Authors: Chris Taylor, Ceki Gulcu. -->
+
+<!-- Version: 1.2 -->
+
+<!-- A configuration element consists of optional renderer
+elements,appender elements, categories and an optional root
+element. -->
+
+<!ELEMENT log4j:configuration (renderer*, throwableRenderer?,
+                               appender*,plugin*, (category|logger)*,root?,
+                               (categoryFactory|loggerFactory)?)>
+
+<!-- The "threshold" attribute takes a level value below which -->
+<!-- all logging statements are disabled. -->
+
+<!-- Setting the "debug" enable the printing of internal log4j logging   -->
+<!-- statements.                                                         -->
+
+<!-- By default, debug attribute is "null", meaning that we not do touch -->
+<!-- internal log4j logging settings. The "null" value for the threshold -->
+<!-- attribute can be misleading. The threshold field of a repository	 -->
+<!-- cannot be set to null. The "null" value for the threshold attribute -->
+<!-- simply means don't touch the threshold field, the threshold field   --> 
+<!-- keeps its old value.                                                -->
+     
+<!ATTLIST log4j:configuration
+  xmlns:log4j              CDATA #FIXED "http://jakarta.apache.org/log4j/" 
+  threshold                (all|trace|debug|info|warn|error|fatal|off|null) "null"
+  debug                    (true|false|null)  "null"
+  reset                    (true|false) "false"
+>
+
+<!-- renderer elements allow the user to customize the conversion of  -->
+<!-- message objects to String.                                       -->
+
+<!ELEMENT renderer EMPTY>
+<!ATTLIST renderer
+  renderedClass  CDATA #REQUIRED
+  renderingClass CDATA #REQUIRED
+>
+
+<!--  throwableRenderer allows the user to customize the conversion
+         of exceptions to a string representation.  -->
+<!ELEMENT throwableRenderer (param*)>
+<!ATTLIST throwableRenderer
+  class  CDATA #REQUIRED
+>
+
+
+<!-- Appenders must have a name and a class. -->
+<!-- Appenders may contain an error handler, a layout, optional parameters -->
+<!-- and filters. They may also reference (or include) other appenders. -->
+<!ELEMENT appender (errorHandler?, param*,
+      rollingPolicy?, triggeringPolicy?, connectionSource?,
+      layout?, filter*, appender-ref*)>
+<!ATTLIST appender
+  name 		CDATA 	#REQUIRED
+  class 	CDATA	#REQUIRED
+>
+
+<!ELEMENT layout (param*)>
+<!ATTLIST layout
+  class		CDATA	#REQUIRED
+>
+
+<!ELEMENT filter (param*)>
+<!ATTLIST filter
+  class		CDATA	#REQUIRED
+>
+
+<!-- ErrorHandlers can be of any class. They can admit any number of -->
+<!-- parameters. -->
+
+<!ELEMENT errorHandler (param*, root-ref?, logger-ref*,  appender-ref?)> 
+<!ATTLIST errorHandler
+   class        CDATA   #REQUIRED 
+>
+
+<!ELEMENT root-ref EMPTY>
+
+<!ELEMENT logger-ref EMPTY>
+<!ATTLIST logger-ref
+  ref CDATA #REQUIRED
+>
+
+<!ELEMENT param EMPTY>
+<!ATTLIST param
+  name		CDATA   #REQUIRED
+  value		CDATA	#REQUIRED
+>
+
+
+<!-- The priority class is org.apache.log4j.Level by default -->
+<!ELEMENT priority (param*)>
+<!ATTLIST priority
+  class   CDATA	#IMPLIED
+  value	  CDATA #REQUIRED
+>
+
+<!-- The level class is org.apache.log4j.Level by default -->
+<!ELEMENT level (param*)>
+<!ATTLIST level
+  class   CDATA	#IMPLIED
+  value	  CDATA #REQUIRED
+>
+
+
+<!-- If no level element is specified, then the configurator MUST not -->
+<!-- touch the level of the named category. -->
+<!ELEMENT category (param*,(priority|level)?,appender-ref*)>
+<!ATTLIST category
+  class         CDATA   #IMPLIED
+  name		CDATA	#REQUIRED
+  additivity	(true|false) "true"  
+>
+
+<!-- If no level element is specified, then the configurator MUST not -->
+<!-- touch the level of the named logger. -->
+<!ELEMENT logger (param*,level?,appender-ref*)>
+<!ATTLIST logger
+  class         CDATA   #IMPLIED
+  name		CDATA	#REQUIRED
+  additivity	(true|false) "true"  
+>
+
+
+<!ELEMENT categoryFactory (param*)>
+<!ATTLIST categoryFactory 
+   class        CDATA #REQUIRED>
+
+<!ELEMENT loggerFactory (param*)>
+<!ATTLIST loggerFactory
+   class        CDATA #REQUIRED>
+
+<!ELEMENT appender-ref EMPTY>
+<!ATTLIST appender-ref
+  ref CDATA #REQUIRED
+>
+
+<!-- plugins must have a name and class and can have optional parameters -->
+<!ELEMENT plugin (param*, connectionSource?)>
+<!ATTLIST plugin
+  name 		CDATA 	   #REQUIRED
+  class 	CDATA  #REQUIRED
+>
+
+<!ELEMENT connectionSource (dataSource?, param*)>
+<!ATTLIST connectionSource
+  class        CDATA  #REQUIRED
+>
+
+<!ELEMENT dataSource (param*)>
+<!ATTLIST dataSource
+  class        CDATA  #REQUIRED
+>
+
+<!ELEMENT triggeringPolicy ((param|filter)*)>
+<!ATTLIST triggeringPolicy
+  name 		CDATA  #IMPLIED
+  class 	CDATA  #REQUIRED
+>
+
+<!ELEMENT rollingPolicy (param*)>
+<!ATTLIST rollingPolicy
+  name 		CDATA  #IMPLIED
+  class 	CDATA  #REQUIRED
+>
+
+
+<!-- If no priority element is specified, then the configurator MUST not -->
+<!-- touch the priority of root. -->
+<!-- The root category always exists and cannot be subclassed. -->
+<!ELEMENT root (param*, (priority|level)?, appender-ref*)>
+
+
+<!-- ==================================================================== -->
+<!--                       A logging event                                -->
+<!-- ==================================================================== -->
+<!ELEMENT log4j:eventSet (log4j:event*)>
+<!ATTLIST log4j:eventSet
+  xmlns:log4j             CDATA #FIXED "http://jakarta.apache.org/log4j/" 
+  version                (1.1|1.2) "1.2" 
+  includesLocationInfo   (true|false) "true"
+>
+
+
+
+<!ELEMENT log4j:event (log4j:message, log4j:NDC?, log4j:throwable?, 
+                       log4j:locationInfo?, log4j:properties?) >
+
+<!-- The timestamp format is application dependent. -->
+<!ATTLIST log4j:event
+    logger     CDATA #REQUIRED
+    level      CDATA #REQUIRED
+    thread     CDATA #REQUIRED
+    timestamp  CDATA #REQUIRED
+    time       CDATA #IMPLIED
+>
+
+<!ELEMENT log4j:message (#PCDATA)>
+<!ELEMENT log4j:NDC (#PCDATA)>
+
+<!ELEMENT log4j:throwable (#PCDATA)>
+
+<!ELEMENT log4j:locationInfo EMPTY>
+<!ATTLIST log4j:locationInfo
+  class  CDATA	#REQUIRED
+  method CDATA	#REQUIRED
+  file   CDATA	#REQUIRED
+  line   CDATA	#REQUIRED
+>
+
+<!ELEMENT log4j:properties (log4j:data*)>
+
+<!ELEMENT log4j:data EMPTY>
+<!ATTLIST log4j:data
+  name   CDATA	#REQUIRED
+  value  CDATA	#REQUIRED
+>
diff --git a/log4j-1.2-api/src/src/site/markdown/index.md b/log4j-1.2-api/src/src/site/markdown/index.md
new file mode 100644
index 0000000..696e0bb
--- /dev/null
+++ b/log4j-1.2-api/src/src/site/markdown/index.md
@@ -0,0 +1,48 @@
+<!-- vim: set syn=markdown : -->
+<!--
+    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.
+-->
+
+# Log4j 1.2 Bridge
+
+The Log4j 1.2 Bridge allows applications coded to use Log4j 1.2 API to use Log4j 2 instead.
+
+## Requirements
+
+The Log4j 1.2 bridge is dependent on the Log4j 2 API. The following Log4j 1.x methods will behave differently when
+the Log4j 2 Core module is included then when it is not:
+
+| Method                        | Without log4j-core | With log4j-core                      |
+| ----------------------------- | ------------------ | ------------------------------------ |
+| Category.getParent()          | Returns null       | Returns parent logger                |
+| Category.setLevel()           | NoOp               | Sets Logger Level                    |
+| Category.setPriority()        | NoOp               | Sets Logger Level                    | 
+| Category.getAdditivity()      | Returns false      | Returns Logger's additivity setting  | 
+| Category.setAdditivity()      | NoOp               | Sets additivity of LoggerConfig      |
+| Category.getResourceBundle()  | NoOp               | Returns the resource bundle associated with the Logger |
+| BasicConfigurator.configure() | NoOp               | Reconfigures Log4j 2                 |
+
+If log4j-core is not present location information will not be accurate in calls using the Log4j 1.2 API. The config
+package which attempts tp convert Log4j 1.x configurations to Log4j 2 is not supported without Log4j 2.    
+
+For more information, see [Runtime Dependencies](../runtime-dependencies.html).
+
+## Usage
+
+To use the Log4j Legacy Bridge just remove all the Log4j 1.x jars from the application and replace them
+with the bridge jar. Once in place all logging that uses Log4j 1.x will be routed to Log4j 2. However,
+applications that attempt to modify legacy Log4j by adding Appenders, Filters, etc may experience problems
+if they try to verify the success of these actions as these methods are largely no-ops.
diff --git a/log4j-1.2-api/src/src/site/site.xml b/log4j-1.2-api/src/src/site/site.xml
new file mode 100644
index 0000000..b27991c
--- /dev/null
+++ b/log4j-1.2-api/src/src/site/site.xml
@@ -0,0 +1,52 @@
+<!--
+ 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 name="Log4j 1.x Adaptor"
+         xmlns="http://maven.apache.org/DECORATION/1.4.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/DECORATION/1.4.0 http://maven.apache.org/xsd/decoration-1.4.0.xsd">
+  <body>
+    <links>
+      <item name="Apache" href="http://www.apache.org/" />
+      <item name="Logging Services" href="http://logging.apache.org/"/>
+      <item name="Log4j" href="../index.html"/>
+    </links>
+
+    <!-- Component-specific reports -->
+    <menu ref="reports"/>
+
+	<!-- Overall Project Info -->
+    <menu name="Log4j Project Information" img="icon-info-sign">
+      <item name="Dependencies" href="../dependencies.html" />
+      <item name="Dependency Convergence" href="../dependency-convergence.html" />
+      <item name="Dependency Management" href="../dependency-management.html" />
+      <item name="Project Team" href="../team-list.html" />
+      <item name="Mailing Lists" href="../mail-lists.html" />
+      <item name="Issue Tracking" href="../issue-tracking.html" />
+      <item name="Project License" href="../license.html" />
+      <item name="Source Repository" href="../source-repository.html" />
+      <item name="Project Summary" href="../project-summary.html" />
+    </menu>
+
+    <menu name="Log4j Project Reports" img="icon-cog">
+      <item name="Changes Report" href="../changes-report.html" />
+      <item name="JIRA Report" href="../jira-report.html" />
+      <item name="Surefire Report" href="../surefire-report.html" />
+      <item name="RAT Report" href="../rat-report.html" />
+    </menu>
+  </body>
+</project>
diff --git a/log4j-1.2-api/src/src/test/java/org/apache/log4j/BasicConfigurationFactory.java b/log4j-1.2-api/src/src/test/java/org/apache/log4j/BasicConfigurationFactory.java
new file mode 100644
index 0000000..d231d82
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/java/org/apache/log4j/BasicConfigurationFactory.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j;
+
+import java.net.URI;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.AbstractConfiguration;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.config.ConfigurationSource;
+import org.apache.logging.log4j.core.config.LoggerConfig;
+
+/**
+ *
+ */
+public class BasicConfigurationFactory extends ConfigurationFactory {
+
+    @Override
+    public String[] getSupportedTypes() {
+        return new String[] { "*" };
+    }
+
+    @Override
+    public Configuration getConfiguration(final LoggerContext loggerContext, final ConfigurationSource source) {
+        return new BasicConfiguration(loggerContext);
+    }
+
+    @Override
+    public Configuration getConfiguration(final LoggerContext loggerContext, final String name, final URI configLocation) {
+        return new BasicConfiguration(loggerContext);
+    }
+
+    public class BasicConfiguration extends AbstractConfiguration {
+
+        private static final long serialVersionUID = -2716784321395089563L;
+
+        private static final String DEFAULT_LEVEL = "org.apache.logging.log4j.level";
+
+        public BasicConfiguration(final LoggerContext loggerContext) {
+            super(loggerContext, ConfigurationSource.NULL_SOURCE);
+
+            final LoggerConfig root = getRootLogger();
+            setName("BasicConfiguration");
+            final String levelName = System.getProperty(DEFAULT_LEVEL);
+            final Level level = (levelName != null && Level.getLevel(levelName) != null) ? Level.getLevel(levelName)
+                    : Level.DEBUG;
+            root.setLevel(level);
+        }
+
+        @Override
+        protected void doConfigure() {
+        }
+    }
+}
diff --git a/log4j-1.2-api/src/src/test/java/org/apache/log4j/CallerInformationTest.java b/log4j-1.2-api/src/src/test/java/org/apache/log4j/CallerInformationTest.java
new file mode 100644
index 0000000..1aa6c31
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/java/org/apache/log4j/CallerInformationTest.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.List;
+
+import org.apache.logging.log4j.junit.LoggerContextRule;
+import org.apache.logging.log4j.test.appender.ListAppender;
+import org.junit.ClassRule;
+import org.junit.Test;
+
+public class CallerInformationTest {
+
+    // config from log4j-core test-jar
+    private static final String CONFIG = "log4j2-calling-class.xml";
+
+    @ClassRule
+    public static final LoggerContextRule ctx = new LoggerContextRule(CONFIG);
+
+    @Test
+    public void testClassLogger() throws Exception {
+        final ListAppender app = ctx.getListAppender("Class").clear();
+        final Logger logger = Logger.getLogger("ClassLogger");
+        logger.info("Ignored message contents.");
+        logger.warn("Verifying the caller class is still correct.");
+        logger.error("Hopefully nobody breaks me!");
+        final List<String> messages = app.getMessages();
+        assertEquals("Incorrect number of messages.", 3, messages.size());
+        for (final String message : messages) {
+            assertEquals("Incorrect caller class name.", this.getClass().getName(), message);
+        }
+    }
+
+    @Test
+    public void testMethodLogger() throws Exception {
+        final ListAppender app = ctx.getListAppender("Method").clear();
+        final Logger logger = Logger.getLogger("MethodLogger");
+        logger.info("More messages.");
+        logger.warn("CATASTROPHE INCOMING!");
+        logger.error("ZOMBIES!!!");
+        logger.warn("brains~~~");
+        logger.info("Itchy. Tasty.");
+        final List<String> messages = app.getMessages();
+        assertEquals("Incorrect number of messages.", 5, messages.size());
+        for (final String message : messages) {
+            assertEquals("Incorrect caller method name.", "testMethodLogger", message);
+        }
+    }
+}
diff --git a/log4j-1.2-api/src/src/test/java/org/apache/log4j/CategoryTest.java b/log4j-1.2-api/src/src/test/java/org/apache/log4j/CategoryTest.java
new file mode 100644
index 0000000..6a8af76
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/java/org/apache/log4j/CategoryTest.java
@@ -0,0 +1,209 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.lang.reflect.Method;
+import java.util.List;
+
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.layout.PatternLayout;
+import org.apache.logging.log4j.message.Message;
+import org.apache.logging.log4j.message.ObjectMessage;
+import org.apache.logging.log4j.test.appender.ListAppender;
+import org.apache.logging.log4j.util.Strings;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+
+/**
+ * Tests of Category.
+ */
+public class CategoryTest {
+
+    static ConfigurationFactory cf = new BasicConfigurationFactory();
+
+    private static ListAppender appender = new ListAppender("List");
+
+    @BeforeClass
+    public static void setupClass() {
+        appender.start();
+        ConfigurationFactory.setConfigurationFactory(cf);
+        LoggerContext.getContext().reconfigure();
+    }
+
+    @AfterClass
+    public static void cleanupClass() {
+        ConfigurationFactory.removeConfigurationFactory(cf);
+        appender.stop();
+    }
+
+    @Before
+    public void before() {
+        appender.clear();
+    }
+    
+    /**
+     * Tests Category.forcedLog.
+     */
+    @Test
+    @SuppressWarnings("deprecation")
+    public void testForcedLog() {
+        final MockCategory category = new MockCategory("org.example.foo");
+        category.setAdditivity(false);
+        ((org.apache.logging.log4j.core.Logger) category.getLogger()).addAppender(appender);
+        category.info("Hello, World");
+        final List<LogEvent> list = appender.getEvents();
+        int events = list.size();
+        assertTrue("Number of events should be 1, was " + events, events == 1);
+        LogEvent event = list.get(0);
+        Message msg = event.getMessage();
+        assertNotNull("No message", msg);
+        assertTrue("Incorrect Message type", msg instanceof ObjectMessage);
+        Object[] objects = msg.getParameters();
+        assertTrue("Incorrect Object type", objects[0] instanceof String);
+        appender.clear();
+        category.log(Priority.INFO, "Hello, World");
+        events = list.size();
+        assertTrue("Number of events should be 1, was " + events, events == 1);
+        event = list.get(0);
+        msg = event.getMessage();
+        assertNotNull("No message", msg);
+        assertTrue("Incorrect Message type", msg instanceof ObjectMessage);
+        objects = msg.getParameters();
+        assertTrue("Incorrect Object type", objects[0] instanceof String);
+        appender.clear();
+    }
+
+    /**
+     * Tests that the return type of getChainedPriority is Priority.
+     *
+     * @throws Exception thrown if Category.getChainedPriority can not be found.
+     */
+    @Test
+    public void testGetChainedPriorityReturnType() throws Exception {
+        final Method method = Category.class.getMethod("getChainedPriority", (Class[]) null);
+        assertTrue(method.getReturnType() == Priority.class);
+    }
+
+    /**
+     * Tests l7dlog(Priority, String, Throwable).
+     */
+    @Test
+    public void testL7dlog() {
+        final Logger logger = Logger.getLogger("org.example.foo");
+        logger.setLevel(Level.ERROR);
+        final Priority debug = Level.DEBUG;
+        logger.l7dlog(debug, "Hello, World", null);
+        assertTrue(appender.getEvents().size() == 0);
+    }
+
+    /**
+     * Tests l7dlog(Priority, String, Object[], Throwable).
+     */
+    @Test
+    public void testL7dlog4Param() {
+        final Logger logger = Logger.getLogger("org.example.foo");
+        logger.setLevel(Level.ERROR);
+        final Priority debug = Level.DEBUG;
+        logger.l7dlog(debug, "Hello, World", new Object[0], null);
+        assertTrue(appender.getEvents().size() == 0);
+    }
+
+    /**
+     * Test using a pre-existing Log4j 2 logger
+     */
+    @Test
+    public void testExistingLog4j2Logger() {
+        // create the logger using LogManager
+        org.apache.logging.log4j.LogManager.getLogger("existingLogger");
+        // Logger will be the one created above
+        final Logger logger = Logger.getLogger("existingLogger");
+        final Logger l2 = LogManager.getLogger("existingLogger");
+        assertEquals(logger, l2);
+        logger.setLevel(Level.ERROR);
+        final Priority debug = Level.DEBUG;
+        // the next line will throw an exception if the LogManager loggers
+        // aren't supported by 1.2 Logger/Category
+        logger.l7dlog(debug, "Hello, World", new Object[0], null);
+        assertTrue(appender.getEvents().size() == 0);
+    }
+
+    /**
+     * Tests setPriority(Priority).
+     *
+     * @deprecated
+     */
+    @Deprecated
+    @Test
+    public void testSetPriority() {
+        final Logger logger = Logger.getLogger("org.example.foo");
+        final Priority debug = Level.DEBUG;
+        logger.setPriority(debug);
+    }
+
+    @Test
+    public void testClassName() {
+        final Category category = Category.getInstance("TestCategory");
+        final Layout<String> layout = PatternLayout.newBuilder().withPattern("%d %p %C{1.} [%t] %m%n").build();
+        final ListAppender appender = new ListAppender("List2", null, layout, false, false);
+        appender.start();
+        category.setAdditivity(false);
+        ((org.apache.logging.log4j.core.Logger) category.getLogger()).addAppender(appender);
+        category.error("Test Message");
+        final List<String> msgs = appender.getMessages();
+        assertTrue("Incorrect number of messages. Expected 1 got " + msgs.size(), msgs.size() == 1);
+        final String msg = msgs.get(0);
+        appender.clear();
+        final String threadName = Thread.currentThread().getName();
+        final String expected = "ERROR o.a.l.CategoryTest [" + threadName + "] Test Message" + Strings.LINE_SEPARATOR;
+        assertTrue("Incorrect message " + Strings.dquote(msg) + " expected " + Strings.dquote(expected), msg.endsWith(expected));
+    }
+
+    /**
+     * Derived category to check method signature of forcedLog.
+     */
+    private static class MockCategory extends Logger {
+        /**
+         * Create new instance of MockCategory.
+         *
+         * @param name category name
+         */
+        public MockCategory(final String name) {
+            super(name);
+        }
+
+        /**
+         * Request an info level message.
+         *
+         * @param msg message
+         */
+        public void info(final String msg) {
+            final Priority info = Level.INFO;
+            forcedLog(MockCategory.class.toString(), info, msg, null);
+        }
+    }
+}
diff --git a/log4j-1.2-api/src/src/test/java/org/apache/log4j/LevelTest.java b/log4j-1.2-api/src/src/test/java/org/apache/log4j/LevelTest.java
new file mode 100644
index 0000000..bb991ad
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/java/org/apache/log4j/LevelTest.java
@@ -0,0 +1,284 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j;
+
+import java.util.Locale;
+
+import org.apache.log4j.util.SerializationTestHelper;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+
+/**
+ * Tests of Level.
+ *
+ * @since 1.2.12
+ */
+public class LevelTest {
+
+    /**
+     * Serialize Level.INFO and check against witness.
+     *
+     * @throws Exception if exception during test.
+     */
+    @Test
+    public void testSerializeINFO() throws Exception {
+        final int[] skip = new int[]{};
+        SerializationTestHelper.assertSerializationEquals(
+            "target/test-classes/witness/serialization/info.bin",
+            Level.INFO, skip, Integer.MAX_VALUE);
+    }
+
+    /**
+     * Deserialize witness and see if resolved to Level.INFO.
+     *
+     * @throws Exception if exception during test.
+     */
+    @Test
+    public void testDeserializeINFO() throws Exception {
+        final Object obj =
+            SerializationTestHelper.deserializeStream(
+                "target/test-classes/witness/serialization/info.bin");
+        assertTrue(obj instanceof Level);
+        final Level info = (Level) obj;
+        assertEquals("INFO", info.toString());
+        //
+        //  JDK 1.1 doesn't support readResolve necessary for the assertion
+        if (!System.getProperty("java.version").startsWith("1.1.")) {
+            assertTrue(obj == Level.INFO);
+        }
+    }
+
+    /**
+     * Tests that a custom level can be serialized and deserialized
+     * and is not resolved to a stock level.
+     *
+     * @throws Exception if exception during test.
+     */
+    @Test
+    public void testCustomLevelSerialization() throws Exception {
+        final CustomLevel custom = new CustomLevel();
+        final Object obj = SerializationTestHelper.serializeClone(custom);
+        assertTrue(obj instanceof CustomLevel);
+
+        final CustomLevel clone = (CustomLevel) obj;
+        assertEquals(Level.INFO.level, clone.level);
+        assertEquals(Level.INFO.levelStr, clone.levelStr);
+        assertEquals(Level.INFO.syslogEquivalent, clone.syslogEquivalent);
+    }
+
+    /**
+     * Custom level to check that custom levels are
+     * serializable, but not resolved to a plain Level.
+     */
+    private static class CustomLevel extends Level {
+        /**
+         * Generated serial version ID.
+         */
+        private static final long serialVersionUID = -6931920872225831135L;
+
+        /**
+         * Create an instance of CustomLevel.
+         */
+        public CustomLevel() {
+            super(
+                Level.INFO.level, Level.INFO.levelStr, Level.INFO.syslogEquivalent);
+        }
+    }
+
+    /**
+     * Tests Level.TRACE_INT.
+     */
+    @Test
+    public void testTraceInt() {
+        assertEquals(5000, Level.TRACE_INT);
+    }
+
+    /**
+     * Tests Level.TRACE.
+     */
+    @Test
+    public void testTrace() {
+        assertEquals("TRACE", Level.TRACE.toString());
+        assertEquals(5000, Level.TRACE.toInt());
+        assertEquals(7, Level.TRACE.getSyslogEquivalent());
+    }
+
+    /**
+     * Tests Level.toLevel(Level.TRACE_INT).
+     */
+    @Test
+    public void testIntToTrace() {
+        final Level trace = Level.toLevel(5000);
+        assertEquals("TRACE", trace.toString());
+    }
+
+    /**
+     * Tests Level.toLevel("TRACE");
+     */
+    @Test
+    public void testStringToTrace() {
+        final Level trace = Level.toLevel("TRACE");
+        assertEquals("TRACE", trace.toString());
+    }
+
+    /**
+     * Tests that Level extends Priority.
+     */
+    @Test
+    public void testLevelExtendsPriority() {
+        assertTrue(Priority.class.isAssignableFrom(Level.class));
+    }
+
+    /**
+     * Tests Level.OFF.
+     */
+    @Test
+    public void testOFF() {
+        assertTrue(Level.OFF instanceof Level);
+    }
+
+    /**
+     * Tests Level.FATAL.
+     */
+    @Test
+    public void testFATAL() {
+        assertTrue(Level.FATAL instanceof Level);
+    }
+
+    /**
+     * Tests Level.ERROR.
+     */
+    @Test
+    public void testERROR() {
+        assertTrue(Level.ERROR instanceof Level);
+    }
+
+    /**
+     * Tests Level.WARN.
+     */
+    @Test
+    public void testWARN() {
+        assertTrue(Level.WARN instanceof Level);
+    }
+
+    /**
+     * Tests Level.INFO.
+     */
+    @Test
+    public void testINFO() {
+        assertTrue(Level.INFO instanceof Level);
+    }
+
+    /**
+     * Tests Level.DEBUG.
+     */
+    @Test
+    public void testDEBUG() {
+        assertTrue(Level.DEBUG instanceof Level);
+    }
+
+    /**
+     * Tests Level.TRACE.
+     */
+    @Test
+    public void testTRACE() {
+        assertTrue(Level.TRACE instanceof Level);
+    }
+
+    /**
+     * Tests Level.ALL.
+     */
+    @Test
+    public void testALL() {
+        assertTrue(Level.ALL instanceof Level);
+    }
+
+    /**
+     * Tests Level.toLevel(Level.All_INT).
+     */
+    @Test
+    public void testIntToAll() {
+        final Level level = Level.toLevel(Priority.ALL_INT);
+        assertEquals("ALL", level.toString());
+    }
+
+    /**
+     * Tests Level.toLevel(Level.FATAL_INT).
+     */
+    @Test
+    public void testIntToFatal() {
+        final Level level = Level.toLevel(Priority.FATAL_INT);
+        assertEquals("FATAL", level.toString());
+    }
+
+
+    /**
+     * Tests Level.toLevel(Level.OFF_INT).
+     */
+    @Test
+    public void testIntToOff() {
+        final Level level = Level.toLevel(Priority.OFF_INT);
+        assertEquals("OFF", level.toString());
+    }
+
+    /**
+     * Tests Level.toLevel(17, Level.FATAL).
+     */
+    @Test
+    public void testToLevelUnrecognizedInt() {
+        final Level level = Level.toLevel(17, Level.FATAL);
+        assertEquals("FATAL", level.toString());
+    }
+
+    /**
+     * Tests Level.toLevel(null, Level.FATAL).
+     */
+    @Test
+    public void testToLevelNull() {
+        final Level level = Level.toLevel(null, Level.FATAL);
+        assertEquals("FATAL", level.toString());
+    }
+
+    /**
+     * Test that dotless lower I + "nfo" is recognized as INFO.
+     */
+    @Test
+    public void testDotlessLowerI() {
+        final Level level = Level.toLevel("\u0131nfo");
+        assertEquals("INFO", level.toString());
+    }
+
+    /**
+     * Test that dotted lower I + "nfo" is recognized as INFO
+     * even in Turkish locale.
+     */
+    @Test
+    public void testDottedLowerI() {
+        final Locale defaultLocale = Locale.getDefault();
+        final Locale turkey = new Locale("tr", "TR");
+        Locale.setDefault(turkey);
+        final Level level = Level.toLevel("info");
+        Locale.setDefault(defaultLocale);
+        assertEquals("INFO", level.toString());
+    }
+
+
+}
+
diff --git a/log4j-1.2-api/src/src/test/java/org/apache/log4j/ListAppender.java b/log4j-1.2-api/src/src/test/java/org/apache/log4j/ListAppender.java
new file mode 100644
index 0000000..83c2758
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/java/org/apache/log4j/ListAppender.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j;
+
+import org.apache.log4j.spi.LoggingEvent;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Used to test Log4j 1 support.
+ */
+public class ListAppender extends AppenderSkeleton {
+    // Use Collections.synchronizedList rather than CopyOnWriteArrayList because we expect
+    // more frequent writes than reads.
+    final List<LoggingEvent> events = Collections.synchronizedList(new ArrayList<>());
+
+    private final List<String> messages = Collections.synchronizedList(new ArrayList<>());
+
+
+    private static final String WINDOWS_LINE_SEP = "\r\n";
+
+    @Override
+    protected void append(LoggingEvent event) {
+        Layout layout = getLayout();
+        if (layout != null) {
+            String result = layout.format(event);
+            if (result != null) {
+                messages.add(result);
+            }
+        } else {
+            events.add(event);
+        }
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public boolean requiresLayout() {
+        return false;
+    }
+
+    /** Returns an immutable snapshot of captured log events */
+    public List<LoggingEvent> getEvents() {
+        return Collections.unmodifiableList(new ArrayList<>(events));
+    }
+
+    /** Returns an immutable snapshot of captured messages */
+    public List<String> getMessages() {
+        return Collections.unmodifiableList(new ArrayList<>(messages));
+    }
+
+    /**
+     * Polls the messages list for it to grow to a given minimum size at most timeout timeUnits and return a copy of
+     * what we have so far.
+     */
+    public List<String> getMessages(final int minSize, final long timeout, final TimeUnit timeUnit) throws InterruptedException {
+        final long endMillis = System.currentTimeMillis() + timeUnit.toMillis(timeout);
+        while (messages.size() < minSize && System.currentTimeMillis() < endMillis) {
+            Thread.sleep(100);
+        }
+        return getMessages();
+    }
+}
diff --git a/log4j-1.2-api/src/src/test/java/org/apache/log4j/LogWithMDCTest.java b/log4j-1.2-api/src/src/test/java/org/apache/log4j/LogWithMDCTest.java
new file mode 100644
index 0000000..997d745
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/java/org/apache/log4j/LogWithMDCTest.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j;
+
+import org.apache.logging.log4j.junit.LoggerContextRule;
+import org.apache.logging.log4j.test.appender.ListAppender;
+import org.junit.ClassRule;
+import org.junit.Test;
+
+import java.util.List;
+
+import static org.junit.Assert.*;
+
+/**
+ * Test logging with MDC values.
+ */
+public class LogWithMDCTest {
+
+    private static final String CONFIG = "logWithMDC.xml";
+
+    @ClassRule
+    public static final LoggerContextRule CTX = new LoggerContextRule(CONFIG);
+
+    @Test
+    public void testMDC() throws Exception {
+        MDC.put("Key1", "John");
+        MDC.put("Key2", "Smith");
+        try {
+            final Logger logger = Logger.getLogger("org.apache.test.logging");
+            logger.debug("This is a test");
+            final ListAppender listApp = (ListAppender) CTX.getAppender("List");
+            assertNotNull(listApp);
+            final List<String> msgs = listApp.getMessages();
+            assertNotNull("No messages received", msgs);
+            assertTrue(msgs.size() == 1);
+            assertTrue("Key1 is missing", msgs.get(0).contains("Key1=John"));
+            assertTrue("Key2 is missing", msgs.get(0).contains("Key2=Smith"));
+        } finally {
+            MDC.remove("Key1");
+            MDC.remove("Key2");
+        }
+    }
+}
diff --git a/log4j-1.2-api/src/src/test/java/org/apache/log4j/LogWithRouteTest.java b/log4j-1.2-api/src/src/test/java/org/apache/log4j/LogWithRouteTest.java
new file mode 100644
index 0000000..606e87b
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/java/org/apache/log4j/LogWithRouteTest.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j;
+
+import org.apache.logging.log4j.junit.LoggerContextRule;
+import org.apache.logging.log4j.test.appender.ListAppender;
+import org.junit.ClassRule;
+import org.junit.Test;
+
+import java.util.List;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test passing MDC values to the Routing appender.
+ */
+public class LogWithRouteTest {
+
+    private static final String CONFIG = "log-RouteWithMDC.xml";
+
+    @ClassRule
+    public static final LoggerContextRule CTX = new LoggerContextRule(CONFIG);
+
+    @Test
+    public void testMDC() throws Exception {
+        MDC.put("Type", "Service");
+        MDC.put("Name", "John Smith");
+        try {
+            final Logger logger = Logger.getLogger("org.apache.test.logging");
+            logger.debug("This is a test");
+            final ListAppender listApp = (ListAppender) CTX.getAppender("List");
+            assertNotNull(listApp);
+            final List<String> msgs = listApp.getMessages();
+            assertNotNull("No messages received", msgs);
+            assertTrue(msgs.size() == 1);
+            assertTrue("Type is missing", msgs.get(0).contains("Type=Service"));
+            assertTrue("Name is missing", msgs.get(0).contains("Name=John Smith"));
+        } finally {
+            MDC.remove("Type");
+            MDC.remove("Name");
+        }
+    }
+}
diff --git a/log4j-1.2-api/src/src/test/java/org/apache/log4j/LoggerTest.java b/log4j-1.2-api/src/src/test/java/org/apache/log4j/LoggerTest.java
new file mode 100644
index 0000000..0c4308f
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/java/org/apache/log4j/LoggerTest.java
@@ -0,0 +1,525 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j;
+
+import java.util.List;
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.appender.AbstractAppender;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.config.Property;
+import org.apache.logging.log4j.core.layout.PatternLayout;
+import org.apache.logging.log4j.test.appender.ListAppender;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Used for internal unit testing the Logger class.
+ */
+public class LoggerTest {
+
+    Appender a1;
+    Appender a2;
+
+    static ResourceBundle rbUS;
+    static ResourceBundle rbFR;
+    static ResourceBundle rbCH;
+
+    // A short message.
+    static String MSG = "M";
+
+    static ConfigurationFactory configurationFactory = new BasicConfigurationFactory();
+
+    @BeforeClass
+    public static void setUpClass() {
+        rbUS = ResourceBundle.getBundle("L7D", new Locale("en", "US"));
+        assertNotNull(rbUS);
+
+        rbFR = ResourceBundle.getBundle("L7D", new Locale("fr", "FR"));
+        assertNotNull("Got a null resource bundle.", rbFR);
+
+        rbCH = ResourceBundle.getBundle("L7D", new Locale("fr", "CH"));
+        assertNotNull("Got a null resource bundle.", rbCH);
+
+        ConfigurationFactory.setConfigurationFactory(configurationFactory);
+    }
+
+    @AfterClass
+    public static void tearDownClass() {
+        ConfigurationFactory.removeConfigurationFactory(configurationFactory);
+    }
+
+    @After
+    public void tearDown() {
+        LoggerContext.getContext().reconfigure();
+        a1 = null;
+        a2 = null;
+    }
+
+    /**
+     * Add an appender and see if it can be retrieved.
+     *  Skipping this test as the Appender interface isn't compatible with legacy Log4j.
+    public void testAppender1() {
+        logger = Logger.getLogger("test");
+        a1 = new ListAppender("testAppender1");
+        logger.addAppender(a1);
+
+        Enumeration enumeration = logger.getAllAppenders();
+        Appender aHat = (Appender) enumeration.nextElement();
+        assertEquals(a1, aHat);
+    } */
+
+    /**
+     * Add an appender X, Y, remove X and check if Y is the only
+     * remaining appender.
+     * Skipping this test as the Appender interface isn't compatible with legacy Log4j.
+    public void testAppender2() {
+        a1 = new FileAppender();
+        a1.setName("testAppender2.1");
+        a2 = new FileAppender();
+        a2.setName("testAppender2.2");
+
+        logger = Logger.getLogger("test");
+        logger.addAppender(a1);
+        logger.addAppender(a2);
+        logger.removeAppender("testAppender2.1");
+        Enumeration enumeration = logger.getAllAppenders();
+        Appender aHat = (Appender) enumeration.nextElement();
+        assertEquals(a2, aHat);
+        assertTrue(!enumeration.hasMoreElements());
+    }  */
+
+    /**
+     * Test if logger a.b inherits its appender from a.
+     */
+    @Test
+    public void testAdditivity1() {
+        final Logger loggerA = Logger.getLogger("a");
+        final Logger loggerAB = Logger.getLogger("a.b");
+        final CountingAppender coutingAppender = new CountingAppender();
+        coutingAppender.start();
+        try {
+            ((org.apache.logging.log4j.core.Logger) loggerA.getLogger()).addAppender(coutingAppender);
+
+            assertEquals(0, coutingAppender.counter);
+            loggerAB.debug(MSG);
+            assertEquals(1, coutingAppender.counter);
+            loggerAB.info(MSG);
+            assertEquals(2, coutingAppender.counter);
+            loggerAB.warn(MSG);
+            assertEquals(3, coutingAppender.counter);
+            loggerAB.error(MSG);
+            assertEquals(4, coutingAppender.counter);
+            coutingAppender.stop();
+        } finally {
+            ((org.apache.logging.log4j.core.Logger) loggerA.getLogger()).removeAppender(coutingAppender);
+        }
+    }
+
+    /**
+     * Test multiple additivity.
+     */
+    @Test
+    public void testAdditivity2() {
+        final Logger a = Logger.getLogger("a");
+        final Logger ab = Logger.getLogger("a.b");
+        final Logger abc = Logger.getLogger("a.b.c");
+        final Logger x = Logger.getLogger("x");
+
+        final CountingAppender ca1 = new CountingAppender();
+        ca1.start();
+        final CountingAppender ca2 = new CountingAppender();
+        ca2.start();
+
+        try {
+            ((org.apache.logging.log4j.core.Logger) a.getLogger()).addAppender(ca1);
+            ((org.apache.logging.log4j.core.Logger) abc.getLogger()).addAppender(ca2);
+
+            assertEquals(ca1.counter, 0);
+            assertEquals(ca2.counter, 0);
+
+            ab.debug(MSG);
+            assertEquals(ca1.counter, 1);
+            assertEquals(ca2.counter, 0);
+
+            abc.debug(MSG);
+            assertEquals(ca1.counter, 2);
+            assertEquals(ca2.counter, 1);
+
+            x.debug(MSG);
+            assertEquals(ca1.counter, 2);
+            assertEquals(ca2.counter, 1);
+            ca1.stop();
+            ca2.stop();
+        } finally {
+            ((org.apache.logging.log4j.core.Logger) a.getLogger()).removeAppender(ca1);
+            ((org.apache.logging.log4j.core.Logger) abc.getLogger()).removeAppender(ca2);
+        }}
+
+    /**
+     * Test additivity flag.
+     */
+    @Test
+    public void testAdditivity3() {
+        final Logger root = Logger.getRootLogger();
+        final Logger a = Logger.getLogger("a");
+        final Logger ab = Logger.getLogger("a.b");
+        final Logger abc = Logger.getLogger("a.b.c");
+        Logger.getLogger("x");
+
+        final CountingAppender caRoot = new CountingAppender();
+        caRoot.start();
+        final CountingAppender caA = new CountingAppender();
+        caA.start();
+        final CountingAppender caABC = new CountingAppender();
+        caABC.start();
+        try {
+            ((org.apache.logging.log4j.core.Logger) root.getLogger()).addAppender(caRoot);
+            ((org.apache.logging.log4j.core.Logger) a.getLogger()).addAppender(caA);
+            ((org.apache.logging.log4j.core.Logger) abc.getLogger()).addAppender(caABC);
+
+            assertEquals(caRoot.counter, 0);
+            assertEquals(caA.counter, 0);
+            assertEquals(caABC.counter, 0);
+
+            ab.setAdditivity(false);
+
+            a.debug(MSG);
+            assertEquals(caRoot.counter, 1);
+            assertEquals(caA.counter, 1);
+            assertEquals(caABC.counter, 0);
+
+            ab.debug(MSG);
+            assertEquals(caRoot.counter, 1);
+            assertEquals(caA.counter, 1);
+            assertEquals(caABC.counter, 0);
+
+            abc.debug(MSG);
+            assertEquals(caRoot.counter, 1);
+            assertEquals(caA.counter, 1);
+            assertEquals(caABC.counter, 1);
+            caRoot.stop();
+            caA.stop();
+            caABC.stop();
+        } finally {
+            ((org.apache.logging.log4j.core.Logger) root.getLogger()).removeAppender(caRoot);
+            ((org.apache.logging.log4j.core.Logger) a.getLogger()).removeAppender(caA);
+            ((org.apache.logging.log4j.core.Logger) abc.getLogger()).removeAppender(caABC);
+        }}
+
+    /* Don't support getLoggerRepository
+    public void testDisable1() {
+        CountingAppender caRoot = new CountingAppender();
+        Logger root = Logger.getRootLogger();
+        root.getLogger().addAppender(caRoot);
+
+        LoggerRepository h = LogManager.getLoggerRepository();
+        //h.disableDebug();
+        h.setThreshold((Level) Level.INFO);
+        assertEquals(caRoot.counter, 0);
+
+        root.debug(MSG);
+        assertEquals(caRoot.counter, 0);
+        root.info(MSG);
+        assertEquals(caRoot.counter, 1);
+        root.log(Level.WARN, MSG);
+        assertEquals(caRoot.counter, 2);
+        root.warn(MSG);
+        assertEquals(caRoot.counter, 3);
+
+        //h.disableInfo();
+        h.setThreshold((Level) Level.WARN);
+        root.debug(MSG);
+        assertEquals(caRoot.counter, 3);
+        root.info(MSG);
+        assertEquals(caRoot.counter, 3);
+        root.log(Level.WARN, MSG);
+        assertEquals(caRoot.counter, 4);
+        root.error(MSG);
+        assertEquals(caRoot.counter, 5);
+        root.log(Level.ERROR, MSG);
+        assertEquals(caRoot.counter, 6);
+
+        //h.disableAll();
+        h.setThreshold(Level.OFF);
+        root.debug(MSG);
+        assertEquals(caRoot.counter, 6);
+        root.info(MSG);
+        assertEquals(caRoot.counter, 6);
+        root.log(Level.WARN, MSG);
+        assertEquals(caRoot.counter, 6);
+        root.error(MSG);
+        assertEquals(caRoot.counter, 6);
+        root.log(Level.FATAL, MSG);
+        assertEquals(caRoot.counter, 6);
+        root.log(Level.FATAL, MSG);
+        assertEquals(caRoot.counter, 6);
+
+        //h.disable(Level.FATAL);
+        h.setThreshold(Level.OFF);
+        root.debug(MSG);
+        assertEquals(caRoot.counter, 6);
+        root.info(MSG);
+        assertEquals(caRoot.counter, 6);
+        root.log(Level.WARN, MSG);
+        assertEquals(caRoot.counter, 6);
+        root.error(MSG);
+        assertEquals(caRoot.counter, 6);
+        root.log(Level.ERROR, MSG);
+        assertEquals(caRoot.counter, 6);
+        root.log(Level.FATAL, MSG);
+        assertEquals(caRoot.counter, 6);
+    }  */
+
+    @Test
+    public void testRB1() {
+        final Logger root = Logger.getRootLogger();
+        root.setResourceBundle(rbUS);
+        ResourceBundle t = root.getResourceBundle();
+        assertSame(t, rbUS);
+
+        final Logger x = Logger.getLogger("x");
+        final Logger x_y = Logger.getLogger("x.y");
+        final Logger x_y_z = Logger.getLogger("x.y.z");
+
+        t = x.getResourceBundle();
+        assertSame(t, rbUS);
+        t = x_y.getResourceBundle();
+        assertSame(t, rbUS);
+        t = x_y_z.getResourceBundle();
+        assertSame(t, rbUS);
+    }
+
+    @Test
+    public void testRB2() {
+        final Logger root = Logger.getRootLogger();
+        root.setResourceBundle(rbUS);
+        ResourceBundle t = root.getResourceBundle();
+        assertTrue(t == rbUS);
+
+        final Logger x = Logger.getLogger("x");
+        final Logger x_y = Logger.getLogger("x.y");
+        final Logger x_y_z = Logger.getLogger("x.y.z");
+
+        x_y.setResourceBundle(rbFR);
+        t = x.getResourceBundle();
+        assertSame(t, rbUS);
+        t = x_y.getResourceBundle();
+        assertSame(t, rbFR);
+        t = x_y_z.getResourceBundle();
+        assertSame(t, rbFR);
+    }
+
+    @Test
+    public void testRB3() {
+        final Logger root = Logger.getRootLogger();
+        root.setResourceBundle(rbUS);
+        ResourceBundle t = root.getResourceBundle();
+        assertTrue(t == rbUS);
+
+        final Logger x = Logger.getLogger("x");
+        final Logger x_y = Logger.getLogger("x.y");
+        final Logger x_y_z = Logger.getLogger("x.y.z");
+
+        x_y.setResourceBundle(rbFR);
+        x_y_z.setResourceBundle(rbCH);
+        t = x.getResourceBundle();
+        assertSame(t, rbUS);
+        t = x_y.getResourceBundle();
+        assertSame(t, rbFR);
+        t = x_y_z.getResourceBundle();
+        assertSame(t, rbCH);
+    }
+
+    @Test
+    public void testExists() {
+        final Logger a = Logger.getLogger("a");
+        final Logger a_b = Logger.getLogger("a.b");
+        final Logger a_b_c = Logger.getLogger("a.b.c");
+
+        Logger t;
+        t = LogManager.exists("xx");
+        assertNull(t);
+        t = LogManager.exists("a");
+        assertSame(a, t);
+        t = LogManager.exists("a.b");
+        assertSame(a_b, t);
+        t = LogManager.exists("a.b.c");
+        assertSame(a_b_c, t);
+    }
+    /* Don't support hierarchy
+    public void testHierarchy1() {
+        Hierarchy h = new Hierarchy(new RootLogger((Level) Level.ERROR));
+        Logger a0 = h.getLogger("a");
+        assertEquals("a", a0.getName());
+        assertNull(a0.getLevel());
+        assertSame(Level.ERROR, a0.getEffectiveLevel());
+
+        Logger a1 = h.getLogger("a");
+        assertSame(a0, a1);
+    } */
+
+    /**
+     * Tests logger.trace(Object).
+     */
+    @Test
+    public void testTrace() {
+        final ListAppender appender = new ListAppender("List");
+        appender.start();
+        final Logger root = Logger.getRootLogger();
+        ((org.apache.logging.log4j.core.Logger) root.getLogger()).addAppender(appender);
+        root.setLevel(Level.INFO);
+
+        final Logger tracer = Logger.getLogger("com.example.Tracer");
+        tracer.setLevel(Level.TRACE);
+
+        tracer.trace("Message 1");
+        root.trace("Discarded Message");
+        root.trace("Discarded Message");
+
+        final List<LogEvent> msgs = appender.getEvents();
+        assertEquals(1, msgs.size());
+        final LogEvent event = msgs.get(0);
+        assertEquals(org.apache.logging.log4j.Level.TRACE, event.getLevel());
+        assertEquals("Message 1", event.getMessage().getFormat());
+        appender.stop();
+        ((org.apache.logging.log4j.core.Logger) root.getLogger()).removeAppender(appender);
+    }
+
+    /**
+     * Tests logger.trace(Object, Exception).
+     */
+    @Test
+    public void testTraceWithException() {
+        final ListAppender appender = new ListAppender("List");
+        appender.start();
+        final Logger root = Logger.getRootLogger();
+        try {
+            ((org.apache.logging.log4j.core.Logger) root.getLogger()).addAppender(appender);
+            root.setLevel(Level.INFO);
+
+            final Logger tracer = Logger.getLogger("com.example.Tracer");
+            tracer.setLevel(Level.TRACE);
+            final NullPointerException ex = new NullPointerException();
+
+            tracer.trace("Message 1", ex);
+            root.trace("Discarded Message", ex);
+            root.trace("Discarded Message", ex);
+
+            final List<LogEvent> msgs = appender.getEvents();
+            assertEquals(1, msgs.size());
+            final LogEvent event = msgs.get(0);
+            assertEquals(org.apache.logging.log4j.Level.TRACE, event.getLevel());
+            assertEquals("Message 1", event.getMessage().getFormattedMessage());
+            appender.stop();
+        } finally {
+            ((org.apache.logging.log4j.core.Logger) root.getLogger()).removeAppender(appender);
+        }
+    }
+
+    /**
+     * Tests isTraceEnabled.
+     */
+    @Test
+    public void testIsTraceEnabled() {
+        final ListAppender appender = new ListAppender("List");
+        appender.start();
+        final Logger root = Logger.getRootLogger();
+        try {
+            ((org.apache.logging.log4j.core.Logger) root.getLogger()).addAppender(appender);
+            root.setLevel(Level.INFO);
+
+            final Logger tracer = Logger.getLogger("com.example.Tracer");
+            tracer.setLevel(Level.TRACE);
+
+            assertTrue(tracer.isTraceEnabled());
+            assertFalse(root.isTraceEnabled());
+            appender.stop();
+        } finally {
+            ((org.apache.logging.log4j.core.Logger) root.getLogger()).removeAppender(appender);
+        }
+    }
+
+    @Test
+    @SuppressWarnings("deprecation")
+    public void testLog() {
+        final PatternLayout layout = PatternLayout.newBuilder().withPattern("%d %C %L %m").build();
+        final ListAppender appender = new ListAppender("List", null, layout, false, false);
+        appender.start();
+        final Logger root = Logger.getRootLogger();
+        try {
+            ((org.apache.logging.log4j.core.Logger) root.getLogger()).addAppender(appender);
+            root.setLevel(Level.INFO);
+            final MyLogger log = new MyLogger(root);
+            log.logInfo("This is a test", null);
+            root.log(Priority.INFO, "Test msg2", null);
+            root.log(Priority.INFO, "Test msg3");
+            final List<String> msgs = appender.getMessages();
+            assertTrue("Incorrect number of messages", msgs.size() == 3);
+            final String msg = msgs.get(0);
+            assertTrue("Message contains incorrect class name: " + msg, msg.contains(LoggerTest.class.getName()));
+            appender.stop();
+        } finally {
+            ((org.apache.logging.log4j.core.Logger) root.getLogger()).removeAppender(appender);
+        }
+    }
+
+    private static class MyLogger {
+
+        private final Logger logger;
+
+        public MyLogger(final Logger logger) {
+            this.logger = logger;
+        }
+
+        @SuppressWarnings("deprecation")
+        public void logInfo(final String msg, final Throwable t) {
+            logger.log(MyLogger.class.getName(), Priority.INFO, msg, t);
+        }
+    }
+
+    private static class CountingAppender extends AbstractAppender {
+
+        private static final long serialVersionUID = 1L;
+
+        int counter;
+
+        CountingAppender() {
+            super("Counter", null, null, true, Property.EMPTY_ARRAY);
+            counter = 0;
+        }
+
+        @Override
+        public void append(final LogEvent event) {
+            counter++;
+        }
+
+        public boolean requiresLayout() {
+            return true;
+        }
+    }
+}
+
diff --git a/log4j-1.2-api/src/src/test/java/org/apache/log4j/LoggingTest.java b/log4j-1.2-api/src/src/test/java/org/apache/log4j/LoggingTest.java
new file mode 100644
index 0000000..4ec4fb8
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/java/org/apache/log4j/LoggingTest.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j;
+
+import org.apache.logging.log4j.junit.LoggerContextRule;
+import org.junit.ClassRule;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ *
+ */
+public class LoggingTest {
+
+    private static final String CONFIG = "log4j2-config.xml";
+
+    @ClassRule
+    public static final LoggerContextRule CTX = new LoggerContextRule(CONFIG);
+
+    @Test
+    public void testParent() {
+        final Logger logger = Logger.getLogger("org.apache.test.logging.Test");
+        final Category parent = logger.getParent();
+        assertNotNull("No parent Logger", parent);
+        assertEquals("Incorrect parent logger", "org.apache.test.logging", parent.getName());
+    }
+
+}
diff --git a/log4j-1.2-api/src/src/test/java/org/apache/log4j/MDCTestCase.java b/log4j-1.2-api/src/src/test/java/org/apache/log4j/MDCTestCase.java
new file mode 100644
index 0000000..c0e5ba5
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/java/org/apache/log4j/MDCTestCase.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class MDCTestCase {
+
+    @Before
+    public void setUp() {
+        MDC.clear();
+    }
+
+    @After
+    public void tearDown() {
+        MDC.clear();
+    }
+
+    @Test
+    public void testPut() throws Exception {
+        MDC.put("key", "some value");
+        Assert.assertEquals("some value", MDC.get("key"));
+        Assert.assertEquals(1, MDC.getContext().size());
+    }
+
+    @Test
+    public void testRemoveLastKey() throws Exception {
+        MDC.put("key", "some value");
+        MDC.remove("key");
+    }
+
+}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-1.2-api/src/src/test/java/org/apache/log4j/NDCTest.java
similarity index 69%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-1.2-api/src/src/test/java/org/apache/log4j/NDCTest.java
index 13aaf9c..c8baf0f 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-1.2-api/src/src/test/java/org/apache/log4j/NDCTest.java
@@ -14,17 +14,23 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
+package org.apache.log4j;
 
+import org.apache.logging.log4j.util.Strings;
+import org.junit.Assert;
 import org.junit.Test;
 
-import static org.junit.Assert.*;
-
-public class ProcessIdUtilTest {
+public class NDCTest {
 
     @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
+    public void testPopEmpty() {
+        NDC.clear();
+        Assert.assertEquals(Strings.EMPTY, NDC.pop());
+    }
+
+    @Test
+    public void testPeekEmpty() {
+        NDC.clear();
+        Assert.assertEquals(Strings.EMPTY, NDC.peek());
     }
 }
diff --git a/log4j-1.2-api/src/src/test/java/org/apache/log4j/PriorityTest.java b/log4j-1.2-api/src/src/test/java/org/apache/log4j/PriorityTest.java
new file mode 100644
index 0000000..63321a7
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/java/org/apache/log4j/PriorityTest.java
@@ -0,0 +1,226 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j;
+
+import java.util.Locale;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Tests of Priority.
+ *
+ */
+public class PriorityTest {
+
+    /**
+     * Tests Priority.OFF_INT.
+     */
+    @Test
+    public void testOffInt() {
+        assertEquals(Integer.MAX_VALUE, Priority.OFF_INT);
+    }
+
+    /**
+     * Tests Priority.FATAL_INT.
+     */
+    @Test
+    public void testFatalInt() {
+        assertEquals(50000, Priority.FATAL_INT);
+    }
+
+    /**
+     * Tests Priority.ERROR_INT.
+     */
+    @Test
+    public void testErrorInt() {
+        assertEquals(40000, Priority.ERROR_INT);
+    }
+
+    /**
+     * Tests Priority.WARN_INT.
+     */
+    @Test
+    public void testWarnInt() {
+        assertEquals(30000, Priority.WARN_INT);
+    }
+
+    /**
+     * Tests Priority.INFO_INT.
+     */
+    @Test
+    public void testInfoInt() {
+        assertEquals(20000, Priority.INFO_INT);
+    }
+
+    /**
+     * Tests Priority.DEBUG_INT.
+     */
+    @Test
+    public void testDebugInt() {
+        assertEquals(10000, Priority.DEBUG_INT);
+    }
+
+    /**
+     * Tests Priority.ALL_INT.
+     */
+    @Test
+    public void testAllInt() {
+        assertEquals(Integer.MIN_VALUE, Priority.ALL_INT);
+    }
+
+    /**
+     * Tests Priority.FATAL.
+     */
+    @Test
+    @SuppressWarnings("deprecation")
+    public void testFatal() {
+        assertTrue(Priority.FATAL instanceof Level);
+    }
+
+    /**
+     * Tests Priority.ERROR.
+     */
+    @Test
+    @SuppressWarnings("deprecation")
+    public void testERROR() {
+        assertTrue(Priority.ERROR instanceof Level);
+    }
+
+    /**
+     * Tests Priority.WARN.
+     */
+    @Test
+    @SuppressWarnings("deprecation")
+    public void testWARN() {
+        assertTrue(Priority.WARN instanceof Level);
+    }
+
+    /**
+     * Tests Priority.INFO.
+     */
+    @Test
+    @SuppressWarnings("deprecation")
+    public void testINFO() {
+        assertTrue(Priority.INFO instanceof Level);
+    }
+
+    /**
+     * Tests Priority.DEBUG.
+     */
+    @Test
+    @SuppressWarnings("deprecation")
+    public void testDEBUG() {
+        assertTrue(Priority.DEBUG instanceof Level);
+    }
+
+    /**
+     * Tests Priority.equals(null).
+     */
+    @Test
+    @SuppressWarnings("deprecation")
+    public void testEqualsNull() {
+        assertFalse(Priority.DEBUG.equals(null));
+    }
+
+    /**
+     * Tests Priority.equals(Level.DEBUG).
+     */
+    @Test
+    @SuppressWarnings("deprecation")
+    public void testEqualsLevel() {
+        //
+        //   this behavior violates the equals contract.
+        //
+        assertTrue(Priority.DEBUG.equals(Level.DEBUG));
+    }
+
+    /**
+     * Tests getAllPossiblePriorities().
+     */
+    @Test
+    @SuppressWarnings("deprecation")
+    public void testGetAllPossiblePriorities() {
+        final Priority[] priorities = Priority.getAllPossiblePriorities();
+        assertEquals(5, priorities.length);
+    }
+
+    /**
+     * Tests toPriority(String).
+     */
+    @Test
+    @SuppressWarnings("deprecation")
+    public void testToPriorityString() {
+        assertTrue(Priority.toPriority("DEBUG") == Level.DEBUG);
+    }
+
+    /**
+     * Tests toPriority(int).
+     */
+    @Test
+    @SuppressWarnings("deprecation")
+    public void testToPriorityInt() {
+        assertTrue(Priority.toPriority(Priority.DEBUG_INT) == Level.DEBUG);
+    }
+
+    /**
+     * Tests toPriority(String, Priority).
+     */
+    @Test
+    @SuppressWarnings("deprecation")
+    public void testToPriorityStringPriority() {
+        assertTrue(Priority.toPriority("foo", Priority.DEBUG) == Priority.DEBUG);
+    }
+
+    /**
+     * Tests toPriority(int, Priority).
+     */
+    @Test
+    @SuppressWarnings("deprecation")
+    public void testToPriorityIntPriority() {
+        assertTrue(Priority.toPriority(17, Priority.DEBUG) == Priority.DEBUG);
+    }
+
+    /**
+     * Test that dotless lower I + "nfo" is recognized as INFO.
+     */
+    @Test
+    @SuppressWarnings("deprecation")
+    public void testDotlessLowerI() {
+        final Priority level = Priority.toPriority("\u0131nfo");
+        assertEquals("INFO", level.toString());
+    }
+
+    /**
+     * Test that dotted lower I + "nfo" is recognized as INFO
+     * even in Turkish locale.
+     */
+    @Test
+    @SuppressWarnings("deprecation")
+    public void testDottedLowerI() {
+        final Locale defaultLocale = Locale.getDefault();
+        final Locale turkey = new Locale("tr", "TR");
+        Locale.setDefault(turkey);
+        final Priority level = Priority.toPriority("info");
+        Locale.setDefault(defaultLocale);
+        assertEquals("INFO", level.toString());
+  }
+
+}
+
diff --git a/log4j-1.2-api/src/src/test/java/org/apache/log4j/VelocityTest.java b/log4j-1.2-api/src/src/test/java/org/apache/log4j/VelocityTest.java
new file mode 100644
index 0000000..99bd5a2
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/java/org/apache/log4j/VelocityTest.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j;
+
+import java.io.StringWriter;
+
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.Configurator;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.Velocity;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Note that this test must clean up after itself or it may cause other tests to fail.
+ */
+public class VelocityTest {
+
+private static LoggerContext context;
+    
+    @BeforeClass
+    public static void setupClass() {
+        context = LoggerContext.getContext(false);
+    }
+
+    @AfterClass
+    public static void tearDownClass() {
+        Configurator.shutdown(context);
+        StatusLogger.getLogger().reset();
+    }    
+    
+    @Test
+    public void testVelocity() {
+        Velocity.init();
+        final VelocityContext vContext = new VelocityContext();
+        vContext.put("name", new String("Velocity"));
+
+        final Template template = Velocity.getTemplate("target/test-classes/hello.vm");
+
+        final StringWriter sw = new StringWriter();
+
+        template.merge(vContext, sw);
+    }
+}
diff --git a/log4j-1.2-api/src/src/test/java/org/apache/log4j/config/AbstractLog4j1ConfigurationConverterTest.java b/log4j-1.2-api/src/src/test/java/org/apache/log4j/config/AbstractLog4j1ConfigurationConverterTest.java
new file mode 100644
index 0000000..9c973ee
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/java/org/apache/log4j/config/AbstractLog4j1ConfigurationConverterTest.java
@@ -0,0 +1,68 @@
+package org.apache.log4j.config;
+
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+/*
+ * 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.
+ */
+
+@RunWith(Parameterized.class)
+public abstract class AbstractLog4j1ConfigurationConverterTest {
+
+    protected static List<Path> getPaths(final String root) throws IOException {
+        final List<Path> paths = new ArrayList<>();
+        Files.walkFileTree(Paths.get(root), new SimpleFileVisitor<Path>() {
+            @Override
+            public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException {
+                paths.add(file.toAbsolutePath());
+                return FileVisitResult.CONTINUE;
+            }
+        });
+        return paths;
+    }
+
+    private final Path pathIn;
+
+    public AbstractLog4j1ConfigurationConverterTest(final Path path) {
+        super();
+        this.pathIn = path;
+    }
+
+    @Test
+    public void test() throws IOException {
+        final Path tempFile = Files.createTempFile("log4j2", ".xml");
+        try {
+            final Log4j1ConfigurationConverter.CommandLineArguments cla = new Log4j1ConfigurationConverter.CommandLineArguments();
+            cla.setPathIn(pathIn);
+            cla.setPathOut(tempFile);
+            Log4j1ConfigurationConverter.run(cla);
+        } finally {
+            Files.deleteIfExists(tempFile);
+        }
+    }
+}
diff --git a/log4j-1.2-api/src/src/test/java/org/apache/log4j/config/AutoConfigTest.java b/log4j-1.2-api/src/src/test/java/org/apache/log4j/config/AutoConfigTest.java
new file mode 100644
index 0000000..764f612
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/java/org/apache/log4j/config/AutoConfigTest.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.config;
+
+import org.apache.log4j.ListAppender;
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
+import org.apache.log4j.bridge.AppenderAdapter;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.spi.LoggerContext;
+import org.junit.Test;
+
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test configuration from XML.
+ */
+public class AutoConfigTest {
+
+    @Test
+    public void testListAppender() {
+        Logger logger = LogManager.getLogger("test");
+        logger.debug("This is a test of the root logger");
+        LoggerContext loggerContext = org.apache.logging.log4j.LogManager.getContext(false);
+        Configuration configuration = ((org.apache.logging.log4j.core.LoggerContext) loggerContext).getConfiguration();
+        Map<String, Appender> appenders = configuration.getAppenders();
+        ListAppender eventAppender = null;
+        ListAppender messageAppender = null;
+        for (Map.Entry<String, Appender> entry : appenders.entrySet()) {
+            if (entry.getKey().equals("list")) {
+                messageAppender = (ListAppender) ((AppenderAdapter.Adapter) entry.getValue()).getAppender();
+            } else if (entry.getKey().equals("events")) {
+                eventAppender = (ListAppender) ((AppenderAdapter.Adapter) entry.getValue()).getAppender();
+            }
+        }
+        assertNotNull("No Event Appender", eventAppender);
+        assertNotNull("No Message Appender", messageAppender);
+        List<LoggingEvent> events = eventAppender.getEvents();
+        assertTrue("No events", events != null && events.size() > 0);
+        List<String> messages = messageAppender.getMessages();
+        assertTrue("No messages", messages != null && messages.size() > 0);
+    }
+
+}
diff --git a/log4j-1.2-api/src/src/test/java/org/apache/log4j/config/Log4j1ConfigurationConverterHadoopTest.java b/log4j-1.2-api/src/src/test/java/org/apache/log4j/config/Log4j1ConfigurationConverterHadoopTest.java
new file mode 100644
index 0000000..152f5dd
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/java/org/apache/log4j/config/Log4j1ConfigurationConverterHadoopTest.java
@@ -0,0 +1,39 @@
+package org.apache.log4j.config;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.List;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+/*
+ * 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.
+ */
+
+@RunWith(Parameterized.class)
+public class Log4j1ConfigurationConverterHadoopTest extends AbstractLog4j1ConfigurationConverterTest {
+
+    @Parameterized.Parameters(name = "{0}")
+    public static List<Path> data() throws IOException {
+        return getPaths("src/test/resources/config-1.2/hadoop");
+    }
+
+    public Log4j1ConfigurationConverterHadoopTest(final Path path) {
+        super(path);
+    }
+
+}
diff --git a/log4j-1.2-api/src/src/test/java/org/apache/log4j/config/Log4j1ConfigurationConverterSparkTest.java b/log4j-1.2-api/src/src/test/java/org/apache/log4j/config/Log4j1ConfigurationConverterSparkTest.java
new file mode 100644
index 0000000..2b39d4f
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/java/org/apache/log4j/config/Log4j1ConfigurationConverterSparkTest.java
@@ -0,0 +1,39 @@
+package org.apache.log4j.config;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.List;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+/*
+ * 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.
+ */
+
+@RunWith(Parameterized.class)
+public class Log4j1ConfigurationConverterSparkTest extends AbstractLog4j1ConfigurationConverterTest {
+
+    @Parameterized.Parameters(name = "{0}")
+    public static List<Path> data() throws IOException {
+        return getPaths("src/test/resources/config-1.2/spark");
+    }
+
+    public Log4j1ConfigurationConverterSparkTest(final Path path) {
+        super(path);
+    }
+
+}
diff --git a/log4j-1.2-api/src/src/test/java/org/apache/log4j/config/Log4j1ConfigurationFactoryTest.java b/log4j-1.2-api/src/src/test/java/org/apache/log4j/config/Log4j1ConfigurationFactoryTest.java
new file mode 100644
index 0000000..ebe3e54
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/java/org/apache/log4j/config/Log4j1ConfigurationFactoryTest.java
@@ -0,0 +1,249 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.config;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.file.FileSystemException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.log4j.layout.Log4j1XmlLayout;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.appender.ConsoleAppender;
+import org.apache.logging.log4j.core.appender.ConsoleAppender.Target;
+import org.apache.logging.log4j.core.appender.FileAppender;
+import org.apache.logging.log4j.core.appender.NullAppender;
+import org.apache.logging.log4j.core.appender.RollingFileAppender;
+import org.apache.logging.log4j.core.appender.rolling.CompositeTriggeringPolicy;
+import org.apache.logging.log4j.core.appender.rolling.DefaultRolloverStrategy;
+import org.apache.logging.log4j.core.appender.rolling.RolloverStrategy;
+import org.apache.logging.log4j.core.appender.rolling.SizeBasedTriggeringPolicy;
+import org.apache.logging.log4j.core.appender.rolling.TimeBasedTriggeringPolicy;
+import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.LoggerConfig;
+import org.apache.logging.log4j.core.layout.HtmlLayout;
+import org.apache.logging.log4j.core.layout.PatternLayout;
+import org.junit.Test;
+
+public class Log4j1ConfigurationFactoryTest {
+
+    private Layout<?> testConsole(final String configResource) throws Exception {
+        final Configuration configuration = getConfiguration(configResource);
+        final String name = "Console";
+        final ConsoleAppender appender = configuration.getAppender(name);
+        assertNotNull("Missing appender '" + name + "' in configuration " + configResource + " → " + configuration,
+                appender);
+        assertEquals(Target.SYSTEM_ERR, appender.getTarget());
+        //
+        final LoggerConfig loggerConfig = configuration.getLoggerConfig("com.example.foo");
+        assertNotNull(loggerConfig);
+        assertEquals(Level.DEBUG, loggerConfig.getLevel());
+        configuration.start();
+        configuration.stop();
+        return appender.getLayout();
+    }
+
+	private Layout<?> testFile(final String configResource) throws Exception {
+		final Configuration configuration = getConfiguration(configResource);
+		final FileAppender appender = configuration.getAppender("File");
+		assertNotNull(appender);
+		assertEquals("target/mylog.txt", appender.getFileName());
+		//
+		final LoggerConfig loggerConfig = configuration.getLoggerConfig("com.example.foo");
+		assertNotNull(loggerConfig);
+		assertEquals(Level.DEBUG, loggerConfig.getLevel());
+		configuration.start();
+		configuration.stop();
+		return appender.getLayout();
+	}
+
+	private Configuration getConfiguration(final String configResource) throws URISyntaxException {
+		final URL configLocation = ClassLoader.getSystemResource(configResource);
+		assertNotNull(configResource, configLocation);
+		final Configuration configuration = new Log4j1ConfigurationFactory().getConfiguration(null, "test",
+				configLocation.toURI());
+		assertNotNull(configuration);
+		return configuration;
+	}
+
+	@Test
+	public void testConsoleEnhancedPatternLayout() throws Exception {
+		final PatternLayout layout = (PatternLayout) testConsole(
+				"config-1.2/log4j-console-EnhancedPatternLayout.properties");
+		assertEquals("%d{ISO8601} [%t][%c] %-5p %properties %ndc: %m%n", layout.getConversionPattern());
+	}
+
+	@Test
+	public void testConsoleHtmlLayout() throws Exception {
+		final HtmlLayout layout = (HtmlLayout) testConsole("config-1.2/log4j-console-HtmlLayout.properties");
+		assertEquals("Headline", layout.getTitle());
+		assertTrue(layout.isLocationInfo());
+	}
+
+	@Test
+	public void testConsolePatternLayout() throws Exception {
+		final PatternLayout layout = (PatternLayout) testConsole("config-1.2/log4j-console-PatternLayout.properties");
+		assertEquals("%d{ISO8601} [%t][%c] %-5p: %m%n", layout.getConversionPattern());
+	}
+
+	@Test
+	public void testConsoleSimpleLayout() throws Exception {
+		final PatternLayout layout = (PatternLayout) testConsole("config-1.2/log4j-console-SimpleLayout.properties");
+		assertEquals("%level - %m%n", layout.getConversionPattern());
+	}
+
+	@Test
+	public void testConsoleTtccLayout() throws Exception {
+		final PatternLayout layout = (PatternLayout) testConsole("config-1.2/log4j-console-TTCCLayout.properties");
+		assertEquals("%r [%t] %p %notEmpty{%ndc }- %m%n", layout.getConversionPattern());
+	}
+
+	@Test
+	public void testConsoleXmlLayout() throws Exception {
+		final Log4j1XmlLayout layout = (Log4j1XmlLayout) testConsole("config-1.2/log4j-console-XmlLayout.properties");
+		assertTrue(layout.isLocationInfo());
+		assertFalse(layout.isProperties());
+	}
+
+	@Test
+	public void testFileSimpleLayout() throws Exception {
+		final PatternLayout layout = (PatternLayout) testFile("config-1.2/log4j-file-SimpleLayout.properties");
+		assertEquals("%level - %m%n", layout.getConversionPattern());
+	}
+
+	@Test
+	public void testNullAppender() throws Exception {
+		final Configuration configuration = getConfiguration("config-1.2/log4j-NullAppender.properties");
+		final Appender appender = configuration.getAppender("NullAppender");
+		assertNotNull(appender);
+		assertEquals("NullAppender", appender.getName());
+		assertTrue(appender.getClass().getName(), appender instanceof NullAppender);
+	}
+
+	@Test
+	public void testRollingFileAppender() throws Exception {
+		testRollingFileAppender("config-1.2/log4j-RollingFileAppender.properties", "RFA", "target/hadoop.log.%i");
+	}
+
+	@Test
+	public void testDailyRollingFileAppender() throws Exception {
+		testDailyRollingFileAppender("config-1.2/log4j-DailyRollingFileAppender.properties", "DRFA", "target/hadoop.log%d{.yyyy-MM-dd}");
+	}
+
+	@Test
+	public void testRollingFileAppenderWithProperties() throws Exception {
+		testRollingFileAppender("config-1.2/log4j-RollingFileAppender-with-props.properties", "RFA", "target/hadoop.log.%i");
+	}
+
+	@Test
+	public void testSystemProperties1() throws Exception {
+        final String tempFileName = System.getProperty("java.io.tmpdir") + "/hadoop.log";
+        final Path tempFilePath = new File(tempFileName).toPath();
+        Files.deleteIfExists(tempFilePath);
+        try {
+            final Configuration configuration = getConfiguration("config-1.2/log4j-system-properties-1.properties");
+            final RollingFileAppender appender = configuration.getAppender("RFA");
+			appender.stop(10, TimeUnit.SECONDS);
+            System.out.println("expected: " + tempFileName + " Actual: " + appender.getFileName());
+            assertEquals(tempFileName, appender.getFileName());
+        } finally {
+			try {
+				Files.deleteIfExists(tempFilePath);
+			} catch (final FileSystemException e) {
+				e.printStackTrace();
+			}
+        }
+	}
+
+	@Test
+	public void testSystemProperties2() throws Exception {
+		final Configuration configuration = getConfiguration("config-1.2/log4j-system-properties-2.properties");
+		final RollingFileAppender appender = configuration.getAppender("RFA");
+		assertEquals("${java.io.tmpdir}/hadoop.log", appender.getFileName());
+		appender.stop(10, TimeUnit.SECONDS);
+		Path path = new File(appender.getFileName()).toPath();
+        Files.deleteIfExists(path);
+        path = new File("${java.io.tmpdir}").toPath();
+        Files.deleteIfExists(path);
+	}
+
+	private void testRollingFileAppender(final String configResource, final String name, final String filePattern) throws URISyntaxException {
+		final Configuration configuration = getConfiguration(configResource);
+		final Appender appender = configuration.getAppender(name);
+		assertNotNull(appender);
+		assertEquals(name, appender.getName());
+		assertTrue(appender.getClass().getName(), appender instanceof RollingFileAppender);
+		final RollingFileAppender rfa = (RollingFileAppender) appender;
+		assertEquals("target/hadoop.log", rfa.getFileName());
+		assertEquals(filePattern, rfa.getFilePattern());
+		final TriggeringPolicy triggeringPolicy = rfa.getTriggeringPolicy();
+		assertNotNull(triggeringPolicy);
+		assertTrue(triggeringPolicy.getClass().getName(), triggeringPolicy instanceof CompositeTriggeringPolicy);
+		final CompositeTriggeringPolicy ctp = (CompositeTriggeringPolicy) triggeringPolicy;
+		final TriggeringPolicy[] triggeringPolicies = ctp.getTriggeringPolicies();
+		assertEquals(1, triggeringPolicies.length);
+		final TriggeringPolicy tp = triggeringPolicies[0];
+		assertTrue(tp.getClass().getName(), tp instanceof SizeBasedTriggeringPolicy);
+		final SizeBasedTriggeringPolicy sbtp = (SizeBasedTriggeringPolicy) tp;
+		assertEquals(256 * 1024 * 1024, sbtp.getMaxFileSize());
+		final RolloverStrategy rolloverStrategy = rfa.getManager().getRolloverStrategy();
+		assertTrue(rolloverStrategy.getClass().getName(), rolloverStrategy instanceof DefaultRolloverStrategy);
+		final DefaultRolloverStrategy drs = (DefaultRolloverStrategy) rolloverStrategy;
+		assertEquals(20, drs.getMaxIndex());
+		configuration.start();
+		configuration.stop();
+	}
+
+	private void testDailyRollingFileAppender(final String configResource, final String name, final String filePattern) throws URISyntaxException {
+		final Configuration configuration = getConfiguration(configResource);
+		final Appender appender = configuration.getAppender(name);
+		assertNotNull(appender);
+		assertEquals(name, appender.getName());
+		assertTrue(appender.getClass().getName(), appender instanceof RollingFileAppender);
+		final RollingFileAppender rfa = (RollingFileAppender) appender;
+		assertEquals("target/hadoop.log", rfa.getFileName());
+		assertEquals(filePattern, rfa.getFilePattern());
+		final TriggeringPolicy triggeringPolicy = rfa.getTriggeringPolicy();
+		assertNotNull(triggeringPolicy);
+		assertTrue(triggeringPolicy.getClass().getName(), triggeringPolicy instanceof CompositeTriggeringPolicy);
+		final CompositeTriggeringPolicy ctp = (CompositeTriggeringPolicy) triggeringPolicy;
+		final TriggeringPolicy[] triggeringPolicies = ctp.getTriggeringPolicies();
+		assertEquals(1, triggeringPolicies.length);
+		final TriggeringPolicy tp = triggeringPolicies[0];
+		assertTrue(tp.getClass().getName(), tp instanceof TimeBasedTriggeringPolicy);
+		final TimeBasedTriggeringPolicy tbtp = (TimeBasedTriggeringPolicy) tp;
+		assertEquals(1, tbtp.getInterval());
+		final RolloverStrategy rolloverStrategy = rfa.getManager().getRolloverStrategy();
+		assertTrue(rolloverStrategy.getClass().getName(), rolloverStrategy instanceof DefaultRolloverStrategy);
+		final DefaultRolloverStrategy drs = (DefaultRolloverStrategy) rolloverStrategy;
+		assertEquals(Integer.MAX_VALUE, drs.getMaxIndex());
+		configuration.start();
+		configuration.stop();
+	}
+
+}
diff --git a/log4j-1.2-api/src/src/test/java/org/apache/log4j/config/XmlConfigurationFactoryTest.java b/log4j-1.2-api/src/src/test/java/org/apache/log4j/config/XmlConfigurationFactoryTest.java
new file mode 100644
index 0000000..d522a18
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/java/org/apache/log4j/config/XmlConfigurationFactoryTest.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.config;
+
+import org.apache.log4j.ListAppender;
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
+import org.apache.log4j.bridge.AppenderAdapter;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.log4j.xml.DOMConfigurator;
+import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.spi.LoggerContext;
+import org.junit.Test;
+
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test configuration from XML.
+ */
+public class XmlConfigurationFactoryTest {
+
+    @Test
+    public void testXML() throws Exception {
+        XmlConfigurationFactory.configure("target/test-classes/log4j1-file.xml");
+        Logger logger = LogManager.getLogger("test");
+        logger.debug("This is a test of the root logger");
+        File file = new File("target/temp.A1");
+        assertTrue("File A1 was not created", file.exists());
+        assertTrue("File A1 is empty", file.length() > 0);
+        file = new File("target/temp.A2");
+        assertTrue("File A2 was not created", file.exists());
+        assertTrue("File A2 is empty", file.length() > 0);
+    }
+
+    @Test
+    public void testListAppender() {
+        XmlConfigurationFactory.configure("target/test-classes/log4j1-list.xml");
+        Logger logger = LogManager.getLogger("test");
+        logger.debug("This is a test of the root logger");
+        LoggerContext loggerContext = org.apache.logging.log4j.LogManager.getContext(false);
+        Configuration configuration = ((org.apache.logging.log4j.core.LoggerContext) loggerContext).getConfiguration();
+        Map<String, Appender> appenders = configuration.getAppenders();
+        ListAppender eventAppender = null;
+        ListAppender messageAppender = null;
+        for (Map.Entry<String, Appender> entry : appenders.entrySet()) {
+            if (entry.getKey().equals("list")) {
+                messageAppender = (ListAppender) ((AppenderAdapter.Adapter) entry.getValue()).getAppender();
+            } else if (entry.getKey().equals("events")) {
+                eventAppender = (ListAppender) ((AppenderAdapter.Adapter) entry.getValue()).getAppender();
+            }
+        }
+        assertNotNull("No Event Appender", eventAppender);
+        assertNotNull("No Message Appender", messageAppender);
+        List<LoggingEvent> events = eventAppender.getEvents();
+        assertTrue("No events", events != null && events.size() > 0);
+        List<String> messages = messageAppender.getMessages();
+        assertTrue("No messages", messages != null && messages.size() > 0);
+    }
+
+}
diff --git a/log4j-1.2-api/src/src/test/java/org/apache/log4j/layout/Log4j1XmlLayoutTest.java b/log4j-1.2-api/src/src/test/java/org/apache/log4j/layout/Log4j1XmlLayoutTest.java
new file mode 100644
index 0000000..28579fe
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/java/org/apache/log4j/layout/Log4j1XmlLayoutTest.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.layout;
+
+import static org.junit.Assert.assertEquals;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.core.impl.ContextDataFactory;
+import org.apache.logging.log4j.core.impl.Log4jLogEvent;
+import org.apache.logging.log4j.junit.ThreadContextRule;
+import org.apache.logging.log4j.message.SimpleMessage;
+import org.apache.logging.log4j.util.StringMap;
+import org.junit.Rule;
+import org.junit.Test;
+
+public class Log4j1XmlLayoutTest {
+
+    @Rule
+    public ThreadContextRule threadContextRule = new ThreadContextRule();
+
+    @Test
+    public void testWithoutThrown() {
+        final Log4j1XmlLayout layout = Log4j1XmlLayout.createLayout(false, true);
+
+        final Log4jLogEvent event = Log4jLogEvent.newBuilder()
+                .setLoggerName("a.B")
+                .setLevel(Level.INFO)
+                .setMessage(new SimpleMessage("Hello, World"))
+                .setTimeMillis(System.currentTimeMillis() + 17)
+                .build();
+
+        final String result = layout.toSerializable(event);
+
+        final String expected =
+                "<log4j:event logger=\"a.B\" timestamp=\"" + event.getTimeMillis() + "\" level=\"INFO\" thread=\"main\">\r\n" +
+                "<log4j:message><![CDATA[Hello, World]]></log4j:message>\r\n" +
+                "</log4j:event>\r\n\r\n";
+
+        assertEquals(expected, result);
+    }
+
+    @Test
+    public void testWithPropertiesAndLocationInfo() {
+        final Log4j1XmlLayout layout = Log4j1XmlLayout.createLayout(true, true);
+
+        final StringMap contextMap = ContextDataFactory.createContextData(2);
+        contextMap.putValue("key1", "value1");
+        contextMap.putValue("key2", "value2");
+        final Log4jLogEvent event = Log4jLogEvent.newBuilder()
+                .setLoggerName("a.B")
+                .setLevel(Level.INFO)
+                .setMessage(new SimpleMessage("Hello, World"))
+                .setTimeMillis(System.currentTimeMillis() + 17)
+                .setIncludeLocation(true)
+                .setSource(new StackTraceElement("pack.MyClass", "myMethod", "MyClass.java", 17))
+                .setContextData(contextMap)
+                .build();
+
+        final String result = layout.toSerializable(event);
+
+        final String expected =
+                "<log4j:event logger=\"a.B\" timestamp=\"" + event.getTimeMillis() + "\" level=\"INFO\" thread=\"main\">\r\n" +
+                "<log4j:message><![CDATA[Hello, World]]></log4j:message>\r\n" +
+                "<log4j:locationInfo class=\"pack.MyClass\" method=\"myMethod\" file=\"MyClass.java\" line=\"17\"/>\r\n" +
+                "<log4j:properties>\r\n" +
+                "<log4j:data name=\"key1\" value=\"value1\"/>\r\n" +
+                "<log4j:data name=\"key2\" value=\"value2\"/>\r\n" +
+                "</log4j:properties>\r\n"+
+                "</log4j:event>\r\n\r\n";
+
+        assertEquals(expected, result);
+    }
+
+}
diff --git a/log4j-1.2-api/src/src/test/java/org/apache/log4j/pattern/Log4j1MdcPatternConverterTest.java b/log4j-1.2-api/src/src/test/java/org/apache/log4j/pattern/Log4j1MdcPatternConverterTest.java
new file mode 100644
index 0000000..c1d5b83
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/java/org/apache/log4j/pattern/Log4j1MdcPatternConverterTest.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.pattern;
+
+import static org.junit.Assert.assertEquals;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.impl.ContextDataFactory;
+import org.apache.logging.log4j.core.impl.Log4jLogEvent;
+import org.apache.logging.log4j.message.SimpleMessage;
+import org.apache.logging.log4j.util.StringMap;
+import org.junit.Test;
+
+public class Log4j1MdcPatternConverterTest {
+
+    @Test
+    public void testConverter0() {
+        final StringMap contextMap = ContextDataFactory.createContextData(0);
+        final String expected = "{}";
+        test(contextMap, expected, null);
+    }
+
+    @Test
+    public void testConverter1() {
+        final StringMap contextMap = ContextDataFactory.createContextData(1);
+        contextMap.putValue("key1", "value1");
+        final String expected = "{{key1,value1}}";
+        test(contextMap, expected, null);
+    }
+
+    @Test
+    public void testConverter2() {
+        final StringMap contextMap = ContextDataFactory.createContextData(2);
+        contextMap.putValue("key1", "value1");
+        contextMap.putValue("key2", "value2");
+        final String expected = "{{key1,value1}{key2,value2}}";
+        test(contextMap, expected, null);
+    }
+
+    @Test
+    public void testConverterWithKey() {
+        final StringMap contextMap = ContextDataFactory.createContextData(2);
+        contextMap.putValue("key1", "value1");
+        contextMap.putValue("key2", "value2");
+        final String expected = "value1";
+        test(contextMap, expected, new String[] {"key1"});
+    }
+
+    private void test(final StringMap contextMap, final String expected, final String[] options) {
+        final LogEvent event = Log4jLogEvent.newBuilder()
+                .setLoggerName("MyLogger")
+                .setLevel(Level.DEBUG)
+                .setMessage(new SimpleMessage("Hello"))
+                .setContextData(contextMap)
+                .build();
+        final StringBuilder sb = new StringBuilder();
+        final Log4j1MdcPatternConverter converter = Log4j1MdcPatternConverter.newInstance(options);
+        converter.format(event, sb);
+        assertEquals(expected, sb.toString());
+    }
+
+}
+
diff --git a/log4j-1.2-api/src/src/test/java/org/apache/log4j/pattern/Log4j1NdcPatternConverterTest.java b/log4j-1.2-api/src/src/test/java/org/apache/log4j/pattern/Log4j1NdcPatternConverterTest.java
new file mode 100644
index 0000000..2f0b80f
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/java/org/apache/log4j/pattern/Log4j1NdcPatternConverterTest.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.pattern;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.ThreadContext;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.impl.Log4jLogEvent;
+import org.apache.logging.log4j.junit.ThreadContextStackRule;
+import org.apache.logging.log4j.message.SimpleMessage;
+import org.junit.Rule;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class Log4j1NdcPatternConverterTest {
+
+    @Rule
+    public final ThreadContextStackRule threadContextRule = new ThreadContextStackRule();
+
+    @Test
+    public void testEmpty() {
+        testConverter("");
+    }
+
+    @Test
+    public void test1() {
+        ThreadContext.push("foo");
+        testConverter("foo");
+    }
+
+    @Test
+    public void test2() {
+        ThreadContext.push("foo");
+        ThreadContext.push("bar");
+        testConverter("foo bar");
+    }
+
+    @Test
+    public void test3() {
+        ThreadContext.push("foo");
+        ThreadContext.push("bar");
+        ThreadContext.push("baz");
+        testConverter("foo bar baz");
+    }
+
+    private void testConverter(final String expected) {
+        final Log4j1NdcPatternConverter converter = Log4j1NdcPatternConverter.newInstance(null);
+        final LogEvent event = Log4jLogEvent.newBuilder()
+                .setLoggerName("MyLogger")
+                .setLevel(Level.DEBUG)
+                .setMessage(new SimpleMessage("Hello"))
+                .build();
+        final StringBuilder sb = new StringBuilder();
+        converter.format(event, sb);
+        assertEquals(expected, sb.toString());
+    }
+
+}
+
diff --git a/log4j-1.2-api/src/src/test/java/org/apache/log4j/util/SerializationTestHelper.java b/log4j-1.2-api/src/src/test/java/org/apache/log4j/util/SerializationTestHelper.java
new file mode 100644
index 0000000..0576463
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/java/org/apache/log4j/util/SerializationTestHelper.java
@@ -0,0 +1,148 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.commons.io.FileUtils;
+
+
+/**
+ * Utiities for serialization tests.
+ */
+public class SerializationTestHelper {
+    /**
+     * Private constructor.
+     */
+    private SerializationTestHelper() {
+    }
+
+    /**
+     * Creates a clone by serializing object and
+     * deserializing byte stream.
+     *
+     * @param obj object to serialize and deserialize.
+     * @return clone
+     * @throws IOException            on IO error.
+     * @throws ClassNotFoundException if class not found.
+     */
+    public static Object serializeClone(final Object obj)
+        throws IOException, ClassNotFoundException {
+        final ByteArrayOutputStream memOut = new ByteArrayOutputStream();
+        try (final ObjectOutputStream objOut = new ObjectOutputStream(memOut)) {
+            objOut.writeObject(obj);
+        }
+
+        final ByteArrayInputStream src = new ByteArrayInputStream(memOut.toByteArray());
+        final ObjectInputStream objIs = new ObjectInputStream(src);
+
+        return objIs.readObject();
+    }
+
+    /**
+     * Deserializes a specified file.
+     *
+     * @param witness serialization file, may not be null.
+     * @return deserialized object.
+     * @throws Exception thrown on IO or deserialization exception.
+     */
+    public static Object deserializeStream(final String witness) throws Exception {
+        try (final ObjectInputStream objIs = new ObjectInputStream(new FileInputStream(witness))) {
+            return objIs.readObject();
+        }
+    }
+
+    /**
+     * Checks the serialization of an object against an file
+     * containing the expected serialization.
+     *
+     * @param witness    name of file containing expected serialization.
+     * @param obj        object to be serialized.
+     * @param skip       positions in serialized stream that should not be compared.
+     * @param endCompare position to stop comparison.
+     * @throws Exception thrown on IO or serialization exception.
+     */
+    public static void assertSerializationEquals(
+        final String witness, final Object obj, final int[] skip,
+        final int endCompare) throws Exception {
+        final ByteArrayOutputStream memOut = new ByteArrayOutputStream();
+        try (final ObjectOutputStream objOut = new ObjectOutputStream(memOut)) {
+            objOut.writeObject(obj);
+        }
+
+        assertStreamEquals(witness, memOut.toByteArray(), skip, endCompare);
+    }
+
+    /**
+     * Asserts the serialized form of an object.
+     *
+     * @param witness    file name of expected serialization.
+     * @param actual     byte array of actual serialization.
+     * @param skip       positions to skip comparison.
+     * @param endCompare position to stop comparison.
+     * @throws IOException thrown on IO or serialization exception.
+     */
+    public static void assertStreamEquals(
+        final String witness, final byte[] actual, final int[] skip,
+        final int endCompare) throws IOException {
+        final File witnessFile = new File(witness);
+
+        if (witnessFile.exists()) {
+            int skipIndex = 0;
+            final byte[] expected = FileUtils.readFileToByteArray(witnessFile);
+            final int bytesRead = expected.length;
+
+            if (bytesRead < endCompare) {
+                assertEquals(bytesRead, actual.length);
+            }
+
+            int endScan = actual.length;
+
+            if (endScan > endCompare) {
+                endScan = endCompare;
+            }
+
+            for (int i = 0; i < endScan; i++) {
+                if ((skipIndex < skip.length) && (skip[skipIndex] == i)) {
+                    skipIndex++;
+                } else {
+                    if (expected[i] != actual[i]) {
+                        assertEquals(
+                            "Difference at offset " + i, expected[i], actual[i]);
+                    }
+                }
+            }
+        } else {
+            //
+            //  if the file doesn't exist then
+            //      assume that we are setting up and need to write it
+            FileUtils.writeByteArrayToFile(witnessFile, actual);
+            fail("Writing witness file " + witness);
+        }
+    }
+}
+
diff --git a/log4j-1.2-api/src/src/test/resources/L7D_en_US.properties b/log4j-1.2-api/src/src/test/resources/L7D_en_US.properties
new file mode 100644
index 0000000..c3c2802
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/L7D_en_US.properties
@@ -0,0 +1,17 @@
+# 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.
+test=This is the English, US test.
+hello_world=Hello world.
+msg1=This is test number {0} with string argument {1}.
diff --git a/log4j-1.2-api/src/src/test/resources/L7D_fr.properties b/log4j-1.2-api/src/src/test/resources/L7D_fr.properties
new file mode 100644
index 0000000..25b878a
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/L7D_fr.properties
@@ -0,0 +1,17 @@
+# 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.
+test=Ceci est le test en francais pour la France.
+hello_world=Bonjour la France.
+msg1=Ceci est le test numero {0} contenant l''argument {1}.
diff --git a/log4j-1.2-api/src/src/test/resources/L7D_fr_CH.properties b/log4j-1.2-api/src/src/test/resources/L7D_fr_CH.properties
new file mode 100644
index 0000000..ba9b1ff
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/L7D_fr_CH.properties
@@ -0,0 +1,16 @@
+# 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.
+test=Ceci est le test en francais pour la p'tite Suisse.
+hello world=Salut le monde.
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-common-project/hadoop-auth-examples/src/main/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-common-project/hadoop-auth-examples/src/main/resources/log4j.properties
new file mode 100644
index 0000000..5fa4020
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-common-project/hadoop-auth-examples/src/main/resources/log4j.properties
@@ -0,0 +1,19 @@
+#
+# 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. See accompanying LICENSE file.
+#
+log4j.appender.test=org.apache.log4j.ConsoleAppender
+log4j.appender.test.Target=System.out
+log4j.appender.test.layout=org.apache.log4j.PatternLayout
+log4j.appender.test.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
+
+log4j.logger.org.apache.hadoop.security.authentication=DEBUG, test
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-common-project/hadoop-common/src/main/conf/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-common-project/hadoop-common/src/main/conf/log4j.properties
new file mode 100644
index 0000000..b08514c
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-common-project/hadoop-common/src/main/conf/log4j.properties
@@ -0,0 +1,323 @@
+# 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.
+
+# Define some default values that can be overridden by system properties
+hadoop.root.logger=INFO,console
+hadoop.log.dir=target
+hadoop.log.file=hadoop.log
+
+# Define the root logger to the system property "hadoop.root.logger".
+log4j.rootLogger=${hadoop.root.logger}, EventCounter
+
+# Logging Threshold
+log4j.threshold=ALL
+
+# Null Appender
+log4j.appender.NullAppender=org.apache.log4j.varia.NullAppender
+
+#
+# Rolling File Appender - cap space usage at 5gb.
+#
+hadoop.log.maxfilesize=256MB
+hadoop.log.maxbackupindex=20
+log4j.appender.RFA=org.apache.log4j.RollingFileAppender
+log4j.appender.RFA.File=${hadoop.log.dir}/${hadoop.log.file}
+
+log4j.appender.RFA.MaxFileSize=${hadoop.log.maxfilesize}
+log4j.appender.RFA.MaxBackupIndex=${hadoop.log.maxbackupindex}
+
+log4j.appender.RFA.layout=org.apache.log4j.PatternLayout
+
+# Pattern format: Date LogLevel LoggerName LogMessage
+log4j.appender.RFA.layout.ConversionPattern=%d{ISO8601} %p %c: %m%n
+# Debugging Pattern format
+#log4j.appender.RFA.layout.ConversionPattern=%d{ISO8601} %-5p %c{2} (%F:%M(%L)) - %m%n
+
+
+#
+# Daily Rolling File Appender
+#
+
+log4j.appender.DRFA=org.apache.log4j.DailyRollingFileAppender
+log4j.appender.DRFA.File=${hadoop.log.dir}/${hadoop.log.file}
+
+# Rollover at midnight
+log4j.appender.DRFA.DatePattern=.yyyy-MM-dd
+
+log4j.appender.DRFA.layout=org.apache.log4j.PatternLayout
+
+# Pattern format: Date LogLevel LoggerName LogMessage
+log4j.appender.DRFA.layout.ConversionPattern=%d{ISO8601} %p %c: %m%n
+# Debugging Pattern format
+#log4j.appender.DRFA.layout.ConversionPattern=%d{ISO8601} %-5p %c{2} (%F:%M(%L)) - %m%n
+
+
+#
+# console
+# Add "console" to rootlogger above if you want to use this
+#
+
+log4j.appender.console=org.apache.log4j.ConsoleAppender
+log4j.appender.console.target=System.err
+log4j.appender.console.layout=org.apache.log4j.PatternLayout
+log4j.appender.console.layout.ConversionPattern=%d{ISO8601} %p %c{2}: %m%n
+
+#
+# TaskLog Appender
+#
+
+#Default values
+hadoop.tasklog.taskid=null
+hadoop.tasklog.iscleanup=false
+hadoop.tasklog.noKeepSplits=4
+hadoop.tasklog.totalLogFileSize=100
+hadoop.tasklog.purgeLogSplits=true
+hadoop.tasklog.logsRetainHours=12
+
+log4j.appender.TLA=org.apache.hadoop.mapred.TaskLogAppender
+log4j.appender.TLA.taskId=${hadoop.tasklog.taskid}
+log4j.appender.TLA.isCleanup=${hadoop.tasklog.iscleanup}
+log4j.appender.TLA.totalLogFileSize=${hadoop.tasklog.totalLogFileSize}
+
+log4j.appender.TLA.layout=org.apache.log4j.PatternLayout
+log4j.appender.TLA.layout.ConversionPattern=%d{ISO8601} %p %c: %m%n
+
+#
+# HDFS block state change log from block manager
+#
+# Uncomment the following to log normal block state change
+# messages from BlockManager in NameNode.
+#log4j.logger.BlockStateChange=DEBUG
+
+#
+#Security appender
+#
+hadoop.security.logger=INFO,NullAppender
+hadoop.security.log.maxfilesize=256MB
+hadoop.security.log.maxbackupindex=20
+log4j.category.SecurityLogger=${hadoop.security.logger}
+hadoop.security.log.file=SecurityAuth-${user.name}.audit
+log4j.appender.RFAS=org.apache.log4j.RollingFileAppender
+log4j.appender.RFAS.File=${hadoop.log.dir}/${hadoop.security.log.file}
+log4j.appender.RFAS.layout=org.apache.log4j.PatternLayout
+log4j.appender.RFAS.layout.ConversionPattern=%d{ISO8601} %p %c: %m%n
+log4j.appender.RFAS.MaxFileSize=${hadoop.security.log.maxfilesize}
+log4j.appender.RFAS.MaxBackupIndex=${hadoop.security.log.maxbackupindex}
+
+#
+# Daily Rolling Security appender
+#
+log4j.appender.DRFAS=org.apache.log4j.DailyRollingFileAppender
+log4j.appender.DRFAS.File=${hadoop.log.dir}/${hadoop.security.log.file}
+log4j.appender.DRFAS.layout=org.apache.log4j.PatternLayout
+log4j.appender.DRFAS.layout.ConversionPattern=%d{ISO8601} %p %c: %m%n
+log4j.appender.DRFAS.DatePattern=.yyyy-MM-dd
+
+#
+# hadoop configuration logging
+#
+
+# Uncomment the following line to turn off configuration deprecation warnings.
+# log4j.logger.org.apache.hadoop.conf.Configuration.deprecation=WARN
+
+#
+# hdfs audit logging
+#
+hdfs.audit.logger=INFO,NullAppender
+hdfs.audit.log.maxfilesize=256MB
+hdfs.audit.log.maxbackupindex=20
+log4j.logger.org.apache.hadoop.hdfs.server.namenode.FSNamesystem.audit=${hdfs.audit.logger}
+log4j.additivity.org.apache.hadoop.hdfs.server.namenode.FSNamesystem.audit=false
+log4j.appender.RFAAUDIT=org.apache.log4j.RollingFileAppender
+log4j.appender.RFAAUDIT.File=${hadoop.log.dir}/hdfs-audit.log
+log4j.appender.RFAAUDIT.layout=org.apache.log4j.PatternLayout
+log4j.appender.RFAAUDIT.layout.ConversionPattern=%d{ISO8601} %p %c{2}: %m%n
+log4j.appender.RFAAUDIT.MaxFileSize=${hdfs.audit.log.maxfilesize}
+log4j.appender.RFAAUDIT.MaxBackupIndex=${hdfs.audit.log.maxbackupindex}
+
+#
+# NameNode metrics logging.
+# The default is to retain two namenode-metrics.log files up to 64MB each.
+#
+namenode.metrics.logger=INFO,NullAppender
+log4j.logger.NameNodeMetricsLog=${namenode.metrics.logger}
+log4j.additivity.NameNodeMetricsLog=false
+log4j.appender.NNMETRICSRFA=org.apache.log4j.RollingFileAppender
+log4j.appender.NNMETRICSRFA.File=${hadoop.log.dir}/namenode-metrics.log
+log4j.appender.NNMETRICSRFA.layout=org.apache.log4j.PatternLayout
+log4j.appender.NNMETRICSRFA.layout.ConversionPattern=%d{ISO8601} %m%n
+log4j.appender.NNMETRICSRFA.MaxBackupIndex=1
+log4j.appender.NNMETRICSRFA.MaxFileSize=64MB
+
+#
+# DataNode metrics logging.
+# The default is to retain two datanode-metrics.log files up to 64MB each.
+#
+datanode.metrics.logger=INFO,NullAppender
+log4j.logger.DataNodeMetricsLog=${datanode.metrics.logger}
+log4j.additivity.DataNodeMetricsLog=false
+log4j.appender.DNMETRICSRFA=org.apache.log4j.RollingFileAppender
+log4j.appender.DNMETRICSRFA.File=${hadoop.log.dir}/datanode-metrics.log
+log4j.appender.DNMETRICSRFA.layout=org.apache.log4j.PatternLayout
+log4j.appender.DNMETRICSRFA.layout.ConversionPattern=%d{ISO8601} %m%n
+log4j.appender.DNMETRICSRFA.MaxBackupIndex=1
+log4j.appender.DNMETRICSRFA.MaxFileSize=64MB
+
+#
+# mapred audit logging
+#
+mapred.audit.logger=INFO,NullAppender
+mapred.audit.log.maxfilesize=256MB
+mapred.audit.log.maxbackupindex=20
+log4j.logger.org.apache.hadoop.mapred.AuditLogger=${mapred.audit.logger}
+log4j.additivity.org.apache.hadoop.mapred.AuditLogger=false
+log4j.appender.MRAUDIT=org.apache.log4j.RollingFileAppender
+log4j.appender.MRAUDIT.File=${hadoop.log.dir}/mapred-audit.log
+log4j.appender.MRAUDIT.layout=org.apache.log4j.PatternLayout
+log4j.appender.MRAUDIT.layout.ConversionPattern=%d{ISO8601} %p %c{2}: %m%n
+log4j.appender.MRAUDIT.MaxFileSize=${mapred.audit.log.maxfilesize}
+log4j.appender.MRAUDIT.MaxBackupIndex=${mapred.audit.log.maxbackupindex}
+
+# Custom Logging levels
+
+#log4j.logger.org.apache.hadoop.mapred.JobTracker=DEBUG
+#log4j.logger.org.apache.hadoop.mapred.TaskTracker=DEBUG
+#log4j.logger.org.apache.hadoop.hdfs.server.namenode.FSNamesystem.audit=DEBUG
+
+# Jets3t library
+log4j.logger.org.jets3t.service.impl.rest.httpclient.RestS3Service=ERROR
+
+# AWS SDK & S3A FileSystem
+log4j.logger.com.amazonaws=ERROR
+log4j.logger.com.amazonaws.http.AmazonHttpClient=ERROR
+log4j.logger.org.apache.hadoop.fs.s3a.S3AFileSystem=WARN
+
+#
+# Event Counter Appender
+# Sends counts of logging messages at different severity levels to Hadoop Metrics.
+#
+log4j.appender.EventCounter=org.apache.hadoop.log.metrics.EventCounter
+
+#
+# Job Summary Appender
+#
+# Use following logger to send summary to separate file defined by
+# hadoop.mapreduce.jobsummary.log.file :
+# hadoop.mapreduce.jobsummary.logger=INFO,JSA
+#
+hadoop.mapreduce.jobsummary.logger=${hadoop.root.logger}
+hadoop.mapreduce.jobsummary.log.file=hadoop-mapreduce.jobsummary.log
+hadoop.mapreduce.jobsummary.log.maxfilesize=256MB
+hadoop.mapreduce.jobsummary.log.maxbackupindex=20
+log4j.appender.JSA=org.apache.log4j.RollingFileAppender
+log4j.appender.JSA.File=${hadoop.log.dir}/${hadoop.mapreduce.jobsummary.log.file}
+log4j.appender.JSA.MaxFileSize=${hadoop.mapreduce.jobsummary.log.maxfilesize}
+log4j.appender.JSA.MaxBackupIndex=${hadoop.mapreduce.jobsummary.log.maxbackupindex}
+log4j.appender.JSA.layout=org.apache.log4j.PatternLayout
+log4j.appender.JSA.layout.ConversionPattern=%d{ISO8601} %p %c{2}: %m%n
+log4j.logger.org.apache.hadoop.mapred.JobInProgress$JobSummary=${hadoop.mapreduce.jobsummary.logger}
+log4j.additivity.org.apache.hadoop.mapred.JobInProgress$JobSummary=false
+
+#
+# shuffle connection log from shuffleHandler
+# Uncomment the following line to enable logging of shuffle connections
+# log4j.logger.org.apache.hadoop.mapred.ShuffleHandler.audit=DEBUG
+
+#
+# Yarn ResourceManager Application Summary Log
+#
+# Set the ResourceManager summary log filename
+yarn.server.resourcemanager.appsummary.log.file=rm-appsummary.log
+# Set the ResourceManager summary log level and appender
+yarn.server.resourcemanager.appsummary.logger=${hadoop.root.logger}
+#yarn.server.resourcemanager.appsummary.logger=INFO,RMSUMMARY
+
+# To enable AppSummaryLogging for the RM,
+# set yarn.server.resourcemanager.appsummary.logger to
+# <LEVEL>,RMSUMMARY in hadoop-env.sh
+
+# Appender for ResourceManager Application Summary Log
+# Requires the following properties to be set
+#    - hadoop.log.dir (Hadoop Log directory)
+#    - yarn.server.resourcemanager.appsummary.log.file (resource manager app summary log filename)
+#    - yarn.server.resourcemanager.appsummary.logger (resource manager app summary log level and appender)
+
+log4j.logger.org.apache.hadoop.yarn.server.resourcemanager.RMAppManager$ApplicationSummary=${yarn.server.resourcemanager.appsummary.logger}
+log4j.additivity.org.apache.hadoop.yarn.server.resourcemanager.RMAppManager$ApplicationSummary=false
+log4j.appender.RMSUMMARY=org.apache.log4j.RollingFileAppender
+log4j.appender.RMSUMMARY.File=${hadoop.log.dir}/${yarn.server.resourcemanager.appsummary.log.file}
+log4j.appender.RMSUMMARY.MaxFileSize=256MB
+log4j.appender.RMSUMMARY.MaxBackupIndex=20
+log4j.appender.RMSUMMARY.layout=org.apache.log4j.PatternLayout
+log4j.appender.RMSUMMARY.layout.ConversionPattern=%d{ISO8601} %p %c{2}: %m%n
+
+# HS audit log configs
+#mapreduce.hs.audit.logger=INFO,HSAUDIT
+#log4j.logger.org.apache.hadoop.mapreduce.v2.hs.HSAuditLogger=${mapreduce.hs.audit.logger}
+#log4j.additivity.org.apache.hadoop.mapreduce.v2.hs.HSAuditLogger=false
+#log4j.appender.HSAUDIT=org.apache.log4j.DailyRollingFileAppender
+#log4j.appender.HSAUDIT.File=${hadoop.log.dir}/hs-audit.log
+#log4j.appender.HSAUDIT.layout=org.apache.log4j.PatternLayout
+#log4j.appender.HSAUDIT.layout.ConversionPattern=%d{ISO8601} %p %c{2}: %m%n
+#log4j.appender.HSAUDIT.DatePattern=.yyyy-MM-dd
+
+# Http Server Request Logs
+#log4j.logger.http.requests.namenode=INFO,namenoderequestlog
+#log4j.appender.namenoderequestlog=org.apache.hadoop.http.HttpRequestLogAppender
+#log4j.appender.namenoderequestlog.Filename=${hadoop.log.dir}/jetty-namenode-yyyy_mm_dd.log
+#log4j.appender.namenoderequestlog.RetainDays=3
+
+#log4j.logger.http.requests.datanode=INFO,datanoderequestlog
+#log4j.appender.datanoderequestlog=org.apache.hadoop.http.HttpRequestLogAppender
+#log4j.appender.datanoderequestlog.Filename=${hadoop.log.dir}/jetty-datanode-yyyy_mm_dd.log
+#log4j.appender.datanoderequestlog.RetainDays=3
+
+#log4j.logger.http.requests.resourcemanager=INFO,resourcemanagerrequestlog
+#log4j.appender.resourcemanagerrequestlog=org.apache.hadoop.http.HttpRequestLogAppender
+#log4j.appender.resourcemanagerrequestlog.Filename=${hadoop.log.dir}/jetty-resourcemanager-yyyy_mm_dd.log
+#log4j.appender.resourcemanagerrequestlog.RetainDays=3
+
+#log4j.logger.http.requests.jobhistory=INFO,jobhistoryrequestlog
+#log4j.appender.jobhistoryrequestlog=org.apache.hadoop.http.HttpRequestLogAppender
+#log4j.appender.jobhistoryrequestlog.Filename=${hadoop.log.dir}/jetty-jobhistory-yyyy_mm_dd.log
+#log4j.appender.jobhistoryrequestlog.RetainDays=3
+
+#log4j.logger.http.requests.nodemanager=INFO,nodemanagerrequestlog
+#log4j.appender.nodemanagerrequestlog=org.apache.hadoop.http.HttpRequestLogAppender
+#log4j.appender.nodemanagerrequestlog.Filename=${hadoop.log.dir}/jetty-nodemanager-yyyy_mm_dd.log
+#log4j.appender.nodemanagerrequestlog.RetainDays=3
+
+
+# WebHdfs request log on datanodes
+# Specify -Ddatanode.webhdfs.logger=INFO,HTTPDRFA on datanode startup to
+# direct the log to a separate file.
+#datanode.webhdfs.logger=INFO,console
+#log4j.logger.datanode.webhdfs=${datanode.webhdfs.logger}
+#log4j.appender.HTTPDRFA=org.apache.log4j.DailyRollingFileAppender
+#log4j.appender.HTTPDRFA.File=${hadoop.log.dir}/hadoop-datanode-webhdfs.log
+#log4j.appender.HTTPDRFA.layout=org.apache.log4j.PatternLayout
+#log4j.appender.HTTPDRFA.layout.ConversionPattern=%d{ISO8601} %m%n
+#log4j.appender.HTTPDRFA.DatePattern=.yyyy-MM-dd
+
+
+# Appender for viewing information for errors and warnings
+yarn.ewma.cleanupInterval=300
+yarn.ewma.messageAgeLimitSeconds=86400
+yarn.ewma.maxUniqueMessages=250
+log4j.appender.EWMA=org.apache.hadoop.yarn.util.Log4jWarningErrorMetricsAppender
+log4j.appender.EWMA.cleanupInterval=${yarn.ewma.cleanupInterval}
+log4j.appender.EWMA.messageAgeLimitSeconds=${yarn.ewma.messageAgeLimitSeconds}
+log4j.appender.EWMA.maxUniqueMessages=${yarn.ewma.maxUniqueMessages}
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-common-project/hadoop-common/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-common-project/hadoop-common/src/test/resources/log4j.properties
new file mode 100644
index 0000000..ced0687
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-common-project/hadoop-common/src/test/resources/log4j.properties
@@ -0,0 +1,18 @@
+#   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.
+# log4j configuration used during build and unit tests
+
+log4j.rootLogger=info,stdout
+log4j.threshold=ALL
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} %-5p %c{2} (%F:%M(%L)) - %m%n
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-common-project/hadoop-kms/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-common-project/hadoop-kms/src/test/resources/log4j.properties
new file mode 100644
index 0000000..b347d27
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-common-project/hadoop-kms/src/test/resources/log4j.properties
@@ -0,0 +1,31 @@
+#
+# 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.
+#
+
+# STDOUT Appender
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.Target=System.out
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} %-5p %c{1} - %m%n
+
+log4j.rootLogger=INFO, stdout
+log4j.logger.org.apache.hadoop.conf=ERROR
+log4j.logger.org.apache.hadoop.crytpo.key.kms.server=ALL
+log4j.logger.com.sun.jersey.server.wadl.generators.WadlGeneratorJAXBGrammarGenerator=OFF
+log4j.logger.org.apache.hadoop.security=OFF
+log4j.logger.org.apache.directory.server.core=OFF
+log4j.logger.org.apache.hadoop.util.NativeCodeLoader=OFF
\ No newline at end of file
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-common-project/hadoop-minikdc/src/main/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-common-project/hadoop-minikdc/src/main/resources/log4j.properties
new file mode 100644
index 0000000..9efd671
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-common-project/hadoop-minikdc/src/main/resources/log4j.properties
@@ -0,0 +1,31 @@
+#
+# 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.
+#
+
+# STDOUT Appender
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.Target=System.err
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} %-5p %c{1} - %m%n
+
+log4j.rootLogger=INFO, stdout
+
+# Switching off most of Apache DS logqing which is QUITE verbose
+log4j.logger.org.apache.directory=OFF
+log4j.logger.org.apache.directory.server.kerberos=INFO, stdout
+log4j.additivity.org.apache.directory=false
+log4j.logger.net.sf.ehcache=INFO, stdout
\ No newline at end of file
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-common-project/hadoop-nfs/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-common-project/hadoop-nfs/src/test/resources/log4j.properties
new file mode 100644
index 0000000..ced0687
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-common-project/hadoop-nfs/src/test/resources/log4j.properties
@@ -0,0 +1,18 @@
+#   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.
+# log4j configuration used during build and unit tests
+
+log4j.rootLogger=info,stdout
+log4j.threshold=ALL
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} %-5p %c{2} (%F:%M(%L)) - %m%n
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-hdfs-project/hadoop-hdfs-client/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-hdfs-project/hadoop-hdfs-client/src/test/resources/log4j.properties
new file mode 100644
index 0000000..7378846
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-hdfs-project/hadoop-hdfs-client/src/test/resources/log4j.properties
@@ -0,0 +1,49 @@
+#
+#   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.
+#
+# log4j configuration used during build and unit tests
+
+log4j.rootLogger=info,stdout
+log4j.threshold=ALL
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} [%t] %-5p %c{2} (%F:%M(%L)) - %m%n
+
+#
+# NameNode metrics logging.
+# The default is to retain two namenode-metrics.log files up to 64MB each.
+#
+log4j.logger.NameNodeMetricsLog=INFO,NNMETRICSRFA
+log4j.additivity.NameNodeMetricsLog=false
+log4j.appender.NNMETRICSRFA=org.apache.log4j.RollingFileAppender
+log4j.appender.NNMETRICSRFA.File=${hadoop.log.dir}/namenode-metrics.log
+log4j.appender.NNMETRICSRFA.layout=org.apache.log4j.PatternLayout
+log4j.appender.NNMETRICSRFA.layout.ConversionPattern=%d{ISO8601} %m%n
+log4j.appender.NNMETRICSRFA.MaxBackupIndex=1
+log4j.appender.NNMETRICSRFA.MaxFileSize=64MB
+
+#
+# DataNode metrics logging.
+# The default is to retain two datanode-metrics.log files up to 64MB each.
+#
+log4j.logger.DataNodeMetricsLog=INFO,DNMETRICSRFA
+log4j.additivity.DataNodeMetricsLog=false
+log4j.appender.DNMETRICSRFA=org.apache.log4j.RollingFileAppender
+log4j.appender.DNMETRICSRFA.File=${hadoop.log.dir}/datanode-metrics.log
+log4j.appender.DNMETRICSRFA.layout=org.apache.log4j.PatternLayout
+log4j.appender.DNMETRICSRFA.layout.ConversionPattern=%d{ISO8601} %m%n
+log4j.appender.DNMETRICSRFA.MaxBackupIndex=1
+log4j.appender.DNMETRICSRFA.MaxFileSize=64MB
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-hdfs-project/hadoop-hdfs/src/contrib/bkjournal/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-hdfs-project/hadoop-hdfs/src/contrib/bkjournal/src/test/resources/log4j.properties
new file mode 100644
index 0000000..52aac43
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-hdfs-project/hadoop-hdfs/src/contrib/bkjournal/src/test/resources/log4j.properties
@@ -0,0 +1,55 @@
+#
+# 
+# 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.
+# 
+#
+
+#
+# Bookkeeper Journal Logging Configuration
+#
+
+# Format is "<default threshold> (, <appender>)+
+
+# DEFAULT: console appender only
+log4j.rootLogger=DEBUG, CONSOLE
+
+# Example with rolling log file
+#log4j.rootLogger=DEBUG, CONSOLE, ROLLINGFILE
+
+# Example with rolling log file and tracing
+#log4j.rootLogger=TRACE, CONSOLE, ROLLINGFILE, TRACEFILE
+
+#
+# Log INFO level and above messages to the console
+#
+log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
+log4j.appender.CONSOLE.Threshold=INFO
+log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
+log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} - %-5p - [%t:%C{1}@%L] - %m%n
+
+#
+# Add ROLLINGFILE to rootLogger to get log file output
+#    Log DEBUG level and above messages to a log file
+log4j.appender.ROLLINGFILE=org.apache.log4j.DailyRollingFileAppender
+log4j.appender.ROLLINGFILE.Threshold=DEBUG
+log4j.appender.ROLLINGFILE.File=hdfs-namenode.log
+log4j.appender.ROLLINGFILE.layout=org.apache.log4j.PatternLayout
+log4j.appender.ROLLINGFILE.layout.ConversionPattern=%d{ISO8601} - %-5p - [%t:%C{1}@%L] - %m%n
+
+# Max log file size of 10MB
+log4j.appender.ROLLINGFILE.MaxFileSize=10MB
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-hdfs-project/hadoop-hdfs/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-hdfs-project/hadoop-hdfs/src/test/resources/log4j.properties
new file mode 100644
index 0000000..7378846
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-hdfs-project/hadoop-hdfs/src/test/resources/log4j.properties
@@ -0,0 +1,49 @@
+#
+#   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.
+#
+# log4j configuration used during build and unit tests
+
+log4j.rootLogger=info,stdout
+log4j.threshold=ALL
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} [%t] %-5p %c{2} (%F:%M(%L)) - %m%n
+
+#
+# NameNode metrics logging.
+# The default is to retain two namenode-metrics.log files up to 64MB each.
+#
+log4j.logger.NameNodeMetricsLog=INFO,NNMETRICSRFA
+log4j.additivity.NameNodeMetricsLog=false
+log4j.appender.NNMETRICSRFA=org.apache.log4j.RollingFileAppender
+log4j.appender.NNMETRICSRFA.File=${hadoop.log.dir}/namenode-metrics.log
+log4j.appender.NNMETRICSRFA.layout=org.apache.log4j.PatternLayout
+log4j.appender.NNMETRICSRFA.layout.ConversionPattern=%d{ISO8601} %m%n
+log4j.appender.NNMETRICSRFA.MaxBackupIndex=1
+log4j.appender.NNMETRICSRFA.MaxFileSize=64MB
+
+#
+# DataNode metrics logging.
+# The default is to retain two datanode-metrics.log files up to 64MB each.
+#
+log4j.logger.DataNodeMetricsLog=INFO,DNMETRICSRFA
+log4j.additivity.DataNodeMetricsLog=false
+log4j.appender.DNMETRICSRFA=org.apache.log4j.RollingFileAppender
+log4j.appender.DNMETRICSRFA.File=${hadoop.log.dir}/datanode-metrics.log
+log4j.appender.DNMETRICSRFA.layout=org.apache.log4j.PatternLayout
+log4j.appender.DNMETRICSRFA.layout.ConversionPattern=%d{ISO8601} %m%n
+log4j.appender.DNMETRICSRFA.MaxBackupIndex=1
+log4j.appender.DNMETRICSRFA.MaxFileSize=64MB
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/test/resources/log4j.properties
new file mode 100644
index 0000000..81a3f6a
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/test/resources/log4j.properties
@@ -0,0 +1,19 @@
+#   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.
+
+# log4j configuration used during build and unit tests
+
+log4j.rootLogger=info,stdout
+log4j.threshold=ALL
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} %-5p [%t] %c{2} (%F:%M(%L)) - %m%n
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-common/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-common/src/test/resources/log4j.properties
new file mode 100644
index 0000000..81a3f6a
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-common/src/test/resources/log4j.properties
@@ -0,0 +1,19 @@
+#   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.
+
+# log4j configuration used during build and unit tests
+
+log4j.rootLogger=info,stdout
+log4j.threshold=ALL
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} %-5p [%t] %c{2} (%F:%M(%L)) - %m%n
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/test/resources/log4j.properties
new file mode 100644
index 0000000..81a3f6a
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/test/resources/log4j.properties
@@ -0,0 +1,19 @@
+#   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.
+
+# log4j configuration used during build and unit tests
+
+log4j.rootLogger=info,stdout
+log4j.threshold=ALL
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} %-5p [%t] %c{2} (%F:%M(%L)) - %m%n
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-hs/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-hs/src/test/resources/log4j.properties
new file mode 100644
index 0000000..81a3f6a
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-hs/src/test/resources/log4j.properties
@@ -0,0 +1,19 @@
+#   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.
+
+# log4j configuration used during build and unit tests
+
+log4j.rootLogger=info,stdout
+log4j.threshold=ALL
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} %-5p [%t] %c{2} (%F:%M(%L)) - %m%n
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-jobclient/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-jobclient/src/test/resources/log4j.properties
new file mode 100644
index 0000000..81a3f6a
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-jobclient/src/test/resources/log4j.properties
@@ -0,0 +1,19 @@
+#   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.
+
+# log4j configuration used during build and unit tests
+
+log4j.rootLogger=info,stdout
+log4j.threshold=ALL
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} %-5p [%t] %c{2} (%F:%M(%L)) - %m%n
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/resources/log4j.properties
new file mode 100644
index 0000000..81a3f6a
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/resources/log4j.properties
@@ -0,0 +1,19 @@
+#   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.
+
+# log4j configuration used during build and unit tests
+
+log4j.rootLogger=info,stdout
+log4j.threshold=ALL
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} %-5p [%t] %c{2} (%F:%M(%L)) - %m%n
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-shuffle/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-shuffle/src/test/resources/log4j.properties
new file mode 100644
index 0000000..81a3f6a
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-shuffle/src/test/resources/log4j.properties
@@ -0,0 +1,19 @@
+#   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.
+
+# log4j configuration used during build and unit tests
+
+log4j.rootLogger=info,stdout
+log4j.threshold=ALL
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} %-5p [%t] %c{2} (%F:%M(%L)) - %m%n
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-tools/hadoop-aws/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-tools/hadoop-aws/src/test/resources/log4j.properties
new file mode 100644
index 0000000..1330ed1
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-tools/hadoop-aws/src/test/resources/log4j.properties
@@ -0,0 +1,23 @@
+#   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.
+# log4j configuration used during build and unit tests
+
+log4j.rootLogger=info,stdout
+log4j.threshold=ALL
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} [%t] %-5p %c{2} (%F:%M(%L)) - %m%n
+
+log4j.logger.org.apache.hadoop.util.NativeCodeLoader=ERROR
+
+# for debugging low level S3a operations, uncomment this line
+# log4j.logger.org.apache.hadoop.fs.s3a=DEBUG
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-tools/hadoop-azure/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-tools/hadoop-azure/src/test/resources/log4j.properties
new file mode 100644
index 0000000..73ee3f9
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-tools/hadoop-azure/src/test/resources/log4j.properties
@@ -0,0 +1,25 @@
+#
+#   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.
+#
+# log4j configuration used during build and unit tests
+
+log4j.rootLogger=INFO,stdout
+log4j.threshold=ALL
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} %-5p [%t]: %c{2} (%F:%M(%L)) - %m%n
+
+log4j.logger.org.apache.hadoop.fs.azure.AzureFileSystemThreadPoolExecutor=DEBUG
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-tools/hadoop-openstack/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-tools/hadoop-openstack/src/test/resources/log4j.properties
new file mode 100644
index 0000000..6aeb41d
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-tools/hadoop-openstack/src/test/resources/log4j.properties
@@ -0,0 +1,42 @@
+#
+# 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.
+#
+
+#   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.
+# log4j configuration used during build and unit tests
+
+log4j.rootLogger=INFO,stdout
+log4j.threshold=ALL
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.target=System.out
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} [%t] %-5p %c{2} (%F:%M(%L)) - %m%n
+#log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} [%t] %-5p %c %x - %m%n"
+#log4j.logger.org.apache.hadoop.fs.swift=DEBUG
+
+#crank back on warnings about -1 content length GETs
+log4j.logger.org.apache.commons.httpclient.HttpMethodBase=ERROR
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-tools/hadoop-sls/src/main/sample-conf/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-tools/hadoop-sls/src/main/sample-conf/log4j.properties
new file mode 100644
index 0000000..cfd405b
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-tools/hadoop-sls/src/main/sample-conf/log4j.properties
@@ -0,0 +1,19 @@
+#
+# 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. See accompanying LICENSE file.
+#
+log4j.appender.test=org.apache.log4j.ConsoleAppender
+log4j.appender.test.Target=System.out
+log4j.appender.test.layout=org.apache.log4j.PatternLayout
+log4j.appender.test.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
+
+log4j.logger=NONE, test
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-distributedshell/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-distributedshell/src/test/resources/log4j.properties
new file mode 100644
index 0000000..81a3f6a
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-distributedshell/src/test/resources/log4j.properties
@@ -0,0 +1,19 @@
+#   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.
+
+# log4j configuration used during build and unit tests
+
+log4j.rootLogger=info,stdout
+log4j.threshold=ALL
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} %-5p [%t] %c{2} (%F:%M(%L)) - %m%n
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-unmanaged-am-launcher/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-unmanaged-am-launcher/src/test/resources/log4j.properties
new file mode 100644
index 0000000..e46856e
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-unmanaged-am-launcher/src/test/resources/log4j.properties
@@ -0,0 +1,37 @@
+#
+# 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.
+#
+
+#   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.
+
+# log4j configuration used during build and unit tests
+
+log4j.rootLogger=INFO,stdout
+log4j.threshold=ALL
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} %-5p [%t] %c{2} (%F:%M(%L)) - %m%n
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/resources/log4j.properties
new file mode 100644
index 0000000..81a3f6a
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/resources/log4j.properties
@@ -0,0 +1,19 @@
+#   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.
+
+# log4j configuration used during build and unit tests
+
+log4j.rootLogger=info,stdout
+log4j.threshold=ALL
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} %-5p [%t] %c{2} (%F:%M(%L)) - %m%n
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-registry/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-registry/src/test/resources/log4j.properties
new file mode 100644
index 0000000..bed1abc
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-registry/src/test/resources/log4j.properties
@@ -0,0 +1,63 @@
+# 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.
+
+# log4j configuration used during build and unit tests
+
+log4j.rootLogger=INFO,stdout
+log4j.threshold=ALL
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} [%t] %-5p %c{2} (%F:%M(%L)) - %m%n
+
+log4j.appender.subprocess=org.apache.log4j.ConsoleAppender
+log4j.appender.subprocess.layout=org.apache.log4j.PatternLayout
+log4j.appender.subprocess.layout.ConversionPattern=[%c{1}]: %m%n
+
+# packages under test
+log4j.logger.org.apache.hadoop.yarn.registry=DEBUG
+log4j.logger.org.apache.hadoop.service=DEBUG
+
+log4j.logger.org.apache.hadoop.security.UserGroupInformation=DEBUG
+
+
+#crank back on some noise
+log4j.logger.org.apache.hadoop.util.NativeCodeLoader=ERROR
+log4j.logger.org.apache.hadoop.hdfs.server.datanode.BlockPoolSliceScanner=WARN
+log4j.logger.org.apache.hadoop.hdfs.server.blockmanagement=WARN
+log4j.logger.org.apache.hadoop.hdfs.server.namenode.FSNamesystem.audit=WARN
+log4j.logger.org.apache.hadoop.hdfs=WARN
+
+
+log4j.logger.org.apache.hadoop.yarn.server.nodemanager.containermanager.monitor=WARN
+log4j.logger.org.apache.hadoop.yarn.server.nodemanager.NodeStatusUpdaterImpl=WARN
+log4j.logger.org.apache.zookeeper=INFO
+log4j.logger.org.apache.zookeeper.ClientCnxn=DEBUG
+
+log4j.logger.org.apache.hadoop.yarn.server.resourcemanager.security=WARN
+log4j.logger.org.apache.hadoop.metrics2=ERROR
+log4j.logger.org.apache.hadoop.util.HostsFileReader=WARN
+log4j.logger.org.apache.hadoop.yarn.event.AsyncDispatcher=WARN
+log4j.logger.org.apache.hadoop.security.token.delegation=WARN
+log4j.logger.org.apache.hadoop.yarn.util.AbstractLivelinessMonitor=WARN
+log4j.logger.org.apache.hadoop.yarn.server.nodemanager.security=WARN
+log4j.logger.org.apache.hadoop.yarn.server.resourcemanager.RMNMInfo=WARN
+
+# curator noise
+log4j.logger.org.apache.curator.framework.imps=WARN
+log4j.logger.org.apache.curator.framework.state.ConnectionStateManager=ERROR
+
+log4j.logger.org.apache.directory.api.ldap=ERROR
+log4j.logger.org.apache.directory.server=ERROR
\ No newline at end of file
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/test/resources/log4j.properties
new file mode 100644
index 0000000..81a3f6a
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/test/resources/log4j.properties
@@ -0,0 +1,19 @@
+#   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.
+
+# log4j configuration used during build and unit tests
+
+log4j.rootLogger=info,stdout
+log4j.threshold=ALL
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} %-5p [%t] %c{2} (%F:%M(%L)) - %m%n
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/resources/log4j.properties
new file mode 100644
index 0000000..81a3f6a
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/resources/log4j.properties
@@ -0,0 +1,19 @@
+#   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.
+
+# log4j configuration used during build and unit tests
+
+log4j.rootLogger=info,stdout
+log4j.threshold=ALL
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} %-5p [%t] %c{2} (%F:%M(%L)) - %m%n
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/resources/log4j.properties
new file mode 100644
index 0000000..81a3f6a
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/resources/log4j.properties
@@ -0,0 +1,19 @@
+#   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.
+
+# log4j configuration used during build and unit tests
+
+log4j.rootLogger=info,stdout
+log4j.threshold=ALL
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} %-5p [%t] %c{2} (%F:%M(%L)) - %m%n
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-tests/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-tests/src/test/resources/log4j.properties
new file mode 100644
index 0000000..c088bb7
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-tests/src/test/resources/log4j.properties
@@ -0,0 +1,19 @@
+#   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.
+
+# log4j configuration used during build and unit tests
+
+log4j.rootLogger=INFO,stdout
+log4j.threshold=ALL
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} %-5p [%t] %c{2} (%F:%M(%L)) - %m%n
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-timelineservice-hbase-tests/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-timelineservice-hbase-tests/src/test/resources/log4j.properties
new file mode 100644
index 0000000..81a3f6a
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-timelineservice-hbase-tests/src/test/resources/log4j.properties
@@ -0,0 +1,19 @@
+#   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.
+
+# log4j configuration used during build and unit tests
+
+log4j.rootLogger=info,stdout
+log4j.threshold=ALL
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} %-5p [%t] %c{2} (%F:%M(%L)) - %m%n
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-timelineservice/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-timelineservice/src/test/resources/log4j.properties
new file mode 100644
index 0000000..81a3f6a
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/hadoop/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-timelineservice/src/test/resources/log4j.properties
@@ -0,0 +1,19 @@
+#   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.
+
+# log4j configuration used during build and unit tests
+
+log4j.rootLogger=info,stdout
+log4j.threshold=ALL
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} %-5p [%t] %c{2} (%F:%M(%L)) - %m%n
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-DailyRollingFileAppender.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-DailyRollingFileAppender.properties
new file mode 100644
index 0000000..123a51d
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-DailyRollingFileAppender.properties
@@ -0,0 +1,26 @@
+###############################################################################
+#
+# Log4J 1.2 Configuration.
+#
+
+hadoop.log.dir=target
+hadoop.log.file=hadoop.log
+
+log4j.rootLogger=TRACE, DRFA
+
+#
+# Daily Rolling File Appender
+#
+
+log4j.appender.DRFA=org.apache.log4j.DailyRollingFileAppender
+log4j.appender.DRFA.File=${hadoop.log.dir}/${hadoop.log.file}
+
+# Rollover at midnight
+log4j.appender.DRFA.DatePattern=.yyyy-MM-dd
+
+log4j.appender.DRFA.layout=org.apache.log4j.PatternLayout
+
+# Pattern format: Date LogLevel LoggerName LogMessage
+log4j.appender.DRFA.layout.ConversionPattern=%d{ISO8601} %p %c: %m%n
+# Debugging Pattern format
+#log4j.appender.DRFA.layout.ConversionPattern=%d{ISO8601} %-5p %c{2} (%F:%M(%L)) - %m%n
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-NullAppender.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-NullAppender.properties
new file mode 100644
index 0000000..d89a4f4
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-NullAppender.properties
@@ -0,0 +1,9 @@
+###############################################################################
+#
+# Log4J 1.2 Configuration.
+#
+
+log4j.rootLogger=TRACE, NullAppender
+
+# Null Appender
+log4j.appender.NullAppender=org.apache.log4j.varia.NullAppender
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-RollingFileAppender-with-props.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-RollingFileAppender-with-props.properties
new file mode 100644
index 0000000..b664bb8
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-RollingFileAppender-with-props.properties
@@ -0,0 +1,27 @@
+###############################################################################
+#
+# Log4J 1.2 Configuration.
+#
+
+hadoop.log.dir=target
+hadoop.log.file=hadoop.log
+
+log4j.rootLogger=TRACE, RFA
+
+#
+# Rolling File Appender - cap space usage at 5gb.
+#
+hadoop.log.maxfilesize=256MB
+hadoop.log.maxbackupindex=20
+log4j.appender.RFA=org.apache.log4j.RollingFileAppender
+log4j.appender.RFA.File=${hadoop.log.dir}/${hadoop.log.file}
+
+log4j.appender.RFA.MaxFileSize=${hadoop.log.maxfilesize}
+log4j.appender.RFA.MaxBackupIndex=${hadoop.log.maxbackupindex}
+
+log4j.appender.RFA.layout=org.apache.log4j.PatternLayout
+
+# Pattern format: Date LogLevel LoggerName LogMessage
+log4j.appender.RFA.layout.ConversionPattern=%d{ISO8601} %p %c: %m%n
+# Debugging Pattern format
+#log4j.appender.RFA.layout.ConversionPattern=%d{ISO8601} %-5p %c{2} (%F:%M(%L)) - %m%n
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-RollingFileAppender.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-RollingFileAppender.properties
new file mode 100644
index 0000000..55234ba
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-RollingFileAppender.properties
@@ -0,0 +1,22 @@
+###############################################################################
+#
+# Log4J 1.2 Configuration.
+#
+
+log4j.rootLogger=TRACE, RFA
+
+#
+# Rolling File Appender - cap space usage at 5gb.
+#
+log4j.appender.RFA=org.apache.log4j.RollingFileAppender
+log4j.appender.RFA.File=target/hadoop.log
+
+log4j.appender.RFA.MaxFileSize=256MB
+log4j.appender.RFA.MaxBackupIndex=20
+
+log4j.appender.RFA.layout=org.apache.log4j.PatternLayout
+
+# Pattern format: Date LogLevel LoggerName LogMessage
+log4j.appender.RFA.layout.ConversionPattern=%d{ISO8601} %p %c: %m%n
+# Debugging Pattern format
+#log4j.appender.RFA.layout.ConversionPattern=%d{ISO8601} %-5p %c{2} (%F:%M(%L)) - %m%n
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-console-EnhancedPatternLayout.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-console-EnhancedPatternLayout.properties
new file mode 100644
index 0000000..6793eb2
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-console-EnhancedPatternLayout.properties
@@ -0,0 +1,18 @@
+###############################################################################
+#
+# Log4J 1.2 Configuration.
+#
+
+log4j.rootLogger=TRACE, Console
+
+##############################################################################
+#
+# The Console log
+#
+
+log4j.appender.Console=org.apache.log4j.ConsoleAppender
+log4j.appender.Console.Target=System.err
+log4j.appender.Console.layout=org.apache.log4j.EnhancedPatternLayout
+log4j.appender.Console.layout.ConversionPattern=%d{ISO8601} [%t][%c] %-5p %X %x: %m%n
+
+log4j.logger.com.example.foo = DEBUG
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-console-HtmlLayout.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-console-HtmlLayout.properties
new file mode 100644
index 0000000..216a12e
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-console-HtmlLayout.properties
@@ -0,0 +1,19 @@
+###############################################################################
+#
+# Log4J 1.2 Configuration.
+#
+
+log4j.rootLogger=TRACE, Console
+
+##############################################################################
+#
+# The Console log
+#
+
+log4j.appender.Console=org.apache.log4j.ConsoleAppender
+log4j.appender.Console.Target=System.err
+log4j.appender.Console.layout=org.apache.log4j.HTMLLayout
+log4j.appender.Console.layout.Title=Headline
+log4j.appender.Console.layout.LocationInfo=true
+
+log4j.logger.com.example.foo = DEBUG
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-console-PatternLayout.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-console-PatternLayout.properties
new file mode 100644
index 0000000..810a494
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-console-PatternLayout.properties
@@ -0,0 +1,18 @@
+###############################################################################
+#
+# Log4J 1.2 Configuration.
+#
+
+log4j.rootLogger=TRACE, Console
+
+##############################################################################
+#
+# The Console log
+#
+
+log4j.appender.Console=org.apache.log4j.ConsoleAppender
+log4j.appender.Console.Target=System.err
+log4j.appender.Console.layout=org.apache.log4j.PatternLayout
+log4j.appender.Console.layout.ConversionPattern=%d{ISO8601} [%t][%c] %-5p: %m%n
+
+log4j.logger.com.example.foo = DEBUG
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-console-SimpleLayout.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-console-SimpleLayout.properties
new file mode 100644
index 0000000..5a8ac4e
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-console-SimpleLayout.properties
@@ -0,0 +1,17 @@
+###############################################################################
+#
+# Log4J 1.2 Configuration.
+#
+
+log4j.rootLogger=TRACE, Console
+
+##############################################################################
+#
+# The Console log
+#
+
+log4j.appender.Console=org.apache.log4j.ConsoleAppender
+log4j.appender.Console.Target=System.err
+log4j.appender.Console.layout=org.apache.log4j.SimpleLayout
+
+log4j.logger.com.example.foo = DEBUG
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-console-TTCCLayout.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-console-TTCCLayout.properties
new file mode 100644
index 0000000..80d38c2
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-console-TTCCLayout.properties
@@ -0,0 +1,19 @@
+###############################################################################
+#
+# Log4J 1.2 Configuration.
+#
+
+log4j.rootLogger=TRACE, Console
+
+##############################################################################
+#
+# The Console log
+#
+
+log4j.appender.Console=org.apache.log4j.ConsoleAppender
+log4j.appender.Console.Target=System.err
+log4j.appender.Console.layout=org.apache.log4j.TTCCLayout
+log4j.appender.Console.layout.ThreadPrinting=true
+log4j.appender.Console.layout.CategoryPrefixing=false
+
+log4j.logger.com.example.foo = DEBUG
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-console-XmlLayout.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-console-XmlLayout.properties
new file mode 100644
index 0000000..c8190ec
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-console-XmlLayout.properties
@@ -0,0 +1,19 @@
+###############################################################################
+#
+# Log4J 1.2 Configuration.
+#
+
+log4j.rootLogger=TRACE, Console
+
+##############################################################################
+#
+# The Console log
+#
+
+log4j.appender.Console=org.apache.log4j.ConsoleAppender
+log4j.appender.Console.Target=System.err
+log4j.appender.Console.layout=org.apache.log4j.xml.XMLLayout
+log4j.appender.Console.layout.LocationInfo=true
+log4j.appender.Console.layout.Properties=false
+
+log4j.logger.com.example.foo = DEBUG
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-file-SimpleLayout.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-file-SimpleLayout.properties
new file mode 100644
index 0000000..4d3ec0d
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-file-SimpleLayout.properties
@@ -0,0 +1,17 @@
+###############################################################################
+#
+# Log4J 1.2 Configuration.
+#
+
+log4j.rootLogger=TRACE, File
+
+##############################################################################
+#
+# The Console log
+#
+
+log4j.appender.File=org.apache.log4j.FileAppender
+log4j.appender.File.File=target/mylog.txt
+log4j.appender.File.layout=org.apache.log4j.SimpleLayout
+
+log4j.logger.com.example.foo = DEBUG
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-system-properties-1.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-system-properties-1.properties
new file mode 100644
index 0000000..a82c4c3
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-system-properties-1.properties
@@ -0,0 +1,14 @@
+###############################################################################
+#
+# Log4J 1.2 Configuration.
+#
+
+hadoop.log.file=hadoop.log
+
+log4j.rootLogger=TRACE, RFA
+
+#
+# Rolling File Appender
+#
+log4j.appender.RFA=org.apache.log4j.RollingFileAppender
+log4j.appender.RFA.File=${java.io.tmpdir}/${hadoop.log.file}
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-system-properties-2.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-system-properties-2.properties
new file mode 100644
index 0000000..9228434
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/log4j-system-properties-2.properties
@@ -0,0 +1,15 @@
+###############################################################################
+#
+# Log4J 1.2 Configuration.
+#
+
+hadoop.log.dir=${java.io.tmpdir}
+hadoop.log.file=hadoop.log
+
+log4j.rootLogger=TRACE, RFA
+
+#
+# Rolling File Appender
+#
+log4j.appender.RFA=org.apache.log4j.RollingFileAppender
+log4j.appender.RFA.File=${hadoop.log.dir}/${hadoop.log.file}
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/spark/R/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/R/log4j.properties
new file mode 100644
index 0000000..cce8d91
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/R/log4j.properties
@@ -0,0 +1,28 @@
+#
+# 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.
+#
+
+# Set everything to be logged to the file target/unit-tests.log
+log4j.rootCategory=INFO, file
+log4j.appender.file=org.apache.log4j.FileAppender
+log4j.appender.file.append=true
+log4j.appender.file.file=R/target/unit-tests.log
+log4j.appender.file.layout=org.apache.log4j.PatternLayout
+log4j.appender.file.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss.SSS} %t %p %c{1}: %m%n
+
+# Ignore messages below warning level from Jetty, because it's a bit verbose
+log4j.logger.org.eclipse.jetty=WARN
+org.eclipse.jetty.LEVEL=WARN
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/spark/common/network-common/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/common/network-common/src/test/resources/log4j.properties
new file mode 100644
index 0000000..e8da774
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/common/network-common/src/test/resources/log4j.properties
@@ -0,0 +1,27 @@
+#
+# 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.
+#
+
+# Set everything to be logged to the file target/unit-tests.log
+log4j.rootCategory=DEBUG, file
+log4j.appender.file=org.apache.log4j.FileAppender
+log4j.appender.file.append=true
+log4j.appender.file.file=target/unit-tests.log
+log4j.appender.file.layout=org.apache.log4j.PatternLayout
+log4j.appender.file.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss.SSS} %t %p %c{1}: %m%n
+
+# Silence verbose logs from 3rd-party libraries.
+log4j.logger.io.netty=INFO
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/spark/common/network-shuffle/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/common/network-shuffle/src/test/resources/log4j.properties
new file mode 100644
index 0000000..e739789
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/common/network-shuffle/src/test/resources/log4j.properties
@@ -0,0 +1,24 @@
+#
+# 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.
+#
+
+# Set everything to be logged to the file target/unit-tests.log
+log4j.rootCategory=DEBUG, file
+log4j.appender.file=org.apache.log4j.FileAppender
+log4j.appender.file.append=true
+log4j.appender.file.file=target/unit-tests.log
+log4j.appender.file.layout=org.apache.log4j.PatternLayout
+log4j.appender.file.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss.SSS} %t %p %c{1}: %m%n
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/spark/core/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/core/src/test/resources/log4j.properties
new file mode 100644
index 0000000..fb9d985
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/core/src/test/resources/log4j.properties
@@ -0,0 +1,36 @@
+#
+# 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.
+#
+
+# Set everything to be logged to the file target/unit-tests.log
+test.appender=file
+log4j.rootCategory=INFO, ${test.appender}
+log4j.appender.file=org.apache.log4j.FileAppender
+log4j.appender.file.append=true
+log4j.appender.file.file=target/unit-tests.log
+log4j.appender.file.layout=org.apache.log4j.PatternLayout
+log4j.appender.file.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss.SSS} %t %p %c{1}: %m%n
+
+# Tests that launch java subprocesses can set the "test.appender" system property to
+# "console" to avoid having the child process's logs overwrite the unit test's
+# log file.
+log4j.appender.console=org.apache.log4j.ConsoleAppender
+log4j.appender.console.target=System.err
+log4j.appender.console.layout=org.apache.log4j.PatternLayout
+log4j.appender.console.layout.ConversionPattern=%t: %m%n
+
+# Ignore messages below warning level from Jetty, because it's a bit verbose
+log4j.logger.org.spark_project.jetty=WARN
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/spark/external/flume-sink/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/external/flume-sink/src/test/resources/log4j.properties
new file mode 100644
index 0000000..1e3f163
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/external/flume-sink/src/test/resources/log4j.properties
@@ -0,0 +1,28 @@
+#
+# 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.
+#
+
+# Set everything to be logged to the file streaming/target/unit-tests.log
+log4j.rootCategory=INFO, file
+log4j.appender.file=org.apache.log4j.FileAppender
+log4j.appender.file.append=true
+log4j.appender.file.file=target/unit-tests.log
+log4j.appender.file.layout=org.apache.log4j.PatternLayout
+log4j.appender.file.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss.SSS} %t %p %c{1}: %m%n
+
+# Ignore messages below warning level from Jetty, because it's a bit verbose
+log4j.logger.org.spark_project.jetty=WARN
+
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/spark/external/flume/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/external/flume/src/test/resources/log4j.properties
new file mode 100644
index 0000000..fd51f8f
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/external/flume/src/test/resources/log4j.properties
@@ -0,0 +1,28 @@
+#
+# 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.
+#
+
+# Set everything to be logged to the file target/unit-tests.log
+log4j.rootCategory=INFO, file
+log4j.appender.file=org.apache.log4j.FileAppender
+log4j.appender.file.append=true
+log4j.appender.file.file=target/unit-tests.log
+log4j.appender.file.layout=org.apache.log4j.PatternLayout
+log4j.appender.file.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss.SSS} %t %p %c{1}: %m%n
+
+# Ignore messages below warning level from Jetty, because it's a bit verbose
+log4j.logger.org.spark_project.jetty=WARN
+
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/spark/external/java8-tests/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/external/java8-tests/src/test/resources/log4j.properties
new file mode 100644
index 0000000..3706a6e
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/external/java8-tests/src/test/resources/log4j.properties
@@ -0,0 +1,27 @@
+#
+# 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.
+#
+
+# Set everything to be logged to the file target/unit-tests.log
+log4j.rootCategory=INFO, file
+log4j.appender.file=org.apache.log4j.FileAppender
+log4j.appender.file.append=true
+log4j.appender.file.file=target/unit-tests.log
+log4j.appender.file.layout=org.apache.log4j.PatternLayout
+log4j.appender.file.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss.SSS} %t %p %c{1}: %m%n
+
+# Ignore messages below warning level from Jetty, because it's a bit verbose
+log4j.logger.org.spark_project.jetty=WARN
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/spark/external/kafka-0-10/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/external/kafka-0-10/src/test/resources/log4j.properties
new file mode 100644
index 0000000..75e3b53
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/external/kafka-0-10/src/test/resources/log4j.properties
@@ -0,0 +1,28 @@
+#
+# 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.
+#
+
+# Set everything to be logged to the file target/unit-tests.log
+log4j.rootCategory=INFO, file
+log4j.appender.file=org.apache.log4j.FileAppender
+log4j.appender.file.append=true
+log4j.appender.file.file=target/unit-tests.log
+log4j.appender.file.layout=org.apache.log4j.PatternLayout
+log4j.appender.file.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss.SSS} %t %p %c{1}: %m%n
+
+# Ignore messages below warning level from Jetty, because it's a bit verbose
+log4j.logger.org.spark-project.jetty=WARN
+
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/spark/external/kafka-0-8/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/external/kafka-0-8/src/test/resources/log4j.properties
new file mode 100644
index 0000000..fd51f8f
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/external/kafka-0-8/src/test/resources/log4j.properties
@@ -0,0 +1,28 @@
+#
+# 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.
+#
+
+# Set everything to be logged to the file target/unit-tests.log
+log4j.rootCategory=INFO, file
+log4j.appender.file=org.apache.log4j.FileAppender
+log4j.appender.file.append=true
+log4j.appender.file.file=target/unit-tests.log
+log4j.appender.file.layout=org.apache.log4j.PatternLayout
+log4j.appender.file.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss.SSS} %t %p %c{1}: %m%n
+
+# Ignore messages below warning level from Jetty, because it's a bit verbose
+log4j.logger.org.spark_project.jetty=WARN
+
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/spark/external/kinesis-asl/src/main/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/external/kinesis-asl/src/main/resources/log4j.properties
new file mode 100644
index 0000000..4f5ea7b
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/external/kinesis-asl/src/main/resources/log4j.properties
@@ -0,0 +1,37 @@
+#
+# 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.
+#
+
+log4j.rootCategory=WARN, console
+
+# File appender
+log4j.appender.file=org.apache.log4j.FileAppender
+log4j.appender.file.append=false
+log4j.appender.file.file=target/unit-tests.log
+log4j.appender.file.layout=org.apache.log4j.PatternLayout
+log4j.appender.file.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss.SSS} %p %c{1}: %m%n
+
+# Console appender
+log4j.appender.console=org.apache.log4j.ConsoleAppender
+log4j.appender.console.target=System.out
+log4j.appender.console.layout=org.apache.log4j.PatternLayout
+log4j.appender.console.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss} %p %c{1}: %m%n
+
+# Settings to quiet third party logs that are too verbose
+log4j.logger.org.spark_project.jetty=WARN
+log4j.logger.org.spark_project.jetty.util.component.AbstractLifeCycle=ERROR
+log4j.logger.org.apache.spark.repl.SparkIMain$exprTyper=INFO
+log4j.logger.org.apache.spark.repl.SparkILoop$SparkILoopInterpreter=INFO
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/spark/external/kinesis-asl/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/external/kinesis-asl/src/test/resources/log4j.properties
new file mode 100644
index 0000000..3706a6e
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/external/kinesis-asl/src/test/resources/log4j.properties
@@ -0,0 +1,27 @@
+#
+# 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.
+#
+
+# Set everything to be logged to the file target/unit-tests.log
+log4j.rootCategory=INFO, file
+log4j.appender.file=org.apache.log4j.FileAppender
+log4j.appender.file.append=true
+log4j.appender.file.file=target/unit-tests.log
+log4j.appender.file.layout=org.apache.log4j.PatternLayout
+log4j.appender.file.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss.SSS} %t %p %c{1}: %m%n
+
+# Ignore messages below warning level from Jetty, because it's a bit verbose
+log4j.logger.org.spark_project.jetty=WARN
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/spark/graphx/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/graphx/src/test/resources/log4j.properties
new file mode 100644
index 0000000..3706a6e
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/graphx/src/test/resources/log4j.properties
@@ -0,0 +1,27 @@
+#
+# 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.
+#
+
+# Set everything to be logged to the file target/unit-tests.log
+log4j.rootCategory=INFO, file
+log4j.appender.file=org.apache.log4j.FileAppender
+log4j.appender.file.append=true
+log4j.appender.file.file=target/unit-tests.log
+log4j.appender.file.layout=org.apache.log4j.PatternLayout
+log4j.appender.file.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss.SSS} %t %p %c{1}: %m%n
+
+# Ignore messages below warning level from Jetty, because it's a bit verbose
+log4j.logger.org.spark_project.jetty=WARN
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/spark/launcher/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/launcher/src/test/resources/log4j.properties
new file mode 100644
index 0000000..744c456
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/launcher/src/test/resources/log4j.properties
@@ -0,0 +1,33 @@
+#
+# 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.
+#
+
+# Set everything to be logged to the file core/target/unit-tests.log
+test.appender=file
+log4j.rootCategory=INFO, ${test.appender}
+log4j.appender.file=org.apache.log4j.FileAppender
+log4j.appender.file.append=false
+log4j.appender.file.file=target/unit-tests.log
+log4j.appender.file.layout=org.apache.log4j.PatternLayout
+log4j.appender.file.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss.SSS} %t %p %c{1}: %m%n
+
+log4j.appender.childproc=org.apache.log4j.ConsoleAppender
+log4j.appender.childproc.target=System.err
+log4j.appender.childproc.layout=org.apache.log4j.PatternLayout
+log4j.appender.childproc.layout.ConversionPattern=%t: %m%n
+
+# Ignore messages below warning level from Jetty, because it's a bit verbose
+log4j.logger.org.spark_project.jetty=WARN
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/spark/mllib/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/mllib/src/test/resources/log4j.properties
new file mode 100644
index 0000000..fd51f8f
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/mllib/src/test/resources/log4j.properties
@@ -0,0 +1,28 @@
+#
+# 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.
+#
+
+# Set everything to be logged to the file target/unit-tests.log
+log4j.rootCategory=INFO, file
+log4j.appender.file=org.apache.log4j.FileAppender
+log4j.appender.file.append=true
+log4j.appender.file.file=target/unit-tests.log
+log4j.appender.file.layout=org.apache.log4j.PatternLayout
+log4j.appender.file.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss.SSS} %t %p %c{1}: %m%n
+
+# Ignore messages below warning level from Jetty, because it's a bit verbose
+log4j.logger.org.spark_project.jetty=WARN
+
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/spark/repl/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/repl/src/test/resources/log4j.properties
new file mode 100644
index 0000000..7665bd5
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/repl/src/test/resources/log4j.properties
@@ -0,0 +1,27 @@
+#
+# 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.
+#
+
+# Set everything to be logged to the target/unit-tests.log
+log4j.rootCategory=INFO, file
+log4j.appender.file=org.apache.log4j.FileAppender
+log4j.appender.file.append=true
+log4j.appender.file.file=target/unit-tests.log
+log4j.appender.file.layout=org.apache.log4j.PatternLayout
+log4j.appender.file.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss.SSS} %t %p %c{1}: %m%n
+
+# Ignore messages below warning level from Jetty, because it's a bit verbose
+log4j.logger.org.spark_project.jetty=WARN
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/spark/sql/catalyst/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/sql/catalyst/src/test/resources/log4j.properties
new file mode 100644
index 0000000..3706a6e
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/sql/catalyst/src/test/resources/log4j.properties
@@ -0,0 +1,27 @@
+#
+# 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.
+#
+
+# Set everything to be logged to the file target/unit-tests.log
+log4j.rootCategory=INFO, file
+log4j.appender.file=org.apache.log4j.FileAppender
+log4j.appender.file.append=true
+log4j.appender.file.file=target/unit-tests.log
+log4j.appender.file.layout=org.apache.log4j.PatternLayout
+log4j.appender.file.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss.SSS} %t %p %c{1}: %m%n
+
+# Ignore messages below warning level from Jetty, because it's a bit verbose
+log4j.logger.org.spark_project.jetty=WARN
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/spark/sql/core/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/sql/core/src/test/resources/log4j.properties
new file mode 100644
index 0000000..33b9ecf
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/sql/core/src/test/resources/log4j.properties
@@ -0,0 +1,57 @@
+#
+# 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.
+#
+
+# Set everything to be logged to the file core/target/unit-tests.log
+log4j.rootLogger=INFO, CA, FA
+
+#Console Appender
+log4j.appender.CA=org.apache.log4j.ConsoleAppender
+log4j.appender.CA.layout=org.apache.log4j.PatternLayout
+log4j.appender.CA.layout.ConversionPattern=%d{HH:mm:ss.SSS} %p %c: %m%n
+log4j.appender.CA.Threshold = WARN
+log4j.appender.CA.follow = true
+
+
+#File Appender
+log4j.appender.FA=org.apache.log4j.FileAppender
+log4j.appender.FA.append=false
+log4j.appender.FA.file=target/unit-tests.log
+log4j.appender.FA.layout=org.apache.log4j.PatternLayout
+log4j.appender.FA.layout.ConversionPattern=%d{HH:mm:ss.SSS} %t %p %c{1}: %m%n
+
+# Set the logger level of File Appender to WARN
+log4j.appender.FA.Threshold = INFO
+
+# Some packages are noisy for no good reason.
+log4j.additivity.org.apache.parquet.hadoop.ParquetRecordReader=false
+log4j.logger.org.apache.parquet.hadoop.ParquetRecordReader=OFF
+
+log4j.additivity.org.apache.parquet.hadoop.ParquetOutputCommitter=false
+log4j.logger.org.apache.parquet.hadoop.ParquetOutputCommitter=OFF
+
+log4j.additivity.org.apache.hadoop.hive.serde2.lazy.LazyStruct=false
+log4j.logger.org.apache.hadoop.hive.serde2.lazy.LazyStruct=OFF
+
+log4j.additivity.org.apache.hadoop.hive.metastore.RetryingHMSHandler=false
+log4j.logger.org.apache.hadoop.hive.metastore.RetryingHMSHandler=OFF
+
+log4j.additivity.hive.ql.metadata.Hive=false
+log4j.logger.hive.ql.metadata.Hive=OFF
+
+# Parquet related logging
+log4j.logger.org.apache.parquet.hadoop=WARN
+log4j.logger.org.apache.spark.sql.parquet=INFO
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/spark/sql/hive/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/sql/hive/src/test/resources/log4j.properties
new file mode 100644
index 0000000..fea3404
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/sql/hive/src/test/resources/log4j.properties
@@ -0,0 +1,61 @@
+#
+# 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.
+#
+
+# Set everything to be logged to the file core/target/unit-tests.log
+log4j.rootLogger=DEBUG, CA, FA
+
+#Console Appender
+log4j.appender.CA=org.apache.log4j.ConsoleAppender
+log4j.appender.CA.layout=org.apache.log4j.PatternLayout
+log4j.appender.CA.layout.ConversionPattern=%d{HH:mm:ss.SSS} %p %c: %m%n
+log4j.appender.CA.Threshold = WARN
+
+
+#File Appender
+log4j.appender.FA=org.apache.log4j.FileAppender
+log4j.appender.FA.append=false
+log4j.appender.FA.file=target/unit-tests.log
+log4j.appender.FA.layout=org.apache.log4j.PatternLayout
+log4j.appender.FA.layout.ConversionPattern=%d{HH:mm:ss.SSS} %t %p %c{1}: %m%n
+
+# Set the logger level of File Appender to WARN
+log4j.appender.FA.Threshold = DEBUG
+
+# Some packages are noisy for no good reason.
+log4j.additivity.org.apache.hadoop.hive.serde2.lazy.LazyStruct=false
+log4j.logger.org.apache.hadoop.hive.serde2.lazy.LazyStruct=OFF
+
+log4j.additivity.org.apache.hadoop.hive.metastore.RetryingHMSHandler=false
+log4j.logger.org.apache.hadoop.hive.metastore.RetryingHMSHandler=OFF
+
+log4j.additivity.hive.log=false
+log4j.logger.hive.log=OFF
+
+log4j.additivity.parquet.hadoop.ParquetRecordReader=false
+log4j.logger.parquet.hadoop.ParquetRecordReader=OFF
+
+log4j.additivity.org.apache.parquet.hadoop.ParquetRecordReader=false
+log4j.logger.org.apache.parquet.hadoop.ParquetRecordReader=OFF
+
+log4j.additivity.org.apache.parquet.hadoop.ParquetOutputCommitter=false
+log4j.logger.org.apache.parquet.hadoop.ParquetOutputCommitter=OFF
+
+log4j.additivity.hive.ql.metadata.Hive=false
+log4j.logger.hive.ql.metadata.Hive=OFF
+
+log4j.additivity.org.apache.hadoop.hive.ql.io.RCFile=false
+log4j.logger.org.apache.hadoop.hive.ql.io.RCFile=ERROR
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/spark/streaming/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/streaming/src/test/resources/log4j.properties
new file mode 100644
index 0000000..fd51f8f
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/streaming/src/test/resources/log4j.properties
@@ -0,0 +1,28 @@
+#
+# 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.
+#
+
+# Set everything to be logged to the file target/unit-tests.log
+log4j.rootCategory=INFO, file
+log4j.appender.file=org.apache.log4j.FileAppender
+log4j.appender.file.append=true
+log4j.appender.file.file=target/unit-tests.log
+log4j.appender.file.layout=org.apache.log4j.PatternLayout
+log4j.appender.file.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss.SSS} %t %p %c{1}: %m%n
+
+# Ignore messages below warning level from Jetty, because it's a bit verbose
+log4j.logger.org.spark_project.jetty=WARN
+
diff --git a/log4j-1.2-api/src/src/test/resources/config-1.2/spark/yarn/src/test/resources/log4j.properties b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/yarn/src/test/resources/log4j.properties
new file mode 100644
index 0000000..d13454d
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/config-1.2/spark/yarn/src/test/resources/log4j.properties
@@ -0,0 +1,31 @@
+#
+# 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.
+#
+
+# Set everything to be logged to the file target/unit-tests.log
+log4j.rootCategory=DEBUG, file
+log4j.appender.file=org.apache.log4j.FileAppender
+log4j.appender.file.append=true
+log4j.appender.file.file=target/unit-tests.log
+log4j.appender.file.layout=org.apache.log4j.PatternLayout
+log4j.appender.file.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss.SSS} %t %p %c{1}: %m%n
+
+# Ignore messages below warning level from a few verbose libraries.
+log4j.logger.com.sun.jersey=WARN
+log4j.logger.org.apache.hadoop=WARN
+log4j.logger.org.eclipse.jetty=WARN
+log4j.logger.org.mortbay=WARN
+log4j.logger.org.spark_project.jetty=WARN
diff --git a/log4j-1.2-api/src/src/test/resources/hello.vm b/log4j-1.2-api/src/src/test/resources/hello.vm
new file mode 100644
index 0000000..5ce9755
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/hello.vm
@@ -0,0 +1,6 @@
+<html>
+<body>
+    #set( $foo = "Velocity" )
+Hello $foo World!
+</body>
+<html>
\ No newline at end of file
diff --git a/log4j-1.2-api/src/src/test/resources/log-RouteWithMDC.xml b/log4j-1.2-api/src/src/test/resources/log-RouteWithMDC.xml
new file mode 100644
index 0000000..eb7e8a5
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/log-RouteWithMDC.xml
@@ -0,0 +1,47 @@
+<?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 name="ConfigTest" status="error" packages="org.apache.logging.log4j.test"
+               monitorInterval="5">
+  <Appenders>
+    <Console name="STDOUT">
+      <PatternLayout pattern="%X{Type, Name} %m%n"/>
+    </Console>
+    <List name="List">
+      <PatternLayout pattern="%X{Type, Name} %m%n"/>
+    </List>
+    <Routing name="Routing">
+      <Routes pattern="$${ctx:Type}">
+        <Route ref="STDOUT"/>
+        <Route ref="STDOUT" key="Audit"/>
+        <Route ref="List" key="Service"/>
+      </Routes>
+    </Routing>
+  </Appenders>
+  <Loggers>
+    <Logger name="org.apache.test.logging" level="debug" additivity="false">
+      <AppenderRef ref="Routing"/>
+    </Logger>
+    <Logger name="org.apache.test" level="trace" additivity="false">
+      <AppenderRef ref="List"/>
+    </Logger>
+    <Root level="error">
+      <AppenderRef ref="STDOUT"/>
+    </Root>
+  </Loggers>
+</Configuration>
\ No newline at end of file
diff --git a/log4j-1.2-api/src/src/test/resources/log4j.xml b/log4j-1.2-api/src/src/test/resources/log4j.xml
new file mode 100644
index 0000000..065c748
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/log4j.xml
@@ -0,0 +1,36 @@
+<?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="list" class="org.apache.log4j.ListAppender">
+    <layout class="org.apache.log4j.PatternLayout">
+      <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n" />
+    </layout>
+  </appender>
+
+  <appender name="events" class="org.apache.log4j.ListAppender">
+  </appender>
+
+  <root>
+    <priority value ="trace" />
+    <appender-ref ref="list" />
+    <appender-ref ref="events" />
+  </root>
+
+</log4j:configuration>
\ No newline at end of file
diff --git a/log4j-1.2-api/src/src/test/resources/log4j1-file.xml b/log4j-1.2-api/src/src/test/resources/log4j1-file.xml
new file mode 100644
index 0000000..bc7df16
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/log4j1-file.xml
@@ -0,0 +1,57 @@
+<?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">
+    <param name="Target" value="System.out"/>
+    <layout class="org.apache.log4j.PatternLayout">
+      <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n" />
+    </layout>
+  </appender>
+
+  <appender name="A1" class="org.apache.log4j.FileAppender">
+
+    <param name="File"   value="target/temp.A1" />
+    <param name="Append" value="false" />
+
+    <layout class="org.apache.log4j.PatternLayout">
+      <param name="ConversionPattern" value="%-5p %c{2} - %m%n"/>
+    </layout>
+  </appender>
+
+  <appender name="A2" class="org.apache.log4j.FileAppender">
+    <param name="File" value="target/temp.A2" />
+    <param name="Append" value="false" />
+    <layout class="org.apache.log4j.TTCCLayout">
+      <param name="DateFormat" value="ISO8601" />
+    </layout>
+  </appender>
+
+  <logger name="org.apache.log4j.xml">
+    <level value="trace" />
+    <appender-ref ref="A1" />
+  </logger>
+
+  <root>
+    <priority value ="trace" />
+    <appender-ref ref="A1" />
+    <appender-ref ref="A2" />
+  </root>
+
+</log4j:configuration>
\ No newline at end of file
diff --git a/log4j-1.2-api/src/src/test/resources/log4j1-list.xml b/log4j-1.2-api/src/src/test/resources/log4j1-list.xml
new file mode 100644
index 0000000..065c748
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/log4j1-list.xml
@@ -0,0 +1,36 @@
+<?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="list" class="org.apache.log4j.ListAppender">
+    <layout class="org.apache.log4j.PatternLayout">
+      <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n" />
+    </layout>
+  </appender>
+
+  <appender name="events" class="org.apache.log4j.ListAppender">
+  </appender>
+
+  <root>
+    <priority value ="trace" />
+    <appender-ref ref="list" />
+    <appender-ref ref="events" />
+  </root>
+
+</log4j:configuration>
\ No newline at end of file
diff --git a/log4j-1.2-api/src/src/test/resources/log4j2-config.xml b/log4j-1.2-api/src/src/test/resources/log4j2-config.xml
new file mode 100644
index 0000000..2427af8
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/log4j2-config.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.
+
+-->
+<Configuration name="ConfigTest" status="error" packages="org.apache.logging.log4j.test"
+               monitorInterval="5">
+  <Appenders>
+    <Console name="STDOUT">
+      <PatternLayout pattern="%m%n"/>
+    </Console>
+    <List name="List">
+    </List>
+  </Appenders>
+  <Loggers>
+    <Logger name="org.apache.test.logging" level="debug" additivity="false">
+      <AppenderRef ref="List"/>
+    </Logger>
+    <Logger name="org.apache.test" level="trace" additivity="false">
+      <AppenderRef ref="List"/>
+    </Logger>
+    <Root level="error">
+      <AppenderRef ref="STDOUT"/>
+    </Root>
+  </Loggers>
+</Configuration>
\ No newline at end of file
diff --git a/log4j-1.2-api/src/src/test/resources/logWithMDC.xml b/log4j-1.2-api/src/src/test/resources/logWithMDC.xml
new file mode 100644
index 0000000..1fe8482
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/logWithMDC.xml
@@ -0,0 +1,40 @@
+<?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 name="ConfigTest" status="error" packages="org.apache.logging.log4j.test"
+               monitorInterval="5">
+  <Appenders>
+    <Console name="STDOUT">
+      <PatternLayout pattern="%m%n"/>
+    </Console>
+    <List name="List">
+      <PatternLayout pattern="%X{Key1, Key2} %m%n"/>
+    </List>
+  </Appenders>
+  <Loggers>
+    <Logger name="org.apache.test.logging" level="debug" additivity="false">
+      <AppenderRef ref="List"/>
+    </Logger>
+    <Logger name="org.apache.test" level="trace" additivity="false">
+      <AppenderRef ref="List"/>
+    </Logger>
+    <Root level="error">
+      <AppenderRef ref="STDOUT"/>
+    </Root>
+  </Loggers>
+</Configuration>
\ No newline at end of file
diff --git a/log4j-1.2-api/src/src/test/resources/witness/serialization/info.bin b/log4j-1.2-api/src/src/test/resources/witness/serialization/info.bin
new file mode 100644
index 0000000..f887f39
--- /dev/null
+++ b/log4j-1.2-api/src/src/test/resources/witness/serialization/info.bin
Binary files differ
diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/ListAppender.java b/log4j-1.2-api/src/test/java/org/apache/log4j/ListAppender.java
new file mode 100644
index 0000000..83c2758
--- /dev/null
+++ b/log4j-1.2-api/src/test/java/org/apache/log4j/ListAppender.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j;
+
+import org.apache.log4j.spi.LoggingEvent;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Used to test Log4j 1 support.
+ */
+public class ListAppender extends AppenderSkeleton {
+    // Use Collections.synchronizedList rather than CopyOnWriteArrayList because we expect
+    // more frequent writes than reads.
+    final List<LoggingEvent> events = Collections.synchronizedList(new ArrayList<>());
+
+    private final List<String> messages = Collections.synchronizedList(new ArrayList<>());
+
+
+    private static final String WINDOWS_LINE_SEP = "\r\n";
+
+    @Override
+    protected void append(LoggingEvent event) {
+        Layout layout = getLayout();
+        if (layout != null) {
+            String result = layout.format(event);
+            if (result != null) {
+                messages.add(result);
+            }
+        } else {
+            events.add(event);
+        }
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public boolean requiresLayout() {
+        return false;
+    }
+
+    /** Returns an immutable snapshot of captured log events */
+    public List<LoggingEvent> getEvents() {
+        return Collections.unmodifiableList(new ArrayList<>(events));
+    }
+
+    /** Returns an immutable snapshot of captured messages */
+    public List<String> getMessages() {
+        return Collections.unmodifiableList(new ArrayList<>(messages));
+    }
+
+    /**
+     * Polls the messages list for it to grow to a given minimum size at most timeout timeUnits and return a copy of
+     * what we have so far.
+     */
+    public List<String> getMessages(final int minSize, final long timeout, final TimeUnit timeUnit) throws InterruptedException {
+        final long endMillis = System.currentTimeMillis() + timeUnit.toMillis(timeout);
+        while (messages.size() < minSize && System.currentTimeMillis() < endMillis) {
+            Thread.sleep(100);
+        }
+        return getMessages();
+    }
+}
diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/config/AsyncAppenderTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/config/AsyncAppenderTest.java
new file mode 100644
index 0000000..bac1338
--- /dev/null
+++ b/log4j-1.2-api/src/test/java/org/apache/log4j/config/AsyncAppenderTest.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.config;
+
+import org.apache.log4j.ListAppender;
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
+import org.apache.log4j.bridge.AppenderAdapter;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.ConfigurationSource;
+import org.apache.logging.log4j.core.config.Configurator;
+import org.apache.logging.log4j.spi.LoggerContextFactory;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test configuration from XML.
+ */
+public class AsyncAppenderTest {
+
+    @Test
+    public void testAsyncXml() throws Exception {
+        LoggerContext loggerContext = configure("target/test-classes/log4j1-async.xml");
+        Logger logger = LogManager.getLogger("test");
+        logger.debug("This is a test of the root logger");
+        Thread.sleep(50);
+        Configuration configuration = loggerContext.getConfiguration();
+        Map<String, Appender> appenders = configuration.getAppenders();
+        ListAppender messageAppender = null;
+        for (Map.Entry<String, Appender> entry : appenders.entrySet()) {
+            if (entry.getKey().equals("list")) {
+                messageAppender = (ListAppender) ((AppenderAdapter.Adapter) entry.getValue()).getAppender();
+            }
+        }
+        assertNotNull("No Message Appender", messageAppender);
+        List<String> messages = messageAppender.getMessages();
+        assertTrue("No messages", messages != null && messages.size() > 0);
+    }
+
+    @Test
+    public void testAsyncProperties() throws Exception {
+        LoggerContext loggerContext = configure("target/test-classes/log4j1-async.properties");
+        Logger logger = LogManager.getLogger("test");
+        logger.debug("This is a test of the root logger");
+        Thread.sleep(50);
+        Configuration configuration = loggerContext.getConfiguration();
+        Map<String, Appender> appenders = configuration.getAppenders();
+        ListAppender messageAppender = null;
+        for (Map.Entry<String, Appender> entry : appenders.entrySet()) {
+            if (entry.getKey().equals("list")) {
+                messageAppender = (ListAppender) ((AppenderAdapter.Adapter) entry.getValue()).getAppender();
+            }
+        }
+        assertNotNull("No Message Appender", messageAppender);
+        List<String> messages = messageAppender.getMessages();
+        assertTrue("No messages", messages != null && messages.size() > 0);
+    }
+
+
+    private LoggerContext configure(String configLocation) throws Exception {
+        File file = new File(configLocation);
+        InputStream is = new FileInputStream(file);
+        ConfigurationSource source = new ConfigurationSource(is, file);
+        LoggerContextFactory factory = org.apache.logging.log4j.LogManager.getFactory();
+        LoggerContext context = (LoggerContext) org.apache.logging.log4j.LogManager.getContext(false);
+        Configuration configuration;
+        if (configLocation.endsWith(".xml")) {
+            configuration = new XmlConfigurationFactory().getConfiguration(context, source);
+        } else {
+            configuration = new PropertiesConfigurationFactory().getConfiguration(context, source);
+        }
+        assertNotNull("No configuration created", configuration);
+        Configurator.reconfigure(configuration);
+        return context;
+    }
+
+}
diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/config/AutoConfigTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/config/AutoConfigTest.java
new file mode 100644
index 0000000..5b4412d
--- /dev/null
+++ b/log4j-1.2-api/src/test/java/org/apache/log4j/config/AutoConfigTest.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.config;
+
+import org.apache.log4j.ListAppender;
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
+import org.apache.log4j.bridge.AppenderAdapter;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.spi.LoggerContext;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test configuration from XML.
+ */
+public class AutoConfigTest {
+
+    @BeforeClass
+    public static void beforeClass() {
+        System.setProperty(ConfigurationFactory.LOG4J1_EXPERIMENTAL, "true");
+    }
+
+    @Test
+    public void testListAppender() {
+        Logger logger = LogManager.getLogger("test");
+        logger.debug("This is a test of the root logger");
+        LoggerContext loggerContext = org.apache.logging.log4j.LogManager.getContext(false);
+        Configuration configuration = ((org.apache.logging.log4j.core.LoggerContext) loggerContext).getConfiguration();
+        Map<String, Appender> appenders = configuration.getAppenders();
+        ListAppender eventAppender = null;
+        ListAppender messageAppender = null;
+        for (Map.Entry<String, Appender> entry : appenders.entrySet()) {
+            if (entry.getKey().equals("list")) {
+                messageAppender = (ListAppender) ((AppenderAdapter.Adapter) entry.getValue()).getAppender();
+            } else if (entry.getKey().equals("events")) {
+                eventAppender = (ListAppender) ((AppenderAdapter.Adapter) entry.getValue()).getAppender();
+            }
+        }
+        assertNotNull("No Event Appender", eventAppender);
+        assertNotNull("No Message Appender", messageAppender);
+        List<LoggingEvent> events = eventAppender.getEvents();
+        assertTrue("No events", events != null && events.size() > 0);
+        List<String> messages = messageAppender.getMessages();
+        assertTrue("No messages", messages != null && messages.size() > 0);
+    }
+
+}
diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/config/Log4j1ConfigurationFactoryTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/config/Log4j1ConfigurationFactoryTest.java
index 8d3e4e2..ebe3e54 100644
--- a/log4j-1.2-api/src/test/java/org/apache/log4j/config/Log4j1ConfigurationFactoryTest.java
+++ b/log4j-1.2-api/src/test/java/org/apache/log4j/config/Log4j1ConfigurationFactoryTest.java
@@ -174,7 +174,7 @@
         } finally {
 			try {
 				Files.deleteIfExists(tempFilePath);
-			} catch (FileSystemException e) {
+			} catch (final FileSystemException e) {
 				e.printStackTrace();
 			}
         }
diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/config/MapRewriteAppenderTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/config/MapRewriteAppenderTest.java
new file mode 100644
index 0000000..840971a
--- /dev/null
+++ b/log4j-1.2-api/src/test/java/org/apache/log4j/config/MapRewriteAppenderTest.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.config;
+
+import org.apache.log4j.ListAppender;
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
+import org.apache.log4j.bridge.AppenderAdapter;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.logging.log4j.ThreadContext;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.junit.After;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test RewriteAppender
+ */
+public class MapRewriteAppenderTest {
+
+    @BeforeClass
+    public static void beforeClass() {
+        System.setProperty(ConfigurationFactory.LOG4J1_CONFIGURATION_FILE_PROPERTY, "target/test-classes/log4j1-mapRewrite.xml");
+    }
+
+    @After
+    public void after() {
+        ThreadContext.clearMap();
+    }
+
+    @Test
+    public void testRewrite() throws Exception {
+        Logger logger = LogManager.getLogger("test");
+        Map<String, String> map = new HashMap<>();
+        map.put("message", "This is a test");
+        map.put("hello", "world");
+        logger.debug(map);
+        LoggerContext context = (LoggerContext) org.apache.logging.log4j.LogManager.getContext(false);
+        Configuration configuration = context.getConfiguration();
+        Map<String, Appender> appenders = configuration.getAppenders();
+        ListAppender eventAppender = null;
+        for (Map.Entry<String, Appender> entry : appenders.entrySet()) {
+            if (entry.getKey().equals("events")) {
+                eventAppender = (ListAppender) ((AppenderAdapter.Adapter) entry.getValue()).getAppender();
+            }
+        }
+        assertNotNull("No Event Appender", eventAppender);
+        List<LoggingEvent> events = eventAppender.getEvents();
+        assertTrue("No events", events != null && events.size() > 0);
+        assertNotNull("No properties in the event", events.get(0).getProperties());
+        assertTrue("Key was not inserted", events.get(0).getProperties().containsKey("hello"));
+        assertEquals("Key value is incorrect", "world", events.get(0).getProperties().get("hello"));
+    }
+}
diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/config/PropertiesConfigurationFactoryTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/config/PropertiesConfigurationFactoryTest.java
new file mode 100644
index 0000000..de81b63
--- /dev/null
+++ b/log4j-1.2-api/src/test/java/org/apache/log4j/config/PropertiesConfigurationFactoryTest.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.config;
+
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.File;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test configuration from Properties.
+ */
+public class PropertiesConfigurationFactoryTest {
+
+    @BeforeClass
+    public static void beforeClass() {
+        System.setProperty(ConfigurationFactory.LOG4J1_CONFIGURATION_FILE_PROPERTY, "target/test-classes/log4j1-file.properties");
+    }
+
+    @Test
+    public void testProperties() throws Exception {
+        Logger logger = LogManager.getLogger("test");
+        logger.debug("This is a test of the root logger");
+        File file = new File("target/temp.A1");
+        assertTrue("File A1 was not created", file.exists());
+        assertTrue("File A1 is empty", file.length() > 0);
+        file = new File("target/temp.A2");
+        assertTrue("File A2 was not created", file.exists());
+        assertTrue("File A2 is empty", file.length() > 0);
+    }
+
+}
diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/config/PropertiesConfigurationTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/config/PropertiesConfigurationTest.java
new file mode 100644
index 0000000..72ff293
--- /dev/null
+++ b/log4j-1.2-api/src/test/java/org/apache/log4j/config/PropertiesConfigurationTest.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.config;
+
+import org.apache.log4j.ListAppender;
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
+import org.apache.log4j.bridge.AppenderAdapter;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.ConfigurationSource;
+import org.apache.logging.log4j.core.config.Configurator;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test configuration from Properties.
+ */
+public class PropertiesConfigurationTest {
+
+    @Test
+    public void testProperties() throws Exception {
+        configure("target/test-classes/log4j1-file.properties");
+        Logger logger = LogManager.getLogger("test");
+        logger.debug("This is a test of the root logger");
+        File file = new File("target/temp.A1");
+        assertTrue("File A1 was not created", file.exists());
+        assertTrue("File A1 is empty", file.length() > 0);
+        file = new File("target/temp.A2");
+        assertTrue("File A2 was not created", file.exists());
+        assertTrue("File A2 is empty", file.length() > 0);
+    }
+
+    @Test
+    public void testListAppender() throws Exception {
+        LoggerContext loggerContext = configure("target/test-classes/log4j1-list.properties");
+        Logger logger = LogManager.getLogger("test");
+        logger.debug("This is a test of the root logger");
+        Configuration configuration = loggerContext.getConfiguration();
+        Map<String, Appender> appenders = configuration.getAppenders();
+        ListAppender eventAppender = null;
+        ListAppender messageAppender = null;
+        for (Map.Entry<String, Appender> entry : appenders.entrySet()) {
+            if (entry.getKey().equals("list")) {
+                messageAppender = (ListAppender) ((AppenderAdapter.Adapter) entry.getValue()).getAppender();
+            } else if (entry.getKey().equals("events")) {
+                eventAppender = (ListAppender) ((AppenderAdapter.Adapter) entry.getValue()).getAppender();
+            }
+        }
+        assertNotNull("No Event Appender", eventAppender);
+        assertNotNull("No Message Appender", messageAppender);
+        List<LoggingEvent> events = eventAppender.getEvents();
+        assertTrue("No events", events != null && events.size() > 0);
+        List<String> messages = messageAppender.getMessages();
+        assertTrue("No messages", messages != null && messages.size() > 0);
+    }
+
+    private LoggerContext configure(String configLocation) throws Exception {
+        File file = new File(configLocation);
+        InputStream is = new FileInputStream(file);
+        ConfigurationSource source = new ConfigurationSource(is, file);
+        LoggerContext context = (LoggerContext) org.apache.logging.log4j.LogManager.getContext(false);
+        Configuration configuration = new PropertiesConfigurationFactory().getConfiguration(context, source);
+        assertNotNull("No configuration created", configuration);
+        Configurator.reconfigure(configuration);
+        return context;
+    }
+
+}
diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/config/RewriteAppenderTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/config/RewriteAppenderTest.java
new file mode 100644
index 0000000..d7aca5c
--- /dev/null
+++ b/log4j-1.2-api/src/test/java/org/apache/log4j/config/RewriteAppenderTest.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.config;
+
+import org.apache.log4j.ListAppender;
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
+import org.apache.log4j.bridge.AppenderAdapter;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.logging.log4j.ThreadContext;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.junit.After;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test RewriteAppender
+ */
+public class RewriteAppenderTest {
+
+    @BeforeClass
+    public static void beforeClass() {
+        System.setProperty(ConfigurationFactory.LOG4J1_CONFIGURATION_FILE_PROPERTY, "target/test-classes/log4j1-rewrite.xml");
+    }
+
+    @After
+    public void after() {
+        ThreadContext.clearMap();
+    }
+
+    @Test
+    public void testRewrite() throws Exception {
+        Logger logger = LogManager.getLogger("test");
+        ThreadContext.put("key1", "This is a test");
+        ThreadContext.put("hello", "world");
+        logger.debug("Say hello");
+        LoggerContext context = (LoggerContext) org.apache.logging.log4j.LogManager.getContext(false);
+        Configuration configuration = context.getConfiguration();
+        Map<String, Appender> appenders = configuration.getAppenders();
+        ListAppender eventAppender = null;
+        for (Map.Entry<String, Appender> entry : appenders.entrySet()) {
+            if (entry.getKey().equals("events")) {
+                eventAppender = (ListAppender) ((AppenderAdapter.Adapter) entry.getValue()).getAppender();
+            }
+        }
+        assertNotNull("No Event Appender", eventAppender);
+        List<LoggingEvent> events = eventAppender.getEvents();
+        assertTrue("No events", events != null && events.size() > 0);
+        assertNotNull("No properties in the event", events.get(0).getProperties());
+        assertTrue("Key was not inserted", events.get(0).getProperties().containsKey("key2"));
+        assertEquals("Key value is incorrect", "Log4j", events.get(0).getProperties().get("key2"));
+    }
+}
diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/config/SyslogAppenderTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/config/SyslogAppenderTest.java
new file mode 100644
index 0000000..7ccb463
--- /dev/null
+++ b/log4j-1.2-api/src/test/java/org/apache/log4j/config/SyslogAppenderTest.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.config;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.net.mock.MockSyslogServer;
+import org.apache.logging.log4j.core.net.mock.MockSyslogServerFactory;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertNotNull;
+
+
+/**
+ * Class Description goes here.
+ */
+public class SyslogAppenderTest {
+
+    private static final int PORTNUM = 9999;
+    private MockSyslogServer syslogServer;
+
+    @BeforeClass
+    public static void beforeClass() {
+        System.setProperty("log4j.configuration", "target/test-classes/log4j1-syslog.xml");
+    }
+
+    @Before
+    public void setUp() {
+    }
+
+    @After
+    public void teardown() {
+        if (syslogServer != null) {
+            syslogServer.shutdown();
+        }
+    }
+
+    @Test
+    public void sendMessage() throws Exception {
+        initTCPTestEnvironment(null);
+        Logger logger = LogManager.getLogger(SyslogAppenderTest.class);
+        logger.info("This is a test");
+        List<String> messages = null;
+        for (int i = 0; i < 5; ++i) {
+            Thread.sleep(250);
+            messages = syslogServer.getMessageList();
+            if (messages != null && messages.size() > 0) {
+                break;
+            }
+        }
+        assertNotNull("No messages received", messages);
+        assertEquals("Sent message not detected", 1, messages.size());
+    }
+
+
+    protected void initTCPTestEnvironment(final String messageFormat) throws IOException {
+        syslogServer = MockSyslogServerFactory.createTCPSyslogServer(1, PORTNUM);
+        syslogServer.start();
+    }
+}
diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/config/XmlConfigurationFactoryTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/config/XmlConfigurationFactoryTest.java
new file mode 100644
index 0000000..65b8d47
--- /dev/null
+++ b/log4j-1.2-api/src/test/java/org/apache/log4j/config/XmlConfigurationFactoryTest.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.config;
+
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test configuration from XML.
+ */
+public class XmlConfigurationFactoryTest {
+
+    @BeforeClass
+    public static void beforeClass() {
+        System.setProperty(ConfigurationFactory.LOG4J1_CONFIGURATION_FILE_PROPERTY, "target/test-classes/log4j1-file.xml");
+    }
+    @Test
+    public void testXML() throws Exception {
+        Logger logger = LogManager.getLogger("test");
+        logger.debug("This is a test of the root logger");
+        File file = new File("target/temp.A1");
+        assertTrue("File A1 was not created", file.exists());
+        assertTrue("File A1 is empty", file.length() > 0);
+        file = new File("target/temp.A2");
+        assertTrue("File A2 was not created", file.exists());
+        assertTrue("File A2 is empty", file.length() > 0);
+    }
+
+}
diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/config/XmlConfigurationTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/config/XmlConfigurationTest.java
new file mode 100644
index 0000000..c4cc360
--- /dev/null
+++ b/log4j-1.2-api/src/test/java/org/apache/log4j/config/XmlConfigurationTest.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.log4j.config;
+
+import org.apache.log4j.ListAppender;
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
+import org.apache.log4j.bridge.AppenderAdapter;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.ConfigurationSource;
+import org.apache.logging.log4j.core.config.Configurator;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.spi.LoggerContextFactory;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test configuration from XML.
+ */
+public class XmlConfigurationTest {
+
+    @Test
+    public void testXML() throws Exception {
+        configure("target/test-classes/log4j1-file.xml");
+        Logger logger = LogManager.getLogger("test");
+        logger.debug("This is a test of the root logger");
+        File file = new File("target/temp.A1");
+        assertTrue("File A1 was not created", file.exists());
+        assertTrue("File A1 is empty", file.length() > 0);
+        file = new File("target/temp.A2");
+        assertTrue("File A2 was not created", file.exists());
+        assertTrue("File A2 is empty", file.length() > 0);
+    }
+
+    @Test
+    public void testListAppender() throws Exception {
+        LoggerContext loggerContext = configure("target/test-classes/log4j1-list.xml");
+        Logger logger = LogManager.getLogger("test");
+        logger.debug("This is a test of the root logger");
+        Configuration configuration = loggerContext.getConfiguration();
+        Map<String, Appender> appenders = configuration.getAppenders();
+        ListAppender eventAppender = null;
+        ListAppender messageAppender = null;
+        for (Map.Entry<String, Appender> entry : appenders.entrySet()) {
+            if (entry.getKey().equals("list")) {
+                messageAppender = (ListAppender) ((AppenderAdapter.Adapter) entry.getValue()).getAppender();
+            } else if (entry.getKey().equals("events")) {
+                eventAppender = (ListAppender) ((AppenderAdapter.Adapter) entry.getValue()).getAppender();
+            }
+        }
+        assertNotNull("No Event Appender", eventAppender);
+        assertNotNull("No Message Appender", messageAppender);
+        List<LoggingEvent> events = eventAppender.getEvents();
+        assertTrue("No events", events != null && events.size() > 0);
+        List<String> messages = messageAppender.getMessages();
+        assertTrue("No messages", messages != null && messages.size() > 0);
+    }
+
+    private LoggerContext configure(String configLocation) throws Exception {
+        File file = new File(configLocation);
+        InputStream is = new FileInputStream(file);
+        ConfigurationSource source = new ConfigurationSource(is, file);
+        LoggerContextFactory factory = org.apache.logging.log4j.LogManager.getFactory();
+        LoggerContext context = (LoggerContext) org.apache.logging.log4j.LogManager.getContext(false);
+        Configuration configuration = new XmlConfigurationFactory().getConfiguration(context, source);
+        assertNotNull("No configuration created", configuration);
+        Configurator.reconfigure(configuration);
+        return context;
+    }
+
+}
diff --git a/log4j-1.2-api/src/test/resources/log4j.xml b/log4j-1.2-api/src/test/resources/log4j.xml
new file mode 100644
index 0000000..065c748
--- /dev/null
+++ b/log4j-1.2-api/src/test/resources/log4j.xml
@@ -0,0 +1,36 @@
+<?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="list" class="org.apache.log4j.ListAppender">
+    <layout class="org.apache.log4j.PatternLayout">
+      <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n" />
+    </layout>
+  </appender>
+
+  <appender name="events" class="org.apache.log4j.ListAppender">
+  </appender>
+
+  <root>
+    <priority value ="trace" />
+    <appender-ref ref="list" />
+    <appender-ref ref="events" />
+  </root>
+
+</log4j:configuration>
\ No newline at end of file
diff --git a/log4j-1.2-api/src/test/resources/log4j1-async.properties b/log4j-1.2-api/src/test/resources/log4j1-async.properties
new file mode 100644
index 0000000..8e80b46
--- /dev/null
+++ b/log4j-1.2-api/src/test/resources/log4j1-async.properties
@@ -0,0 +1,21 @@
+# 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.
+
+log4j.appender.list=org.apache.log4j.ListAppender
+log4j.appender.list.layout=org.apache.log4j.PatternLayout
+log4j.appender.list.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
+log4j.appender.async=org.apache.log4j.AsyncAppender
+log4j.appender.async.appender-ref=list
+log4j.rootLogger=trace, async
\ No newline at end of file
diff --git a/log4j-1.2-api/src/test/resources/log4j1-async.xml b/log4j-1.2-api/src/test/resources/log4j1-async.xml
new file mode 100644
index 0000000..a0cb7f6
--- /dev/null
+++ b/log4j-1.2-api/src/test/resources/log4j1-async.xml
@@ -0,0 +1,35 @@
+<?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="list" class="org.apache.log4j.ListAppender">
+    <layout class="org.apache.log4j.PatternLayout">
+      <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n" />
+    </layout>
+  </appender>
+  <appender name="async" class="org.apache.log4j.AsyncAppender">
+    <appender-ref ref="list"/>
+  </appender>
+
+  <root>
+    <priority value ="trace" />
+    <appender-ref ref="async" />
+  </root>
+
+</log4j:configuration>
\ No newline at end of file
diff --git a/log4j-1.2-api/src/test/resources/log4j1-file.properties b/log4j-1.2-api/src/test/resources/log4j1-file.properties
new file mode 100644
index 0000000..ee870df
--- /dev/null
+++ b/log4j-1.2-api/src/test/resources/log4j1-file.properties
@@ -0,0 +1,31 @@
+# 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.
+
+log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
+log4j.appender.CONSOLE.Target=System.out
+log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
+log4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
+log4j.appender.A1=org.apache.log4j.FileAppender
+log4j.appender.A1.File=target/temp.A1
+log4j.appender.A1.Append=false
+log4j.appender.A1.layout=org.apache.log4j.PatternLayout
+log4j.appender.A1.layout.ConversionPattern=%-5p %c{2} - %m%n
+log4j.appender.A2=org.apache.log4j.FileAppender
+log4j.appender.A2.File=target/temp.A2
+log4j.appender.A2.Append=false
+log4j.appender.A2.layout=org.apache.log4j.TTCCLayout
+log4j.appender.A2.layout.DateFormat=ISO8601
+log4j.logger.org.apache.log4j.xml=trace, A1
+log4j.rootLogger=trace, A1, A2
\ No newline at end of file
diff --git a/log4j-1.2-api/src/test/resources/log4j1-file.xml b/log4j-1.2-api/src/test/resources/log4j1-file.xml
new file mode 100644
index 0000000..bc7df16
--- /dev/null
+++ b/log4j-1.2-api/src/test/resources/log4j1-file.xml
@@ -0,0 +1,57 @@
+<?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">
+    <param name="Target" value="System.out"/>
+    <layout class="org.apache.log4j.PatternLayout">
+      <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n" />
+    </layout>
+  </appender>
+
+  <appender name="A1" class="org.apache.log4j.FileAppender">
+
+    <param name="File"   value="target/temp.A1" />
+    <param name="Append" value="false" />
+
+    <layout class="org.apache.log4j.PatternLayout">
+      <param name="ConversionPattern" value="%-5p %c{2} - %m%n"/>
+    </layout>
+  </appender>
+
+  <appender name="A2" class="org.apache.log4j.FileAppender">
+    <param name="File" value="target/temp.A2" />
+    <param name="Append" value="false" />
+    <layout class="org.apache.log4j.TTCCLayout">
+      <param name="DateFormat" value="ISO8601" />
+    </layout>
+  </appender>
+
+  <logger name="org.apache.log4j.xml">
+    <level value="trace" />
+    <appender-ref ref="A1" />
+  </logger>
+
+  <root>
+    <priority value ="trace" />
+    <appender-ref ref="A1" />
+    <appender-ref ref="A2" />
+  </root>
+
+</log4j:configuration>
\ No newline at end of file
diff --git a/log4j-1.2-api/src/test/resources/log4j1-list.properties b/log4j-1.2-api/src/test/resources/log4j1-list.properties
new file mode 100644
index 0000000..43d6208
--- /dev/null
+++ b/log4j-1.2-api/src/test/resources/log4j1-list.properties
@@ -0,0 +1,20 @@
+# 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.
+
+log4j.appender.list=org.apache.log4j.ListAppender
+log4j.appender.list.layout=org.apache.log4j.PatternLayout
+log4j.appender.list.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
+log4j.appender.events=org.apache.log4j.ListAppender
+log4j.rootLogger=trace, list, events
\ No newline at end of file
diff --git a/log4j-1.2-api/src/test/resources/log4j1-list.xml b/log4j-1.2-api/src/test/resources/log4j1-list.xml
new file mode 100644
index 0000000..065c748
--- /dev/null
+++ b/log4j-1.2-api/src/test/resources/log4j1-list.xml
@@ -0,0 +1,36 @@
+<?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="list" class="org.apache.log4j.ListAppender">
+    <layout class="org.apache.log4j.PatternLayout">
+      <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n" />
+    </layout>
+  </appender>
+
+  <appender name="events" class="org.apache.log4j.ListAppender">
+  </appender>
+
+  <root>
+    <priority value ="trace" />
+    <appender-ref ref="list" />
+    <appender-ref ref="events" />
+  </root>
+
+</log4j:configuration>
\ No newline at end of file
diff --git a/log4j-1.2-api/src/test/resources/log4j1-maprewrite.xml b/log4j-1.2-api/src/test/resources/log4j1-maprewrite.xml
new file mode 100644
index 0000000..19973f4
--- /dev/null
+++ b/log4j-1.2-api/src/test/resources/log4j1-maprewrite.xml
@@ -0,0 +1,35 @@
+<?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="events" class="org.apache.log4j.ListAppender">
+  </appender>
+
+  <appender name="rewrite" class="org.apache.log4j.rewrite.RewriteAppender">
+    <appender-ref ref="events"/>
+    <rewritePolicy class="org.apache.log4j.rewrite.MapRewritePolicy">
+    </rewritePolicy>
+  </appender>
+
+  <root>
+    <priority value ="trace" />
+    <appender-ref ref="rewrite" />
+  </root>
+
+</log4j:configuration>
\ No newline at end of file
diff --git a/log4j-1.2-api/src/test/resources/log4j1-rewrite.xml b/log4j-1.2-api/src/test/resources/log4j1-rewrite.xml
new file mode 100644
index 0000000..25eb1b5
--- /dev/null
+++ b/log4j-1.2-api/src/test/resources/log4j1-rewrite.xml
@@ -0,0 +1,36 @@
+<?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="events" class="org.apache.log4j.ListAppender">
+  </appender>
+
+  <appender name="rewrite" class="org.apache.log4j.rewrite.RewriteAppender">
+    <appender-ref ref="events"/>
+    <rewritePolicy class="org.apache.log4j.rewrite.PropertyRewritePolicy">
+      <param name="properties" value="key2=Log4j"/>
+    </rewritePolicy>
+  </appender>
+
+  <root>
+    <priority value ="trace" />
+    <appender-ref ref="rewrite" />
+  </root>
+
+</log4j:configuration>
\ No newline at end of file
diff --git a/log4j-1.2-api/src/test/resources/log4j1-syslog.xml b/log4j-1.2-api/src/test/resources/log4j1-syslog.xml
new file mode 100644
index 0000000..4fd96a8
--- /dev/null
+++ b/log4j-1.2-api/src/test/resources/log4j1-syslog.xml
@@ -0,0 +1,36 @@
+<?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="syslog" class="org.apache.log4j.net.SyslogAppender">
+    <param name="SyslogHost" value="localhost:9999"/>
+    <param name="Facility" value="USER"/>
+    <param name="FacilityPrinting" value="true"/>
+    <param name="Threshold" value="DEBUG"/>
+    <layout class="org.apache.log4j.PatternLayout">
+      <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n" />
+    </layout>
+  </appender>
+
+  <root>
+    <priority value ="trace" />
+    <appender-ref ref="syslog" />
+  </root>
+
+</log4j:configuration>
\ No newline at end of file
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/LogManager.java b/log4j-api/src/main/java/org/apache/logging/log4j/LogManager.java
index 2da1e84..45b83ff 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/LogManager.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/LogManager.java
@@ -404,7 +404,7 @@
      *            used and if the caller is a class in the container's classpath then a different LoggerContext may
      *            be used.
      * @param allContexts if true all LoggerContexts that can be located will be shutdown.
-     * @since 3.0
+     * @since 2.13.0
      */
     public static void shutdown(final boolean currentContext, final boolean allContexts) {
         factory.shutdown(FQCN, null, currentContext, allContexts);
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java b/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java
index c4ae445..5318410 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java
@@ -247,6 +247,24 @@
     }
 
     /**
+     * Puts a context value (the <code>value</code> parameter) as identified with the <code>key</code> parameter into
+     * the current thread's context map if the key does not exist.
+     *
+     * <p>
+     * If the current thread does not have a context map it is created as a side effect.
+     * </p>
+     *
+     * @param key The key name.
+     * @param value The key value.
+     * @since 2.13.0
+     */
+    public static void putIfNull(final String key, final String value) {
+        if(!contextMap.containsKey(key)) {
+            contextMap.put(key, value);
+        }
+    }
+
+    /**
      * Puts all given context map entries into the current thread's
      * context map.
      *
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggerContext.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggerContext.java
index 88c3b7e..25b0071 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggerContext.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggerContext.java
@@ -30,6 +30,58 @@
     Object getExternalContext();
 
     /**
+     * Retrieve an object by its name.
+     * @param key The object's key.
+     * @since 2.13.0
+     */
+    default Object getObject(String key) {
+        return null;
+    }
+
+    /**
+     * Store an object into the LoggerContext by name for later use.
+     * @param key The object's key.
+     * @param value The object.
+     * @return The previous object or null.
+     * @since 2.13.0
+     */
+    default Object putObject(String key, Object value) {
+        return null;
+    }
+
+    /**
+     * Store an object into the LoggerContext by name for later use if an object is not already stored with that key.
+     * @param key The object's key.
+     * @param value The object.
+     * @return The previous object or null.
+     * @since 2.13.0
+     */
+    default Object putObjectIfAbsent(String key, Object value) {
+        return null;
+    }
+
+    /**
+     * Remove an object if it is present.
+     * @param key The object's key.
+     * @return The object if it was present, null if it was not.
+     * @since 2.13.0
+     */
+    default Object removeObject(String key) {
+        return null;
+    }
+
+    /**
+     * Remove an object if it is present and the provided object is stored.
+     * @param key The object's key.
+     * @param value The object.
+     * @return The object if it was present, null if it was not.
+     * @since 2.13.0
+     */
+    default boolean removeObject(String key, Object value) {
+        return false;
+    }
+
+    /**
      * Returns an ExtendedLogger.
      * @param name The name of the Logger to return.
      * @return The logger with the specified name.
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggerContextFactory.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggerContextFactory.java
index 14aaa37..3dcee76 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggerContextFactory.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggerContextFactory.java
@@ -31,8 +31,7 @@
      * @param currentContext If true shuts down the current Context, if false shuts down the Context appropriate
      * for the caller if a more appropriate Context can be determined.
      * @param allContexts if true all LoggerContexts that can be located will be shutdown.
-     * @return true if a LoggerContext has been installed, false otherwise.
-     * @since 3.0
+     * @since 2.13.0
      */
     default void shutdown(String fqcn, ClassLoader loader, boolean currentContext, boolean allContexts) {
         if (hasContext(fqcn, loader, currentContext)) {
@@ -50,7 +49,7 @@
      * @param currentContext If true returns the current Context, if false returns the Context appropriate
      * for the caller if a more appropriate Context can be determined.
      * @return true if a LoggerContext has been installed, false otherwise.
-     * @since 3.0
+     * @since 2.13.0
      */
     default boolean hasContext(String fqcn, ClassLoader loader, boolean currentContext) {
         return false;
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java
index 4feb207..6dd01b7 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java
@@ -19,6 +19,9 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.charset.Charset;
+import java.time.Duration;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.TemporalUnit;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -155,6 +158,24 @@
     }
 
     /**
+     * Retrieves a property that may be prefixed by more than one string.
+     * @param prefixes The array of prefixes.
+     * @param key The key to locate.
+     * @param supplier The method to call to derive the default value. If the value is null, null will be returned
+     * if no property is found.
+     * @return The value or null if it is not found.
+     * @since 2.13.0
+     */
+    public Boolean getBooleanProperty(final String[] prefixes, String key, Supplier<Boolean> supplier) {
+        for (String prefix : prefixes) {
+            if (hasProperty(prefix + key)) {
+                return getBooleanProperty(prefix + key);
+            }
+        }
+        return supplier != null ? supplier.get() : null;
+    }
+
+    /**
      * Gets the named property as a Charset value.
      *
      * @param name the name of the property to look up
@@ -232,6 +253,24 @@
     }
 
     /**
+     * Retrieves a property that may be prefixed by more than one string.
+     * @param prefixes The array of prefixes.
+     * @param key The key to locate.
+     * @param supplier The method to call to derive the default value. If the value is null, null will be returned
+     * if no property is found.
+     * @return The value or null if it is not found.
+     * @since 2.13.0
+     */
+    public Integer getIntegerProperty(final String[] prefixes, String key, Supplier<Integer> supplier) {
+        for (String prefix : prefixes) {
+            if (hasProperty(prefix + key)) {
+                return getIntegerProperty(prefix + key, 0);
+            }
+        }
+        return supplier != null ? supplier.get() : null;
+    }
+
+    /**
      * Gets the named property as a long.
      *
      * @param name         the name of the property to look up
@@ -249,6 +288,76 @@
         }
         return defaultValue;
     }
+    /**
+     * Retrieves a property that may be prefixed by more than one string.
+     * @param prefixes The array of prefixes.
+     * @param key The key to locate.
+     * @param supplier The method to call to derive the default value. If the value is null, null will be returned
+     * if no property is found.
+     * @return The value or null if it is not found.
+     * @since 2.13.0
+     */
+    public Long getLongProperty(final String[] prefixes, String key, Supplier<Long> supplier) {
+        for (String prefix : prefixes) {
+            if (hasProperty(prefix + key)) {
+                return getLongProperty(prefix + key, 0);
+            }
+        }
+        return supplier != null ? supplier.get() : null;
+    }
+
+    /**
+     * Retrieves a Duration where the String is of the format nnn[unit] where nnn represents an integer value
+     * and unit represents a time unit.
+     * @param name The property name.
+     * @param defaultValue The default value.
+     * @return The value of the String as a Duration or the default value, which may be null.
+     * @since 2.13.0
+     */
+    public Duration getDurationProperty(final String name, Duration defaultValue) {
+        final String prop = getStringProperty(name);
+        if (prop != null) {
+            return TimeUnit.getDuration(prop);
+        }
+        return defaultValue;
+    }
+
+    /**
+     * Retrieves a property that may be prefixed by more than one string.
+     * @param prefixes The array of prefixes.
+     * @param key The key to locate.
+     * @param supplier The method to call to derive the default value. If the value is null, null will be returned
+     * if no property is found.
+     * @return The value or null if it is not found.
+     * @since 2.13.0
+     */
+    public Duration getDurationProperty(final String[] prefixes, String key, Supplier<Duration> supplier) {
+        for (String prefix : prefixes) {
+            if (hasProperty(prefix + key)) {
+                return getDurationProperty(prefix + key, null);
+            }
+        }
+        return supplier != null ? supplier.get() : null;
+    }
+
+    /**
+     * Retrieves a property that may be prefixed by more than one string.
+     * @param prefixes The array of prefixes.
+     * @param key The key to locate.
+     * @param supplier The method to call to derive the default value. If the value is null, null will be returned
+     * if no property is found.
+     * @return The value or null if it is not found.
+     * @since 2.13.0
+     */
+    public String getStringProperty(final String[] prefixes, String key, Supplier<String> supplier) {
+        for (String prefix : prefixes) {
+            String result = getStringProperty(prefix + key);
+            if (result != null) {
+                return result;
+            }
+        }
+        return supplier != null ? supplier.get() : null;
+    }
 
     /**
      * Gets the named property as a String.
@@ -387,6 +496,11 @@
             if (hasSystemProperty(key)) {
                 return System.getProperty(key);
             }
+            for (final PropertySource source : sources) {
+                if (source.containsProperty(key)) {
+                    return source.getProperty(key);
+                }
+            }
             return tokenized.get(PropertySource.Util.tokenize(key));
         }
 
@@ -463,4 +577,40 @@
         return getStringProperty("os.name", "").startsWith("Windows");
     }
 
+    private enum TimeUnit {
+        NANOS("ns,nano,nanos,nanosecond,nanoseconds", ChronoUnit.NANOS),
+        MICROS("us,micro,micros,microsecond,microseconds", ChronoUnit.MICROS),
+        MILLIS("ms,milli,millis,millsecond,milliseconds", ChronoUnit.MILLIS),
+        SECONDS("s,second,seconds", ChronoUnit.SECONDS),
+        MINUTES("m,minute,minutes", ChronoUnit.MINUTES),
+        HOURS("h,hour,hours", ChronoUnit.HOURS),
+        DAYS("d,day,days", ChronoUnit.DAYS);
+
+        private final String[] descriptions;
+        private final ChronoUnit timeUnit;
+
+        TimeUnit(String descriptions, ChronoUnit timeUnit) {
+            this.descriptions = descriptions.split(",");
+            this.timeUnit = timeUnit;
+        }
+
+        ChronoUnit getTimeUnit() {
+            return this.timeUnit;
+        }
+
+        static Duration getDuration(String time) {
+            String value = time.trim();
+            TemporalUnit temporalUnit = ChronoUnit.MILLIS;
+            long timeVal = 0;
+            for (TimeUnit timeUnit : values()) {
+                for (String suffix : timeUnit.descriptions) {
+                    if (value.endsWith(suffix)) {
+                        temporalUnit = timeUnit.timeUnit;
+                        timeVal = Long.parseLong(value.substring(0, value.length() - suffix.length()));
+                    }
+                }
+            }
+            return Duration.of(timeVal, temporalUnit);
+        }
+    }
 }
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertySource.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertySource.java
index 75399d9..77ccd4b 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertySource.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertySource.java
@@ -45,7 +45,8 @@
      *
      * @param action action to perform on each key/value pair
      */
-    void forEach(BiConsumer<String, String> action);
+    default void forEach(BiConsumer<String, String> action) {
+    }
 
     /**
      * Converts a list of property name tokens into a normal form. For example, a list of tokens such as
@@ -54,7 +55,30 @@
      * @param tokens list of property name tokens
      * @return a normalized property name using the given tokens
      */
-    CharSequence getNormalForm(Iterable<? extends CharSequence> tokens);
+    default CharSequence getNormalForm(Iterable<? extends CharSequence> tokens) {
+        return null;
+    }
+
+    /**
+     * For PropertySources that cannot iterate over all the potential properties this provides a direct lookup.
+     * @param key The key to search for.
+     * @return The value or null;
+     * @since 2.13.0
+     */
+    default String getProperty(String key) {
+        return null;
+    }
+
+
+    /**
+     * For PropertySources that cannot iterate over all the potential properties this provides a direct lookup.
+     * @param key The key to search for.
+     * @return The value or null;
+     * @since 2.13.0
+     */
+    default boolean containsProperty(String key) {
+        return false;
+    }
 
     /**
      * Comparator for ordering PropertySource instances by priority.
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/StringBuilders.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/StringBuilders.java
index 48fa98f..7ae03eb 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/StringBuilders.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/StringBuilders.java
@@ -35,7 +35,9 @@
      * @return {@code "value"}
      */
     public static StringBuilder appendDqValue(final StringBuilder sb, final Object value) {
-        return sb.append(Chars.DQUOTE).append(value).append(Chars.DQUOTE);
+        sb.append(Chars.DQUOTE);
+        appendValue(sb, value);
+        return sb.append(Chars.DQUOTE);
     }
 
     /**
@@ -58,7 +60,8 @@
      * @return the specified StringBuilder
      */
     public static StringBuilder appendKeyDqValue(final StringBuilder sb, final String key, final Object value) {
-        return sb.append(key).append(Chars.EQ).append(Chars.DQUOTE).append(value).append(Chars.DQUOTE);
+        sb.append(key).append(Chars.EQ);
+        return appendDqValue(sb, value);
     }
 
     /**
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/Strings.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/Strings.java
index e285502..f236b61 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/Strings.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/Strings.java
@@ -19,6 +19,7 @@
 import java.util.Iterator;
 import java.util.Locale;
 import java.util.Objects;
+import java.util.Optional;
 
 /**
  * <em>Consider this class private.</em>
@@ -214,6 +215,16 @@
     }
 
     /**
+     * Removes control characters from both ends of this String returning {@code Optional.empty()} if the String is
+     * empty ("") after the trim or if it is {@code null}.
+     *
+     * @see #trimToNull(String)
+     */
+    public static Optional<String> trimToOptional(final String str) {
+        return Optional.ofNullable(str).map(String::trim).filter(s -> !s.isEmpty());
+    }
+
+    /**
      * <p>Joins the elements of the provided {@code Iterable} into
      * a single String containing the provided elements.</p>
      *
diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/ThreadContextTest.java b/log4j-api/src/test/java/org/apache/logging/log4j/ThreadContextTest.java
index baec493..63f21df 100644
--- a/log4j-api/src/test/java/org/apache/logging/log4j/ThreadContextTest.java
+++ b/log4j-api/src/test/java/org/apache/logging/log4j/ThreadContextTest.java
@@ -108,6 +108,18 @@
     }
 
     @Test
+    public void testPutIfNotNull() {
+        ThreadContext.clearMap();
+        assertNull(ThreadContext.get("testKey"));
+        ThreadContext.put("testKey", "testValue");
+        assertEquals("testValue", ThreadContext.get("testKey"));
+        assertEquals("Incorrect value in test key", "testValue", ThreadContext.get("testKey"));
+        ThreadContext.putIfNull("testKey", "new Value");
+        assertEquals("Incorrect value in test key", "testValue", ThreadContext.get("testKey"));
+        ThreadContext.clearMap();
+    }
+
+    @Test
     public void testPutAll() {
         assertTrue(ThreadContext.isEmpty());
         assertFalse(ThreadContext.containsKey("key"));
diff --git a/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/CassandraAppender.java b/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/CassandraAppender.java
index 9df9f97..c017d2e 100644
--- a/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/CassandraAppender.java
+++ b/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/CassandraAppender.java
@@ -27,8 +27,8 @@
 import org.apache.logging.log4j.core.time.Clock;
 import org.apache.logging.log4j.plugins.Plugin;
 import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
 import org.apache.logging.log4j.plugins.PluginElement;
+import org.apache.logging.log4j.plugins.PluginFactory;
 import org.apache.logging.log4j.plugins.validation.constraints.Required;
 
 /**
@@ -45,7 +45,7 @@
         super(name, filter, null, ignoreExceptions, properties, manager);
     }
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static <B extends Builder<B>> B newBuilder() {
         return new Builder<B>().asBuilder();
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/Layout.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/Layout.java
index ba4b4b5..f5bc7f4 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/Layout.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/Layout.java
@@ -98,7 +98,7 @@
     Map<String, String> getContentFormat();
 
     /**
-     * Indiates whether this Layout requires location information.
+     * Indicates whether this Layout requires location information.
      * @return returns true if the Layout requires location information.
      */
     default boolean requiresLocation() {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
index d84ab2a..21cb54e 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
@@ -27,6 +27,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.TimeUnit;
@@ -93,7 +94,8 @@
      * reference is updated.
      */
     private volatile Configuration configuration = new DefaultConfiguration();
-    private Object externalContext;
+    private static final String EXTERNAL_CONTEXT_KEY = "__EXTERNAL_CONTEXT_KEY__";
+    private ConcurrentMap<String, Object> externalMap = new ConcurrentHashMap<>();
     private String contextName;
     private volatile URI configLocation;
     private Cancellable shutdownCallback;
@@ -128,7 +130,11 @@
      */
     public LoggerContext(final String name, final Object externalContext, final URI configLocn) {
         this.contextName = name;
-        this.externalContext = externalContext;
+        if (externalContext == null) {
+            externalMap.remove(EXTERNAL_CONTEXT_KEY);
+        } else {
+            externalMap.put(EXTERNAL_CONTEXT_KEY, externalContext);
+        }
         this.configLocation = configLocn;
     }
 
@@ -142,7 +148,11 @@
      */
     public LoggerContext(final String name, final Object externalContext, final String configLocn) {
         this.contextName = name;
-        this.externalContext = externalContext;
+        if (externalContext == null) {
+            externalMap.remove(EXTERNAL_CONTEXT_KEY);
+        } else {
+            externalMap.put(EXTERNAL_CONTEXT_KEY, externalContext);
+        }
         if (configLocn != null) {
             URI uri;
             try {
@@ -372,7 +382,7 @@
             configuration = NULL_CONFIGURATION;
             updateLoggers();
             ((LifeCycle) prev).stop(timeout, timeUnit);
-            externalContext = null;
+            externalMap.clear();
             LogManager.getFactory().removeContext(this);
         } finally {
             configLock.unlock();
@@ -419,13 +429,42 @@
     	contextName = Objects.requireNonNull(name);
     }
 
+    @Override
+    public Object getObject(String key) {
+        return externalMap.get(key);
+    }
+
+    @Override
+    public Object putObject(String key, Object value) {
+        return externalMap.put(key, value);
+    }
+
+    @Override
+    public Object putObjectIfAbsent(String key, Object value) {
+        return externalMap.putIfAbsent(key, value);
+    }
+
+    @Override
+    public Object removeObject(String key) {
+        return externalMap.remove(key);
+    }
+
+    @Override
+    public boolean removeObject(String key, Object value) {
+        return externalMap.remove(key, value);
+    }
+
     /**
      * Sets the external context.
      *
      * @param context The external context.
      */
     public void setExternalContext(final Object context) {
-        this.externalContext = context;
+        if (context != null) {
+            this.externalMap.put(EXTERNAL_CONTEXT_KEY, context);
+        } else {
+            this.externalMap.remove(EXTERNAL_CONTEXT_KEY);
+        }
     }
 
     /**
@@ -435,7 +474,7 @@
      */
     @Override
     public Object getExternalContext() {
-        return this.externalContext;
+        return this.externalMap.get(EXTERNAL_CONTEXT_KEY);
     }
 
     /**
@@ -637,6 +676,7 @@
      * Reconfigures the context.
      */
     private void reconfigure(final URI configURI) {
+        Object externalContext = externalMap.get(EXTERNAL_CONTEXT_KEY);
         final ClassLoader cl = ClassLoader.class.isInstance(externalContext) ? (ClassLoader) externalContext : null;
         LOGGER.debug("Reconfiguration started for context[name={}] at URI {} ({}) with optional ClassLoader: {}",
                 contextName, configURI, this, cl);
@@ -664,6 +704,17 @@
         reconfigure(configLocation);
     }
 
+    public void reconfigure(Configuration configuration) {
+        setConfiguration(configuration);
+        ConfigurationSource source = configuration.getConfigurationSource();
+        if (source != null) {
+            URI uri = source.getURI();
+            if (uri != null) {
+                configLocation = uri;
+            }
+        }
+    }
+
     /**
      * Causes all Loggers to be updated against the current Configuration.
      */
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractAppender.java
index ebfe279..d1c171b 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractAppender.java
@@ -136,6 +136,35 @@
         this.ignoreExceptions = ignoreExceptions;
     }
 
+    /**
+     * Constructor that defaults to suppressing exceptions.
+     *
+     * @param name The Appender name.
+     * @param filter The Filter to associate with the Appender.
+     * @param layout The layout to use to format the event.
+     * @deprecated Use {@link #AbstractAppender(String, Filter, Layout, boolean, Property[])}.
+     */
+    @Deprecated
+    protected AbstractAppender(final String name, final Filter filter, final Layout<? extends Serializable> layout) {
+        this(name, filter, layout, true, Property.EMPTY_ARRAY);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param name The Appender name.
+     * @param filter The Filter to associate with the Appender.
+     * @param layout The layout to use to format the event.
+     * @param ignoreExceptions If true, exceptions will be logged and suppressed. If false errors will be logged and
+     *            then passed to the application.
+     * @deprecated Use {@link #AbstractAppender(String, Filter, Layout, boolean, Property[])}
+     */
+    @Deprecated
+    protected AbstractAppender(final String name, final Filter filter, final Layout<? extends Serializable> layout,
+            final boolean ignoreExceptions) {
+        this(name, filter, layout, ignoreExceptions, Property.EMPTY_ARRAY);
+    }
+
     public static int parseInt(final String s, final int defaultValue) {
         try {
             return Integers.parseInt(s, defaultValue);
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AppenderSet.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AppenderSet.java
index ff1e074..b592738 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AppenderSet.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AppenderSet.java
@@ -16,21 +16,21 @@
  */
 package org.apache.logging.log4j.core.appender;
 
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
 import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.Core;
 import org.apache.logging.log4j.core.config.Configuration;
 import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
 import org.apache.logging.log4j.plugins.Node;
 import org.apache.logging.log4j.plugins.Plugin;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
+import org.apache.logging.log4j.plugins.PluginFactory;
 import org.apache.logging.log4j.plugins.PluginNode;
 import org.apache.logging.log4j.plugins.validation.constraints.Required;
 import org.apache.logging.log4j.status.StatusLogger;
 
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
 /**
  * A deferred plugin for appenders.
  */
@@ -104,7 +104,7 @@
     private final Configuration configuration;
     private final Map<String, Node> nodeMap;
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static Builder newBuilder() {
         return new Builder();
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java
index 361ce15..0ea5ae6 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java
@@ -16,14 +16,6 @@
  */
 package org.apache.logging.log4j.core.appender;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TransferQueue;
-import java.util.concurrent.atomic.AtomicLong;
-
 import org.apache.logging.log4j.core.AbstractLogEvent;
 import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.Core;
@@ -42,18 +34,26 @@
 import org.apache.logging.log4j.core.config.Configuration;
 import org.apache.logging.log4j.core.config.ConfigurationException;
 import org.apache.logging.log4j.core.config.Property;
-import org.apache.logging.log4j.plugins.Plugin;
-import org.apache.logging.log4j.plugins.PluginAliases;
-import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
 import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
-import org.apache.logging.log4j.plugins.PluginElement;
-import org.apache.logging.log4j.plugins.validation.constraints.Required;
 import org.apache.logging.log4j.core.filter.AbstractFilterable;
 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
 import org.apache.logging.log4j.core.util.Log4jThread;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.plugins.PluginAliases;
+import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
+import org.apache.logging.log4j.plugins.PluginElement;
+import org.apache.logging.log4j.plugins.PluginFactory;
+import org.apache.logging.log4j.plugins.validation.constraints.Required;
 import org.apache.logging.log4j.spi.AbstractLogger;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TransferQueue;
+import java.util.concurrent.atomic.AtomicLong;
+
 /**
  * Appends to one or more Appenders asynchronously. You can configure an AsyncAppender with one or more Appenders and an
  * Appender to append to if the queue is full. The AsyncAppender does not allow a filter to be specified on the Appender
@@ -239,7 +239,7 @@
         }
     }
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static Builder newBuilder() {
         return new Builder();
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java
index e563806..3a150cf 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java
@@ -21,17 +21,23 @@
 import org.apache.logging.log4j.core.Filter;
 import org.apache.logging.log4j.core.Layout;
 import org.apache.logging.log4j.core.config.Property;
-import org.apache.logging.log4j.plugins.Plugin;
-import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
-import org.apache.logging.log4j.plugins.validation.constraints.Required;
 import org.apache.logging.log4j.core.util.CloseShieldOutputStream;
 import org.apache.logging.log4j.core.util.Loader;
 import org.apache.logging.log4j.core.util.Throwables;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
+import org.apache.logging.log4j.plugins.PluginFactory;
+import org.apache.logging.log4j.plugins.validation.constraints.Required;
 import org.apache.logging.log4j.util.Chars;
 import org.apache.logging.log4j.util.PropertiesUtil;
 
-import java.io.*;
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.Serializable;
+import java.io.UnsupportedEncodingException;
 import java.lang.reflect.Constructor;
 import java.nio.charset.Charset;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -100,7 +106,7 @@
                 getDefaultManager(DEFAULT_TARGET, false, false, layout), true, DEFAULT_TARGET, null);
     }
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static <B extends Builder<B>> B newBuilder() {
         return new Builder<B>().asBuilder();
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/CountingNoOpAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/CountingNoOpAppender.java
index 51e4d3b..e5628f4 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/CountingNoOpAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/CountingNoOpAppender.java
@@ -53,7 +53,7 @@
      * Creates a CountingNoOp Appender.
      */
     @PluginFactory
-    public static CountingNoOpAppender createAppender(@PluginAttribute("name") final String name) {
+    public static CountingNoOpAppender createAppender(@PluginAttribute final String name) {
         return new CountingNoOpAppender(Objects.requireNonNull(name), null);
     }
 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/FailoverAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/FailoverAppender.java
index e907fe3..7cab755 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/FailoverAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/FailoverAppender.java
@@ -37,6 +37,7 @@
 import org.apache.logging.log4j.plugins.PluginFactory;
 import org.apache.logging.log4j.core.util.Booleans;
 import org.apache.logging.log4j.core.util.Constants;
+import org.apache.logging.log4j.plugins.validation.constraints.Required;
 
 /**
  * The FailoverAppender will capture exceptions in an Appender and then route the event
@@ -182,38 +183,22 @@
      */
     @PluginFactory
     public static FailoverAppender createAppender(
-            @PluginAttribute("name") final String name,
-            @PluginAttribute("primary") final String primary,
-            @PluginElement("Failovers") final String[] failovers,
+            @PluginAttribute @Required(message = "A name for the Appender must be specified") final String name,
+            @PluginAttribute @Required(message = "A primary Appender must be specified") final String primary,
+            @PluginElement @Required(message = "At least one failover Appender must be specified") final String[] failovers,
             @PluginAliases("retryInterval") // deprecated
-            @PluginAttribute("retryIntervalSeconds") final String retryIntervalSeconds,
+            @PluginAttribute(defaultInt = DEFAULT_INTERVAL_SECONDS) final int retryIntervalSeconds,
             @PluginConfiguration final Configuration config,
-            @PluginElement("Filter") final Filter filter,
-            @PluginAttribute("ignoreExceptions") final String ignore) {
-        if (name == null) {
-            LOGGER.error("A name for the Appender must be specified");
-            return null;
-        }
-        if (primary == null) {
-            LOGGER.error("A primary Appender must be specified");
-            return null;
-        }
-        if (failovers == null || failovers.length == 0) {
-            LOGGER.error("At least one failover Appender must be specified");
-            return null;
-        }
+            @PluginElement final Filter filter,
+            @PluginAttribute(defaultBoolean = true) final boolean ignoreExceptions) {
 
-        final int seconds = parseInt(retryIntervalSeconds, DEFAULT_INTERVAL_SECONDS);
         int retryIntervalMillis;
-        if (seconds >= 0) {
-            retryIntervalMillis = seconds * Constants.MILLIS_IN_SECONDS;
+        if (retryIntervalSeconds >= 0) {
+            retryIntervalMillis = retryIntervalSeconds * Constants.MILLIS_IN_SECONDS;
         } else {
-            LOGGER.warn("Interval " + retryIntervalSeconds + " is less than zero. Using default");
+            LOGGER.warn("Interval {} is less than zero. Using default", retryIntervalSeconds);
             retryIntervalMillis = DEFAULT_INTERVAL_SECONDS * Constants.MILLIS_IN_SECONDS;
         }
-
-        final boolean ignoreExceptions = Booleans.parseBoolean(ignore, true);
-
         return new FailoverAppender(name, filter, primary, failovers, retryIntervalMillis, config, ignoreExceptions, Property.EMPTY_ARRAY);
     }
 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/FileAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/FileAppender.java
index b9e4168..70f12f8 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/FileAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/FileAppender.java
@@ -16,21 +16,21 @@
  */
 package org.apache.logging.log4j.core.appender;
 
-import java.io.Serializable;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-
 import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.Core;
 import org.apache.logging.log4j.core.Filter;
 import org.apache.logging.log4j.core.Layout;
 import org.apache.logging.log4j.core.config.Property;
+import org.apache.logging.log4j.core.net.Advertiser;
 import org.apache.logging.log4j.plugins.Plugin;
 import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
+import org.apache.logging.log4j.plugins.PluginFactory;
 import org.apache.logging.log4j.plugins.validation.constraints.Required;
-import org.apache.logging.log4j.core.net.Advertiser;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
 
 /**
  * File Appender.
@@ -185,7 +185,7 @@
     
     private static final int DEFAULT_BUFFER_SIZE = 8192;
     
-    @PluginBuilderFactory
+    @PluginFactory
     public static <B extends Builder<B>> B newBuilder() {
         return new Builder<B>().asBuilder();
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/HttpAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/HttpAppender.java
index 4a2cc47..4c2dfe6 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/HttpAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/HttpAppender.java
@@ -17,11 +17,6 @@
 
 package org.apache.logging.log4j.core.appender;
 
-import java.io.Serializable;
-import java.net.URL;
-import java.util.Objects;
-import java.util.concurrent.TimeUnit;
-
 import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.Filter;
 import org.apache.logging.log4j.core.Layout;
@@ -31,10 +26,15 @@
 import org.apache.logging.log4j.plugins.Node;
 import org.apache.logging.log4j.plugins.Plugin;
 import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
 import org.apache.logging.log4j.plugins.PluginElement;
+import org.apache.logging.log4j.plugins.PluginFactory;
 import org.apache.logging.log4j.plugins.validation.constraints.Required;
 
+import java.io.Serializable;
+import java.net.URL;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
 
 /**
  * Sends log events over HTTP.
@@ -145,7 +145,7 @@
     /**
      * @return a builder for a HttpAppender.
      */
-    @PluginBuilderFactory
+    @PluginFactory
     public static <B extends Builder<B>> B newBuilder() {
         return new Builder<B>().asBuilder();
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/MemoryMappedFileAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/MemoryMappedFileAppender.java
index 1e9c63f..105d4c8 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/MemoryMappedFileAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/MemoryMappedFileAppender.java
@@ -16,22 +16,22 @@
  */
 package org.apache.logging.log4j.core.appender;
 
-import java.io.Serializable;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-
 import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.Core;
 import org.apache.logging.log4j.core.Filter;
 import org.apache.logging.log4j.core.Layout;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.config.Property;
-import org.apache.logging.log4j.plugins.Plugin;
-import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
 import org.apache.logging.log4j.core.net.Advertiser;
 import org.apache.logging.log4j.core.util.Integers;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
+import org.apache.logging.log4j.plugins.PluginFactory;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Memory Mapped File Appender.
@@ -187,7 +187,7 @@
         return getManager().getRegionLength();
     }
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static <B extends Builder<B>> B newBuilder() {
         return new Builder<B>().asBuilder();
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/NullAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/NullAppender.java
index 0aa4ced..f84e04c 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/NullAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/NullAppender.java
@@ -35,7 +35,7 @@
 
     @PluginFactory
     public static NullAppender createAppender(
-            @PluginAttribute(value = "name", defaultString = "null") final String name) {
+            @PluginAttribute(defaultString = "null") final String name) {
         return new NullAppender(name);
     }
 
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
index f8bf4d8..4fa88c7 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamAppender.java
@@ -16,9 +16,6 @@
  */

 package org.apache.logging.log4j.core.appender;

 

-import java.io.OutputStream;

-import java.io.Serializable;

-

 import org.apache.logging.log4j.core.Appender;

 import org.apache.logging.log4j.core.Core;

 import org.apache.logging.log4j.core.Filter;

@@ -28,9 +25,11 @@
 import org.apache.logging.log4j.core.util.CloseShieldOutputStream;

 import org.apache.logging.log4j.core.util.NullOutputStream;

 import org.apache.logging.log4j.plugins.Plugin;

-import org.apache.logging.log4j.plugins.PluginBuilderFactory;

 import org.apache.logging.log4j.plugins.PluginFactory;

 

+import java.io.OutputStream;

+import java.io.Serializable;

+

 /**

  * Appends log events to a given output stream using a layout.

  * <p>

@@ -160,7 +159,7 @@
         return OutputStreamManager.getManager(managerName, new FactoryData(os, managerName, layout), factory);

     }

 

-    @PluginBuilderFactory

+    @PluginFactory

     public static <B extends Builder<B>> B newBuilder() {

         return new Builder<B>().asBuilder();

     }

diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RandomAccessFileAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RandomAccessFileAppender.java
index e333248..6e63f71 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RandomAccessFileAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RandomAccessFileAppender.java
@@ -16,20 +16,20 @@
  */
 package org.apache.logging.log4j.core.appender;
 
-import java.io.Serializable;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-
 import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.Core;
 import org.apache.logging.log4j.core.Filter;
 import org.apache.logging.log4j.core.Layout;
 import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.net.Advertiser;
 import org.apache.logging.log4j.plugins.Plugin;
 import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
-import org.apache.logging.log4j.core.net.Advertiser;
+import org.apache.logging.log4j.plugins.PluginFactory;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
 
 /**
  * File Appender.
@@ -177,7 +177,7 @@
      * Creates a builder for a RandomAccessFileAppender.
      * @return a builder for a RandomAccessFileAppender.
      */
-    @PluginBuilderFactory
+    @PluginFactory
     public static <B extends Builder<B>> B newBuilder() {
         return new Builder<B>().asBuilder();
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingFileAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingFileAppender.java
index a1afb46..5e02fae 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingFileAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingFileAppender.java
@@ -16,12 +16,6 @@
  */
 package org.apache.logging.log4j.core.appender;
 
-import java.io.Serializable;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-import java.util.zip.Deflater;
-
 import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.Core;
 import org.apache.logging.log4j.core.Filter;
@@ -33,12 +27,18 @@
 import org.apache.logging.log4j.core.appender.rolling.RollingFileManager;
 import org.apache.logging.log4j.core.appender.rolling.RolloverStrategy;
 import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
+import org.apache.logging.log4j.core.net.Advertiser;
 import org.apache.logging.log4j.plugins.Plugin;
 import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
 import org.apache.logging.log4j.plugins.PluginElement;
+import org.apache.logging.log4j.plugins.PluginFactory;
 import org.apache.logging.log4j.plugins.validation.constraints.Required;
-import org.apache.logging.log4j.core.net.Advertiser;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.zip.Deflater;
 
 /**
  * An appender that writes to files and can roll over at intervals.
@@ -337,7 +337,7 @@
      * @return a new Builder.
      * @since 2.7
      */
-    @PluginBuilderFactory
+    @PluginFactory
     public static <B extends Builder<B>> B newBuilder() {
         return new Builder<B>().asBuilder();
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingRandomAccessFileAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingRandomAccessFileAppender.java
index 6a59d41..e24bc9f 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingRandomAccessFileAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingRandomAccessFileAppender.java
@@ -16,12 +16,6 @@
  */
 package org.apache.logging.log4j.core.appender;
 
-import java.io.Serializable;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-import java.util.zip.Deflater;
-
 import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.Core;
 import org.apache.logging.log4j.core.Filter;
@@ -33,11 +27,17 @@
 import org.apache.logging.log4j.core.appender.rolling.RollingRandomAccessFileManager;
 import org.apache.logging.log4j.core.appender.rolling.RolloverStrategy;
 import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
+import org.apache.logging.log4j.core.net.Advertiser;
 import org.apache.logging.log4j.plugins.Plugin;
 import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
 import org.apache.logging.log4j.plugins.PluginElement;
-import org.apache.logging.log4j.core.net.Advertiser;
+import org.apache.logging.log4j.plugins.PluginFactory;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.zip.Deflater;
 
 /**
  * An appender that writes to random access files and can roll over at
@@ -273,7 +273,7 @@
         return getManager().getBufferSize();
     }
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static <B extends Builder<B>> B newBuilder() {
         return new Builder<B>().asBuilder();
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/ScriptAppenderSelector.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/ScriptAppenderSelector.java
index 13df86d..cfcf580 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/ScriptAppenderSelector.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/ScriptAppenderSelector.java
@@ -16,11 +16,6 @@
  */
 package org.apache.logging.log4j.core.appender;
 
-import java.io.Serializable;
-import java.util.Objects;
-
-import javax.script.Bindings;
-
 import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.Core;
 import org.apache.logging.log4j.core.Filter;
@@ -28,14 +23,18 @@
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.config.Configuration;
 import org.apache.logging.log4j.core.config.Property;
-import org.apache.logging.log4j.plugins.Plugin;
-import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
 import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
-import org.apache.logging.log4j.plugins.PluginElement;
-import org.apache.logging.log4j.plugins.validation.constraints.Required;
 import org.apache.logging.log4j.core.script.AbstractScript;
 import org.apache.logging.log4j.core.script.ScriptManager;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
+import org.apache.logging.log4j.plugins.PluginElement;
+import org.apache.logging.log4j.plugins.PluginFactory;
+import org.apache.logging.log4j.plugins.validation.constraints.Required;
+
+import javax.script.Bindings;
+import java.io.Serializable;
+import java.util.Objects;
 
 @Plugin(name = "ScriptAppenderSelector", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE, printObject = true)
 public class ScriptAppenderSelector extends AbstractAppender {
@@ -128,7 +127,7 @@
 
     }
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static Builder newBuilder() {
         return new Builder();
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SocketAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SocketAppender.java
index 5a90fc1..ec2041b 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SocketAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SocketAppender.java
@@ -16,11 +16,6 @@
  */
 package org.apache.logging.log4j.core.appender;
 
-import java.io.Serializable;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-
 import org.apache.logging.log4j.core.AbstractLifeCycle;
 import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.Core;
@@ -38,11 +33,16 @@
 import org.apache.logging.log4j.plugins.Plugin;
 import org.apache.logging.log4j.plugins.PluginAliases;
 import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
 import org.apache.logging.log4j.plugins.PluginElement;
+import org.apache.logging.log4j.plugins.PluginFactory;
 import org.apache.logging.log4j.plugins.validation.constraints.ValidHost;
 import org.apache.logging.log4j.plugins.validation.constraints.ValidPort;
 
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
 /**
  * An Appender that delivers events over socket connections. Supports both TCP and UDP.
  */
@@ -222,7 +222,7 @@
         }
     }
     
-    @PluginBuilderFactory
+    @PluginFactory
     public static Builder newBuilder() {
         return new Builder();
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SyslogAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SyslogAppender.java
index ada063e..dec5c5e 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SyslogAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SyslogAppender.java
@@ -16,19 +16,11 @@
  */
 package org.apache.logging.log4j.core.appender;
 
-import java.io.Serializable;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-
 import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.Core;
 import org.apache.logging.log4j.core.Filter;
 import org.apache.logging.log4j.core.Layout;
 import org.apache.logging.log4j.core.config.Configuration;
-import org.apache.logging.log4j.plugins.Plugin;
-import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
-import org.apache.logging.log4j.plugins.PluginElement;
 import org.apache.logging.log4j.core.layout.LoggerFields;
 import org.apache.logging.log4j.core.layout.Rfc5424Layout;
 import org.apache.logging.log4j.core.layout.SyslogLayout;
@@ -38,6 +30,14 @@
 import org.apache.logging.log4j.core.net.Protocol;
 import org.apache.logging.log4j.core.net.ssl.SslConfiguration;
 import org.apache.logging.log4j.core.util.Constants;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
+import org.apache.logging.log4j.plugins.PluginElement;
+import org.apache.logging.log4j.plugins.PluginFactory;
+
+import java.io.Serializable;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
 
 /**
  * The Syslog Appender.
@@ -310,7 +310,7 @@
     }
 
     // Calling this method newBuilder() does not compile
-    @PluginBuilderFactory
+    @PluginFactory
     public static <B extends Builder<B>> B newSyslogAppenderBuilder() {
         return new Builder<B>().asBuilder();
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/WriterAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/WriterAppender.java
index c27ef72..496d83e 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/WriterAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/WriterAppender.java
@@ -16,18 +16,17 @@
  */
 package org.apache.logging.log4j.core.appender;
 
-import java.io.Writer;
-
 import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.Core;
 import org.apache.logging.log4j.core.Filter;
 import org.apache.logging.log4j.core.StringLayout;
 import org.apache.logging.log4j.core.config.Property;
-import org.apache.logging.log4j.plugins.Plugin;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
-import org.apache.logging.log4j.plugins.PluginFactory;
 import org.apache.logging.log4j.core.layout.PatternLayout;
 import org.apache.logging.log4j.core.util.CloseShieldWriter;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.plugins.PluginFactory;
+
+import java.io.Writer;
 
 /**
  * Appends log events to a {@link Writer}.
@@ -147,7 +146,7 @@
         return WriterManager.getManager(managerName, new FactoryData(writer, managerName, layout), factory);
     }
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static <B extends Builder<B>> B newBuilder() {
         return new Builder<B>().asBuilder();
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManager.java
index c555df0..fd61dfb 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManager.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManager.java
@@ -44,7 +44,7 @@
          * Constructs the base factory data.
          *
          * @param bufferSize The size of the buffer.
-         * @param bufferSize The appender-level layout
+         * @param layout The appender-level layout
          */
         protected AbstractFactoryData(final int bufferSize, final Layout<? extends Serializable> layout) {
             this.bufferSize = bufferSize;
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/ColumnMapping.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/ColumnMapping.java
index 6b25301..740ebc8 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/ColumnMapping.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/ColumnMapping.java
@@ -16,25 +16,25 @@
  */
 package org.apache.logging.log4j.core.appender.db;
 
-import java.util.Date;
-import java.util.Locale;
-
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.Core;
 import org.apache.logging.log4j.core.StringLayout;
 import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
+import org.apache.logging.log4j.core.layout.PatternLayout;
 import org.apache.logging.log4j.plugins.Plugin;
 import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
-import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
 import org.apache.logging.log4j.plugins.PluginElement;
+import org.apache.logging.log4j.plugins.PluginFactory;
 import org.apache.logging.log4j.plugins.validation.constraints.Required;
-import org.apache.logging.log4j.core.layout.PatternLayout;
 import org.apache.logging.log4j.spi.ThreadContextMap;
 import org.apache.logging.log4j.spi.ThreadContextStack;
 import org.apache.logging.log4j.status.StatusLogger;
 import org.apache.logging.log4j.util.ReadOnlyStringMap;
 
+import java.util.Date;
+import java.util.Locale;
+
 /**
  * A configuration element for specifying a database column name mapping.
  *
@@ -190,7 +190,7 @@
 
     private static final Logger LOGGER = StatusLogger.getLogger();
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static Builder newBuilder() {
         return new Builder();
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/nosql/NoSqlAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/nosql/NoSqlAppender.java
index 7055e11..8819040 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/nosql/NoSqlAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/nosql/NoSqlAppender.java
@@ -16,8 +16,6 @@
  */
 package org.apache.logging.log4j.core.appender.nosql;
 
-import java.io.Serializable;
-
 import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.Filter;
 import org.apache.logging.log4j.core.Layout;
@@ -26,8 +24,10 @@
 import org.apache.logging.log4j.core.config.Property;
 import org.apache.logging.log4j.plugins.Plugin;
 import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
 import org.apache.logging.log4j.plugins.PluginElement;
+import org.apache.logging.log4j.plugins.PluginFactory;
+
+import java.io.Serializable;
 
 /**
  * This Appender writes logging events to a NoSQL database using a configured NoSQL provider. It requires
@@ -107,7 +107,7 @@
         }
     }
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static <B extends Builder<B>> B newBuilder() {
         return new Builder<B>().asBuilder();
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rewrite/MapRewritePolicy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rewrite/MapRewritePolicy.java
index 1082573..0072d29 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rewrite/MapRewritePolicy.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rewrite/MapRewritePolicy.java
@@ -127,7 +127,7 @@
      */
     @PluginFactory
     public static MapRewritePolicy createPolicy(
-            @PluginAttribute("mode") final String mode,
+            @PluginAttribute final String mode,
             @PluginElement("KeyValuePair") final KeyValuePair[] pairs) {
         Mode op = mode == null ? op = Mode.Add : Mode.valueOf(mode);
         if (pairs == null || pairs.length == 0) {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rewrite/RewriteAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rewrite/RewriteAppender.java
index 5e2661f..3d8aa26 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rewrite/RewriteAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rewrite/RewriteAppender.java
@@ -33,7 +33,7 @@
 import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
 import org.apache.logging.log4j.plugins.PluginElement;
 import org.apache.logging.log4j.plugins.PluginFactory;
-import org.apache.logging.log4j.core.util.Booleans;
+import org.apache.logging.log4j.plugins.validation.constraints.Required;
 
 /**
  * This Appender allows the logging event to be manipulated before it is processed by other Appenders.
@@ -98,22 +98,12 @@
      */
     @PluginFactory
     public static RewriteAppender createAppender(
-            @PluginAttribute("name") final String name,
-            @PluginAttribute("ignoreExceptions") final String ignore,
-            @PluginElement("AppenderRef") final AppenderRef[] appenderRefs,
+            @PluginAttribute @Required(message = "No name provided for RewriteAppender") final String name,
+            @PluginAttribute(defaultBoolean = true) final boolean ignoreExceptions,
+            @PluginElement @Required(message = "No appender references defined for RewriteAppender") final AppenderRef[] appenderRefs,
             @PluginConfiguration final Configuration config,
-            @PluginElement("RewritePolicy") final RewritePolicy rewritePolicy,
-            @PluginElement("Filter") final Filter filter) {
-
-        final boolean ignoreExceptions = Booleans.parseBoolean(ignore, true);
-        if (name == null) {
-            LOGGER.error("No name provided for RewriteAppender");
-            return null;
-        }
-        if (appenderRefs == null) {
-            LOGGER.error("No appender references defined for RewriteAppender");
-            return null;
-        }
+            @PluginElement final RewritePolicy rewritePolicy,
+            @PluginElement final Filter filter) {
         return new RewriteAppender(name, filter, ignoreExceptions, appenderRefs, rewritePolicy, config, Property.EMPTY_ARRAY);
     }
 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/AbstractRolloverStrategy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/AbstractRolloverStrategy.java
index a69e220..9b46168 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/AbstractRolloverStrategy.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/AbstractRolloverStrategy.java
@@ -91,14 +91,16 @@
         final StringBuilder buf = new StringBuilder();
         final String pattern = manager.getPatternProcessor().getPattern();
         manager.getPatternProcessor().formatFileName(strSubstitutor, buf, NotANumber.NAN);
-        return getEligibleFiles(buf.toString(), pattern, isAscending);
+        final String fileName = manager.isDirectWrite() ? "" : manager.getFileName();
+        return getEligibleFiles(fileName, buf.toString(), pattern, isAscending);
     }
 
     protected SortedMap<Integer, Path> getEligibleFiles(final String path, final String pattern) {
-        return getEligibleFiles(path, pattern, true);
+        return getEligibleFiles("", path, pattern, true);
     }
 
-    protected SortedMap<Integer, Path> getEligibleFiles(final String path, final String logfilePattern, final boolean isAscending) {
+    protected SortedMap<Integer, Path> getEligibleFiles(final String currentFile, final String path,
+            final String logfilePattern, final boolean isAscending) {
         final TreeMap<Integer, Path> eligibleFiles = new TreeMap<>();
         final File file = new File(path);
         File parent = file.getParentFile();
@@ -118,11 +120,13 @@
         }
         final String filePattern = fileName.replace(NotANumber.VALUE, "(\\d+)");
         final Pattern pattern = Pattern.compile(filePattern);
+        final Path current = currentFile.length() > 0 ? new File(currentFile).toPath() : null;
+        LOGGER.debug("Current file: {}", currentFile);
 
         try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
             for (final Path entry: stream) {
                 final Matcher matcher = pattern.matcher(entry.toFile().getName());
-                if (matcher.matches()) {
+                if (matcher.matches() && !entry.equals(current)) {
                     final Integer index = Integer.parseInt(matcher.group(1));
                     eligibleFiles.put(index, entry);
                 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/CronTriggeringPolicy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/CronTriggeringPolicy.java
index 03cf69b..1dbc119 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/CronTriggeringPolicy.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/CronTriggeringPolicy.java
@@ -120,8 +120,8 @@
      */
     @PluginFactory
     public static CronTriggeringPolicy createPolicy(@PluginConfiguration final Configuration configuration,
-            @PluginAttribute("evaluateOnStartup") final String evaluateOnStartup,
-            @PluginAttribute("schedule") final String schedule) {
+            @PluginAttribute final String evaluateOnStartup,
+            @PluginAttribute final String schedule) {
         CronExpression cronExpression;
         final boolean checkOnStartup = Boolean.parseBoolean(evaluateOnStartup);
         if (schedule == null) {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DefaultRolloverStrategy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DefaultRolloverStrategy.java
index 4b27223..182afcb 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DefaultRolloverStrategy.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DefaultRolloverStrategy.java
@@ -16,6 +16,21 @@
  */
 package org.apache.logging.log4j.core.appender.rolling;
 
+import org.apache.logging.log4j.core.Core;
+import org.apache.logging.log4j.core.appender.rolling.action.Action;
+import org.apache.logging.log4j.core.appender.rolling.action.CompositeAction;
+import org.apache.logging.log4j.core.appender.rolling.action.FileRenameAction;
+import org.apache.logging.log4j.core.appender.rolling.action.PathCondition;
+import org.apache.logging.log4j.core.appender.rolling.action.PosixViewAttributeAction;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
+import org.apache.logging.log4j.core.lookup.StrSubstitutor;
+import org.apache.logging.log4j.core.util.Integers;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
+import org.apache.logging.log4j.plugins.PluginElement;
+import org.apache.logging.log4j.plugins.PluginFactory;
+
 import java.io.File;
 import java.io.IOException;
 import java.nio.file.Files;
@@ -28,21 +43,6 @@
 import java.util.concurrent.TimeUnit;
 import java.util.zip.Deflater;
 
-import org.apache.logging.log4j.core.Core;
-import org.apache.logging.log4j.core.appender.rolling.action.Action;
-import org.apache.logging.log4j.core.appender.rolling.action.CompositeAction;
-import org.apache.logging.log4j.core.appender.rolling.action.FileRenameAction;
-import org.apache.logging.log4j.core.appender.rolling.action.PathCondition;
-import org.apache.logging.log4j.core.appender.rolling.action.PosixViewAttributeAction;
-import org.apache.logging.log4j.core.config.Configuration;
-import org.apache.logging.log4j.plugins.Plugin;
-import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
-import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
-import org.apache.logging.log4j.plugins.PluginElement;
-import org.apache.logging.log4j.core.lookup.StrSubstitutor;
-import org.apache.logging.log4j.core.util.Integers;
-
 /**
  * When rolling over, <code>DefaultRolloverStrategy</code> renames files according to an algorithm as described below.
  *
@@ -268,7 +268,7 @@
         }
     }
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static Builder newBuilder() {
         return new Builder();
     }
@@ -413,6 +413,7 @@
         // Retrieve the files in descending order, so the highest key will be first.
         final SortedMap<Integer, Path> eligibleFiles = getEligibleFiles(manager, false);
         final int maxFiles = highIndex - lowIndex + 1;
+        LOGGER.debug("Eligible files: {}", eligibleFiles);
 
         while (eligibleFiles.size() >= maxFiles) {
             try {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DirectWriteRolloverStrategy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DirectWriteRolloverStrategy.java
index 3a0ab1b..b70b15e 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DirectWriteRolloverStrategy.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DirectWriteRolloverStrategy.java
@@ -16,6 +16,21 @@
  */
 package org.apache.logging.log4j.core.appender.rolling;
 
+import org.apache.logging.log4j.core.Core;
+import org.apache.logging.log4j.core.appender.rolling.action.Action;
+import org.apache.logging.log4j.core.appender.rolling.action.CompositeAction;
+import org.apache.logging.log4j.core.appender.rolling.action.FileRenameAction;
+import org.apache.logging.log4j.core.appender.rolling.action.PathCondition;
+import org.apache.logging.log4j.core.appender.rolling.action.PosixViewAttributeAction;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
+import org.apache.logging.log4j.core.lookup.StrSubstitutor;
+import org.apache.logging.log4j.core.util.Integers;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
+import org.apache.logging.log4j.plugins.PluginElement;
+import org.apache.logging.log4j.plugins.PluginFactory;
+
 import java.io.File;
 import java.io.IOException;
 import java.nio.file.Files;
@@ -27,21 +42,6 @@
 import java.util.concurrent.TimeUnit;
 import java.util.zip.Deflater;
 
-import org.apache.logging.log4j.core.Core;
-import org.apache.logging.log4j.core.appender.rolling.action.Action;
-import org.apache.logging.log4j.core.appender.rolling.action.CompositeAction;
-import org.apache.logging.log4j.core.appender.rolling.action.FileRenameAction;
-import org.apache.logging.log4j.core.appender.rolling.action.PathCondition;
-import org.apache.logging.log4j.core.appender.rolling.action.PosixViewAttributeAction;
-import org.apache.logging.log4j.core.config.Configuration;
-import org.apache.logging.log4j.plugins.Plugin;
-import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
-import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
-import org.apache.logging.log4j.plugins.PluginElement;
-import org.apache.logging.log4j.core.lookup.StrSubstitutor;
-import org.apache.logging.log4j.core.util.Integers;
-
 /**
  * When rolling over, <code>DirectWriteRolloverStrategy</code> writes directly to the file as resolved by the file
  * pattern. Files will be renamed files according to an algorithm as described below.
@@ -189,7 +189,7 @@
         }
     }
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static Builder newBuilder() {
         return new Builder();
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/OnStartupTriggeringPolicy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/OnStartupTriggeringPolicy.java
index cfd8f38..d7a2c74 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/OnStartupTriggeringPolicy.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/OnStartupTriggeringPolicy.java
@@ -103,7 +103,7 @@
 
     @PluginFactory
     public static OnStartupTriggeringPolicy createPolicy(
-            @PluginAttribute(value = "minSize", defaultLong = 1) final long minSize) {
+            @PluginAttribute(defaultLong = 1) final long minSize) {
         return new OnStartupTriggeringPolicy(minSize);
     }
 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/RollingFileManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/RollingFileManager.java
index 2863e63..6ba451a 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/RollingFileManager.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/RollingFileManager.java
@@ -70,6 +70,7 @@
     private volatile boolean initialized = false;
     private volatile String fileName;
     private final FileExtension fileExtension;
+    private final boolean directWrite;
 
     /* This executor pool will create a new Thread for every work async action to be performed. Using it allows
        us to make sure all the Threads are completed when the Manager is stopped. */
@@ -103,6 +104,7 @@
         this.patternProcessor = new PatternProcessor(pattern);
         this.patternProcessor.setPrevFileTime(initialTime);
         this.fileName = fileName;
+        this.directWrite = rolloverStrategy instanceof DirectWriteRolloverStrategy;
         this.fileExtension = FileExtension.lookupForFile(pattern);
     }
 
@@ -115,7 +117,7 @@
             if (triggeringPolicy instanceof LifeCycle) {
                 ((LifeCycle) triggeringPolicy).start();
             }
-            if (rolloverStrategy instanceof DirectFileRolloverStrategy) {
+            if (directWrite) {
                 // LOG4J2-2485: Initialize size from the most recently written file.
                 File file = new File(getFileName());
                 if (file.exists()) {
@@ -169,12 +171,16 @@
      */
     @Override
     public String getFileName() {
-        if (rolloverStrategy instanceof DirectFileRolloverStrategy) {
+        if (directWrite) {
             fileName = ((DirectFileRolloverStrategy) rolloverStrategy).getCurrentFileName(this);
         }
         return fileName;
     }
 
+    public boolean isDirectWrite() {
+        return directWrite;
+    }
+
     public FileExtension getFileExtension() {
         return fileExtension;
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/SizeBasedTriggeringPolicy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/SizeBasedTriggeringPolicy.java
index 8fde3d9..73245d1 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/SizeBasedTriggeringPolicy.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/SizeBasedTriggeringPolicy.java
@@ -92,7 +92,7 @@
      * @return A SizeBasedTriggeringPolicy.
      */
     @PluginFactory
-    public static SizeBasedTriggeringPolicy createPolicy(@PluginAttribute("size") final String size) {
+    public static SizeBasedTriggeringPolicy createPolicy(@PluginAttribute final String size) {
 
         final long maxSize = size == null ? MAX_FILE_SIZE : FileSize.parse(size, MAX_FILE_SIZE);
         return new SizeBasedTriggeringPolicy(maxSize);
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/TimeBasedTriggeringPolicy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/TimeBasedTriggeringPolicy.java
index 884e9d8..e2bcb09 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/TimeBasedTriggeringPolicy.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/TimeBasedTriggeringPolicy.java
@@ -16,14 +16,14 @@
  */
 package org.apache.logging.log4j.core.appender.rolling;
 
-import java.util.concurrent.ThreadLocalRandom;
-import java.util.concurrent.TimeUnit;
-
 import org.apache.logging.log4j.core.Core;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.plugins.Plugin;
 import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
+import org.apache.logging.log4j.plugins.PluginFactory;
+
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Rolls a file over based on time.
@@ -136,7 +136,7 @@
         return false;
     }
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static TimeBasedTriggeringPolicy.Builder newBuilder() {
         return new Builder();
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/DeleteAction.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/DeleteAction.java
index cebafb7..995d8d1 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/DeleteAction.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/DeleteAction.java
@@ -199,13 +199,13 @@
     @PluginFactory
     public static DeleteAction createDeleteAction(
             // @formatter:off
-            @PluginAttribute("basePath") final String basePath, 
-            @PluginAttribute(value = "followLinks") final boolean followLinks,
-            @PluginAttribute(value = "maxDepth", defaultInt = 1) final int maxDepth,
-            @PluginAttribute(value = "testMode") final boolean testMode,
-            @PluginElement("PathSorter") final PathSorter sorterParameter,
-            @PluginElement("PathConditions") final PathCondition[] pathConditions,
-            @PluginElement("ScriptCondition") final ScriptCondition scriptCondition,
+            @PluginAttribute final String basePath,
+            @PluginAttribute final boolean followLinks,
+            @PluginAttribute(defaultInt = 1) final int maxDepth,
+            @PluginAttribute final boolean testMode,
+            @PluginElement final PathSorter sorterParameter,
+            @PluginElement final PathCondition[] pathConditions,
+            @PluginElement final ScriptCondition scriptCondition,
             @PluginConfiguration final Configuration config) {
             // @formatter:on
         final PathSorter sorter = sorterParameter == null ? new PathSortByModificationTime(true) : sorterParameter;
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/FileRenameAction.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/FileRenameAction.java
index 2538306..d2797a6 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/FileRenameAction.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/FileRenameAction.java
@@ -139,6 +139,7 @@
                                         exDelete.getClass().getName(), exDelete.getMessage());
                                 try {
                                     new PrintWriter(source.getAbsolutePath()).close();
+                                    result = true;
                                     LOGGER.trace("Renamed file {} to {} with copy and truncation",
                                             source.getAbsolutePath(), destination.getAbsolutePath());
                                 } catch (final IOException exOwerwrite) {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/IfFileName.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/IfFileName.java
index 509fbc6..bdf14dd 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/IfFileName.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/IfFileName.java
@@ -135,8 +135,8 @@
     @PluginFactory
     public static IfFileName createNameCondition( 
             // @formatter:off
-            @PluginAttribute("glob") final String glob, 
-            @PluginAttribute("regex") final String regex, 
+            @PluginAttribute final String glob,
+            @PluginAttribute final String regex,
             @PluginElement("PathConditions") final PathCondition... nestedConditions) {
             // @formatter:on
         return new IfFileName(glob, regex, nestedConditions);
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/IfLastModified.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/IfLastModified.java
index d232280..7aa3e73 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/IfLastModified.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/IfLastModified.java
@@ -100,7 +100,7 @@
     @PluginFactory
     public static IfLastModified createAgeCondition( 
             // @formatter:off
-            @PluginAttribute("age") final Duration age, 
+            @PluginAttribute final Duration age,
             @PluginElement("PathConditions") final PathCondition... nestedConditions) {
             // @formatter:on
         return new IfLastModified(age, nestedConditions);
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/PathSortByModificationTime.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/PathSortByModificationTime.java
index 1568dba..68c0086 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/PathSortByModificationTime.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/PathSortByModificationTime.java
@@ -53,7 +53,7 @@
      */
     @PluginFactory
     public static PathSorter createSorter( 
-            @PluginAttribute(value = "recentFirst", defaultBoolean = true) final boolean recentFirst) {
+            @PluginAttribute(defaultBoolean = true) final boolean recentFirst) {
         return new PathSortByModificationTime(recentFirst);
     }
 
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/PosixViewAttributeAction.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/PosixViewAttributeAction.java
index 7897259..c9a0c8b 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/PosixViewAttributeAction.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/PosixViewAttributeAction.java
@@ -16,6 +16,18 @@
  */
 package org.apache.logging.log4j.core.appender.rolling.action;
 
+import org.apache.logging.log4j.core.Core;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
+import org.apache.logging.log4j.core.lookup.StrSubstitutor;
+import org.apache.logging.log4j.core.util.FileUtils;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
+import org.apache.logging.log4j.plugins.PluginElement;
+import org.apache.logging.log4j.plugins.PluginFactory;
+import org.apache.logging.log4j.plugins.validation.constraints.Required;
+import org.apache.logging.log4j.util.Strings;
+
 import java.io.IOException;
 import java.nio.file.FileVisitResult;
 import java.nio.file.FileVisitor;
@@ -29,18 +41,6 @@
 import java.util.List;
 import java.util.Set;
 
-import org.apache.logging.log4j.core.Core;
-import org.apache.logging.log4j.core.config.Configuration;
-import org.apache.logging.log4j.plugins.Plugin;
-import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
-import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
-import org.apache.logging.log4j.plugins.PluginElement;
-import org.apache.logging.log4j.plugins.validation.constraints.Required;
-import org.apache.logging.log4j.core.lookup.StrSubstitutor;
-import org.apache.logging.log4j.core.util.FileUtils;
-import org.apache.logging.log4j.util.Strings;
-
 /**
  * File posix attribute view action.
  * 
@@ -74,7 +74,7 @@
         this.fileGroup = fileGroup;
     }
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static Builder newBuilder() {
         return new Builder();
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/IdlePurgePolicy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/IdlePurgePolicy.java
index 2b9510c..950cdd9 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/IdlePurgePolicy.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/IdlePurgePolicy.java
@@ -130,9 +130,9 @@
      */
     @PluginFactory
     public static PurgePolicy createPurgePolicy(
-        @PluginAttribute("timeToLive") final String timeToLive,
-        @PluginAttribute("checkInterval") final String checkInterval,
-        @PluginAttribute("timeUnit") final String timeUnit,
+        @PluginAttribute final String timeToLive,
+        @PluginAttribute final String checkInterval,
+        @PluginAttribute final String timeUnit,
         @PluginConfiguration final Configuration configuration) {
 
         if (timeToLive == null) {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/Route.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/Route.java
index 5211b7d..a5a6290 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/Route.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/Route.java
@@ -96,7 +96,7 @@
     @PluginFactory
     public static Route createRoute(
             @PluginAttribute("ref") final String appenderRef,
-            @PluginAttribute("key") final String key,
+            @PluginAttribute final String key,
             @PluginNode final Node node) {
         if (node != null && node.hasChildren()) {
             if (appenderRef != null) {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/Routes.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/Routes.java
index a783cd6..0dbab8b 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/Routes.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/Routes.java
@@ -16,27 +16,26 @@
  */
 package org.apache.logging.log4j.core.appender.routing;
 
-import static org.apache.logging.log4j.core.appender.routing.RoutingAppender.STATIC_VARIABLES_KEY;
-
-import java.util.Objects;
-import java.util.concurrent.ConcurrentMap;
-
-import javax.script.Bindings;
-
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.Core;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.config.Configuration;
-import org.apache.logging.log4j.plugins.Plugin;
-import org.apache.logging.log4j.plugins.PluginAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
 import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
-import org.apache.logging.log4j.plugins.PluginElement;
-import org.apache.logging.log4j.plugins.validation.constraints.Required;
 import org.apache.logging.log4j.core.script.AbstractScript;
 import org.apache.logging.log4j.core.script.ScriptManager;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.plugins.PluginAttribute;
+import org.apache.logging.log4j.plugins.PluginElement;
+import org.apache.logging.log4j.plugins.PluginFactory;
+import org.apache.logging.log4j.plugins.validation.constraints.Required;
 import org.apache.logging.log4j.status.StatusLogger;
 
+import javax.script.Bindings;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentMap;
+
+import static org.apache.logging.log4j.core.appender.routing.RoutingAppender.STATIC_VARIABLES_KEY;
+
 /**
  * Contains the individual Route elements.
  */
@@ -50,13 +49,13 @@
         @PluginConfiguration 
         private Configuration configuration;
 
-        @PluginAttribute("pattern") 
+        @PluginAttribute
         private String pattern;
         
         @PluginElement("Script")
         private AbstractScript patternScript;
 
-        @PluginElement("Routes")
+        @PluginElement
         @Required
         private Route[] routes;
 
@@ -119,7 +118,7 @@
 
     private static final Logger LOGGER = StatusLogger.getLogger();
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static Builder newBuilder() {
         return new Builder();
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/RoutingAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/RoutingAppender.java
index 800ca6e..65ecf92 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/RoutingAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/RoutingAppender.java
@@ -16,16 +16,6 @@
  */
 package org.apache.logging.log4j.core.appender.routing;
 
-import java.util.Collections;
-import java.util.Map;
-import java.util.Objects;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import javax.script.Bindings;
-
 import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.Core;
 import org.apache.logging.log4j.core.Filter;
@@ -39,8 +29,17 @@
 import org.apache.logging.log4j.core.script.ScriptManager;
 import org.apache.logging.log4j.plugins.Node;
 import org.apache.logging.log4j.plugins.Plugin;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
 import org.apache.logging.log4j.plugins.PluginElement;
+import org.apache.logging.log4j.plugins.PluginFactory;
+
+import javax.script.Bindings;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * This Appender "routes" between various Appenders, some of which can be references to
@@ -136,7 +135,7 @@
 
     }
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static <B extends Builder<B>> B newBuilder() {
         return new Builder<B>().asBuilder();
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfig.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfig.java
index 1ecf153..3a6613f 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfig.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfig.java
@@ -208,14 +208,14 @@
      */
     @PluginFactory
     public static LoggerConfig createLogger(
-            @PluginAttribute(value = "additivity", defaultBoolean = true) final boolean additivity,
-            @PluginAttribute("level") final Level level,
+            @PluginAttribute(defaultBoolean = true) final boolean additivity,
+            @PluginAttribute final Level level,
             @Required(message = "Loggers cannot be configured without a name") @PluginAttribute("name") final String loggerName,
-            @PluginAttribute("includeLocation") final String includeLocation,
-            @PluginElement("AppenderRef") final AppenderRef[] refs,
-            @PluginElement("Properties") final Property[] properties,
+            @PluginAttribute final String includeLocation,
+            @PluginElement final AppenderRef[] refs,
+            @PluginElement final Property[] properties,
             @PluginConfiguration final Configuration config,
-            @PluginElement("Filter") final Filter filter) {
+            @PluginElement final Filter filter) {
         final String name = loggerName.equals(ROOT) ? Strings.EMPTY : loggerName;
         return new AsyncLoggerConfig(name, Arrays.asList(refs), filter, level, additivity, properties, config,
                 includeLocation(includeLocation));
@@ -237,13 +237,13 @@
          */
         @PluginFactory
         public static LoggerConfig createLogger(
-                @PluginAttribute("additivity") final String additivity,
-                @PluginAttribute("level") final Level level,
-                @PluginAttribute("includeLocation") final String includeLocation,
-                @PluginElement("AppenderRef") final AppenderRef[] refs,
-                @PluginElement("Properties") final Property[] properties,
+                @PluginAttribute final String additivity,
+                @PluginAttribute final Level level,
+                @PluginAttribute final String includeLocation,
+                @PluginElement final AppenderRef[] refs,
+                @PluginElement final Property[] properties,
                 @PluginConfiguration final Configuration config,
-                @PluginElement("Filter") final Filter filter) {
+                @PluginElement final Filter filter) {
             final List<AppenderRef> appenderRefs = Arrays.asList(refs);
             final Level actualLevel = level == null ? Level.ERROR : level;
             final boolean additive = Booleans.parseBoolean(additivity, true);
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDelegate.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDelegate.java
index 5e01f8b..b791f0a 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDelegate.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDelegate.java
@@ -57,7 +57,7 @@
 

     /**

      * Notifies the delegate what LogEventFactory an AsyncLoggerConfig is using, so the delegate can determine

-     * whether to populate the ring buffer with mutable log events or not. This method may be invoced multiple times

+     * whether to populate the ring buffer with mutable log events or not. This method may be invoked multiple times

      * for all AsyncLoggerConfigs that use this delegate.

      *

      * @param logEventFactory the factory used

diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/DisruptorBlockingQueueFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/DisruptorBlockingQueueFactory.java
index 66bd78a..766daf6 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/DisruptorBlockingQueueFactory.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/DisruptorBlockingQueueFactory.java
@@ -46,7 +46,7 @@
 
     @PluginFactory
     public static <E> DisruptorBlockingQueueFactory<E> createFactory(
-        @PluginAttribute(value = "SpinPolicy", defaultString = "WAITING") final SpinPolicy spinPolicy
+        @PluginAttribute(defaultString = "WAITING") final SpinPolicy spinPolicy
     ) {
         return new DisruptorBlockingQueueFactory<>(spinPolicy);
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/JCToolsBlockingQueueFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/JCToolsBlockingQueueFactory.java
index c3517c3..9333611 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/JCToolsBlockingQueueFactory.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/JCToolsBlockingQueueFactory.java
@@ -48,7 +48,7 @@
 
     @PluginFactory
     public static <E> JCToolsBlockingQueueFactory<E> createFactory(
-        @PluginAttribute(value = "WaitStrategy", defaultString = "PARK") final WaitStrategy waitStrategy) {
+        @PluginAttribute(defaultString = "PARK") final WaitStrategy waitStrategy) {
         return new JCToolsBlockingQueueFactory<>(waitStrategy);
     }
 
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEventHandler.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEventHandler.java
index f0cab8d..dfec3e4 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEventHandler.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEventHandler.java
@@ -42,12 +42,16 @@
     @Override
     public void onEvent(final RingBufferLogEvent event, final long sequence,
             final boolean endOfBatch) throws Exception {
-        event.execute(endOfBatch);
-        event.clear();
-        // notify the BatchEventProcessor that the sequence has progressed.
-        // Without this callback the sequence would not be progressed
-        // until the batch has completely finished.
-        notifyCallback(sequence);
+        try {
+            event.execute(endOfBatch);
+        }
+        finally {
+            event.clear();
+            // notify the BatchEventProcessor that the sequence has progressed.
+            // Without this callback the sequence would not be progressed
+            // until the batch has completely finished.
+            notifyCallback(sequence);
+        }
     }
 
     private void notifyCallback(long sequence) {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/ThreadNameCachingStrategy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/ThreadNameCachingStrategy.java
index def4d8d..32e15e8 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/ThreadNameCachingStrategy.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/ThreadNameCachingStrategy.java
@@ -17,7 +17,11 @@
 

 package org.apache.logging.log4j.core.async;

 

+import java.util.regex.Matcher;

+import java.util.regex.Pattern;

+

 import org.apache.logging.log4j.status.StatusLogger;

+import org.apache.logging.log4j.util.Constants;

 import org.apache.logging.log4j.util.PropertiesUtil;

 

 /**

@@ -44,24 +48,39 @@
 

     private static final StatusLogger LOGGER = StatusLogger.getLogger();

     private static final ThreadLocal<String> THREADLOCAL_NAME = new ThreadLocal<>();

+    static final ThreadNameCachingStrategy DEFAULT_STRATEGY = isAllocatingThreadGetName() ? CACHED : UNCACHED;

 

     abstract String getThreadName();

 

     public static ThreadNameCachingStrategy create() {

-        final String defaultStrategy = System.getProperty("java.version").compareTo("1.8.0_102") < 0

-                ? "CACHED" // LOG4J2-2052 JDK 8u102 removed the String allocation in Thread.getName()

-                : "UNCACHED";

         final String name = PropertiesUtil.getProperties().getStringProperty("AsyncLogger.ThreadNameStrategy");

         try {

-            final ThreadNameCachingStrategy result = ThreadNameCachingStrategy.valueOf(

-                    name != null ? name : defaultStrategy);

+            final ThreadNameCachingStrategy result = name != null ? ThreadNameCachingStrategy.valueOf(name) : DEFAULT_STRATEGY;

             LOGGER.debug("AsyncLogger.ThreadNameStrategy={} (user specified {}, default is {})",

-                    result, name, defaultStrategy);

+                         result.name(), name, DEFAULT_STRATEGY.name());

             return result;

         } catch (final Exception ex) {

             LOGGER.debug("Using AsyncLogger.ThreadNameStrategy.{}: '{}' not valid: {}",

-                    defaultStrategy, name, ex.toString());

-            return ThreadNameCachingStrategy.valueOf(defaultStrategy);

+                         DEFAULT_STRATEGY.name(), name, ex.toString());

+            return DEFAULT_STRATEGY;

         }

     }

-}
+

+    static boolean isAllocatingThreadGetName() {

+        // LOG4J2-2052, LOG4J2-2635 JDK 8u102 ("1.8.0_102") removed the String allocation in Thread.getName()

+        if (Constants.JAVA_MAJOR_VERSION == 8) {

+            try {

+                Pattern javaVersionPattern = Pattern.compile("(\\d+)\\.(\\d+)\\.(\\d+)_(\\d+)");

+                Matcher m = javaVersionPattern.matcher(System.getProperty("java.version"));

+                if (m.matches()) {

+                    return Integer.parseInt(m.group(3)) == 0 && Integer.parseInt(m.group(4)) < 102;

+                }

+                return true;

+            } catch (Exception e) {

+                return true;

+            }

+        } else {

+            return Constants.JAVA_MAJOR_VERSION < 8;

+        }

+    }

+}

diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
index b3e1e7d..47794fa 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
@@ -63,7 +63,6 @@
 import org.apache.logging.log4j.core.util.Constants;
 import org.apache.logging.log4j.core.time.internal.DummyNanoClock;
 import org.apache.logging.log4j.core.util.Loader;
-import org.apache.logging.log4j.plugins.inject.PluginInjectionBuilder;
 import org.apache.logging.log4j.util.NameUtil;
 import org.apache.logging.log4j.core.util.Source;
 import org.apache.logging.log4j.core.time.NanoClock;
@@ -971,7 +970,7 @@
      * @param event the LogEvent that spurred the creation of this plugin
      * @return the created plugin object or {@code null} if there was an error setting it up.
      * @see org.apache.logging.log4j.core.config.plugins.util.PluginBuilder
-     * @see org.apache.logging.log4j.plugins.inject.PluginInjectionBuilder
+     * @see org.apache.logging.log4j.plugins.inject.ConfigurationInjector
      * @see org.apache.logging.log4j.plugins.convert.TypeConverter
      */
     private Object createPluginObject(final PluginType<?> type, final Node node, final LogEvent event) {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AppenderRef.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AppenderRef.java
index eee3c01..04a932b 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AppenderRef.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AppenderRef.java
@@ -17,7 +17,6 @@
 package org.apache.logging.log4j.core.config;
 
 import org.apache.logging.log4j.Level;
-import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.Filter;
 import org.apache.logging.log4j.plugins.Node;
 import org.apache.logging.log4j.plugins.Plugin;
@@ -25,7 +24,7 @@
 import org.apache.logging.log4j.plugins.PluginAttribute;
 import org.apache.logging.log4j.plugins.PluginElement;
 import org.apache.logging.log4j.plugins.PluginFactory;
-import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.plugins.validation.constraints.Required;
 
 /**
  * An Appender reference.
@@ -33,7 +32,6 @@
 @Plugin(name = "AppenderRef", category = Node.CATEGORY, printObject = true)
 @PluginAliases("appender-ref")
 public final class AppenderRef {
-    private static final Logger LOGGER = StatusLogger.getLogger();
 
     private final String ref;
     private final Level level;
@@ -71,14 +69,9 @@
      */
     @PluginFactory
     public static AppenderRef createAppenderRef(
-            @PluginAttribute("ref") final String ref,
-            @PluginAttribute("level") final Level level,
-            @PluginElement("Filter") final Filter filter) {
-
-        if (ref == null) {
-            LOGGER.error("Appender references must contain a reference");
-            return null;
-        }
+            @PluginAttribute @Required(message = "Appender references must contain a reference") final String ref,
+            @PluginAttribute final Level level,
+            @PluginElement final Filter filter) {
         return new AppenderRef(ref, level, filter);
     }
 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java
index 1a5172c..d47a02f 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java
@@ -136,7 +136,9 @@
      * Returns the source of this configuration.
      *
      * @return the source of this configuration, never {@code null}, but may be
-     * {@link org.apache.logging.log4j.core.config.ConfigurationSource#NULL_SOURCE}.
+     * {@link org.apache.logging.log4j.core.config.ConfigurationSource#NULL_SOURCE}
+     * or
+     * {@link org.apache.logging.log4j.core.config.ConfigurationSource#COMPOSITE_SOURCE}
      */
     ConfigurationSource getConfigurationSource();
 
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationFactory.java
index ef0643d..6757f04 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationFactory.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationFactory.java
@@ -45,10 +45,10 @@
 import org.apache.logging.log4j.core.util.NetUtils;
 import org.apache.logging.log4j.plugins.util.PluginManager;
 import org.apache.logging.log4j.plugins.util.PluginType;
-import org.apache.logging.log4j.util.ReflectionUtil;
 import org.apache.logging.log4j.status.StatusLogger;
 import org.apache.logging.log4j.util.LoaderUtil;
 import org.apache.logging.log4j.util.PropertiesUtil;
+import org.apache.logging.log4j.util.ReflectionUtil;
 import org.apache.logging.log4j.util.Strings;
 
 /**
@@ -91,6 +91,10 @@
      */
     public static final String CONFIGURATION_FILE_PROPERTY = "log4j.configurationFile";
 
+    public static final String LOG4J1_CONFIGURATION_FILE_PROPERTY = "log4j.configuration";
+
+    public static final String LOG4J1_EXPERIMENTAL = "log4j1.compatibility";
+
     public static final String AUTHORIZATION_PROVIDER = "log4j2.authorizationProvider";
 
     /**
@@ -116,6 +120,9 @@
      */
     protected static final String DEFAULT_PREFIX = "log4j2";
 
+    protected static final String LOG4J1_VERSION = "1";
+    protected static final String LOG4J2_VERSION = "2";
+
     /**
      * The name of the classloader URI scheme.
      */
@@ -137,7 +144,7 @@
     private static final String HTTPS = "https";
     private static final String HTTP = "http";
 
-    private static AuthorizationProvider authorizationProvider = null;
+    private static volatile AuthorizationProvider authorizationProvider = null;
 
     /**
      * Returns the ConfigurationFactory.
@@ -174,22 +181,7 @@
                     // see above comments about double-checked locking
                     //noinspection NonThreadSafeLazyInitialization
                     factories = Collections.unmodifiableList(list);
-                    final String authClass = props.getStringProperty(AUTHORIZATION_PROVIDER);
-                    if (authClass != null) {
-                        try {
-                            Object obj = LoaderUtil.newInstanceOf(authClass);
-                            if (obj instanceof AuthorizationProvider) {
-                                authorizationProvider = (AuthorizationProvider) obj;
-                            } else {
-                                LOGGER.warn("{} is not an AuthorizationProvider, using default", obj.getClass().getName());
-                            }
-                        } catch (Exception ex) {
-                            LOGGER.warn("Unable to create {}, using default: {}", authClass, ex.getMessage());
-                        }
-                    }
-                    if (authorizationProvider == null) {
-                        authorizationProvider = new BasicAuthorizationProvider(props);
-                    }
+                    authorizationProvider = authorizationProvider(props);
                 }
             } finally {
                 LOCK.unlock();
@@ -200,6 +192,27 @@
         return configFactory;
     }
 
+    public static AuthorizationProvider authorizationProvider(PropertiesUtil props) {
+        final String authClass = props.getStringProperty(AUTHORIZATION_PROVIDER);
+        AuthorizationProvider provider = null;
+        if (authClass != null) {
+            try {
+                Object obj = LoaderUtil.newInstanceOf(authClass);
+                if (obj instanceof AuthorizationProvider) {
+                    provider = (AuthorizationProvider) obj;
+                } else {
+                    LOGGER.warn("{} is not an AuthorizationProvider, using default", obj.getClass().getName());
+                }
+            } catch (Exception ex) {
+                LOGGER.warn("Unable to create {}, using default: {}", authClass, ex.getMessage());
+            }
+        }
+        if (provider == null) {
+            provider = new BasicAuthorizationProvider(props);
+        }
+        return provider;
+    }
+
     public static AuthorizationProvider getAuthorizationProvider() {
         return authorizationProvider;
     }
@@ -249,6 +262,18 @@
 
     protected abstract String[] getSupportedTypes();
 
+    protected String getTestPrefix() {
+        return TEST_PREFIX;
+    }
+
+    protected String getDefaultPrefix() {
+        return DEFAULT_PREFIX;
+    }
+
+    protected String getVersion() {
+        return LOG4J2_VERSION;
+    }
+
     protected boolean isActive() {
         return true;
     }
@@ -383,6 +408,13 @@
                         return new CompositeConfiguration(configs);
                     }
                     return getConfiguration(loggerContext, configLocationStr);
+                } else {
+                    final String log4j1ConfigStr = this.substitutor.replace(PropertiesUtil.getProperties()
+                            .getStringProperty(LOG4J1_CONFIGURATION_FILE_PROPERTY));
+                    if (log4j1ConfigStr != null) {
+                        System.setProperty(LOG4J1_EXPERIMENTAL, "true");
+                        return getConfiguration(LOG4J1_VERSION, loggerContext, log4j1ConfigStr);
+                    }
                 }
                 for (final ConfigurationFactory factory : getFactories()) {
                     final String[] types = factory.getSupportedTypes();
@@ -428,7 +460,7 @@
             if (config != null) {
                 return config;
             }
-            LOGGER.error("No Log4j 2 configuration file found. " +
+            LOGGER.warn("No Log4j 2 configuration file found. " +
                     "Using default configuration (logging only errors to the console), " +
                     "or user programmatically provided configurations. " +
                     "Set system property 'log4j2.debug' " +
@@ -438,6 +470,11 @@
         }
 
         private Configuration getConfiguration(final LoggerContext loggerContext, final String configLocationStr) {
+            return getConfiguration(null, loggerContext, configLocationStr);
+        }
+
+        private Configuration getConfiguration(String requiredVersion, final LoggerContext loggerContext,
+                final String configLocationStr) {
             ConfigurationSource source = null;
             try {
                 source = ConfigurationSource.fromUri(NetUtils.toURI(configLocationStr));
@@ -451,6 +488,9 @@
             }
             if (source != null) {
                 for (final ConfigurationFactory factory : getFactories()) {
+                    if (requiredVersion != null && !factory.getVersion().equals(requiredVersion)) {
+                        continue;
+                    }
                     final String[] types = factory.getSupportedTypes();
                     if (types != null) {
                         for (final String type : types) {
@@ -472,7 +512,7 @@
             final ClassLoader loader = LoaderUtil.getThreadContextClassLoader();
             for (final ConfigurationFactory factory : getFactories()) {
                 String configName;
-                final String prefix = isTest ? TEST_PREFIX : DEFAULT_PREFIX;
+                final String prefix = isTest ? factory.getTestPrefix() : factory.getDefaultPrefix();
                 final String [] types = factory.getSupportedTypes();
                 if (types == null) {
                     continue;
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationSource.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationSource.java
index 9ba3331..bbbb483 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationSource.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationSource.java
@@ -42,11 +42,15 @@
  * Represents the source for the logging configuration.
  */
 public class ConfigurationSource {
-    
+
     /**
      * ConfigurationSource to use with Configurations that do not require a "real" configuration source.
      */
     public static final ConfigurationSource NULL_SOURCE = new ConfigurationSource(new byte[0], null, 0);
+    /**
+     * ConfigurationSource to use with {@link org.apache.logging.log4j.core.config.composite.CompositeConfiguration}.
+     */
+    public static final ConfigurationSource COMPOSITE_SOURCE = new ConfigurationSource(new byte[0], null, 0);
     private static final String HTTPS = "https";
     private static final String HTTP = "http";
 
@@ -285,6 +289,9 @@
         if (this == NULL_SOURCE) {
             return "NULL_SOURCE";
         }
+        if (this == COMPOSITE_SOURCE) {
+            return "COMPOSITE_SOURCE";
+        }
         final int length = data == null ? -1 : data.length;
         return "stream (" + length + " bytes, unknown location)";
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configurator.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configurator.java
index 30f8ca8..8effd0a 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configurator.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configurator.java
@@ -227,6 +227,24 @@
     }
 
     /**
+     * Reconfigure using an already constructed Configuration.
+     * @param configuration The configuration.
+     * @since 2.13.0
+     */
+    public static void reconfigure(final Configuration configuration) {
+        try {
+            final Log4jContextFactory factory = getFactory();
+            if (factory != null) {
+                factory.getContext(FQCN, null, null, false)
+                        .reconfigure(configuration);
+            }
+        } catch (final Exception ex) {
+            LOGGER.error("There was a problem initializing the LoggerContext using configuration {}",
+                    configuration.getName(), ex);
+        }
+    }
+
+    /**
      * Reload the existing reconfiguration.
      * @since 2.12.0
      */
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/CustomLevelConfig.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/CustomLevelConfig.java
index 2194617..d54a9f0 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/CustomLevelConfig.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/CustomLevelConfig.java
@@ -50,7 +50,7 @@
     @PluginFactory
     public static CustomLevelConfig createLevel(// @formatter:off
             @PluginAttribute("name") final String levelName,
-            @PluginAttribute("intLevel") final int intLevel) {
+            @PluginAttribute final int intLevel) {
         // @formatter:on
 
         StatusLogger.getLogger().debug("Creating CustomLevel(name='{}', intValue={})", levelName, intLevel);
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java
index a4e08ee..4170f42 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java
@@ -531,14 +531,14 @@
     @PluginFactory
     public static LoggerConfig createLogger(
          // @formatter:off
-        @PluginAttribute(value = "additivity", defaultBoolean = true) final boolean additivity,
-        @PluginAttribute("level") final Level level,
+        @PluginAttribute(defaultBoolean = true) final boolean additivity,
+        @PluginAttribute final Level level,
         @Required(message = "Loggers cannot be configured without a name") @PluginAttribute("name") final String loggerName,
-        @PluginAttribute("includeLocation") final String includeLocation,
-        @PluginElement("AppenderRef") final AppenderRef[] refs,
-        @PluginElement("Properties") final Property[] properties,
+        @PluginAttribute final String includeLocation,
+        @PluginElement final AppenderRef[] refs,
+        @PluginElement final Property[] properties,
         @PluginConfiguration final Configuration config,
-        @PluginElement("Filter") final Filter filter
+        @PluginElement final Filter filter
         // @formatter:on
     ) {
         final String name = loggerName.equals(ROOT) ? Strings.EMPTY : loggerName;
@@ -576,13 +576,13 @@
         @PluginFactory
         public static LoggerConfig createLogger(
                 // @formatter:off
-                @PluginAttribute("additivity") final String additivity,
-                @PluginAttribute("level") final Level level,
-                @PluginAttribute("includeLocation") final String includeLocation,
-                @PluginElement("AppenderRef") final AppenderRef[] refs,
-                @PluginElement("Properties") final Property[] properties,
+                @PluginAttribute final String additivity,
+                @PluginAttribute final Level level,
+                @PluginAttribute final String includeLocation,
+                @PluginElement final AppenderRef[] refs,
+                @PluginElement final Property[] properties,
                 @PluginConfiguration final Configuration config,
-                @PluginElement("Filter") final Filter filter) {
+                @PluginElement final Filter filter) {
                 // @formatter:on
             final List<AppenderRef> appenderRefs = Arrays.asList(refs);
             final Level actualLevel = level == null ? Level.ERROR : level;
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Property.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Property.java
index 53cf84e..5e180f1 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Property.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Property.java
@@ -18,13 +18,12 @@
 
 import java.util.Objects;
 
-import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.plugins.Node;
 import org.apache.logging.log4j.plugins.Plugin;
 import org.apache.logging.log4j.plugins.PluginAttribute;
 import org.apache.logging.log4j.plugins.PluginFactory;
 import org.apache.logging.log4j.plugins.PluginValue;
-import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.plugins.validation.constraints.Required;
 import org.apache.logging.log4j.util.Strings;
 
 /**
@@ -38,8 +37,6 @@
      */
     public static final Property[] EMPTY_ARRAY = new Property[0];
 
-    private static final Logger LOGGER = StatusLogger.getLogger();
-
     private final String name;
     private final String value;
     private final boolean valueNeedsLookup;
@@ -83,11 +80,8 @@
      */
     @PluginFactory
     public static Property createProperty(
-            @PluginAttribute("name") final String name,
-            @PluginValue("value") final String value) {
-        if (name == null) {
-            LOGGER.error("Property name cannot be null");
-        }
+            @PluginAttribute @Required(message = "Property name cannot be null") final String name,
+            @PluginValue final String value) {
         return new Property(name, value);
     }
 
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/CompositeConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/CompositeConfiguration.java
index 329f861..4a6de10 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/CompositeConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/CompositeConfiguration.java
@@ -56,12 +56,12 @@
     private MergeStrategy mergeStrategy;
 
     /**
-     * Construct the ComponsiteConfiguration.
+     * Construct the CompositeConfiguration.
      *
      * @param configurations The List of Configurations to merge.
      */
     public CompositeConfiguration(final List<? extends AbstractConfiguration> configurations) {
-        super(configurations.get(0).getLoggerContext(), ConfigurationSource.NULL_SOURCE);
+        super(configurations.get(0).getLoggerContext(), ConfigurationSource.COMPOSITE_SOURCE);
         rootNode = configurations.get(0).getRootNode();
         this.configurations = configurations;
         final String mergeStrategyClassName = PropertiesUtil.getProperties().getStringProperty(MERGE_STRATEGY_PROPERTY,
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/DefaultMergeStrategy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/DefaultMergeStrategy.java
index c4caa6d..343d315 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/DefaultMergeStrategy.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/DefaultMergeStrategy.java
@@ -41,7 +41,7 @@
  * configurations.</li>
  * <li>Filters are aggregated under a CompositeFilter if more than one Filter is defined. Since Filters are not named
  * duplicates may be present.</li>
- * <li>Scripts and ScriptFile references are aggregated. Duplicate definiations replace those in previous
+ * <li>Scripts and ScriptFile references are aggregated. Duplicate definitions replace those in previous
  * configurations.</li>
  * <li>Appenders are aggregated. Appenders with the same name are replaced by those in later configurations, including
  * all of the Appender's subcomponents.</li>
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginAttribute.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginAttribute.java
index a5595cf..e75de09 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginAttribute.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginAttribute.java
@@ -16,11 +16,15 @@
  */
 package org.apache.logging.log4j.core.config.plugins;
 
-import org.apache.logging.log4j.plugins.inject.InjectionStrategy;
 import org.apache.logging.log4j.core.config.plugins.visitors.PluginAttributeVisitor;
+import org.apache.logging.log4j.plugins.inject.InjectorStrategy;
 import org.apache.logging.log4j.util.Strings;
 
-import java.lang.annotation.*;
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 
 /**
  * Identifies a Plugin Attribute and its default value. Note that only one of the defaultFoo attributes will be
@@ -33,7 +37,7 @@
 @Documented
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.PARAMETER, ElementType.FIELD})
-@InjectionStrategy(PluginAttributeVisitor.class)
+@InjectorStrategy(PluginAttributeVisitor.class)
 public @interface PluginAttribute {
 
     /**
@@ -86,7 +90,6 @@
      */
     String defaultString() default Strings.EMPTY;
 
-    // TODO: could we allow a blank value and infer the attribute name through reflection?
     /**
      * Specifies the name of the attribute (case-insensitive) this annotation corresponds to.
      */
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderAttribute.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderAttribute.java
index 584d5f8..17ad890 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderAttribute.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderAttribute.java
@@ -17,11 +17,15 @@
 
 package org.apache.logging.log4j.core.config.plugins;
 
-import org.apache.logging.log4j.plugins.inject.InjectionStrategy;
 import org.apache.logging.log4j.core.config.plugins.visitors.PluginBuilderAttributeVisitor;
+import org.apache.logging.log4j.plugins.inject.InjectorStrategy;
 import org.apache.logging.log4j.util.Strings;
 
-import java.lang.annotation.*;
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 
 /**
  * Marks a field as a Plugin Attribute.
@@ -30,7 +34,7 @@
 @Documented
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.PARAMETER, ElementType.FIELD})
-@InjectionStrategy(PluginBuilderAttributeVisitor.class)
+@InjectorStrategy(PluginBuilderAttributeVisitor.class)
 public @interface PluginBuilderAttribute {
 
     /**
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginConfiguration.java
index e941388..dee6f67 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginConfiguration.java
@@ -16,23 +16,24 @@
  */
 package org.apache.logging.log4j.core.config.plugins;
 
+import org.apache.logging.log4j.core.config.plugins.inject.PluginConfigurationInjector;
+import org.apache.logging.log4j.plugins.inject.InjectorStrategy;
+
 import java.lang.annotation.Documented;
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
-import org.apache.logging.log4j.core.config.plugins.visitors.PluginConfigurationVisitor;
-import org.apache.logging.log4j.plugins.inject.InjectionStrategy;
-
 /**
- * Identifies a parameter or field as a Configuration.
- * @see org.apache.logging.log4j.core.config.Configuration
+ * Identifies the current {@link org.apache.logging.log4j.core.config.Configuration}. This can be injected as a
+ * parameter to a static {@linkplain org.apache.logging.log4j.plugins.PluginFactory factory method}, or as a field
+ * or single-parameter method in a plugin {@linkplain org.apache.logging.log4j.plugins.util.Builder builder class}.
  */
 @Documented
 @Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.PARAMETER, ElementType.FIELD})
-@InjectionStrategy(PluginConfigurationVisitor.class)
+@Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD})
+@InjectorStrategy(PluginConfigurationInjector.class)
 public @interface PluginConfiguration {
     // empty
 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginElement.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginElement.java
index 81c5a47..5c4f41e 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginElement.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginElement.java
@@ -17,9 +17,13 @@
 package org.apache.logging.log4j.core.config.plugins;
 
 import org.apache.logging.log4j.core.config.plugins.visitors.PluginElementVisitor;
-import org.apache.logging.log4j.plugins.inject.InjectionStrategy;
+import org.apache.logging.log4j.plugins.inject.InjectorStrategy;
 
-import java.lang.annotation.*;
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 
 /**
  * Identifies a parameter as a Plugin and corresponds with an XML element (or equivalent) in configuration files.
@@ -28,7 +32,7 @@
 @Documented
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.PARAMETER, ElementType.FIELD})
-@InjectionStrategy(PluginElementVisitor.class)
+@InjectorStrategy(PluginElementVisitor.class)
 public @interface PluginElement {
 
     /**
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginNode.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginNode.java
index 3411a12..14a136c 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginNode.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginNode.java
@@ -17,9 +17,13 @@
 package org.apache.logging.log4j.core.config.plugins;
 
 import org.apache.logging.log4j.core.config.plugins.visitors.PluginNodeVisitor;
-import org.apache.logging.log4j.plugins.inject.InjectionStrategy;
+import org.apache.logging.log4j.plugins.inject.InjectorStrategy;
 
-import java.lang.annotation.*;
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 
 /**
  * Identifies a Plugin configuration Node.
@@ -28,7 +32,7 @@
 @Documented
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.PARAMETER, ElementType.FIELD})
-@InjectionStrategy(PluginNodeVisitor.class)
+@InjectorStrategy(PluginNodeVisitor.class)
 public @interface PluginNode {
     // empty
 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginValue.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginValue.java
index 0a93acb..9389aa9 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginValue.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginValue.java
@@ -17,10 +17,13 @@
 package org.apache.logging.log4j.core.config.plugins;
 
 import org.apache.logging.log4j.core.config.plugins.visitors.PluginValueVisitor;
-import org.apache.logging.log4j.plugins.inject.InjectionStrategy;
+import org.apache.logging.log4j.plugins.inject.InjectorStrategy;
 
-
-import java.lang.annotation.*;
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 
 /**
  * Identifies a parameter as a value. These correspond with property values generally, but are meant as values to be
@@ -32,7 +35,7 @@
 @Documented
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.PARAMETER, ElementType.FIELD})
-@InjectionStrategy(PluginValueVisitor.class)
+@InjectorStrategy(PluginValueVisitor.class)
 public @interface PluginValue {
 
     String value();
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginConfigurationVisitor.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/inject/PluginConfigurationInjector.java
similarity index 62%
rename from log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginConfigurationVisitor.java
rename to log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/inject/PluginConfigurationInjector.java
index 20976c7..f7bbf34 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginConfigurationVisitor.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/inject/PluginConfigurationInjector.java
@@ -15,30 +15,25 @@
  * limitations under the license.
  */
 
-package org.apache.logging.log4j.core.config.plugins.visitors;
+package org.apache.logging.log4j.core.config.plugins.inject;
 
 import org.apache.logging.log4j.core.config.Configuration;
 import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
+import org.apache.logging.log4j.core.util.TypeUtil;
+import org.apache.logging.log4j.plugins.inject.AbstractConfigurationInjector;
 
-/**
- * PluginVisitor implementation for {@link PluginConfiguration}.
- */
-public class PluginConfigurationVisitor extends AbstractPluginVisitor<PluginConfiguration, Configuration> {
-    public PluginConfigurationVisitor() {
-        super(PluginConfiguration.class);
-    }
-
+public class PluginConfigurationInjector extends AbstractConfigurationInjector<PluginConfiguration, Configuration> {
     @Override
-    public Object build() {
-        if (this.conversionType.isInstance(configuration)) {
+    public void inject(final Object factory) {
+        if (TypeUtil.isAssignable(conversionType, configuration.getClass())) {
             debugLog.append("Configuration");
             if (configuration.getName() != null) {
                 debugLog.append('(').append(configuration.getName()).append(')');
             }
-            return configuration;
+            configurationBinder.bindObject(factory, configuration);
+        } else {
+            LOGGER.warn("Element with type {} annotated with @PluginConfiguration is not compatible with type {}.",
+                    conversionType, configuration.getClass());
         }
-        LOGGER.warn("Variable annotated with @PluginConfiguration is not compatible with type {}.",
-                configuration.getClass());
-        return null;
     }
 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginBuilder.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginBuilder.java
index 877c537..5fa120d 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginBuilder.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginBuilder.java
@@ -20,18 +20,17 @@
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.config.Configuration;
-import org.apache.logging.log4j.core.config.ConfigurationException;
 import org.apache.logging.log4j.core.lookup.StrSubstitutor;
 import org.apache.logging.log4j.plugins.Node;
 import org.apache.logging.log4j.plugins.PluginAliases;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
 import org.apache.logging.log4j.plugins.PluginFactory;
-import org.apache.logging.log4j.plugins.inject.PluginInjectionBuilder;
+import org.apache.logging.log4j.plugins.bind.FactoryMethodBinder;
+import org.apache.logging.log4j.plugins.bind.FieldConfigurationBinder;
+import org.apache.logging.log4j.plugins.bind.MethodConfigurationBinder;
+import org.apache.logging.log4j.plugins.inject.ConfigurationInjector;
 import org.apache.logging.log4j.plugins.util.Builder;
 import org.apache.logging.log4j.plugins.util.PluginType;
 import org.apache.logging.log4j.plugins.util.TypeUtil;
-import org.apache.logging.log4j.plugins.validation.ConstraintValidator;
-import org.apache.logging.log4j.plugins.validation.ConstraintValidators;
 import org.apache.logging.log4j.status.StatusLogger;
 import org.apache.logging.log4j.util.ReflectionUtil;
 import org.apache.logging.log4j.util.StringBuilders;
@@ -42,11 +41,9 @@
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
-import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import java.util.Optional;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.function.Function;
@@ -119,33 +116,31 @@
     @Override
     public Object build() {
         verify();
+        LOGGER.debug("Building Plugin[name={}, class={}].", pluginType.getElementName(),
+                pluginType.getPluginClass().getName());
         substitutor = new Substitutor(event);
         // first try to use a builder class if one is available
         try {
-            LOGGER.debug("Building Plugin[name={}, class={}].", pluginType.getElementName(),
-                    pluginType.getPluginClass().getName());
             final Builder<?> builder = createBuilder(this.clazz);
             if (builder != null) {
-                injectFields(builder);
-                return builder.build();
+                return injectBuilder(builder);
             }
-        } catch (final ConfigurationException e) { // LOG4J2-1908
-            LOGGER.error("Could not create plugin of type {} for element {}", this.clazz, node.getName(), e);
+        } catch (final InvocationTargetException e) {
+            LOGGER.error("Could not create plugin builder for plugin {} and element {}", clazz, node.getName(), e.getCause());
+            return null;
+        } catch (final IllegalAccessException e) {
+            LOGGER.error("Could not access plugin builder for plugin {} and element {}", clazz, node.getName());
+            return null;
+        } catch (final RuntimeException e) { // LOG4J2-1908
+            LOGGER.error("Could not create plugin of type {} for element {}", clazz, node.getName(), e);
             return null; // no point in trying the factory method
-        } catch (final Exception e) {
-            LOGGER.error("Could not create plugin of type {} for element {}: {}",
-                    this.clazz, node.getName(),
-                    (e instanceof InvocationTargetException ? e.getCause() : e).toString(), e);
         }
         // or fall back to factory method if no builder class is available
         try {
-            final Method factory = findFactoryMethod(this.clazz);
-            final Object[] params = generateParameters(factory);
-            return factory.invoke(null, params);
-        } catch (final Exception e) {
-            LOGGER.error("Unable to invoke factory method in {} for element {}: {}",
-                    this.clazz, this.node.getName(),
-                    (e instanceof InvocationTargetException ? e.getCause() : e).toString(), e);
+            return injectFactoryMethod(findFactoryMethod(this.clazz));
+        } catch (final Throwable e) {
+            LOGGER.error("Could not create plugin of type {} for element {}: {}", clazz, node.getName(),
+                    e.toString(), e);
             return null;
         }
     }
@@ -158,7 +153,7 @@
     private static Builder<?> createBuilder(final Class<?> clazz)
         throws InvocationTargetException, IllegalAccessException {
         for (final Method method : clazz.getDeclaredMethods()) {
-            if (method.isAnnotationPresent(PluginBuilderFactory.class) &&
+            if ((method.isAnnotationPresent(PluginFactory.class)) &&
                 Modifier.isStatic(method.getModifiers()) &&
                 TypeUtil.isAssignable(Builder.class, method.getReturnType())) {
                 ReflectionUtil.makeAccessible(method);
@@ -173,62 +168,47 @@
         return null;
     }
 
-    private void injectFields(final Builder<?> builder) throws IllegalAccessException {
+    private Object injectBuilder(final Builder<?> builder) {
         final Object target = builder instanceof BuilderWrapper ? ((BuilderWrapper) builder).getBuilder() : builder;
         final List<Field> fields = TypeUtil.getAllDeclaredFields(target.getClass());
-        AccessibleObject.setAccessible(fields.toArray(new Field[] {}), true);
+        AccessibleObject.setAccessible(fields.toArray(new Field[0]), true);
         final StringBuilder log = new StringBuilder();
-        boolean invalid = false;
-        StringBuilder reason = new StringBuilder();
+        // TODO: collect OptionBindingExceptions into a composite error message (ConfigurationException?)
         for (final Field field : fields) {
-            log.append(log.length() == 0 ? simpleName(target) + "(" : ", ");
-            final Annotation[] annotations = field.getDeclaredAnnotations();
-            final String[] aliases = extractPluginAliases(annotations);
-            for (Annotation a : annotations) {
-                if (a instanceof PluginAliases ||
-                        a instanceof org.apache.logging.log4j.core.config.plugins.PluginAliases) {
-                    continue; // already processed
+            ConfigurationInjector.forAnnotatedElement(field).ifPresent(injector -> {
+                log.append(log.length() == 0 ? simpleName(target) + "(" : ", ");
+                injector.withAliases(extractPluginAliases(field.getAnnotations()))
+                        .withConversionType(field.getGenericType())
+                        .withConfigurationBinder(new FieldConfigurationBinder(field))
+                        .withDebugLog(log)
+                        .withStringSubstitutionStrategy(substitutor)
+                        .withConfiguration(configuration)
+                        .withNode(node)
+                        .inject(target);
+            });
+        }
+        // TODO: tests
+        for (final Method method : target.getClass().getMethods()) {
+            ConfigurationInjector.forAnnotatedElement(method).ifPresent(injector -> {
+                if (method.getParameterCount() != 1) {
+                    throw new IllegalArgumentException("Cannot inject to a plugin builder method with parameter count other than 1");
                 }
-                final Object value = PluginInjectionBuilder.findBuilderForInjectionStrategy(a.annotationType())
-                        .flatMap(b -> Optional.ofNullable(b
-                                .withAliases(aliases)
-                                .withAnnotation(a)
-                                .withConfiguration(configuration)
-                                .withConfigurationNode(node)
-                                .withConversionType(field.getType())
-                                .withDebugLog(log)
-                                .withMember(field)
-                                .withStringSubstitutionStrategy(substitutor)
-                                .build()))
-                        .orElse(null);
-                if (value != null) {
-                    field.set(target, value);
-                }
-            }
-            final Collection<ConstraintValidator<?>> validators =
-                ConstraintValidators.findValidators(annotations);
-            final Object value = field.get(target);
-            for (final ConstraintValidator<?> validator : validators) {
-                if (!validator.isValid(field.getName(), value)) {
-                    invalid = true;
-                    if (reason.length() > 0) {
-                        reason.append(", ");
-                    } else {
-                        reason.append("Arguments given for element ").append(node.getName())
-                            .append(" are invalid: ");
-                    }
-                    reason.append("field '").append(field.getName()).append("' has invalid value '")
-                        .append(value).append("'");
-                }
-            }
+                log.append(log.length() == 0 ? simpleName(target) + "(" : ", ");
+                injector.withAliases(extractPluginAliases(method.getAnnotations()))
+                        .withConversionType(method.getGenericParameterTypes()[0])
+                        .withConfigurationBinder(new MethodConfigurationBinder(method))
+                        .withDebugLog(log)
+                        .withStringSubstitutionStrategy(substitutor)
+                        .withConfiguration(configuration)
+                        .withNode(node)
+                        .inject(target);
+            });
         }
         log.append(log.length() == 0 ? builder.getClass().getSimpleName() + "()" : ")");
         LOGGER.debug(log.toString());
-        if (invalid) {
-            throw new ConfigurationException(reason.toString());
-        }
         checkForRemainingAttributes();
         verifyNodeChildrenUsed();
+        return builder.build();
     }
 
     /**
@@ -255,60 +235,30 @@
         throw new IllegalStateException("No factory method found for class " + clazz.getName());
     }
 
-    private Object[] generateParameters(final Method factory) {
+    private Object injectFactoryMethod(final Method factory) throws Throwable {
         final StringBuilder log = new StringBuilder();
-        final Class<?>[] types = factory.getParameterTypes();
-        final Annotation[][] annotations = factory.getParameterAnnotations();
-        final Object[] args = new Object[annotations.length];
-        boolean invalid = false;
-        for (int i = 0; i < annotations.length; i++) {
+        final FactoryMethodBinder binder = new FactoryMethodBinder(factory);
+        binder.forEachParameter((parameter, optionBinder) -> {
             log.append(log.length() == 0 ? factory.getName() + "(" : ", ");
-            final String[] aliases = extractPluginAliases(annotations[i]);
-            final Class<?> conversionType = types[i];
-            for (final Annotation a : annotations[i]) {
-                if (a instanceof PluginAliases ||
-                        a instanceof org.apache.logging.log4j.core.config.plugins.PluginAliases) {
-                    continue; // already processed
-                }
-                final Object value = PluginInjectionBuilder.findBuilderForInjectionStrategy(a.annotationType())
-                        .flatMap(b -> Optional.ofNullable(b
-                                .withAliases(aliases)
-                                .withAnnotation(a)
-                                .withConfiguration(configuration)
-                                .withConfigurationNode(node)
-                                .withConversionType(conversionType)
-                                .withDebugLog(log)
-                                .withMember(factory)
-                                .withStringSubstitutionStrategy(substitutor)
-                                .build()))
-                        .orElse(null);
-                // don't overwrite existing values if the builder gives us no value to inject
-                if (value != null) {
-                    args[i] = value;
-                }
-            }
-            final Collection<ConstraintValidator<?>> validators =
-                ConstraintValidators.findValidators(annotations[i]);
-            final Object value = args[i];
-            final String argName = "arg[" + i + "](" + simpleName(value) + ")";
-            for (final ConstraintValidator<?> validator : validators) {
-                if (!validator.isValid(argName, value)) {
-                    invalid = true;
-                }
-            }
-        }
+            ConfigurationInjector.forAnnotatedElement(parameter).ifPresent(injector -> injector
+                            .withAliases(extractPluginAliases(parameter.getAnnotations()))
+                            .withConversionType(parameter.getParameterizedType())
+                            .withConfigurationBinder(optionBinder)
+                            .withDebugLog(log)
+                            .withStringSubstitutionStrategy(substitutor)
+                            .withConfiguration(configuration)
+                            .withNode(node)
+                            .inject(binder));
+        });
         log.append(log.length() == 0 ? factory.getName() + "()" : ")");
         checkForRemainingAttributes();
         verifyNodeChildrenUsed();
         LOGGER.debug(log.toString());
-        if (invalid) {
-            throw new ConfigurationException("Arguments given for element " + node.getName() + " are invalid");
-        }
-        return args;
+        return binder.invoke();
     }
 
     private static String[] extractPluginAliases(final Annotation... parmTypes) {
-        String[] aliases = null;
+        String[] aliases = {};
         for (final Annotation a : parmTypes) {
             if (a instanceof PluginAliases) {
                 aliases = ((PluginAliases) a).value();
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/AbstractPluginVisitor.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/AbstractPluginVisitor.java
deleted file mode 100644
index 266a3e0..0000000
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/AbstractPluginVisitor.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package org.apache.logging.log4j.core.config.plugins.visitors;
-
-import org.apache.logging.log4j.plugins.Node;
-import org.apache.logging.log4j.plugins.inject.AbstractPluginInjectionBuilder;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Member;
-import java.util.function.Function;
-
-abstract class AbstractPluginVisitor<Ann extends Annotation, Cfg> extends AbstractPluginInjectionBuilder<Ann, Cfg> {
-
-    AbstractPluginVisitor(final Class<Ann> clazz) {
-        super(clazz);
-    }
-
-    public AbstractPluginVisitor<Ann, Cfg> setAnnotation(final Annotation annotation) {
-        if (clazz.isInstance(annotation)) {
-            withAnnotation(clazz.cast(annotation));
-        }
-        return this;
-    }
-
-    public AbstractPluginVisitor<Ann, Cfg> setAliases(final String... aliases) {
-        withAliases(aliases);
-        return this;
-    }
-
-    public AbstractPluginVisitor<Ann, Cfg> setConversionType(final Class<?> conversionType) {
-        withConversionType(conversionType);
-        return this;
-    }
-
-    public AbstractPluginVisitor<Ann, Cfg> setMember(final Member member) {
-        withMember(member);
-        return this;
-    }
-
-    public Object visit(final Cfg configuration, final Node node, final Function<String, String> substitutor, final StringBuilder log) {
-        return this.withConfiguration(configuration)
-                .withConfigurationNode(node)
-                .withStringSubstitutionStrategy(substitutor)
-                .withDebugLog(log)
-                .build();
-    }
-}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginAttributeVisitor.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginAttributeVisitor.java
index f8e30c2..76e9c31 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginAttributeVisitor.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginAttributeVisitor.java
@@ -16,62 +16,77 @@
  */
 package org.apache.logging.log4j.core.config.plugins.visitors;
 
+import org.apache.logging.log4j.core.config.Configuration;
 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
+import org.apache.logging.log4j.plugins.inject.AbstractConfigurationInjector;
 import org.apache.logging.log4j.util.NameUtil;
 import org.apache.logging.log4j.util.StringBuilders;
+import org.apache.logging.log4j.util.Strings;
 
+import java.lang.reflect.Type;
+import java.util.Collections;
 import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.Function;
 
 /**
  * @deprecated Provided to support legacy plugins.
  */
-public class PluginAttributeVisitor extends AbstractPluginVisitor<PluginAttribute, Object> {
-    public PluginAttributeVisitor() {
-        super(PluginAttribute.class);
+// copy of PluginAttributeInjector
+public class PluginAttributeVisitor extends AbstractConfigurationInjector<PluginAttribute, Configuration> {
+
+    private static final Map<Type, Function<PluginAttribute, Object>> DEFAULT_VALUE_EXTRACTORS;
+
+    static {
+        final Map<Class<?>, Function<PluginAttribute, Object>> extractors = new ConcurrentHashMap<>();
+        extractors.put(int.class, PluginAttribute::defaultInt);
+        extractors.put(Integer.class, PluginAttribute::defaultInt);
+        extractors.put(long.class, PluginAttribute::defaultLong);
+        extractors.put(Long.class, PluginAttribute::defaultLong);
+        extractors.put(boolean.class, PluginAttribute::defaultBoolean);
+        extractors.put(Boolean.class, PluginAttribute::defaultBoolean);
+        extractors.put(float.class, PluginAttribute::defaultFloat);
+        extractors.put(Float.class, PluginAttribute::defaultFloat);
+        extractors.put(double.class, PluginAttribute::defaultDouble);
+        extractors.put(Double.class, PluginAttribute::defaultDouble);
+        extractors.put(byte.class, PluginAttribute::defaultByte);
+        extractors.put(Byte.class, PluginAttribute::defaultByte);
+        extractors.put(char.class, PluginAttribute::defaultChar);
+        extractors.put(Character.class, PluginAttribute::defaultChar);
+        extractors.put(short.class, PluginAttribute::defaultShort);
+        extractors.put(Short.class, PluginAttribute::defaultShort);
+        extractors.put(Class.class, PluginAttribute::defaultClass);
+        DEFAULT_VALUE_EXTRACTORS = Collections.unmodifiableMap(extractors);
     }
 
     @Override
-    public Object build() {
-        final String name = this.annotation.value();
-        final Map<String, String> attributes = node.getAttributes();
-        final String rawValue = removeAttributeValue(attributes, name, this.aliases);
-        final String replacedValue = stringSubstitutionStrategy.apply(rawValue);
-        final Object defaultValue = findDefaultValue(stringSubstitutionStrategy);
-        final Object value = convert(replacedValue, defaultValue);
-        final Object debugValue = this.annotation.sensitive() ? NameUtil.md5(value + this.getClass().getName()) : value;
-        StringBuilders.appendKeyDqValue(debugLog, name, debugValue);
-        return value;
+    public void inject(final Object factory) {
+        final Optional<String> value = findAndRemoveNodeAttribute().map(stringSubstitutionStrategy);
+        if (value.isPresent()) {
+            configurationBinder.bindString(factory, value.get());
+        } else {
+            injectDefaultValue(factory);
+        }
     }
 
-    private Object findDefaultValue(Function<String, String> substitutor) {
-        if (this.conversionType == int.class || this.conversionType == Integer.class) {
-            return this.annotation.defaultInt();
+    private void injectDefaultValue(final Object factory) {
+        final Function<PluginAttribute, Object> extractor = DEFAULT_VALUE_EXTRACTORS.get(conversionType);
+        if (extractor != null) {
+            final Object value = extractor.apply(annotation);
+            debugLog(value);
+            configurationBinder.bindObject(factory, value);
+        } else {
+            final String value = stringSubstitutionStrategy.apply(annotation.defaultString());
+            if (Strings.isNotBlank(value)) {
+                debugLog(value);
+                configurationBinder.bindString(factory, value);
+            }
         }
-        if (this.conversionType == long.class || this.conversionType == Long.class) {
-            return this.annotation.defaultLong();
-        }
-        if (this.conversionType == boolean.class || this.conversionType == Boolean.class) {
-            return this.annotation.defaultBoolean();
-        }
-        if (this.conversionType == float.class || this.conversionType == Float.class) {
-            return this.annotation.defaultFloat();
-        }
-        if (this.conversionType == double.class || this.conversionType == Double.class) {
-            return this.annotation.defaultDouble();
-        }
-        if (this.conversionType == byte.class || this.conversionType == Byte.class) {
-            return this.annotation.defaultByte();
-        }
-        if (this.conversionType == char.class || this.conversionType == Character.class) {
-            return this.annotation.defaultChar();
-        }
-        if (this.conversionType == short.class || this.conversionType == Short.class) {
-            return this.annotation.defaultShort();
-        }
-        if (this.conversionType == Class.class) {
-            return this.annotation.defaultClass();
-        }
-        return substitutor.apply(this.annotation.defaultString());
+    }
+
+    private void debugLog(final Object value) {
+        final Object debugValue = annotation.sensitive() ? NameUtil.md5(value + getClass().getName()) : value;
+        StringBuilders.appendKeyDqValue(debugLog, name, debugValue);
     }
 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginBuilderAttributeVisitor.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginBuilderAttributeVisitor.java
index 6c7f6b0..dc3aa06 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginBuilderAttributeVisitor.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginBuilderAttributeVisitor.java
@@ -17,31 +17,34 @@
 
 package org.apache.logging.log4j.core.config.plugins.visitors;
 
+import org.apache.logging.log4j.core.config.Configuration;
 import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
+import org.apache.logging.log4j.plugins.inject.AbstractConfigurationInjector;
 import org.apache.logging.log4j.util.NameUtil;
 import org.apache.logging.log4j.util.StringBuilders;
 
-import java.util.Map;
+import java.util.Optional;
 
 /**
  * @deprecated Provided for support for PluginBuilderAttribute.
  */
-public class PluginBuilderAttributeVisitor extends AbstractPluginVisitor<PluginBuilderAttribute, Object> {
-
-    public PluginBuilderAttributeVisitor() {
-        super(PluginBuilderAttribute.class);
+// copy of PluginBuilderAttributeInjector
+public class PluginBuilderAttributeVisitor extends AbstractConfigurationInjector<PluginBuilderAttribute, Configuration> {
+    @Override
+    public void inject(final Object factory) {
+        final Optional<String> value = findAndRemoveNodeAttribute().map(stringSubstitutionStrategy);
+        if (value.isPresent()) {
+            final String str = value.get();
+            debugLog(str);
+            configurationBinder.bindString(factory, str);
+        } else {
+            debugLog.append(name).append("=null");
+            configurationBinder.bindObject(factory, null);
+        }
     }
 
-    @Override
-    public Object build() {
-        final String overridden = this.annotation.value();
-        final String name = overridden.isEmpty() ? this.member.getName() : overridden;
-        final Map<String, String> attributes = node.getAttributes();
-        final String rawValue = removeAttributeValue(attributes, name, this.aliases);
-        final String replacedValue = stringSubstitutionStrategy.apply(rawValue);
-        final Object value = convert(replacedValue, null);
-        final Object debugValue = this.annotation.sensitive() ? NameUtil.md5(value + this.getClass().getName()) : value;
+    private void debugLog(final Object value) {
+        final Object debugValue = annotation.sensitive() ? NameUtil.md5(value + getClass().getName()) : value;
         StringBuilders.appendKeyDqValue(debugLog, name, debugValue);
-        return value;
     }
 }
\ No newline at end of file
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginElementVisitor.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginElementVisitor.java
index de80831..90dc00e 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginElementVisitor.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginElementVisitor.java
@@ -17,37 +17,38 @@
 
 package org.apache.logging.log4j.core.config.plugins.visitors;
 
+import org.apache.logging.log4j.core.config.Configuration;
 import org.apache.logging.log4j.core.config.plugins.PluginElement;
 import org.apache.logging.log4j.plugins.Node;
+import org.apache.logging.log4j.plugins.inject.AbstractConfigurationInjector;
 import org.apache.logging.log4j.plugins.util.PluginType;
+import org.apache.logging.log4j.plugins.util.TypeUtil;
 
 import java.lang.reflect.Array;
+import java.lang.reflect.Type;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
+import java.util.Optional;
 
 /**
  *  @deprecated Provided to support legacy plugins.
  */
-public class PluginElementVisitor extends AbstractPluginVisitor<PluginElement, Object> {
-    public PluginElementVisitor() {
-        super(PluginElement.class);
-    }
-
+// copy of PluginElementInjector
+public class PluginElementVisitor extends AbstractConfigurationInjector<PluginElement, Configuration> {
     @Override
-    public Object build() {
-        final String name = this.annotation.value();
-        if (this.conversionType.isArray()) {
-            setConversionType(this.conversionType.getComponentType());
+    public void inject(final Object factory) {
+        final Optional<Class<?>> componentType = getComponentType(conversionType);
+        if (componentType.isPresent()) {
+            final Class<?> compType = componentType.get();
             final List<Object> values = new ArrayList<>();
             final Collection<Node> used = new ArrayList<>();
             debugLog.append("={");
             boolean first = true;
             for (final Node child : node.getChildren()) {
-                final PluginType<?> childType = child.getType();
-                if (name.equalsIgnoreCase(childType.getElementName()) ||
-                        this.conversionType.isAssignableFrom(childType.getPluginClass())) {
+                final PluginType<?> type = child.getType();
+                if (name.equalsIgnoreCase(type.getElementName()) || compType.isAssignableFrom(type.getPluginClass())) {
                     if (!first) {
                         debugLog.append(", ");
                     }
@@ -55,56 +56,57 @@
                     used.add(child);
                     final Object childObject = child.getObject();
                     if (childObject == null) {
-                        LOGGER.error("Null object returned for {} in {}.", child.getName(), node.getName());
-                        continue;
-                    }
-                    if (childObject.getClass().isArray()) {
-                        debugLog.append(Arrays.toString((Object[]) childObject)).append('}');
+                        LOGGER.warn("Skipping null object returned for element {} in node {}", child.getName(), node.getName());
+                    } else if (childObject.getClass().isArray()) {
+                        Object[] children = (Object[]) childObject;
+                        debugLog.append(Arrays.toString(children)).append('}');
                         node.getChildren().removeAll(used);
-                        return childObject;
+                        configurationBinder.bindObject(factory, children);
+                        return;
+                    } else {
+                        debugLog.append(child.toString());
+                        values.add(childObject);
                     }
-                    debugLog.append(child.toString());
-                    values.add(childObject);
                 }
             }
             debugLog.append('}');
-            // note that we need to return an empty array instead of null if the types are correct
-            if (!values.isEmpty() && !this.conversionType.isAssignableFrom(values.get(0).getClass())) {
-                LOGGER.error("Attempted to assign attribute {} to list of type {} which is incompatible with {}.",
-                        name, values.get(0).getClass(), this.conversionType);
-                return null;
+            if (!values.isEmpty() && !TypeUtil.isAssignable(compType, values.get(0).getClass())) {
+                LOGGER.error("Cannot assign element {} a list of {} as it is incompatible with {}", name, values.get(0).getClass(), compType);
+                return;
             }
             node.getChildren().removeAll(used);
-            // we need to use reflection here because values.toArray() will cause type errors at runtime
-            final Object[] array = (Object[]) Array.newInstance(this.conversionType, values.size());
-            for (int i = 0; i < array.length; i++) {
-                array[i] = values.get(i);
+            // using List::toArray here would cause type mismatch later on
+            final Object[] vals = (Object[]) Array.newInstance(compType, values.size());
+            for (int i = 0; i < vals.length; i++) {
+                vals[i] = values.get(i);
             }
-            return array;
+            configurationBinder.bindObject(factory, vals);
+        } else {
+            final Optional<Node> matchingChild = node.getChildren().stream().filter(this::isRequestedNode).findAny();
+            if (matchingChild.isPresent()) {
+                final Node child = matchingChild.get();
+                debugLog.append(child.getName()).append('(').append(child.toString()).append(')');
+                node.getChildren().remove(child);
+                configurationBinder.bindObject(factory, child.getObject());
+            } else {
+                debugLog.append(name).append("=null");
+                configurationBinder.bindObject(factory, null);
+            }
         }
-        final Node namedNode = findNamedNode(name, node.getChildren());
-        if (namedNode == null) {
-            debugLog.append(name).append("=null");
-            return null;
-        }
-        debugLog.append(namedNode.getName()).append('(').append(namedNode.toString()).append(')');
-        node.getChildren().remove(namedNode);
-        return namedNode.getObject();
     }
 
-    private Node findNamedNode(final String name, final Iterable<Node> children) {
-        for (final Node child : children) {
-            final PluginType<?> childType = child.getType();
-            if (childType == null) {
-                //System.out.println();
-            }
-            if (name.equalsIgnoreCase(childType.getElementName()) ||
-                this.conversionType.isAssignableFrom(childType.getPluginClass())) {
-                // FIXME: check child.getObject() for null?
-                // doing so would be more consistent with the array version
-                return child;
+    private boolean isRequestedNode(final Node child) {
+        final PluginType<?> type = child.getType();
+        return name.equalsIgnoreCase(type.getElementName()) || TypeUtil.isAssignable(conversionType, type.getPluginClass());
+    }
+
+    private static Optional<Class<?>> getComponentType(final Type type) {
+        if (type instanceof Class<?>) {
+            final Class<?> clazz = (Class<?>) type;
+            if (clazz.isArray()) {
+                return Optional.of(clazz.getComponentType());
             }
         }
-        return null;
+        return Optional.empty();
     }
 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginNodeVisitor.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginNodeVisitor.java
index 57c0d89..f2f25f0 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginNodeVisitor.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginNodeVisitor.java
@@ -17,23 +17,23 @@
 
 package org.apache.logging.log4j.core.config.plugins.visitors;
 
+import org.apache.logging.log4j.core.config.Configuration;
 import org.apache.logging.log4j.core.config.plugins.PluginNode;
+import org.apache.logging.log4j.plugins.inject.AbstractConfigurationInjector;
+import org.apache.logging.log4j.plugins.util.TypeUtil;
 
 /**
  *  @deprecated Provided to support legacy plugins.
  */
-public class PluginNodeVisitor extends AbstractPluginVisitor<PluginNode, Object> {
-    public PluginNodeVisitor() {
-        super(PluginNode.class);
-    }
-
+// copy of PluginNodeInjector
+public class PluginNodeVisitor extends AbstractConfigurationInjector<PluginNode, Configuration> {
     @Override
-    public Object build() {
-        if (this.conversionType.isInstance(node)) {
+    public void inject(final Object factory) {
+        if (TypeUtil.isAssignable(conversionType, node.getClass())) {
             debugLog.append("Node=").append(node.getName());
-            return node;
+            configurationBinder.bindObject(factory, node);
+        } else {
+            LOGGER.error("Element with type {} annotated with @PluginNode not compatible with type {}.", conversionType, node.getClass());
         }
-        LOGGER.warn("Variable annotated with @PluginNode is not compatible with the type {}.", node.getClass());
-        return null;
     }
 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginValueVisitor.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginValueVisitor.java
index 9600514..c2ba2ab 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginValueVisitor.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginValueVisitor.java
@@ -17,23 +17,21 @@
 
 package org.apache.logging.log4j.core.config.plugins.visitors;
 
+import org.apache.logging.log4j.core.config.Configuration;
 import org.apache.logging.log4j.core.config.plugins.PluginValue;
+import org.apache.logging.log4j.plugins.inject.AbstractConfigurationInjector;
 import org.apache.logging.log4j.util.StringBuilders;
 import org.apache.logging.log4j.util.Strings;
 
 /**
  *  @deprecated Provided to support legacy plugins.
  */
-public class PluginValueVisitor extends AbstractPluginVisitor<PluginValue, Object> {
-    public PluginValueVisitor() {
-        super(PluginValue.class);
-    }
-
+// copy of PluginValueInjector
+public class PluginValueVisitor extends AbstractConfigurationInjector<PluginValue, Configuration> {
     @Override
-    public Object build() {
-        final String name = this.annotation.value();
+    public void inject(final Object factory) {
         final String elementValue = node.getValue();
-        final String attributeValue = node.getAttributes().get("value");
+        final String attributeValue = node.getAttributes().get(name);
         String rawValue = null; // if neither is specified, return null (LOG4J2-1313)
         if (Strings.isNotEmpty(elementValue)) {
             if (Strings.isNotEmpty(attributeValue)) {
@@ -43,10 +41,10 @@
             }
             rawValue = elementValue;
         } else {
-            rawValue = removeAttributeValue(node.getAttributes(), "value");
+            rawValue = findAndRemoveNodeAttribute().orElse(null);
         }
         final String value = stringSubstitutionStrategy.apply(rawValue);
         StringBuilders.appendKeyDqValue(debugLog, name, value);
-        return value;
+        configurationBinder.bindString(factory, value);
     }
 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/package-info.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/package-info.java
index 04badd1..9b747e3 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/package-info.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/package-info.java
@@ -16,9 +16,7 @@
  */
 
 /**
- * Visitor classes for extracting values from a Configuration or Node corresponding to a plugin annotation.
- * Visitor implementations must implement {@link org.apache.logging.log4j.plugins.inject.PluginInjectionBuilder},
- * and the corresponding annotation must be annotated with
- * {@link org.apache.logging.log4j.plugins.inject.InjectionStrategy}.
+ * Legacy injector strategies for legacy annotations. Plugins should use the updated annotations provided in
+ * {@code org.apache.logging.log4j.plugins}.
  */
 package org.apache.logging.log4j.core.config.plugins.visitors;
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/BurstFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/BurstFilter.java
index 8edae28..b815ee4 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/BurstFilter.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/BurstFilter.java
@@ -17,22 +17,22 @@
 
 package org.apache.logging.log4j.core.filter;
 
-import java.util.Queue;
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.DelayQueue;
-import java.util.concurrent.Delayed;
-import java.util.concurrent.TimeUnit;
-
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.Marker;
 import org.apache.logging.log4j.core.Filter;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.Logger;
+import org.apache.logging.log4j.message.Message;
 import org.apache.logging.log4j.plugins.Node;
 import org.apache.logging.log4j.plugins.Plugin;
 import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
-import org.apache.logging.log4j.message.Message;
+import org.apache.logging.log4j.plugins.PluginFactory;
+
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.DelayQueue;
+import java.util.concurrent.Delayed;
+import java.util.concurrent.TimeUnit;
 
 /**
  * The <code>BurstFilter</code> is a logging filter that regulates logging traffic.
@@ -285,7 +285,7 @@
         }
     }
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static Builder newBuilder() {
         return new Builder();
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/DenyAllFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/DenyAllFilter.java
new file mode 100644
index 0000000..dbdc550
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/DenyAllFilter.java
@@ -0,0 +1,156 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.core.filter;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.Logger;
+import org.apache.logging.log4j.message.Message;
+import org.apache.logging.log4j.plugins.Node;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.plugins.PluginFactory;
+
+import org.apache.logging.log4j.util.PerformanceSensitive;
+
+/**
+ * This filter causes all logging events to be dropped.
+ */
+@Plugin(name = "DenyAllFilter", category = Node.CATEGORY, elementType = Filter.ELEMENT_TYPE, printObject = true)
+@PerformanceSensitive("allocation")
+public final class DenyAllFilter extends AbstractFilter {
+
+    private DenyAllFilter(final Result onMatch, final Result onMismatch) {
+        super(onMatch, onMismatch);
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
+                         final Object... params) {
+        return Result.DENY;
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final Object msg,
+                         final Throwable t) {
+        return Result.DENY;
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final Message msg,
+                         final Throwable t) {
+        return Result.DENY;
+    }
+
+    @Override
+    public Result filter(final LogEvent event) {
+        return Result.DENY;
+    }
+
+    private Result filter(final Marker marker) {
+        return Result.DENY;
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
+            final Object p0) {
+        return Result.DENY;
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
+            final Object p0, final Object p1) {
+        return Result.DENY;
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
+            final Object p0, final Object p1, final Object p2) {
+        return filter(marker);
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
+            final Object p0, final Object p1, final Object p2, final Object p3) {
+        return Result.DENY;
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
+            final Object p0, final Object p1, final Object p2, final Object p3,
+            final Object p4) {
+        return Result.DENY;
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
+            final Object p0, final Object p1, final Object p2, final Object p3,
+            final Object p4, final Object p5) {
+        return Result.DENY;
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
+            final Object p0, final Object p1, final Object p2, final Object p3,
+            final Object p4, final Object p5, final Object p6) {
+        return Result.DENY;
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
+            final Object p0, final Object p1, final Object p2, final Object p3,
+            final Object p4, final Object p5, final Object p6,
+            final Object p7) {
+        return Result.DENY;
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
+            final Object p0, final Object p1, final Object p2, final Object p3,
+            final Object p4, final Object p5, final Object p6,
+            final Object p7, final Object p8) {
+        return Result.DENY;
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
+            final Object p0, final Object p1, final Object p2, final Object p3,
+            final Object p4, final Object p5, final Object p6,
+            final Object p7, final Object p8, final Object p9) {
+        return Result.DENY;
+    }
+
+    @Override
+    public String toString() {
+        return "DenyAll";
+    }
+
+    @PluginFactory
+    public static DenyAllFilter.Builder newBuilder() {
+        return new DenyAllFilter.Builder();
+    }
+
+    public static class Builder extends AbstractFilterBuilder<DenyAllFilter.Builder> implements org.apache.logging.log4j.core.util.Builder<DenyAllFilter> {
+
+        @Override
+        public DenyAllFilter build() {
+            return new DenyAllFilter(this.getOnMatch(), this.getOnMismatch());
+        }
+    }
+
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/DynamicThresholdFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/DynamicThresholdFilter.java
index 738f49a..40738d3 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/DynamicThresholdFilter.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/DynamicThresholdFilter.java
@@ -59,11 +59,11 @@
     // TODO Consider refactoring to use AbstractFilter.AbstractFilterBuilder
     @PluginFactory
     public static DynamicThresholdFilter createFilter(
-            @PluginAttribute("key") final String key,
-            @PluginElement("Pairs") final KeyValuePair[] pairs,
-            @PluginAttribute("defaultThreshold") final Level defaultThreshold,
-            @PluginAttribute("onMatch") final Result onMatch,
-            @PluginAttribute("onMismatch") final Result onMismatch) {
+            @PluginAttribute final String key,
+            @PluginElement final KeyValuePair[] pairs,
+            @PluginAttribute final Level defaultThreshold,
+            @PluginAttribute final Result onMatch,
+            @PluginAttribute final Result onMismatch) {
         final Map<String, Level> map = new HashMap<>();
         for (final KeyValuePair pair : pairs) {
             map.put(pair.getKey(), Level.toLevel(pair.getValue()));
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/LevelMatchFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/LevelMatchFilter.java
new file mode 100644
index 0000000..cafbac1
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/LevelMatchFilter.java
@@ -0,0 +1,173 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.core.filter;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.Logger;
+import org.apache.logging.log4j.message.Message;
+import org.apache.logging.log4j.plugins.Node;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
+import org.apache.logging.log4j.plugins.PluginFactory;
+import org.apache.logging.log4j.util.PerformanceSensitive;
+
+/**
+ * This filter returns the onMatch result if the logging level in the event matches the specified logging level
+ * exactly.
+ */
+@Plugin(name = "LevelMatchFilter", category = Node.CATEGORY, elementType = Filter.ELEMENT_TYPE, printObject = true)
+@PerformanceSensitive("allocation")
+public final class LevelMatchFilter extends AbstractFilter {
+
+    public static final String ATTR_MATCH = "match";
+    private final Level level;
+
+    private LevelMatchFilter(final Level level, final Result onMatch, final Result onMismatch) {
+        super(onMatch, onMismatch);
+        this.level = level;
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
+                         final Object... params) {
+        return filter(level);
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final Object msg,
+                         final Throwable t) {
+        return filter(level);
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final Message msg,
+                         final Throwable t) {
+        return filter(level);
+    }
+
+    @Override
+    public Result filter(final LogEvent event) {
+        return filter(event.getLevel());
+    }
+
+    private Result filter(final Level level) {
+        return level == this.level ? onMatch : onMismatch;
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
+            final Object p0) {
+        return filter(level);
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
+            final Object p0, final Object p1) {
+        return filter(level);
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
+            final Object p0, final Object p1, final Object p2) {
+        return filter(level);
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
+            final Object p0, final Object p1, final Object p2, final Object p3) {
+        return filter(level);
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
+            final Object p0, final Object p1, final Object p2, final Object p3,
+            final Object p4) {
+        return filter(level);
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
+            final Object p0, final Object p1, final Object p2, final Object p3,
+            final Object p4, final Object p5) {
+        return filter(level);
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
+            final Object p0, final Object p1, final Object p2, final Object p3,
+            final Object p4, final Object p5, final Object p6) {
+        return filter(level);
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
+            final Object p0, final Object p1, final Object p2, final Object p3,
+            final Object p4, final Object p5, final Object p6,
+            final Object p7) {
+        return filter(level);
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
+            final Object p0, final Object p1, final Object p2, final Object p3,
+            final Object p4, final Object p5, final Object p6,
+            final Object p7, final Object p8) {
+        return filter(level);
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
+            final Object p0, final Object p1, final Object p2, final Object p3,
+            final Object p4, final Object p5, final Object p6,
+            final Object p7, final Object p8, final Object p9) {
+        return filter(level);
+    }
+
+    @Override
+    public String toString() {
+        return level.toString();
+    }
+
+    @PluginFactory
+    public static LevelMatchFilter.Builder newBuilder() {
+        return new LevelMatchFilter.Builder();
+    }
+
+    public static class Builder extends AbstractFilterBuilder<LevelMatchFilter.Builder> implements org.apache.logging.log4j.core.util.Builder<LevelMatchFilter> {
+        @PluginBuilderAttribute
+        private Level level = Level.ERROR;
+
+        /**
+         * Sets the logging level to use.
+         * @param level the logging level to use.
+         * @return this
+         */
+        public LevelMatchFilter.Builder setLevel(final Level level) {
+            this.level = level;
+            return this;
+        }
+
+        @Override
+        public LevelMatchFilter build() {
+            return new LevelMatchFilter(this.level, this.getOnMatch(), this.getOnMismatch());
+        }
+    }
+
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/LevelRangeFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/LevelRangeFilter.java
index 983873c..99d80a0 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/LevelRangeFilter.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/LevelRangeFilter.java
@@ -59,10 +59,10 @@
     @PluginFactory
     public static LevelRangeFilter createFilter(
             // @formatter:off
-            @PluginAttribute("minLevel") final Level minLevel,
-            @PluginAttribute("maxLevel") final Level maxLevel,
-            @PluginAttribute("onMatch") final Result match,
-            @PluginAttribute("onMismatch") final Result mismatch) {
+            @PluginAttribute final Level minLevel,
+            @PluginAttribute final Level maxLevel,
+            @PluginAttribute final Result match,
+            @PluginAttribute final Result mismatch) {
             // @formatter:on
         final Level actualMinLevel = minLevel == null ? Level.ERROR : minLevel;
         final Level actualMaxLevel = maxLevel == null ? Level.ERROR : maxLevel;
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/MapFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/MapFilter.java
index 7f64384..b5e9ba0 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/MapFilter.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/MapFilter.java
@@ -224,10 +224,10 @@
     // TODO Consider refactoring to use AbstractFilter.AbstractFilterBuilder
     @PluginFactory
     public static MapFilter createFilter(
-            @PluginElement("Pairs") final KeyValuePair[] pairs,
-            @PluginAttribute("operator") final String oper,
-            @PluginAttribute("onMatch") final Result match,
-            @PluginAttribute("onMismatch") final Result mismatch) {
+            @PluginElement final KeyValuePair[] pairs,
+            @PluginAttribute final String operator,
+            @PluginAttribute final Result onMatch,
+            @PluginAttribute final Result onMismatch) {
         if (pairs == null || pairs.length == 0) {
             LOGGER.error("keys and values must be specified for the MapFilter");
             return null;
@@ -257,7 +257,7 @@
             LOGGER.error("MapFilter is not configured with any valid key value pairs");
             return null;
         }
-        final boolean isAnd = oper == null || !oper.equalsIgnoreCase("or");
-        return new MapFilter(map, isAnd, match, mismatch);
+        final boolean isAnd = operator == null || !operator.equalsIgnoreCase("or");
+        return new MapFilter(map, isAnd, onMatch, onMismatch);
     }
 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/MarkerFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/MarkerFilter.java
index 5d63518..d83eeae 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/MarkerFilter.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/MarkerFilter.java
@@ -36,7 +36,6 @@
 @PerformanceSensitive("allocation")
 public final class MarkerFilter extends AbstractFilter {
 
-    public static final String ATTR_MARKER = "marker";
     private final String name;
 
     private MarkerFilter(final String name, final Result onMatch, final Result onMismatch) {
@@ -148,22 +147,22 @@
     /**
      * Creates the MarkerFilter.
      * @param marker The Marker name to match.
-     * @param match The action to take if a match occurs.
-     * @param mismatch The action to take if no match occurs.
+     * @param onMatch The action to take if a match occurs.
+     * @param onMismatch The action to take if no match occurs.
      * @return A MarkerFilter.
      */
     // TODO Consider refactoring to use AbstractFilter.AbstractFilterBuilder
     @PluginFactory
     public static MarkerFilter createFilter(
-            @PluginAttribute(ATTR_MARKER) final String marker,
-            @PluginAttribute(AbstractFilterBuilder.ATTR_ON_MATCH) final Result match,
-            @PluginAttribute(AbstractFilterBuilder.ATTR_ON_MISMATCH) final Result mismatch) {
+            @PluginAttribute final String marker,
+            @PluginAttribute final Result onMatch,
+            @PluginAttribute final Result onMismatch) {
 
         if (marker == null) {
             LOGGER.error("A marker must be provided for MarkerFilter");
             return null;
         }
-        return new MarkerFilter(marker, match, mismatch);
+        return new MarkerFilter(marker, onMatch, onMismatch);
     }
 
 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/NoMarkerFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/NoMarkerFilter.java
index 258a4be..92fcf63 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/NoMarkerFilter.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/NoMarkerFilter.java
@@ -24,7 +24,7 @@
 import org.apache.logging.log4j.message.Message;
 import org.apache.logging.log4j.plugins.Node;
 import org.apache.logging.log4j.plugins.Plugin;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
+import org.apache.logging.log4j.plugins.PluginFactory;
 import org.apache.logging.log4j.util.PerformanceSensitive;
 
 /**
@@ -135,7 +135,7 @@
     }
 
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static Builder newBuilder() {
         return new Builder();
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java
index d7ab68a..f5c87ac 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java
@@ -107,12 +107,12 @@
      * @param regex
      *        The regular expression to match.
      * @param patternFlags
-     *        An array of Stirngs where each String is a {@link Pattern#compile(String, int)} compilation flag.
+     *        An array of Strings where each String is a {@link Pattern#compile(String, int)} compilation flag.
      * @param useRawMsg
      *        If true, the raw message will be used, otherwise the formatted message will be used.
-     * @param match
+     * @param onMatch
      *        The action to perform when a match occurs.
-     * @param mismatch
+     * @param onMismatch
      *        The action to perform when a mismatch occurs.
      * @return The RegexFilter.
      * @throws IllegalAccessException
@@ -122,18 +122,18 @@
     @PluginFactory
     public static RegexFilter createFilter(
             //@formatter:off
-            @PluginAttribute("regex") final String regex,
-            @PluginElement("PatternFlags") final String[] patternFlags,
-            @PluginAttribute("useRawMsg") final Boolean useRawMsg,
-            @PluginAttribute("onMatch") final Result match,
-            @PluginAttribute("onMismatch") final Result mismatch)
+            @PluginAttribute final String regex,
+            @PluginElement final String[] patternFlags,
+            @PluginAttribute final Boolean useRawMsg,
+            @PluginAttribute final Result onMatch,
+            @PluginAttribute final Result onMismatch)
             //@formatter:on
             throws IllegalArgumentException, IllegalAccessException {
         if (regex == null) {
             LOGGER.error("A regular expression must be provided for RegexFilter");
             return null;
         }
-        return new RegexFilter(useRawMsg, Pattern.compile(regex, toPatternFlags(patternFlags)), match, mismatch);
+        return new RegexFilter(useRawMsg, Pattern.compile(regex, toPatternFlags(patternFlags)), onMatch, onMismatch);
     }
 
     private static int toPatternFlags(final String[] patternFlags) throws IllegalArgumentException,
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/ScriptFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/ScriptFilter.java
index 31086e0..a911d00 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/ScriptFilter.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/ScriptFilter.java
@@ -125,17 +125,17 @@
      * Creates the ScriptFilter.
      * @param script The script to run. The script must return a boolean value. Either script or scriptFile must be 
      *      provided.
-     * @param match The action to take if a match occurs.
-     * @param mismatch The action to take if no match occurs.
+     * @param onMatch The action to take if a match occurs.
+     * @param onMismatch The action to take if no match occurs.
      * @param configuration the configuration 
      * @return A ScriptFilter.
      */
     // TODO Consider refactoring to use AbstractFilter.AbstractFilterBuilder
     @PluginFactory
     public static ScriptFilter createFilter(
-            @PluginElement("Script") final AbstractScript script,
-            @PluginAttribute("onMatch") final Result match,
-            @PluginAttribute("onMismatch") final Result mismatch,
+            @PluginElement final AbstractScript script,
+            @PluginAttribute final Result onMatch,
+            @PluginAttribute final Result onMismatch,
             @PluginConfiguration final Configuration configuration) {
 
         if (script == null) {
@@ -149,7 +149,7 @@
             }
         }
 
-        return new ScriptFilter(script, configuration, match, mismatch);
+        return new ScriptFilter(script, configuration, onMatch, onMismatch);
     }
 
 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/StringMatchFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/StringMatchFilter.java
new file mode 100644
index 0000000..a273726
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/StringMatchFilter.java
@@ -0,0 +1,175 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.core.filter;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.Logger;
+import org.apache.logging.log4j.message.Message;
+import org.apache.logging.log4j.plugins.Node;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
+import org.apache.logging.log4j.plugins.PluginFactory;
+import org.apache.logging.log4j.util.PerformanceSensitive;
+
+/**
+ * This filter returns the onMatch result if the logging level in the event matches the specified logging level
+ * exactly.
+ */
+@Plugin(name = "StringMatchFilter", category = Node.CATEGORY, elementType = Filter.ELEMENT_TYPE, printObject = true)
+@PerformanceSensitive("allocation")
+public final class StringMatchFilter extends AbstractFilter {
+
+    public static final String ATTR_MATCH = "match";
+    private final String text;
+
+    private StringMatchFilter(final String text, final Result onMatch, final Result onMismatch) {
+        super(onMatch, onMismatch);
+        this.text = text;
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
+                         final Object... params) {
+        return filter(logger.getMessageFactory().newMessage(msg, params).getFormattedMessage());
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final Object msg,
+                         final Throwable t) {
+        return filter(logger.getMessageFactory().newMessage(msg).getFormattedMessage());
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final Message msg,
+                         final Throwable t) {
+        return filter(msg.getFormattedMessage());
+    }
+
+    @Override
+    public Result filter(final LogEvent event) {
+        return filter(event.getMessage().getFormattedMessage());
+    }
+
+    private Result filter(final String msg) {
+        return msg.contains(this.text) ? onMatch : onMismatch;
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
+            final Object p0) {
+        return filter(logger.getMessageFactory().newMessage(msg, p0).getFormattedMessage());
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
+            final Object p0, final Object p1) {
+        return filter(logger.getMessageFactory().newMessage(msg, p0, p1).getFormattedMessage());
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
+            final Object p0, final Object p1, final Object p2) {
+        return filter(logger.getMessageFactory().newMessage(msg, p0, p1, p2).getFormattedMessage());
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
+            final Object p0, final Object p1, final Object p2, final Object p3) {
+        return filter(logger.getMessageFactory().newMessage(msg, p0, p1, p2, p3).getFormattedMessage());
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
+            final Object p0, final Object p1, final Object p2, final Object p3,
+            final Object p4) {
+        return filter(logger.getMessageFactory().newMessage(msg, p0, p1, p2, p3, p4).getFormattedMessage());
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
+            final Object p0, final Object p1, final Object p2, final Object p3,
+            final Object p4, final Object p5) {
+        return filter(logger.getMessageFactory().newMessage(msg, p0, p1, p2, p3, p4, p5).getFormattedMessage());
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
+            final Object p0, final Object p1, final Object p2, final Object p3,
+            final Object p4, final Object p5, final Object p6) {
+        return filter(logger.getMessageFactory().newMessage(msg, p0, p1, p2, p3, p4, p5, p6).getFormattedMessage());
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
+            final Object p0, final Object p1, final Object p2, final Object p3,
+            final Object p4, final Object p5, final Object p6,
+            final Object p7) {
+        return filter(logger.getMessageFactory().newMessage(msg, p0, p1, p2, p3, p4, p5, p6, p7).getFormattedMessage());
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
+            final Object p0, final Object p1, final Object p2, final Object p3,
+            final Object p4, final Object p5, final Object p6,
+            final Object p7, final Object p8) {
+        return filter(logger.getMessageFactory().newMessage(msg, p0, p1, p2, p3, p4, p5, p6, p7, p8)
+                .getFormattedMessage());
+    }
+
+    @Override
+    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
+            final Object p0, final Object p1, final Object p2, final Object p3,
+            final Object p4, final Object p5, final Object p6,
+            final Object p7, final Object p8, final Object p9) {
+        return filter(logger.getMessageFactory().newMessage(msg, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)
+                .getFormattedMessage());
+    }
+
+    @Override
+    public String toString() {
+        return text;
+    }
+
+    @PluginFactory
+    public static StringMatchFilter.Builder newBuilder() {
+        return new StringMatchFilter.Builder();
+    }
+
+    public static class Builder extends AbstractFilterBuilder<StringMatchFilter.Builder> implements org.apache.logging.log4j.core.util.Builder<StringMatchFilter> {
+        @PluginBuilderAttribute
+        private String text = "";
+
+        /**
+         * Sets the logging level to use.
+         * @param level the logging level to use.
+         * @return this
+         */
+        public StringMatchFilter.Builder setMatchString(final String text) {
+            this.text = text;
+            return this;
+        }
+
+        @Override
+        public StringMatchFilter build() {
+            return new StringMatchFilter(this.text, this.getOnMatch(), this.getOnMismatch());
+        }
+    }
+
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/StructuredDataFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/StructuredDataFilter.java
index d806869..c3b2684 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/StructuredDataFilter.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/StructuredDataFilter.java
@@ -149,18 +149,18 @@
     /**
      * Creates the StructuredDataFilter.
      * @param pairs Key and value pairs.
-     * @param oper The operator to perform. If not "or" the operation will be an "and".
-     * @param match The action to perform on a match.
-     * @param mismatch The action to perform on a mismatch.
+     * @param operator The operator to perform. If not "or" the operation will be an "and".
+     * @param onMatch The action to perform on a match.
+     * @param onMismatch The action to perform on a mismatch.
      * @return The StructuredDataFilter.
      */
     // TODO Consider refactoring to use AbstractFilter.AbstractFilterBuilder
     @PluginFactory
     public static StructuredDataFilter createFilter(
-            @PluginElement("Pairs") final KeyValuePair[] pairs,
-            @PluginAttribute("operator") final String oper,
-            @PluginAttribute("onMatch") final Result match,
-            @PluginAttribute("onMismatch") final Result mismatch) {
+            @PluginElement final KeyValuePair[] pairs,
+            @PluginAttribute final String operator,
+            @PluginAttribute final Result onMatch,
+            @PluginAttribute final Result onMismatch) {
         if (pairs == null || pairs.length == 0) {
             LOGGER.error("keys and values must be specified for the StructuredDataFilter");
             return null;
@@ -190,7 +190,7 @@
             LOGGER.error("StructuredDataFilter is not configured with any valid key value pairs");
             return null;
         }
-        final boolean isAnd = oper == null || !oper.equalsIgnoreCase("or");
-        return new StructuredDataFilter(map, isAnd, match, mismatch);
+        final boolean isAnd = operator == null || !operator.equalsIgnoreCase("or");
+        return new StructuredDataFilter(map, isAnd, onMatch, onMismatch);
     }
 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/ThreadContextMapFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/ThreadContextMapFilter.java
index 22b2f94..5f4beb7 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/ThreadContextMapFilter.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/ThreadContextMapFilter.java
@@ -197,10 +197,10 @@
     // TODO Consider refactoring to use AbstractFilter.AbstractFilterBuilder
     @PluginFactory
     public static ThreadContextMapFilter createFilter(
-            @PluginElement("Pairs") final KeyValuePair[] pairs,
-            @PluginAttribute("operator") final String oper,
-            @PluginAttribute("onMatch") final Result match,
-            @PluginAttribute("onMismatch") final Result mismatch) {
+            @PluginElement final KeyValuePair[] pairs,
+            @PluginAttribute final String operator,
+            @PluginAttribute final Result onMatch,
+            @PluginAttribute final Result onMismatch) {
         if (pairs == null || pairs.length == 0) {
             LOGGER.error("key and value pairs must be specified for the ThreadContextMapFilter");
             return null;
@@ -230,7 +230,7 @@
             LOGGER.error("ThreadContextMapFilter is not configured with any valid key value pairs");
             return null;
         }
-        final boolean isAnd = oper == null || !oper.equalsIgnoreCase("or");
-        return new ThreadContextMapFilter(map, isAnd, match, mismatch);
+        final boolean isAnd = operator == null || !operator.equalsIgnoreCase("or");
+        return new ThreadContextMapFilter(map, isAnd, onMatch, onMismatch);
     }
 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/ThresholdFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/ThresholdFilter.java
index db6f99a..76befe0 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/ThresholdFilter.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/ThresholdFilter.java
@@ -162,7 +162,7 @@
     // TODO Consider refactoring to use AbstractFilter.AbstractFilterBuilder
     @PluginFactory
     public static ThresholdFilter createFilter(
-            @PluginAttribute("level") final Level level,
+            @PluginAttribute final Level level,
             @PluginAttribute("onMatch") final Result match,
             @PluginAttribute("onMismatch") final Result mismatch) {
         final Level actualLevel = level == null ? Level.ERROR : level;
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/TimeFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/TimeFilter.java
index 1fe61d3..2c675ca 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/TimeFilter.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/TimeFilter.java
@@ -231,8 +231,8 @@
     // TODO Consider refactoring to use AbstractFilter.AbstractFilterBuilder
     @PluginFactory
     public static TimeFilter createFilter(
-            @PluginAttribute("start") final String start,
-            @PluginAttribute("end") final String end,
+            @PluginAttribute final String start,
+            @PluginAttribute final String end,
             @PluginAttribute("timezone") final String tz,
             @PluginAttribute("onMatch") final Result match,
             @PluginAttribute("onMismatch") final Result mismatch) {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jContextFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jContextFactory.java
index e00eb29..1ca8280 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jContextFactory.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jContextFactory.java
@@ -299,7 +299,7 @@
      * @param currentContext If true returns the current Context, if false returns the Context appropriate
      * for the caller if a more appropriate Context can be determined.
      * @return true if a LoggerContext has been installed, false otherwise.
-     * @since 3.0
+     * @since 2.13.0
      */
     @Override
     public boolean hasContext(String fqcn, ClassLoader loader, boolean currentContext) {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractStringLayout.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractStringLayout.java
index 759fe38..76c00b2 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractStringLayout.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractStringLayout.java
@@ -93,13 +93,19 @@
         default boolean requiresLocation() {
             return false;
         }
+
+        default StringBuilder toSerializable(final LogEvent event, final StringBuilder builder) {
+            builder.append(toSerializable(event));
+            return builder;
+        }
     }
 
     /**
      * Variation of {@link Serializer} that avoids allocating temporary objects.
+     * As of 2.13 this interface was merged into the Serializer interface.
      * @since 2.6
      */
-    public interface Serializer2 {
+    public interface Serializer2  {
         StringBuilder toSerializable(final LogEvent event, final StringBuilder builder);
     }
 
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/GelfLayout.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/GelfLayout.java
index 2f5c5e9..268ec6a 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/GelfLayout.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/GelfLayout.java
@@ -16,37 +16,43 @@
  */
 package org.apache.logging.log4j.core.layout;
 
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.layout.internal.ExcludeChecker;
+import org.apache.logging.log4j.core.layout.internal.IncludeChecker;
+import org.apache.logging.log4j.core.layout.internal.ListChecker;
+import org.apache.logging.log4j.core.lookup.StrSubstitutor;
+import org.apache.logging.log4j.core.net.Severity;
+import org.apache.logging.log4j.core.util.JsonUtils;
+import org.apache.logging.log4j.core.util.KeyValuePair;
+import org.apache.logging.log4j.core.util.NetUtils;
+import org.apache.logging.log4j.core.util.Patterns;
+import org.apache.logging.log4j.message.Message;
+import org.apache.logging.log4j.plugins.Node;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
+import org.apache.logging.log4j.plugins.PluginElement;
+import org.apache.logging.log4j.plugins.PluginFactory;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.StringBuilderFormattable;
+import org.apache.logging.log4j.util.Strings;
+import org.apache.logging.log4j.util.TriConsumer;
+
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
 import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 import java.util.zip.DeflaterOutputStream;
 import java.util.zip.GZIPOutputStream;
 
-import org.apache.logging.log4j.Level;
-import org.apache.logging.log4j.core.Layout;
-import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.core.config.Configuration;
-import org.apache.logging.log4j.plugins.Node;
-import org.apache.logging.log4j.plugins.Plugin;
-import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
-import org.apache.logging.log4j.plugins.PluginElement;
-import org.apache.logging.log4j.core.lookup.StrSubstitutor;
-import org.apache.logging.log4j.core.net.Severity;
-import org.apache.logging.log4j.core.util.JsonUtils;
-import org.apache.logging.log4j.core.util.KeyValuePair;
-import org.apache.logging.log4j.core.util.NetUtils;
-import org.apache.logging.log4j.message.Message;
-import org.apache.logging.log4j.status.StatusLogger;
-import org.apache.logging.log4j.util.StringBuilderFormattable;
-import org.apache.logging.log4j.util.Strings;
-import org.apache.logging.log4j.util.TriConsumer;
-
 /**
  * Lays out events in the Graylog Extended Log Format (GELF) 1.1.
  * <p>
@@ -97,6 +103,8 @@
     private final boolean includeStacktrace;
     private final boolean includeThreadContext;
     private final boolean includeNullDelimiter;
+    private final PatternLayout layout;
+    private final FieldWriter fieldWriter;
 
     public static class Builder<B extends Builder<B>> extends AbstractStringLayout.Builder<B>
         implements org.apache.logging.log4j.plugins.util.Builder<GelfLayout> {
@@ -122,6 +130,15 @@
         @PluginBuilderAttribute
         private boolean includeNullDelimiter = false;
 
+        @PluginBuilderAttribute
+        private String threadContextIncludes = null;
+
+        @PluginBuilderAttribute
+        private String threadContextExcludes = null;
+
+        @PluginBuilderAttribute
+        private String messagePattern = null;
+
         public Builder() {
             super();
             setCharset(StandardCharsets.UTF_8);
@@ -129,8 +146,39 @@
 
         @Override
         public GelfLayout build() {
+            ListChecker checker = null;
+            if (threadContextExcludes != null) {
+                final String[] array = threadContextExcludes.split(Patterns.COMMA_SEPARATOR);
+                if (array.length > 0) {
+                    List<String> excludes = new ArrayList<>(array.length);
+                    for (final String str : array) {
+                        excludes.add(str.trim());
+                    }
+                    checker = new ExcludeChecker(excludes);
+                }
+            }
+            if (threadContextIncludes != null) {
+                final String[] array = threadContextIncludes.split(Patterns.COMMA_SEPARATOR);
+                if (array.length > 0) {
+                    List<String> includes = new ArrayList<>(array.length);
+                    for (final String str : array) {
+                        includes.add(str.trim());
+                    }
+                    checker = new IncludeChecker(includes);
+                }
+            }
+            if (checker == null) {
+                checker = ListChecker.NOOP_CHECKER;
+            }
+            PatternLayout patternLayout = null;
+            if (messagePattern != null) {
+                patternLayout = PatternLayout.newBuilder().setPattern(messagePattern)
+                        .setAlwaysWriteExceptions(includeStacktrace)
+                        .setConfiguration(getConfiguration())
+                        .build();
+            }
             return new GelfLayout(getConfiguration(), host, additionalFields, compressionType, compressionThreshold,
-                includeStacktrace, includeThreadContext, includeNullDelimiter);
+                includeStacktrace, includeThreadContext, includeNullDelimiter, checker, patternLayout);
         }
 
         public String getHost() {
@@ -230,10 +278,42 @@
             this.additionalFields = additionalFields;
             return asBuilder();
         }
+
+        /**
+         * The pattern to use to format the message.
+         * @param pattern the pattern string.
+         * @return this builder
+         */
+        public B setMessagePattern(final String pattern) {
+            this.messagePattern = pattern;
+            return asBuilder();
+        }
+
+        /**
+         * A comma separated list of thread context keys to include;
+         * @param mdcIncludes the list of keys.
+         * @return this builder
+         */
+        public B setMdcIncludes(final String mdcIncludes) {
+            this.threadContextIncludes = mdcIncludes;
+            return asBuilder();
+        }
+
+        /**
+         * A comma separated list of thread context keys to include;
+         * @param mdcExcludes the list of keys.
+         * @return this builder
+         */
+        public B setMdcExcludes(final String mdcExcludes) {
+            this.threadContextExcludes = mdcExcludes;
+            return asBuilder();
+        }
     }
 
-    private GelfLayout(final Configuration config, final String host, final KeyValuePair[] additionalFields, final CompressionType compressionType,
-               final int compressionThreshold, final boolean includeStacktrace, final boolean includeThreadContext, final boolean includeNullDelimiter) {
+    private GelfLayout(final Configuration config, final String host, final KeyValuePair[] additionalFields,
+            final CompressionType compressionType, final int compressionThreshold, final boolean includeStacktrace,
+            final boolean includeThreadContext, final boolean includeNullDelimiter, final ListChecker listChecker,
+            final PatternLayout patternLayout) {
         super(config, StandardCharsets.UTF_8, null, null);
         this.host = host != null ? host : NetUtils.getLocalHostname();
         this.additionalFields = additionalFields != null ? additionalFields : new KeyValuePair[0];
@@ -252,9 +332,30 @@
         if (includeNullDelimiter && compressionType != CompressionType.OFF) {
             throw new IllegalArgumentException("null delimiter cannot be used with compression");
         }
+        this.fieldWriter = new FieldWriter(listChecker);
+        this.layout = patternLayout;
     }
 
-    @PluginBuilderFactory
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("host=").append(host);
+        sb.append(", compressionType=").append(compressionType.toString());
+        sb.append(", compressionThreshold=").append(compressionThreshold);
+        sb.append(", includeStackTrace=").append(includeStacktrace);
+        sb.append(", includeThreadContext=").append(includeThreadContext);
+        sb.append(", includeNullDelimiter=").append(includeNullDelimiter);
+        String threadVars = fieldWriter.getChecker().toString();
+        if (threadVars.length() > 0) {
+            sb.append(", ").append(threadVars);
+        }
+        if (layout != null) {
+            sb.append(", PatternLayout{").append(layout.toString()).append("}");
+        }
+        return sb.toString();
+    }
+
+    @PluginFactory
     public static <B extends Builder<B>> B newBuilder() {
         return new Builder<B>().asBuilder();
     }
@@ -342,14 +443,21 @@
             }
         }
         if (includeThreadContext) {
-            event.getContextData().forEach(WRITE_KEY_VALUES_INTO, builder);
+            event.getContextData().forEach(fieldWriter, builder);
         }
-        if (event.getThrown() != null) {
+
+        if (event.getThrown() != null || layout != null) {
             builder.append("\"full_message\":\"");
-            if (includeStacktrace) {
-                JsonUtils.quoteAsString(formatThrowable(event.getThrown()), builder);
+            if (layout != null) {
+                final StringBuilder messageBuffer = getMessageStringBuilder();
+                layout.serialize(event, messageBuffer);
+                JsonUtils.quoteAsString(messageBuffer, builder);
             } else {
-                JsonUtils.quoteAsString(event.getThrown().toString(), builder);
+                if (includeStacktrace) {
+                    JsonUtils.quoteAsString(formatThrowable(event.getThrown()), builder);
+                } else {
+                    JsonUtils.quoteAsString(event.getThrown().toString(), builder);
+                }
             }
             builder.append(QC);
         }
@@ -357,7 +465,7 @@
         builder.append("\"short_message\":\"");
         final Message message = event.getMessage();
         if (message instanceof CharSequence) {
-            JsonUtils.quoteAsString(((CharSequence)message), builder);
+            JsonUtils.quoteAsString(((CharSequence) message), builder);
         } else if (gcFree && message instanceof StringBuilderFormattable) {
             final StringBuilder messageBuffer = getMessageStringBuilder();
             try {
@@ -381,14 +489,26 @@
         return value != null && value.contains("${");
     }
 
-    private static final TriConsumer<String, Object, StringBuilder> WRITE_KEY_VALUES_INTO = new TriConsumer<String, Object, StringBuilder>() {
+    private static class FieldWriter implements TriConsumer<String, Object, StringBuilder> {
+        private final ListChecker checker;
+
+        FieldWriter(ListChecker checker) {
+            this.checker = checker;
+        }
+
         @Override
         public void accept(final String key, final Object value, final StringBuilder stringBuilder) {
-            stringBuilder.append(QU);
-            JsonUtils.quoteAsString(key, stringBuilder);
-            stringBuilder.append("\":\"");
-            JsonUtils.quoteAsString(toNullSafeString(String.valueOf(value)), stringBuilder);
-            stringBuilder.append(QC);
+            if (checker.check(key)) {
+                stringBuilder.append(QU);
+                JsonUtils.quoteAsString(key, stringBuilder);
+                stringBuilder.append("\":\"");
+                JsonUtils.quoteAsString(toNullSafeString(String.valueOf(value)), stringBuilder);
+                stringBuilder.append(QC);
+            }
+        }
+
+        public ListChecker getChecker() {
+            return checker;
         }
     };
 
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/HtmlLayout.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/HtmlLayout.java
index bbd650d..cbfa59a 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/HtmlLayout.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/HtmlLayout.java
@@ -16,6 +16,18 @@
  */
 package org.apache.logging.log4j.core.layout;
 
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.LoggerConfig;
+import org.apache.logging.log4j.core.util.Transform;
+import org.apache.logging.log4j.plugins.Node;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.plugins.PluginAttribute;
+import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
+import org.apache.logging.log4j.plugins.PluginFactory;
+import org.apache.logging.log4j.util.Strings;
+
 import java.io.IOException;
 import java.io.InterruptedIOException;
 import java.io.LineNumberReader;
@@ -27,19 +39,6 @@
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 
-import org.apache.logging.log4j.Level;
-import org.apache.logging.log4j.core.Layout;
-import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.core.config.LoggerConfig;
-import org.apache.logging.log4j.plugins.Node;
-import org.apache.logging.log4j.plugins.Plugin;
-import org.apache.logging.log4j.plugins.PluginAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
-import org.apache.logging.log4j.plugins.PluginFactory;
-import org.apache.logging.log4j.core.util.Transform;
-import org.apache.logging.log4j.util.Strings;
-
 /**
  * Outputs events as rows in an HTML table on an HTML page.
  * <p>
@@ -341,11 +340,11 @@
      */
     @PluginFactory
     public static HtmlLayout createLayout(
-            @PluginAttribute(value = "locationInfo") final boolean locationInfo,
-            @PluginAttribute(value = "title", defaultString = DEFAULT_TITLE) final String title,
-            @PluginAttribute("contentType") String contentType,
-            @PluginAttribute(value = "charset", defaultString = "UTF-8") final Charset charset,
-            @PluginAttribute("fontSize") String fontSize,
+            @PluginAttribute final boolean locationInfo,
+            @PluginAttribute(defaultString = DEFAULT_TITLE) final String title,
+            @PluginAttribute String contentType,
+            @PluginAttribute(defaultString = "UTF-8") final Charset charset,
+            @PluginAttribute String fontSize,
             @PluginAttribute(value = "fontName", defaultString = DEFAULT_FONT_FAMILY) final String font) {
         final FontSize fs = FontSize.getFontSize(fontSize);
         fontSize = fs.getFontSize();
@@ -365,7 +364,7 @@
         return newBuilder().build();
     }
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static Builder newBuilder() {
         return new Builder();
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/LevelPatternSelector.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/LevelPatternSelector.java
new file mode 100644
index 0000000..0a08efb
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/LevelPatternSelector.java
@@ -0,0 +1,239 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.core.layout;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
+import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
+import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
+import org.apache.logging.log4j.core.config.plugins.PluginElement;
+import org.apache.logging.log4j.core.pattern.PatternFormatter;
+import org.apache.logging.log4j.core.pattern.PatternParser;
+import org.apache.logging.log4j.plugins.Node;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.status.StatusLogger;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Selects the pattern to use based on the Level in the LogEvent.
+ */
+@Plugin(name = "LevelPatternSelector", category = Node.CATEGORY, elementType = PatternSelector.ELEMENT_TYPE, printObject = true)
+public class LevelPatternSelector implements PatternSelector{
+
+    /**
+     * Custom MarkerPatternSelector builder. Use the {@link LevelPatternSelector#newBuilder() builder factory method} to create this.
+     */
+    public static class Builder implements org.apache.logging.log4j.core.util.Builder<LevelPatternSelector> {
+
+        @PluginElement("PatternMatch")
+        private PatternMatch[] properties;
+
+        @PluginBuilderAttribute("defaultPattern")
+        private String defaultPattern;
+
+        @PluginBuilderAttribute(value = "alwaysWriteExceptions")
+        private boolean alwaysWriteExceptions = true;
+
+        @PluginBuilderAttribute(value = "disableAnsi")
+        private boolean disableAnsi;
+
+        @PluginBuilderAttribute(value = "noConsoleNoAnsi")
+        private boolean noConsoleNoAnsi;
+
+        @PluginConfiguration
+        private Configuration configuration;
+
+        @Override
+        public LevelPatternSelector build() {
+            if (defaultPattern == null) {
+                defaultPattern = PatternLayout.DEFAULT_CONVERSION_PATTERN;
+            }
+            if (properties == null || properties.length == 0) {
+                LOGGER.warn("No marker patterns were provided with PatternMatch");
+                return null;
+            }
+            return new LevelPatternSelector(properties, defaultPattern, alwaysWriteExceptions, disableAnsi,
+                    noConsoleNoAnsi, configuration);
+        }
+
+        public Builder setProperties(final PatternMatch[] properties) {
+            this.properties = properties;
+            return this;
+        }
+
+        public Builder setDefaultPattern(final String defaultPattern) {
+            this.defaultPattern = defaultPattern;
+            return this;
+        }
+
+        public Builder setAlwaysWriteExceptions(final boolean alwaysWriteExceptions) {
+            this.alwaysWriteExceptions = alwaysWriteExceptions;
+            return this;
+        }
+
+        public Builder setDisableAnsi(final boolean disableAnsi) {
+            this.disableAnsi = disableAnsi;
+            return this;
+        }
+
+        public Builder setNoConsoleNoAnsi(final boolean noConsoleNoAnsi) {
+            this.noConsoleNoAnsi = noConsoleNoAnsi;
+            return this;
+        }
+
+        public Builder setConfiguration(final Configuration configuration) {
+            this.configuration = configuration;
+            return this;
+        }
+
+    }
+
+    private final Map<String, PatternFormatter[]> formatterMap = new HashMap<>();
+
+    private final Map<String, String> patternMap = new HashMap<>();
+
+    private final PatternFormatter[] defaultFormatters;
+
+    private final String defaultPattern;
+
+    private static Logger LOGGER = StatusLogger.getLogger();
+
+    private final boolean requiresLocation;
+
+    /**
+     * @deprecated Use {@link #newBuilder()} instead. This will be private in a future version.
+     */
+    @Deprecated
+    public LevelPatternSelector(final PatternMatch[] properties, final String defaultPattern,
+                                 final boolean alwaysWriteExceptions, final boolean noConsoleNoAnsi,
+                                 final Configuration config) {
+        this(properties, defaultPattern, alwaysWriteExceptions, false, noConsoleNoAnsi, config);
+    }
+
+    private LevelPatternSelector(final PatternMatch[] properties, final String defaultPattern,
+                                 final boolean alwaysWriteExceptions, final boolean disableAnsi,
+                                 final boolean noConsoleNoAnsi, final Configuration config) {
+        boolean needsLocation = false;
+        final PatternParser parser = PatternLayout.createPatternParser(config);
+        for (final PatternMatch property : properties) {
+            try {
+                final List<PatternFormatter> list = parser.parse(property.getPattern(), alwaysWriteExceptions,
+                        disableAnsi, noConsoleNoAnsi);
+                PatternFormatter[] formatters = list.toArray(new PatternFormatter[0]);
+                formatterMap.put(property.getKey(), formatters);
+                for (int i = 0; !needsLocation && i < formatters.length; ++i) {
+                    needsLocation = formatters[i].requiresLocation();
+                }
+
+                patternMap.put(property.getKey(), property.getPattern());
+            } catch (final RuntimeException ex) {
+                throw new IllegalArgumentException("Cannot parse pattern '" + property.getPattern() + "'", ex);
+            }
+        }
+        try {
+            final List<PatternFormatter> list = parser.parse(defaultPattern, alwaysWriteExceptions, disableAnsi,
+                    noConsoleNoAnsi);
+            defaultFormatters = list.toArray(new PatternFormatter[0]);
+            this.defaultPattern = defaultPattern;
+            for (int i = 0; !needsLocation && i < defaultFormatters.length; ++i) {
+                needsLocation = defaultFormatters[i].requiresLocation();
+            }
+        } catch (final RuntimeException ex) {
+            throw new IllegalArgumentException("Cannot parse pattern '" + defaultPattern + "'", ex);
+        }
+        requiresLocation = needsLocation;
+    }
+
+    @Override
+    public boolean requiresLocation() {
+        return requiresLocation;
+    }
+
+    @Override
+    public PatternFormatter[] getFormatters(final LogEvent event) {
+        final Level level = event.getLevel();
+        if (level == null) {
+            return defaultFormatters;
+        }
+        for (final String key : formatterMap.keySet()) {
+            if (level.name().equalsIgnoreCase(key)) {
+                return formatterMap.get(key);
+            }
+        }
+        return defaultFormatters;
+    }
+
+    /**
+     * Creates a builder for a custom ScriptPatternSelector.
+     *
+     * @return a ScriptPatternSelector builder.
+     */
+    @PluginBuilderFactory
+    public static Builder newBuilder() {
+        return new Builder();
+    }
+
+    /**
+     * Deprecated, use {@link #newBuilder()} instead.
+     * @param properties
+     * @param defaultPattern
+     * @param alwaysWriteExceptions
+     * @param noConsoleNoAnsi
+     * @param configuration
+     * @return a new MarkerPatternSelector.
+     * @deprecated Use {@link #newBuilder()} instead.
+     */
+    @Deprecated
+    public static LevelPatternSelector createSelector(
+            final PatternMatch[] properties,
+            final String defaultPattern,
+            final boolean alwaysWriteExceptions,
+            final boolean noConsoleNoAnsi,
+            final Configuration configuration) {
+        final Builder builder = newBuilder();
+        builder.setProperties(properties);
+        builder.setDefaultPattern(defaultPattern);
+        builder.setAlwaysWriteExceptions(alwaysWriteExceptions);
+        builder.setNoConsoleNoAnsi(noConsoleNoAnsi);
+        builder.setConfiguration(configuration);
+        return builder.build();
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        boolean first = true;
+        for (final Map.Entry<String, String> entry : patternMap.entrySet()) {
+            if (!first) {
+                sb.append(", ");
+            }
+            sb.append("key=\"").append(entry.getKey()).append("\", pattern=\"").append(entry.getValue()).append("\"");
+            first = false;
+        }
+        if (!first) {
+            sb.append(", ");
+        }
+        sb.append("default=\"").append(defaultPattern).append("\"");
+        return sb.toString();
+    }
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/LoggerFields.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/LoggerFields.java
index 0995c69..6218bab 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/LoggerFields.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/LoggerFields.java
@@ -71,10 +71,10 @@
      */
     @PluginFactory
     public static LoggerFields createLoggerFields(
-        @PluginElement("LoggerFields") final KeyValuePair[] keyValuePairs,
-        @PluginAttribute("sdId") final String sdId,
-        @PluginAttribute("enterpriseId") final String enterpriseId,
-        @PluginAttribute(value = "discardIfAllFieldsAreEmpty") final boolean discardIfAllFieldsAreEmpty) {
+        @PluginElement final KeyValuePair[] keyValuePairs,
+        @PluginAttribute final String sdId,
+        @PluginAttribute final String enterpriseId,
+        @PluginAttribute final boolean discardIfAllFieldsAreEmpty) {
         final Map<String, String> map = new HashMap<>();
 
         for (final KeyValuePair keyValuePair : keyValuePairs) {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/MarkerPatternSelector.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/MarkerPatternSelector.java
index b8d5ed5..c1278ca 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/MarkerPatternSelector.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/MarkerPatternSelector.java
@@ -16,24 +16,24 @@
  */
 package org.apache.logging.log4j.core.layout;
 
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.Marker;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
+import org.apache.logging.log4j.core.pattern.PatternFormatter;
+import org.apache.logging.log4j.core.pattern.PatternParser;
 import org.apache.logging.log4j.plugins.Node;
 import org.apache.logging.log4j.plugins.Plugin;
 import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
-import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
 import org.apache.logging.log4j.plugins.PluginElement;
-import org.apache.logging.log4j.core.pattern.PatternFormatter;
-import org.apache.logging.log4j.core.pattern.PatternParser;
+import org.apache.logging.log4j.plugins.PluginFactory;
 import org.apache.logging.log4j.status.StatusLogger;
 
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
 /**
  * Selects the pattern to use based on the Marker in the LogEvent.
  */
@@ -177,7 +177,7 @@
      *
      * @return a ScriptPatternSelector builder.
      */
-    @PluginBuilderFactory
+    @PluginFactory
     public static Builder newBuilder() {
         return new Builder();
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java
index 16f8b84..10a36c5 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java
@@ -16,29 +16,29 @@
  */
 package org.apache.logging.log4j.core.layout;
 
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.DefaultConfiguration;
+import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
+import org.apache.logging.log4j.core.pattern.LogEventPatternConverter;
+import org.apache.logging.log4j.core.pattern.PatternFormatter;
+import org.apache.logging.log4j.core.pattern.PatternParser;
+import org.apache.logging.log4j.core.pattern.RegexReplacement;
+import org.apache.logging.log4j.plugins.Node;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
+import org.apache.logging.log4j.plugins.PluginElement;
+import org.apache.logging.log4j.plugins.PluginFactory;
+import org.apache.logging.log4j.util.PropertiesUtil;
+import org.apache.logging.log4j.util.Strings;
+
 import java.nio.charset.Charset;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import org.apache.logging.log4j.core.Layout;
-import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.core.config.Configuration;
-import org.apache.logging.log4j.core.config.DefaultConfiguration;
-import org.apache.logging.log4j.plugins.Node;
-import org.apache.logging.log4j.plugins.Plugin;
-import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
-import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
-import org.apache.logging.log4j.plugins.PluginElement;
-import org.apache.logging.log4j.core.pattern.LogEventPatternConverter;
-import org.apache.logging.log4j.core.pattern.PatternFormatter;
-import org.apache.logging.log4j.core.pattern.PatternParser;
-import org.apache.logging.log4j.core.pattern.RegexReplacement;
-import org.apache.logging.log4j.util.PropertiesUtil;
-import org.apache.logging.log4j.util.Strings;
-
 /**
  * A flexible layout configurable with pattern string.
  * <p>
@@ -184,6 +184,10 @@
         return eventSerializer.toSerializable(event);
     }
 
+    public void serialize(final LogEvent event, StringBuilder stringBuilder) {
+        eventSerializer.toSerializable(event, stringBuilder);
+    }
+
     @Override
     public void encode(final LogEvent event, final ByteBufferDestination destination) {
         if (!(eventSerializer instanceof Serializer2)) {
@@ -446,7 +450,7 @@
      *
      * @return a PatternLayout builder.
      */
-    @PluginBuilderFactory
+    @PluginFactory
     public static Builder newBuilder() {
         return new Builder();
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternMatch.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternMatch.java
index d1b7504..bb6ff55 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternMatch.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternMatch.java
@@ -17,13 +17,13 @@
 
 package org.apache.logging.log4j.core.layout;
 
-import java.io.ObjectStreamException;
-import java.io.Serializable;
-
 import org.apache.logging.log4j.plugins.Node;
 import org.apache.logging.log4j.plugins.Plugin;
 import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
+import org.apache.logging.log4j.plugins.PluginFactory;
+
+import java.io.ObjectStreamException;
+import java.io.Serializable;
 
 /**
  * PatternMatch configuration item.
@@ -67,7 +67,7 @@
         return key + '=' + pattern;
     }
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static Builder newBuilder() {
         return new Builder();
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/Rfc5424Layout.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/Rfc5424Layout.java
index 7e48f08..969a769 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/Rfc5424Layout.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/Rfc5424Layout.java
@@ -35,6 +35,9 @@
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.appender.TlsSyslogFrame;
 import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.layout.internal.ExcludeChecker;
+import org.apache.logging.log4j.core.layout.internal.IncludeChecker;
+import org.apache.logging.log4j.core.layout.internal.ListChecker;
 import org.apache.logging.log4j.plugins.Node;
 import org.apache.logging.log4j.plugins.Plugin;
 import org.apache.logging.log4j.plugins.PluginAttribute;
@@ -55,7 +58,7 @@
 import org.apache.logging.log4j.message.StructuredDataCollectionMessage;
 import org.apache.logging.log4j.message.StructuredDataId;
 import org.apache.logging.log4j.message.StructuredDataMessage;
-import org.apache.logging.log4j.util.ProcessIdUtil;
+import org.apache.logging.log4j.core.util.ProcessIdUtil;
 import org.apache.logging.log4j.util.StringBuilders;
 import org.apache.logging.log4j.util.Strings;
 
@@ -112,7 +115,6 @@
     private final List<String> mdcIncludes;
     private final List<String> mdcRequired;
     private final ListChecker listChecker;
-    private final ListChecker noopChecker = new NoopChecker();
     private final boolean includeNewLine;
     private final String escapeNewLine;
     private final boolean useTlsMessageFormat;
@@ -146,12 +148,12 @@
         this.messageId = messageId;
         this.useTlsMessageFormat = useTLSMessageFormat;
         this.localHostName = NetUtils.getLocalHostname();
-        ListChecker c = null;
+        ListChecker checker = null;
         if (excludes != null) {
             final String[] array = excludes.split(Patterns.COMMA_SEPARATOR);
             if (array.length > 0) {
-                c = new ExcludeChecker();
                 mdcExcludes = new ArrayList<>(array.length);
+                checker = new ExcludeChecker(mdcExcludes);
                 for (final String str : array) {
                     mdcExcludes.add(str.trim());
                 }
@@ -164,8 +166,8 @@
         if (includes != null) {
             final String[] array = includes.split(Patterns.COMMA_SEPARATOR);
             if (array.length > 0) {
-                c = new IncludeChecker();
                 mdcIncludes = new ArrayList<>(array.length);
+                checker = new IncludeChecker(mdcIncludes);
                 for (final String str : array) {
                     mdcIncludes.add(str.trim());
                 }
@@ -189,7 +191,7 @@
         } else {
             mdcRequired = null;
         }
-        this.listChecker = c != null ? c : noopChecker;
+        this.listChecker = checker != null ? checker : ListChecker.NOOP_CHECKER;
         final String name = config == null ? null : config.getName();
         configName = Strings.isNotEmpty(name) ? name : null;
         this.fieldFormatters = createFieldFormatters(loggerFields, config);
@@ -513,7 +515,7 @@
         sb.append('[');
         sb.append(id);
         if (!mdcSdId.toString().equals(id)) {
-            appendMap(data.getPrefix(), data.getFields(), sb, noopChecker);
+            appendMap(data.getPrefix(), data.getFields(), sb, ListChecker.NOOP_CHECKER);
         } else {
             appendMap(data.getPrefix(), data.getFields(), sb, checker);
         }
@@ -566,43 +568,6 @@
         return PARAM_VALUE_ESCAPE_PATTERN.matcher(value).replaceAll("\\\\$0");
     }
 
-    /**
-     * Interface used to check keys in a Map.
-     */
-    private interface ListChecker {
-        boolean check(String key);
-    }
-
-    /**
-     * Includes only the listed keys.
-     */
-    private class IncludeChecker implements ListChecker {
-        @Override
-        public boolean check(final String key) {
-            return mdcIncludes.contains(key);
-        }
-    }
-
-    /**
-     * Excludes the listed keys.
-     */
-    private class ExcludeChecker implements ListChecker {
-        @Override
-        public boolean check(final String key) {
-            return !mdcExcludes.contains(key);
-        }
-    }
-
-    /**
-     * Does nothing.
-     */
-    private class NoopChecker implements ListChecker {
-        @Override
-        public boolean check(final String key) {
-            return true;
-        }
-    }
-
     @Override
     public String toString() {
         final StringBuilder sb = new StringBuilder();
@@ -643,25 +608,24 @@
     @PluginFactory
     public static Rfc5424Layout createLayout(
             // @formatter:off
-            @PluginAttribute(value = "facility", defaultString = "LOCAL0") final Facility facility,
-            @PluginAttribute("id") final String id,
-            @PluginAttribute(value = "enterpriseNumber", defaultInt = DEFAULT_ENTERPRISE_NUMBER)
-            final int enterpriseNumber,
-            @PluginAttribute(value = "includeMDC", defaultBoolean = true) final boolean includeMDC,
-            @PluginAttribute(value = "mdcId", defaultString = DEFAULT_MDCID) final String mdcId,
-            @PluginAttribute("mdcPrefix") final String mdcPrefix,
-            @PluginAttribute("eventPrefix") final String eventPrefix,
-            @PluginAttribute(value = "newLine") final boolean newLine,
+            @PluginAttribute(defaultString = "LOCAL0") final Facility facility,
+            @PluginAttribute final String id,
+            @PluginAttribute(defaultInt = DEFAULT_ENTERPRISE_NUMBER) final int enterpriseNumber,
+            @PluginAttribute(defaultBoolean = true) final boolean includeMDC,
+            @PluginAttribute(defaultString = DEFAULT_MDCID) final String mdcId,
+            @PluginAttribute final String mdcPrefix,
+            @PluginAttribute final String eventPrefix,
+            @PluginAttribute final boolean newLine,
             @PluginAttribute("newLineEscape") final String escapeNL,
-            @PluginAttribute("appName") final String appName,
+            @PluginAttribute final String appName,
             @PluginAttribute("messageId") final String msgId,
             @PluginAttribute("mdcExcludes") final String excludes,
             @PluginAttribute("mdcIncludes") String includes,
             @PluginAttribute("mdcRequired") final String required,
-            @PluginAttribute("exceptionPattern") final String exceptionPattern,
+            @PluginAttribute final String exceptionPattern,
             // RFC 5425
-            @PluginAttribute(value = "useTlsMessageFormat") final boolean useTlsMessageFormat,
-            @PluginElement("LoggerFields") final LoggerFields[] loggerFields,
+            @PluginAttribute final boolean useTlsMessageFormat,
+            @PluginElement final LoggerFields[] loggerFields,
             @PluginConfiguration final Configuration config) {
         // @formatter:on
         if (includes != null && excludes != null) {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/ScriptPatternSelector.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/ScriptPatternSelector.java
index 2560ad1..159df57 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/ScriptPatternSelector.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/ScriptPatternSelector.java
@@ -16,27 +16,26 @@
  */
 package org.apache.logging.log4j.core.layout;
 
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.script.SimpleBindings;
-
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.config.Configuration;
-import org.apache.logging.log4j.plugins.Node;
-import org.apache.logging.log4j.plugins.Plugin;
-import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
 import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
-import org.apache.logging.log4j.plugins.PluginElement;
 import org.apache.logging.log4j.core.pattern.PatternFormatter;
 import org.apache.logging.log4j.core.pattern.PatternParser;
 import org.apache.logging.log4j.core.script.AbstractScript;
 import org.apache.logging.log4j.core.script.ScriptRef;
+import org.apache.logging.log4j.plugins.Node;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
+import org.apache.logging.log4j.plugins.PluginElement;
+import org.apache.logging.log4j.plugins.PluginFactory;
 import org.apache.logging.log4j.status.StatusLogger;
 
+import javax.script.SimpleBindings;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
 /**
  * Selects the pattern to use based on the Marker in the LogEvent.
  */
@@ -207,7 +206,7 @@
      *
      * @return a ScriptPatternSelector builder.
      */
-    @PluginBuilderFactory
+    @PluginFactory
     public static Builder newBuilder() {
         return new Builder();
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/SyslogLayout.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/SyslogLayout.java
index 2fcb52f..5e6d51b 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/SyslogLayout.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/SyslogLayout.java
@@ -16,6 +16,17 @@
  */
 package org.apache.logging.log4j.core.layout;
 
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.net.Facility;
+import org.apache.logging.log4j.core.net.Priority;
+import org.apache.logging.log4j.core.util.NetUtils;
+import org.apache.logging.log4j.plugins.Node;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
+import org.apache.logging.log4j.plugins.PluginFactory;
+import org.apache.logging.log4j.util.Chars;
+
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 import java.text.SimpleDateFormat;
@@ -26,17 +37,6 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import org.apache.logging.log4j.core.Layout;
-import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.plugins.Node;
-import org.apache.logging.log4j.plugins.Plugin;
-import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
-import org.apache.logging.log4j.core.net.Facility;
-import org.apache.logging.log4j.core.net.Priority;
-import org.apache.logging.log4j.core.util.NetUtils;
-import org.apache.logging.log4j.util.Chars;
-
 /**
  * Formats a log event as a BSD Log record.
  */
@@ -105,7 +105,7 @@
 
     }
     
-    @PluginBuilderFactory
+    @PluginFactory
     public static <B extends Builder<B>> B newBuilder() {
         return new Builder<B>().asBuilder();
     }
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/internal/ExcludeChecker.java
similarity index 61%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-core/src/main/java/org/apache/logging/log4j/core/layout/internal/ExcludeChecker.java
index 13aaf9c..2841dd2 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/internal/ExcludeChecker.java
@@ -14,17 +14,27 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
+package org.apache.logging.log4j.core.layout.internal;
 
-import org.junit.Test;
+import java.util.List;
 
-import static org.junit.Assert.*;
+/**
+ * Excludes the listed keys.
+ */
+public class ExcludeChecker implements ListChecker {
+    private final List<String> list;
 
-public class ProcessIdUtilTest {
+    public ExcludeChecker(final List<String> list) {
+        this.list = list;
+    }
 
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
+    @Override
+    public boolean check(final String key) {
+        return !list.contains(key);
+    }
+
+    @Override
+    public String toString() {
+        return "ThreadContextExcludes=" + list.toString();
     }
 }
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/internal/IncludeChecker.java
similarity index 61%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-core/src/main/java/org/apache/logging/log4j/core/layout/internal/IncludeChecker.java
index 13aaf9c..c87b807 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/internal/IncludeChecker.java
@@ -14,17 +14,27 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
+package org.apache.logging.log4j.core.layout.internal;
 
-import org.junit.Test;
+import java.util.List;
 
-import static org.junit.Assert.*;
+/**
+ * Includes only the listed keys.
+ */
+public class IncludeChecker implements ListChecker {
+    private final List<String> list;
 
-public class ProcessIdUtilTest {
+    public IncludeChecker(final List<String> list) {
+        this.list = list;
+    }
+    @Override
+    public boolean check(final String key) {
+        return list.contains(key);
+    }
 
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
+    @Override
+    public String toString() {
+        return "ThreadContextIncludes=" + list.toString();
     }
 }
+
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/internal/ListChecker.java
similarity index 60%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-core/src/main/java/org/apache/logging/log4j/core/layout/internal/ListChecker.java
index 13aaf9c..1993bc0 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/internal/ListChecker.java
@@ -14,17 +14,32 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
+package org.apache.logging.log4j.core.layout.internal;
 
-import org.junit.Test;
+import java.util.List;
 
-import static org.junit.Assert.*;
+/**
+ * Class Description goes here.
+ */
 
-public class ProcessIdUtilTest {
+public interface ListChecker {
 
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
+    static final NoopChecker NOOP_CHECKER = new NoopChecker();
+
+    boolean check(final String key);
+
+    /**
+     * Does nothing.
+     */
+    public class NoopChecker implements ListChecker {
+        @Override
+        public boolean check(final String key) {
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            return "";
+        }
     }
 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/Interpolator.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/Interpolator.java
index 854a762..7003e3f 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/Interpolator.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/Interpolator.java
@@ -40,6 +40,10 @@
 
     private static final String LOOKUP_KEY_DOCKER = "docker";
 
+    private static final String LOOKUP_KEY_KUBERNETES = "kubernetes";
+
+    private static final String LOOKUP_KEY_SPRING = "spring";
+
     private static final String LOOKUP_KEY_JNDI = "jndi";
 
     private static final String LOOKUP_KEY_JVMRUNARGS = "jvmrunargs";
@@ -100,6 +104,8 @@
         strLookupMap.put("marker", new MarkerLookup());
         strLookupMap.put("java", new JavaLookup());
         strLookupMap.put("base64", new Base64StrLookup());
+        strLookupMap.put("lower", new LowerLookup());
+        strLookupMap.put("upper", new UpperLookup());
         // JNDI
         try {
             // [LOG4J2-703] We might be on Android
@@ -135,6 +141,20 @@
         } catch (final Exception ignored) {
             handleError(LOOKUP_KEY_DOCKER, ignored);
         }
+        try {
+            strLookupMap.put(LOOKUP_KEY_SPRING,
+                    Loader.newCheckedInstanceOf("org.apache.logging.log4j.spring.cloud.config.client.SpringLookup", StrLookup.class));
+        } catch (final Exception ignored) {
+            handleError(LOOKUP_KEY_SPRING, ignored);
+        }
+        try {
+            strLookupMap.put(LOOKUP_KEY_KUBERNETES,
+                    Loader.newCheckedInstanceOf("org.apache.logging.log4j.kubernetes.KubernetesLookup", StrLookup.class));
+        } catch (final Exception ignored) {
+            handleError(LOOKUP_KEY_KUBERNETES, ignored);
+        } catch (final NoClassDefFoundError error) {
+            handleError(LOOKUP_KEY_KUBERNETES, error);
+        }
     }
 
     public Map<String, StrLookup> getStrLookupMap() {
@@ -160,7 +180,12 @@
                         "available. If you want better web container support, please add the log4j-web JAR to your " +
                         "web archive or server lib directory.");
                 break;
-            case LOOKUP_KEY_DOCKER:
+            case LOOKUP_KEY_DOCKER: case LOOKUP_KEY_SPRING:
+                break;
+            case LOOKUP_KEY_KUBERNETES:
+                if (t instanceof NoClassDefFoundError) {
+                    LOGGER.warn("Unable to create Kubernetes lookup due to missing dependency: {}", t.getMessage());
+                }
                 break;
             default:
                 LOGGER.error("Unable to create Lookup for {}", lookupKey, t);
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/LowerLookup.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/LowerLookup.java
new file mode 100644
index 0000000..366ff9a
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/LowerLookup.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.core.lookup;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.plugins.Plugin;
+
+/**
+ * Converts values to lower case. The passed in "key" should be the value of another lookup.
+ */
+@Plugin(name = "lower", category = StrLookup.CATEGORY)
+public class LowerLookup implements StrLookup {
+
+    /**
+     * Converts the "key" to lower case.
+     * @param key  the key to be looked up, may be null
+     * @return The value associated with the key.
+     */
+    @Override
+    public String lookup(final String key) {
+        return key != null ? key.toLowerCase() : null;
+    }
+
+    /**
+     * Converts the "key" to lower case.
+     * @param event The current LogEvent.
+     * @param key  the key to be looked up, may be null
+     * @return The value associated with the key.
+     */
+    @Override
+    public String lookup(final LogEvent event, final String key) {
+        return lookup(key);
+    }
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/UpperLookup.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/UpperLookup.java
new file mode 100644
index 0000000..94737b9
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/UpperLookup.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.core.lookup;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.plugins.Plugin;
+
+/**
+ * Converts values to upper case. The passed in "key" should be the value of another lookup.
+ */
+@Plugin(name = "upper", category = StrLookup.CATEGORY)
+public class UpperLookup implements StrLookup {
+
+    /**
+     * Converts the "key" to upper case.
+     * @param key  the key to be looked up, may be null
+     * @return The value associated with the key.
+     */
+    @Override
+    public String lookup(final String key) {
+        return key != null ? key.toUpperCase() : null;
+    }
+
+    /**
+     * Converts the "key" to upper case.
+     * @param event The current LogEvent.
+     * @param key  the key to be looked up, may be null
+     * @return The value associated with the key.
+     */
+    @Override
+    public String lookup(final LogEvent event, final String key) {
+        return lookup(key);
+    }
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SocketAddress.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SocketAddress.java
index e771dc0..9ae43e2 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SocketAddress.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SocketAddress.java
@@ -16,16 +16,16 @@
  */
 package org.apache.logging.log4j.core.net;
 
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-
 import org.apache.logging.log4j.plugins.Node;
 import org.apache.logging.log4j.plugins.Plugin;
 import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
+import org.apache.logging.log4j.plugins.PluginFactory;
 import org.apache.logging.log4j.plugins.validation.constraints.ValidHost;
 import org.apache.logging.log4j.plugins.validation.constraints.ValidPort;
 
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+
 /**
  * Plugin to hold a hostname and port (socket address).
  *
@@ -66,7 +66,7 @@
         return socketAddress.getHostName();
     }
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static Builder newBuilder() {
         return new Builder();
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SocketOptions.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SocketOptions.java
index afad2b3..f0a8156 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SocketOptions.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SocketOptions.java
@@ -16,23 +16,23 @@
  */
 package org.apache.logging.log4j.core.net;
 
-import java.net.Socket;
-import java.net.SocketException;
-
 import org.apache.logging.log4j.core.Core;
 import org.apache.logging.log4j.plugins.Plugin;
 import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
 import org.apache.logging.log4j.plugins.PluginElement;
+import org.apache.logging.log4j.plugins.PluginFactory;
 import org.apache.logging.log4j.plugins.util.Builder;
 
+import java.net.Socket;
+import java.net.SocketException;
+
 /**
  * Holds all socket options settable via {@link Socket} methods.
  */
 @Plugin(name = "SocketOptions", category = Core.CATEGORY_NAME, printObject = true)
 public class SocketOptions implements Builder<SocketOptions>, Cloneable {
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static SocketOptions newBuilder() {
         return new SocketOptions();
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SocketPerformancePreferences.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SocketPerformancePreferences.java
index 3ba8d09..67a1856 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SocketPerformancePreferences.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SocketPerformancePreferences.java
@@ -16,13 +16,14 @@
  */
 package org.apache.logging.log4j.core.net;
 
-import java.net.Socket;
 import org.apache.logging.log4j.core.Core;
 import org.apache.logging.log4j.plugins.Plugin;
 import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
-import org.apache.logging.log4j.plugins.validation.constraints.Required;
+import org.apache.logging.log4j.plugins.PluginFactory;
 import org.apache.logging.log4j.plugins.util.Builder;
+import org.apache.logging.log4j.plugins.validation.constraints.Required;
+
+import java.net.Socket;
 
 /**
  * Holds all socket options settable via {@link Socket#setPerformancePreferences(int, int, int)}.
@@ -33,7 +34,7 @@
 @Plugin(name = "SocketPerformancePreferences", category = Core.CATEGORY_NAME, printObject = true)
 public class SocketPerformancePreferences implements Builder<SocketPerformancePreferences>, Cloneable {
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static SocketPerformancePreferences newBuilder() {
         return new SocketPerformancePreferences();
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfiguration.java
index b58c91d..abe1e25 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/KeyStoreConfiguration.java
@@ -94,12 +94,12 @@
     @PluginFactory
     public static KeyStoreConfiguration createKeyStoreConfiguration(
             // @formatter:off
-            @PluginAttribute("location") final String location,
-            @PluginAttribute(value = "password", sensitive = true) final char[] password,
-            @PluginAttribute("passwordEnvironmentVariable") final String passwordEnvironmentVariable,
-            @PluginAttribute("passwordFile") final String passwordFile,
+            @PluginAttribute final String location,
+            @PluginAttribute(sensitive = true) final char[] password,
+            @PluginAttribute final String passwordEnvironmentVariable,
+            @PluginAttribute final String passwordFile,
             @PluginAttribute("type") final String keyStoreType,
-            @PluginAttribute("keyManagerFactoryAlgorithm") final String keyManagerFactoryAlgorithm) throws StoreConfigurationException {
+            @PluginAttribute final String keyManagerFactoryAlgorithm) throws StoreConfigurationException {
             // @formatter:on
 
         if (password != null && passwordEnvironmentVariable != null && passwordFile != null) {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/SslConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/SslConfiguration.java
index c39db8d..466f693 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/SslConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/SslConfiguration.java
@@ -129,7 +129,7 @@
         try {
             return createSslContext(true, false);
         } catch (final KeyStoreConfigurationException dummy) {
-             LOGGER.debug("Exception occured while using default keystore. This should be a BUG");
+             LOGGER.debug("Exception occurred while using default keystore. This should be a BUG");
              return null;
         }
     }
@@ -139,7 +139,7 @@
             return createSslContext(false, true);
         }
         catch (final TrustStoreConfigurationException dummy) {
-            LOGGER.debug("Exception occured while using default truststore. This should be a BUG");
+            LOGGER.debug("Exception occurred while using default truststore. This should be a BUG");
             return null;
         }
     }
@@ -230,9 +230,9 @@
     @PluginFactory
     public static SslConfiguration createSSLConfiguration(
             // @formatter:off
-            @PluginAttribute("protocol") final String protocol,
-            @PluginElement("KeyStore") final KeyStoreConfiguration keyStoreConfig, 
-            @PluginElement("TrustStore") final TrustStoreConfiguration trustStoreConfig) {
+            @PluginAttribute final String protocol,
+            @PluginElement final KeyStoreConfiguration keyStoreConfig,
+            @PluginElement final TrustStoreConfiguration trustStoreConfig) {
             // @formatter:on
         return new SslConfiguration(protocol, keyStoreConfig, trustStoreConfig, false);
     }
@@ -248,10 +248,10 @@
      */
     public static SslConfiguration createSSLConfiguration(
             // @formatter:off
-            @PluginAttribute("protocol") final String protocol,
-            @PluginElement("KeyStore") final KeyStoreConfiguration keyStoreConfig,
-            @PluginElement("TrustStore") final TrustStoreConfiguration trustStoreConfig,
-            @PluginElement("verifyHostName") final boolean verifyHostName) {
+            @PluginAttribute final String protocol,
+            @PluginElement final KeyStoreConfiguration keyStoreConfig,
+            @PluginElement final TrustStoreConfiguration trustStoreConfig,
+            @PluginElement final boolean verifyHostName) {
         // @formatter:on
         return new SslConfiguration(protocol, keyStoreConfig, trustStoreConfig, verifyHostName);
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfiguration.java
index d64dcca..17cbe51 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/TrustStoreConfiguration.java
@@ -73,12 +73,12 @@
     @PluginFactory
     public static TrustStoreConfiguration createKeyStoreConfiguration(
             // @formatter:off
-            @PluginAttribute("location") final String location,
-            @PluginAttribute(value = "password", sensitive = true) final char[] password,
-            @PluginAttribute("passwordEnvironmentVariable") final String passwordEnvironmentVariable,
-            @PluginAttribute("passwordFile") final String passwordFile,
+            @PluginAttribute final String location,
+            @PluginAttribute(sensitive = true) final char[] password,
+            @PluginAttribute final String passwordEnvironmentVariable,
+            @PluginAttribute final String passwordFile,
             @PluginAttribute("type") final String keyStoreType,
-            @PluginAttribute("trustManagerFactoryAlgorithm") final String trustManagerFactoryAlgorithm) throws StoreConfigurationException {
+            @PluginAttribute final String trustManagerFactoryAlgorithm) throws StoreConfigurationException {
             // @formatter:on
 
         if (password != null && passwordEnvironmentVariable != null && passwordFile != null) {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/osgi/BundleContextSelector.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/osgi/BundleContextSelector.java
index 7cb433f..ba0a14e 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/osgi/BundleContextSelector.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/osgi/BundleContextSelector.java
@@ -77,8 +77,6 @@
                 }
             }
         }
-
-
     }
 
     private LoggerContext getLoggerContext(final Bundle bundle) {
@@ -97,7 +95,7 @@
     @Override
     public boolean hasContext(final String fqcn, final ClassLoader loader, final boolean currentContext) {
         if (currentContext && ContextAnchor.THREAD_CONTEXT.get() != null) {
-            return true;
+            return ContextAnchor.THREAD_CONTEXT.get().isStarted();
         }
         if (loader instanceof BundleReference) {
             return hasContext(((BundleReference) loader).getBundle());
@@ -106,7 +104,7 @@
         if (callerClass != null) {
             return hasContext(FrameworkUtil.getBundle(callerClass));
         }
-        return ContextAnchor.THREAD_CONTEXT.get() != null;
+        return ContextAnchor.THREAD_CONTEXT.get() != null && ContextAnchor.THREAD_CONTEXT.get().isStarted();
     }
 
     @Override
@@ -134,7 +132,7 @@
     private static boolean hasContext(final Bundle bundle) {
         final String name = Objects.requireNonNull(bundle, "No Bundle provided").getSymbolicName();
         final AtomicReference<WeakReference<LoggerContext>> ref = CONTEXT_MAP.get(name);
-        return ref != null && ref.get() != null;
+        return ref != null && ref.get() != null && ref.get().get() != null && ref.get().get().isStarted();
     }
 
     private static LoggerContext locateContext(final Bundle bundle, final URI configLocation) {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LogEventPatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LogEventPatternConverter.java
index 1e31c7e..2ff4297 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LogEventPatternConverter.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LogEventPatternConverter.java
@@ -66,7 +66,7 @@
     }
 
     /**
-     * Some pattern converters require location informatoin. By returning true the location can be
+     * Some pattern converters require location information. By returning true the location can be
      * calculated efficiently.
      * @return true if this PatternConverter uses location information.
      */
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ProcessIdPatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ProcessIdPatternConverter.java
index d3d8bc4..4d73cdc 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ProcessIdPatternConverter.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ProcessIdPatternConverter.java
@@ -18,7 +18,7 @@
 
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.plugins.Plugin;
-import org.apache.logging.log4j.util.ProcessIdUtil;
+import org.apache.logging.log4j.core.util.ProcessIdUtil;
 
 @Plugin(name = "ProcessIdPatternConverter", category = "Converter")
 @ConverterKeys({ "pid", "processId" })
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RegexReplacement.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RegexReplacement.java
index 602048a..0d6961b 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RegexReplacement.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RegexReplacement.java
@@ -70,8 +70,8 @@
      */
     @PluginFactory
     public static RegexReplacement createRegexReplacement(
-            @PluginAttribute("regex") final Pattern regex,
-            @PluginAttribute("replacement") final String replacement) {
+            @PluginAttribute final Pattern regex,
+            @PluginAttribute final String replacement) {
         if (regex == null) {
             LOGGER.error("A regular expression is required for replacement");
             return null;
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/script/Script.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/script/Script.java
index 15b2096..b51eb37 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/script/Script.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/script/Script.java
@@ -39,9 +39,9 @@
     @PluginFactory
     public static Script createScript(
             // @formatter:off
-            @PluginAttribute("name") final String name,
-            @PluginAttribute(ATTR_LANGUAGE) String language,
-            @PluginValue(ATTR_SCRIPT_TEXT) final String scriptText) {
+            @PluginAttribute final String name,
+            @PluginAttribute String language,
+            @PluginValue final String scriptText) {
             // @formatter:on
         if (language == null) {
             LOGGER.error("No '{}' attribute provided for {} plugin '{}'", ATTR_LANGUAGE, PLUGIN_NAME, name);
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/script/ScriptFile.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/script/ScriptFile.java
index d2a5863a..097c191 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/script/ScriptFile.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/script/ScriptFile.java
@@ -62,11 +62,11 @@
     @PluginFactory
     public static ScriptFile createScript(
             // @formatter:off
-            @PluginAttribute("name") String name,
-            @PluginAttribute("language") String language,
+            @PluginAttribute String name,
+            @PluginAttribute String language,
             @PluginAttribute("path") final String filePathOrUri,
-            @PluginAttribute("isWatched") final Boolean isWatched,
-            @PluginAttribute("charset") final Charset charset) {
+            @PluginAttribute final Boolean isWatched,
+            @PluginAttribute final Charset charset) {
             // @formatter:on
         if (filePathOrUri == null) {
             LOGGER.error("No script path provided for ScriptFile");
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/BasicContextSelector.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/BasicContextSelector.java
index 1006a60..aac0221 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/BasicContextSelector.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/BasicContextSelector.java
@@ -39,7 +39,8 @@
 

     @Override

     public boolean hasContext(String fqcn, ClassLoader loader, boolean currentContext) {

-        return ContextAnchor.THREAD_CONTEXT.get() != null;

+        LoggerContext ctx = ContextAnchor.THREAD_CONTEXT.get();

+        return ctx != null && ctx.isStarted();

     }

 

     @Override

diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/ClassLoaderContextSelector.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/ClassLoaderContextSelector.java
index b2c7282..9a8b6c9 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/ClassLoaderContextSelector.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/ClassLoaderContextSelector.java
@@ -83,17 +83,20 @@
 
     @Override
     public boolean hasContext(final String fqcn, final ClassLoader loader, final boolean currentContext) {
+        LoggerContext ctx;
         if (currentContext) {
-            return ContextAnchor.THREAD_CONTEXT.get() != null;
+            ctx = ContextAnchor.THREAD_CONTEXT.get();
         } else if (loader != null) {
-            return findContext(loader) != null;
+            ctx = findContext(loader);
         } else {
             final Class<?> clazz = StackLocatorUtil.getCallerClass(fqcn);
             if (clazz != null) {
-                return findContext(clazz.getClassLoader()) != null;
+                ctx = findContext(clazz.getClassLoader());
+            } else {
+                ctx = ContextAnchor.THREAD_CONTEXT.get();
             }
-            return ContextAnchor.THREAD_CONTEXT.get() != null;
         }
+        return ctx != null && ctx.isStarted();
     }
 
     private LoggerContext findContext(ClassLoader loaderOrNull) {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/ContextSelector.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/ContextSelector.java
index 41f7d39..3eb0837 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/ContextSelector.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/ContextSelector.java
@@ -35,7 +35,7 @@
      * @param loader The ClassLoader to use or null.
      * @param currentContext If true returns the current Context, if false returns the Context appropriate
      * @param allContexts if true all LoggerContexts that can be located will be shutdown.
-     * @since 3.0
+     * @since 2.13.0
      */
     default void shutdown(final String fqcn, final ClassLoader loader, final boolean currentContext,
                           final boolean allContexts) {
@@ -51,7 +51,7 @@
      * @param currentContext If true returns the current Context, if false returns the Context appropriate
      * for the caller if a more appropriate Context can be determined.
      * @return true if a LoggerContext has been installed, false otherwise.
-     * @since 3.0
+     * @since 2.13.0
      */
     default boolean hasContext(String fqcn, ClassLoader loader, boolean currentContext) {
         return false;
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/JndiContextSelector.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/JndiContextSelector.java
index 67c32ae..36571fd 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/JndiContextSelector.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/JndiContextSelector.java
@@ -109,14 +109,15 @@
 
     @Override
     public boolean hasContext(String fqcn, ClassLoader loader, boolean currentContext) {
-        if (ContextAnchor.THREAD_CONTEXT.get() != null) {
-            return true;
+        LoggerContext ctx = ContextAnchor.THREAD_CONTEXT.get();
+        if (ctx == null) {
+            String loggingContextName = getContextName();
+            if (loggingContextName == null) {
+                return false;
+            }
+            ctx = CONTEXT_MAP.get(loggingContextName);
         }
-        String loggingContextName = getContextName();
-        if (loggingContextName == null) {
-            return false;
-        }
-        return CONTEXT_MAP.containsKey(loggingContextName);
+        return ctx != null && ctx.isStarted();
     }
 
     @Override
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/BasicAuthorizationProvider.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/BasicAuthorizationProvider.java
index 038cced..03820ca 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/BasicAuthorizationProvider.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/BasicAuthorizationProvider.java
@@ -28,7 +28,10 @@
  * Provides the Basic Authorization header to a request.
  */
 public class BasicAuthorizationProvider implements AuthorizationProvider {
-
+    private static final String[] PREFIXES = {"log4j2.config.", "logging.auth."};
+    private static final String AUTH_USER_NAME = "username";
+    private static final String AUTH_PASSWORD = "password";
+    private static final String AUTH_PASSWORD_DECRYPTOR = "passwordDecryptor";
     public static final String CONFIG_USER_NAME = "log4j2.configurationUserName";
     public static final String CONFIG_PASSWORD = "log4j2.configurationPassword";
     public static final String PASSWORD_DECRYPTOR = "log4j2.passwordDecryptor";
@@ -39,9 +42,12 @@
     private String authString = null;
 
     public BasicAuthorizationProvider(PropertiesUtil props) {
-        String userName = props.getStringProperty(CONFIG_USER_NAME);
-        String password = props.getStringProperty(CONFIG_PASSWORD);
-        String decryptor = props.getStringProperty(PASSWORD_DECRYPTOR);
+        String userName = props.getStringProperty(PREFIXES,AUTH_USER_NAME,
+                () -> props.getStringProperty(CONFIG_USER_NAME));
+        String password = props.getStringProperty(PREFIXES, AUTH_PASSWORD,
+                () -> props.getStringProperty(CONFIG_PASSWORD));
+        String decryptor = props.getStringProperty(PREFIXES, AUTH_PASSWORD_DECRYPTOR,
+                () -> props.getStringProperty(PASSWORD_DECRYPTOR));
         if (decryptor != null) {
             try {
                 Object obj = LoaderUtil.newInstanceOf(decryptor);
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/CronExpression.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/CronExpression.java
index a850672..da580ff 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/CronExpression.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/CronExpression.java
@@ -1471,7 +1471,7 @@
                         cl.set(Calendar.MONTH, mon);
                         // no '- 1' here because we are promoting the month
                         continue;
-                    } else if (daysToAdd > 0) { // are we swithing days?
+                    } else if (daysToAdd > 0) { // are we switching days?
                         cl.set(Calendar.SECOND, 0);
                         cl.set(Calendar.MINUTE, 0);
                         cl.set(Calendar.HOUR_OF_DAY, 0);
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/KeyValuePair.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/KeyValuePair.java
index 39fa707..83d0078 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/KeyValuePair.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/KeyValuePair.java
@@ -20,7 +20,7 @@
 import org.apache.logging.log4j.plugins.Node;
 import org.apache.logging.log4j.plugins.Plugin;
 import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
+import org.apache.logging.log4j.plugins.PluginFactory;
 
 /**
  * Key/Value pair configuration item.
@@ -64,7 +64,7 @@
         return key + '=' + value;
     }
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static Builder newBuilder() {
         return new Builder();
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/OptionConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/OptionConverter.java
index aad31be..eacd715 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/OptionConverter.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/OptionConverter.java
@@ -16,9 +16,11 @@
  */
 package org.apache.logging.log4j.core.util;
 
+import java.io.InterruptedIOException;
 import java.util.Locale;
 import java.util.Properties;
 
+import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.status.StatusLogger;
 import org.apache.logging.log4j.util.PropertiesUtil;
@@ -154,6 +156,72 @@
         return defaultValue;
     }
 
+    public static Level toLevel(String value, Level defaultValue) {
+        if(value == null) {
+            return defaultValue;
+        }
+
+        value = value.trim();
+
+        int hashIndex = value.indexOf('#');
+        if (hashIndex == -1) {
+            if("NULL".equalsIgnoreCase(value)) {
+                return null;
+            } else {
+                // no class name specified : use standard Level class
+                return Level.toLevel(value, defaultValue);
+            }
+        }
+
+        Level result = defaultValue;
+
+        String clazz = value.substring(hashIndex+1);
+        String levelName = value.substring(0, hashIndex);
+
+        // This is degenerate case but you never know.
+        if("NULL".equalsIgnoreCase(levelName)) {
+            return null;
+        }
+
+        LOGGER.debug("toLevel" + ":class=[" + clazz + "]"
+                + ":pri=[" + levelName + "]");
+
+        try {
+            Class customLevel = Loader.loadClass(clazz);
+
+            // get a ref to the specified class' static method
+            // toLevel(String, org.apache.log4j.Level)
+            Class[] paramTypes = new Class[] { String.class, Level.class
+            };
+            java.lang.reflect.Method toLevelMethod =
+                    customLevel.getMethod("toLevel", paramTypes);
+
+            // now call the toLevel method, passing level string + default
+            Object[] params = new Object[] {levelName, defaultValue};
+            Object o = toLevelMethod.invoke(null, params);
+
+            result = (Level) o;
+        } catch(ClassNotFoundException e) {
+            LOGGER.warn("custom level class [" + clazz + "] not found.");
+        } catch(NoSuchMethodException e) {
+            LOGGER.warn("custom level class [" + clazz + "]"
+                    + " does not have a class function toLevel(String, Level)", e);
+        } catch(java.lang.reflect.InvocationTargetException e) {
+            if (e.getTargetException() instanceof InterruptedException
+                    || e.getTargetException() instanceof InterruptedIOException) {
+                Thread.currentThread().interrupt();
+            }
+            LOGGER.warn("custom level class [" + clazz + "]" + " could not be instantiated", e);
+        } catch(ClassCastException e) {
+            LOGGER.warn("class [" + clazz + "] is not a subclass of org.apache.log4j.Level", e);
+        } catch(IllegalAccessException e) {
+            LOGGER.warn("class ["+clazz+ "] cannot be instantiated due to access restrictions", e);
+        } catch(RuntimeException e) {
+            LOGGER.warn("class ["+clazz+"], level [" + levelName + "] conversion failed.", e);
+        }
+        return result;
+    }
+
     /**
      *
      * @param value The size of the file as a String.
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/util/ProcessIdUtil.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ProcessIdUtil.java
similarity index 97%
rename from log4j-core/src/main/java/org/apache/logging/log4j/util/ProcessIdUtil.java
rename to log4j-core/src/main/java/org/apache/logging/log4j/core/util/ProcessIdUtil.java
index 685aabe..2579350 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/util/ProcessIdUtil.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ProcessIdUtil.java
@@ -14,7 +14,7 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
+package org.apache.logging.log4j.core.util;
 
 import java.io.File;
 import java.io.IOException;
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/UuidUtil.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/UuidUtil.java
index 7b392ed..cf1d9d3 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/UuidUtil.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/UuidUtil.java
@@ -52,8 +52,6 @@
     private static final long NUM_100NS_INTERVALS_SINCE_UUID_EPOCH = 0x01b21dd213814000L;
     private static final long INITIAL_UUID_SEQNO = PropertiesUtil.getProperties().getLongProperty(UUID_SEQUENCE, 0);
 
-    private static final long LEAST;
-
     private static final long LOW_MASK = 0xffffffffL;
     private static final long MID_MASK = 0xffff00000000L;
     private static final long HIGH_MASK = 0xfff000000000000L;
@@ -63,8 +61,19 @@
     private static final int SHIFT_6 = 48;
     private static final int HUNDRED_NANOS_PER_MILLI = 10000;
 
-    static {
-        byte[] mac = NetUtils.getMacAddress();
+    private static final long LEAST = initialize(NetUtils.getMacAddress());
+
+    /* This class cannot be instantiated */
+    private UuidUtil() {
+    }
+
+    /**
+     * Initializes this class
+     * 
+     * @param mac MAC address
+     * @return Least
+     */
+    static long initialize(byte[] mac) {
         final Random randomGenerator = new SecureRandom();
         if (mac == null || mac.length == 0) {
             mac = new byte[6];
@@ -78,7 +87,7 @@
         for (int i = 2; i < NODE_SIZE; ++i) {
             node[i] = 0;
         }
-        System.arraycopy(mac, index, node, index + 2, length);
+        System.arraycopy(mac, index, node, 2, length);
         final ByteBuffer buf = ByteBuffer.wrap(node);
         long rand = INITIAL_UUID_SEQNO;
         String assigned = PropertiesUtil.getProperties().getStringProperty(ASSIGNED_SEQUENCES);
@@ -114,12 +123,7 @@
         assigned = assigned == null ? Long.toString(rand) : assigned + ',' + Long.toString(rand);
         System.setProperty(ASSIGNED_SEQUENCES, assigned);
 
-        LEAST = buf.getLong() | rand << SHIFT_6;
-    }
-
-
-    /* This class cannot be instantiated */
-    private UuidUtil() {
+        return buf.getLong() | rand << SHIFT_6;
     }
 
     /**
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Watcher.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Watcher.java
index 426307f..61552a9 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Watcher.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Watcher.java
@@ -18,7 +18,6 @@
 
 import java.util.List;
 
-import org.apache.logging.log4j.core.config.Configuration;
 import org.apache.logging.log4j.core.config.ConfigurationListener;
 import org.apache.logging.log4j.core.config.Reconfigurable;
 
@@ -40,7 +39,6 @@
 
     /**
      * Called when the configuration has been modified.
-     * @param source The location of the configuration that was modified.
      */
     void modified();
 
@@ -52,7 +50,7 @@
 
     /**
      * Returns the time the source was last modified or 0 if it is not available.
-     * @return the time the soruce was last modified.
+     * @return the time the source was last modified.
      */
     long getLastModified();
 
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/CronRolloverApp.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/CronRolloverApp.java
index d149148..6bf68c4 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/CronRolloverApp.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/CronRolloverApp.java
@@ -37,7 +37,7 @@
             }
         } catch (final Exception e) {
             //e.printStackTrace();
-            logger.error("Excepcion general", e);
+            logger.error("Exception general", e);
         }
     }
 }
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/GarbageCollectionHelper.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/GarbageCollectionHelper.java
index 01b9d8a..c175e67 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/GarbageCollectionHelper.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/GarbageCollectionHelper.java
@@ -27,7 +27,7 @@
 
 import static org.junit.Assert.assertTrue;
 
-final class GarbageCollectionHelper implements Closeable, Runnable {
+public final class GarbageCollectionHelper implements Closeable, Runnable {
     private static final OutputStream sink = ByteStreams.nullOutputStream();
     public final AtomicBoolean running = new AtomicBoolean();
     private final CountDownLatch latch = new CountDownLatch(1);
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/TimestampMessageTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/TimestampMessageTest.java
index 188c6f8..728c038 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/TimestampMessageTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/TimestampMessageTest.java
@@ -79,7 +79,7 @@
     public static class PoisonClock implements Clock {
         public PoisonClock() {
             super();
-            // Breakpoint here for debuging.
+            // Breakpoint here for debugging.
         }
 
         @Override
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/HangingAppender.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/HangingAppender.java
index 785e9a5..a371c49 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/HangingAppender.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/HangingAppender.java
@@ -58,14 +58,14 @@
 
     @PluginFactory
     public static HangingAppender createAppender(
-            @PluginAttribute("name")
+            @PluginAttribute
             @Required(message = "No name provided for HangingAppender")
             final String name,
-            @PluginAttribute("delay") final long delay,
-            @PluginAttribute("startupDelay") final long startupDelay,
-            @PluginAttribute("shutdownDelay") final long shutdownDelay,
-            @PluginElement("Layout") final Layout<? extends Serializable> layout,
-            @PluginElement("Filter") final Filter filter) {
+            @PluginAttribute final long delay,
+            @PluginAttribute final long startupDelay,
+            @PluginAttribute final long shutdownDelay,
+            @PluginElement final Layout<? extends Serializable> layout,
+            @PluginElement final Filter filter) {
         return new HangingAppender(name, delay, startupDelay, shutdownDelay);
     }
 
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderSizeTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderSizeTest.java
index 103a001..625c2eb 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderSizeTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderSizeTest.java
@@ -75,6 +75,7 @@
                 // @formatter:off
                {"log4j-rolling-gz-lazy.xml", ".gz", true},
                {"log4j-rolling-gz.xml", ".gz", false},
+               {"log4j-rolling-numbered-gz.xml", ".gz", false},
                {"log4j-rolling-zip-lazy.xml", ".zip", true},
                {"log4j-rolling-zip.xml", ".zip", false},
                 // Apache Commons Compress
@@ -150,7 +151,7 @@
                         in = new CompressorStreamFactory().createCompressorInputStream(ext.name().toLowerCase(), fis);
                     } catch (final CompressorException ce) {
                         ce.printStackTrace();
-                        fail("Error creating intput stream from " + file.toString() + ": " + ce.getMessage());
+                        fail("Error creating input stream from " + file.toString() + ": " + ce.getMessage());
                     }
                     final ByteArrayOutputStream baos = new ByteArrayOutputStream();
                     assertNotNull("No input stream for " + file.getName(), in);
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigTest.java
index a11365e..1e713d5 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigTest.java
@@ -74,14 +74,14 @@
     	final LoggerConfig rootLoggerConfig =
     			AsyncLoggerConfig.RootLogger.createLogger(
     					null, Level.INFO, null, new AppenderRef[0], null, new DefaultConfiguration(), null);
-    	assertFalse("Include location should default to false for async logggers",
+	assertFalse("Include location should default to false for async loggers",
     			    rootLoggerConfig.isIncludeLocation());
 
     	final LoggerConfig loggerConfig =
     	        AsyncLoggerConfig.createLogger(
     	                false, Level.INFO, "com.foo.Bar", null, new AppenderRef[0], null, new DefaultConfiguration(),
     	        		null);
-    	assertFalse("Include location should default to false for async logggers",
+	assertFalse("Include location should default to false for async loggers",
     			    loggerConfig.isIncludeLocation());
     }
 }
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTestArgumentFreedOnError.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTestArgumentFreedOnError.java
new file mode 100644
index 0000000..5f9f4b5
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTestArgumentFreedOnError.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.core.async;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.categories.AsyncLoggers;
+import org.apache.logging.log4j.core.GarbageCollectionHelper;
+import org.apache.logging.log4j.core.util.Constants;
+import org.apache.logging.log4j.message.Message;
+import org.apache.logging.log4j.util.StringBuilderFormattable;
+import org.apache.logging.log4j.util.Strings;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import static org.junit.Assert.assertTrue;
+
+@Category(AsyncLoggers.class)
+public class AsyncLoggerTestArgumentFreedOnError {
+
+    @BeforeClass
+    public static void beforeClass() {
+        System.setProperty("log4j2.enable.threadlocals", "true");
+        System.setProperty("log4j2.enable.direct.encoders", "true");
+        System.setProperty("log4j2.is.webapp", "false");
+        System.setProperty("log4j.format.msg.async", "true");
+        System.setProperty(Constants.LOG4J_CONTEXT_SELECTOR,
+                AsyncLoggerContextSelector.class.getName());
+    }
+
+    @AfterClass
+    public static void afterClass() {
+        System.setProperty(Constants.LOG4J_CONTEXT_SELECTOR, Strings.EMPTY);
+    }
+
+    // LOG4J2-2725: events are cleared even after failure
+    @Test
+    public void testMessageIsGarbageCollected() throws Exception {
+        final AsyncLogger log = (AsyncLogger) LogManager.getLogger("com.foo.Bar");
+        CountDownLatch garbageCollectionLatch = new CountDownLatch(1);
+        log.fatal(new ThrowingMessage(garbageCollectionLatch));
+        GarbageCollectionHelper gcHelper = new GarbageCollectionHelper();
+        gcHelper.run();
+        try {
+            assertTrue("Parameter should have been garbage collected",
+                    garbageCollectionLatch.await(30, TimeUnit.SECONDS));
+        } finally {
+            gcHelper.close();
+        }
+    }
+
+    private static class ThrowingMessage implements Message, StringBuilderFormattable {
+
+        private final CountDownLatch latch;
+
+        ThrowingMessage(CountDownLatch latch) {
+            this.latch = latch;
+        }
+
+        @Override
+        protected void finalize() throws Throwable {
+            latch.countDown();
+            super.finalize();
+        }
+
+        @Override
+        public String getFormattedMessage() {
+            throw new Error("Expected");
+        }
+
+        @Override
+        public String getFormat() {
+            return "";
+        }
+
+        @Override
+        public Object[] getParameters() {
+            return new Object[0];
+        }
+
+        @Override
+        public Throwable getThrowable() {
+            return null;
+        }
+
+        @Override
+        public void formatTo(StringBuilder buffer) {
+            throw new Error("Expected");
+        }
+    }
+}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerThreadNameStrategyTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerThreadNameStrategyTest.java
index 546cc68..bc5945e 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerThreadNameStrategyTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerThreadNameStrategyTest.java
@@ -26,10 +26,6 @@
 
 @Category(AsyncLoggers.class)
 public class AsyncLoggerThreadNameStrategyTest {
-    static final String DEFAULT_STRATEGY = System.getProperty("java.version").compareTo("1.8.0_102") < 0
-            ? "CACHED" // LOG4J2-2052 JDK 8u102 removed the String allocation in Thread.getName()
-            : "UNCACHED";
-
     @After
     public void after() {
         System.clearProperty("AsyncLogger.ThreadNameStrategy");
@@ -41,16 +37,16 @@
     }
 
     @Test
-    public void testDefaultThreadNameIsCached() throws Exception {
+    public void testDefaultIfNotConfigured() throws Exception {
         final ThreadNameCachingStrategy tns = ThreadNameCachingStrategy.create();
-        assertSame(ThreadNameCachingStrategy.valueOf(DEFAULT_STRATEGY), tns);
+        assertSame(ThreadNameCachingStrategy.DEFAULT_STRATEGY, tns);
     }
 
     @Test
-    public void testUseCachedThreadNameIfInvalidConfig() throws Exception {
+    public void testDefaultIfInvalidConfig() throws Exception {
         System.setProperty("AsyncLogger.ThreadNameStrategy", "\\%%InValid ");
         final ThreadNameCachingStrategy tns = ThreadNameCachingStrategy.create();
-        assertSame(ThreadNameCachingStrategy.valueOf(DEFAULT_STRATEGY), tns);
+        assertSame(ThreadNameCachingStrategy.DEFAULT_STRATEGY, tns);
     }
 
     @Test
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncRootReloadTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncRootReloadTest.java
index 49dec04..27ee560 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncRootReloadTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncRootReloadTest.java
@@ -51,7 +51,7 @@
         final File configFile = FileUtils.fileFromUri(url.toURI());
 
         final Logger logger = LogManager.getLogger(AsyncRootReloadTest.class);
-        logger.info("Log4j configured, will be reconfigured in aprox. 5 sec");
+        logger.info("Log4j configured, will be reconfigured in approx. 5 sec");
 
         configFile.setLastModified(System.currentTimeMillis());
 
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/BlockingAppender.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/BlockingAppender.java
index 209dbe8..2db6368 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/BlockingAppender.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/BlockingAppender.java
@@ -71,11 +71,11 @@
 
     @PluginFactory
     public static BlockingAppender createAppender(
-            @PluginAttribute("name")
+            @PluginAttribute
             @Required(message = "No name provided for HangingAppender")
             final String name,
-            @PluginElement("Layout") final Layout<? extends Serializable> layout,
-            @PluginElement("Filter") final Filter filter) {
+            @PluginElement final Layout<? extends Serializable> layout,
+            @PluginElement final Filter filter) {
         return new BlockingAppender(name);
     }
 
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/CompositeConfigurationTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/CompositeConfigurationTest.java
index cb7b497..845573c 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/CompositeConfigurationTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/CompositeConfigurationTest.java
@@ -115,6 +115,9 @@
                         appendersMap.size());
                 assertTrue(appendersMap.get("File") instanceof FileAppender);
                 assertTrue(appendersMap.get("STDOUT") instanceof ConsoleAppender);
+
+                assertEquals("Expected COMPOSITE_SOURCE for composite configuration but got " + config.getConfigurationSource(),
+                        config.getConfigurationSource(), ConfigurationSource.COMPOSITE_SOURCE);
             }
         };
         runTest(lcr, test);
@@ -157,7 +160,7 @@
                 //Regression
                 //Check level on cat3 (not present in root config)
                 assertEquals("Expected cat3 log level to be ERROR", Level.ERROR, config.getLogger("cat3").getLevel());
-                //Check level on cat1 (not present in overriden config)
+                //Check level on cat1 (not present in overridden config)
                 assertEquals("Expected cat1 log level to be DEBUG", Level.DEBUG, config.getLogger("cat1").getLevel());
             }
         };
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/RequiredValidatorTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/RequiredValidatorTest.java
index f5de649..c2dd9d4 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/RequiredValidatorTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/RequiredValidatorTest.java
@@ -38,7 +38,7 @@
         final PluginManager manager = new PluginManager("Test");
         manager.collectPlugins();
         plugin = (PluginType<ValidatingPlugin>) manager.getPluginType("Validator");
-        assertNotNull("Rebuild this module to make sure annotaion processing kicks in.", plugin);
+        assertNotNull("Rebuild this module to make sure annotation processing kicks in.", plugin);
         node = new Node(null, "Validator", plugin);
     }
 
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithGenericBuilderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithGenericBuilderTest.java
index d70f358..814ac68 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithGenericBuilderTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithGenericBuilderTest.java
@@ -40,7 +40,7 @@
         final PluginManager manager = new PluginManager("Test");
         manager.collectPlugins();
         plugin = (PluginType<ValidatingPluginWithGenericBuilder>) manager.getPluginType("ValidatingPluginWithGenericBuilder");
-        assertNotNull("Rebuild this module to make sure annotaion processing kicks in.", plugin);
+        assertNotNull("Rebuild this module to make sure annotation processing kicks in.", plugin);
         node = new Node(null, "Validator", plugin);
     }
 
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithGenericSubclassFoo1BuilderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithGenericSubclassFoo1BuilderTest.java
index d567a40..bea4e5a 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithGenericSubclassFoo1BuilderTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithGenericSubclassFoo1BuilderTest.java
@@ -40,7 +40,7 @@
         final PluginManager manager = new PluginManager("Test");
         manager.collectPlugins();
         plugin = (PluginType<PluginWithGenericSubclassFoo1Builder>) manager.getPluginType("PluginWithGenericSubclassFoo1Builder");
-        assertNotNull("Rebuild this module to make sure annotaion processing kicks in.", plugin);
+        assertNotNull("Rebuild this module to make sure annotation processing kicks in.", plugin);
         node = new Node(null, "Validator", plugin);
     }
 
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithTypedBuilderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithTypedBuilderTest.java
index 839bcaf..0f00d46 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithTypedBuilderTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithTypedBuilderTest.java
@@ -41,7 +41,7 @@
         manager.collectPlugins();
         plugin = (PluginType<ValidatingPluginWithTypedBuilder>) manager
                 .getPluginType("ValidatingPluginWithTypedBuilder");
-        assertNotNull("Rebuild this module to make sure annotaion processing kicks in.", plugin);
+        assertNotNull("Rebuild this module to make sure annotation processing kicks in.", plugin);
         node = new Node(null, "Validator", plugin);
     }
 
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/GelfLayoutTest3.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/GelfLayoutTest3.java
new file mode 100644
index 0000000..9e02b65
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/GelfLayoutTest3.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.core.layout;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.ThreadContext;
+import org.apache.logging.log4j.core.lookup.JavaLookup;
+import org.apache.logging.log4j.junit.LoggerContextRule;
+import org.junit.After;
+import org.junit.ClassRule;
+import org.junit.Test;
+
+import java.io.IOException;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+public class GelfLayoutTest3 {
+
+    @ClassRule
+    public static LoggerContextRule context = new LoggerContextRule("GelfLayoutTest3.xml");
+
+    @After
+    public void teardown() throws Exception {
+        ThreadContext.clearMap();
+    }
+
+    @Test
+    public void gelfLayout() throws IOException {
+        final Logger logger = context.getLogger();
+        ThreadContext.put("loginId", "rgoers");
+        ThreadContext.put("internalId", "12345");
+        logger.info("My Test Message");
+        final String gelf = context.getListAppender("list").getMessages().get(0);
+        final ObjectMapper mapper = new ObjectMapper();
+        final JsonNode json = mapper.readTree(gelf);
+        assertEquals("My Test Message", json.get("short_message").asText());
+        assertEquals("myhost", json.get("host").asText());
+        assertNotNull(json.get("_loginId"));
+        assertEquals("rgoers", json.get("_loginId").asText());
+        assertNull(json.get("_internalId"));
+        assertNull(json.get("_requestId"));
+        String message = json.get("full_message").asText();
+        assertTrue(message.contains("loginId=rgoers"));
+        assertTrue(message.contains("GelfLayoutTest3"));
+    }
+
+}
+
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternSelectorTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternSelectorTest.java
index 45b33b7..a332f1e 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternSelectorTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternSelectorTest.java
@@ -38,7 +38,7 @@
     LoggerContext ctx = LoggerContext.getContext();
 
     @Test
-    public void testPatternSelector() throws Exception {
+    public void testMarkerPatternSelector() throws Exception {
         final PatternMatch[] patterns = new PatternMatch[1];
         patterns[0] = new PatternMatch("FLOW", "%d %-5p [%t]: ====== %C{1}.%M:%L %m ======%n");
         // @formatter:off
@@ -59,7 +59,7 @@
                 .setIncludeLocation(true)
                 .setMessage(new SimpleMessage("entry")).build();
         final String result1 = new FauxLogger().formatEvent(event1, layout);
-        final String expectSuffix1 = String.format("====== PatternSelectorTest.testPatternSelector:61 entry ======%n");
+        final String expectSuffix1 = String.format("====== PatternSelectorTest.testMarkerPatternSelector:61 entry ======%n");
         assertTrue("Unexpected result: " + result1, result1.endsWith(expectSuffix1));
         final LogEvent event2 = Log4jLogEvent.newBuilder() //
                 .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
@@ -70,4 +70,27 @@
         assertTrue("Unexpected result: " + result2, result2.endsWith(expectSuffix2));
     }
 
+    @Test
+    public void testLevelPatternSelector() throws Exception {
+        final PatternMatch[] patterns = new PatternMatch[1];
+        patterns[0] = new PatternMatch("TRACE", "%d %-5p [%t]: ====== %C{1}.%M:%L %m ======%n");
+        final PatternSelector selector = LevelPatternSelector.createSelector(patterns, "%d %-5p [%t]: %m%n", true, true, ctx.getConfiguration());
+        final PatternLayout layout = PatternLayout.newBuilder().setPatternSelector(selector)
+                .setConfiguration(ctx.getConfiguration()).build();
+        final LogEvent event1 = Log4jLogEvent.newBuilder() //
+                .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.layout.PatternSelectorTest$FauxLogger")
+                .setLevel(Level.TRACE) //
+                .setIncludeLocation(true)
+                .setMessage(new SimpleMessage("entry")).build();
+        final String result1 = new FauxLogger().formatEvent(event1, layout);
+        final String expectSuffix1 = String.format("====== PatternSelectorTest.testLevelPatternSelector:85 entry ======%n");
+        assertTrue("Unexpected result: " + result1, result1.endsWith(expectSuffix1));
+        final LogEvent event2 = Log4jLogEvent.newBuilder() //
+                .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
+                .setLevel(Level.INFO) //
+                .setMessage(new SimpleMessage("Hello, world 1!")).build();
+        final String result2 = new String(layout.toByteArray(event2));
+        final String expectSuffix2 = String.format("Hello, world 1!%n");
+        assertTrue("Unexpected result: " + result2, result2.endsWith(expectSuffix2));
+    }
 }
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/Rfc5424LayoutTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/Rfc5424LayoutTest.java
index 1987c44..4d900a1 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/Rfc5424LayoutTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/Rfc5424LayoutTest.java
@@ -36,7 +36,7 @@
 import org.apache.logging.log4j.message.StructuredDataMessage;
 import org.apache.logging.log4j.status.StatusLogger;
 import org.apache.logging.log4j.test.appender.ListAppender;
-import org.apache.logging.log4j.util.ProcessIdUtil;
+import org.apache.logging.log4j.core.util.ProcessIdUtil;
 import org.apache.logging.log4j.util.Strings;
 import org.junit.AfterClass;
 import org.junit.Assert;
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/CaseLookupTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/CaseLookupTest.java
new file mode 100644
index 0000000..ae7d5ac
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/CaseLookupTest.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.core.lookup;
+
+import java.util.Calendar;
+
+import org.apache.logging.log4j.core.AbstractLogEvent;
+import org.apache.logging.log4j.core.LogEvent;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+/**
+ *
+ */
+public class CaseLookupTest {
+
+
+    @Test
+    public void testLookup() {
+        final String testStr = "JabberWocky";
+        final String lower = "jabberwocky";
+        final String upper = "JABBERWOCKY";
+        StrLookup lookup = new LowerLookup();
+        String value = lookup.lookup(null, testStr);
+        assertNotNull(value);
+        assertEquals(lower, value);
+        lookup = new UpperLookup();
+        value = lookup.lookup(null, testStr);
+        assertNotNull(value);
+        assertEquals(upper, value);
+    }
+}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/MainInputArgumentsMapLookup.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/MainInputArgumentsMapLookup.java
index f6bad22..cce9d1e 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/MainInputArgumentsMapLookup.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/MainInputArgumentsMapLookup.java
@@ -34,7 +34,7 @@
             final StackTraceElement[] stackTraceElements = entry.getValue();
             entry.getKey();
             // Can't use the thread name to look for "main" since anyone can set it.
-            // Can't use thread ID since it can be any positive value, and is likely vender dependent. Oracle seems to
+            // Can't use thread ID since it can be any positive value, and is likely vendor dependent. Oracle seems to
             // use 1.
             // We are left to look for "main" at the top of the stack
             if (stackTraceElements != null) {
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/CronExpressionTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/util/CronExpressionTest.java
index 54bf666..c00d2f0 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/CronExpressionTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/util/CronExpressionTest.java
@@ -95,7 +95,7 @@
     }
 
     /**
-     * 35,45, and 55 minutes past the hour evern hour.
+     * 35,45, and 55 minutes past the hour every hour.
      */
     @Test
     public void testPrevFireTime3() throws Exception {
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/util/ProcessIdUtilTest.java
similarity index 91%
rename from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
rename to log4j-core/src/test/java/org/apache/logging/log4j/core/util/ProcessIdUtilTest.java
index 13aaf9c..44cee0a 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/util/ProcessIdUtilTest.java
@@ -14,8 +14,9 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
+package org.apache.logging.log4j.core.util;
 
+import org.apache.logging.log4j.core.util.ProcessIdUtil;
 import org.junit.Test;
 
 import static org.junit.Assert.*;
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/UuidTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/util/UuidTest.java
index 556f765..dbb4517 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/UuidTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/util/UuidTest.java
@@ -64,6 +64,22 @@
     }
 
     @Test
+    public void testInitialize() {
+        // Test if no ArrayIndexOutOfBoundsException is thrown when Mac address array is null
+        UuidUtil.initialize(null);
+
+        // Test if no ArrayIndexOutOfBoundsException is thrown for different Mac address lengths
+        for (int i=0; i < 10; i++) {
+            // Create MAC address byte array with i as size
+            byte[] mac = new byte[i];
+            for(int j=0; j < i; j++) {
+                mac[j] = (byte)j;
+            }
+            UuidUtil.initialize(mac);
+        }
+    }
+
+    @Test
     public void testThreads() throws Exception {
         final Thread[] threads = new Thread[THREADS];
         final UUID[] uuids = new UUID[COUNT * THREADS];
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/AlwaysFailAppender.java b/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/AlwaysFailAppender.java
index 5572605..380dfe5 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/AlwaysFailAppender.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/AlwaysFailAppender.java
@@ -42,7 +42,7 @@
 
     @PluginFactory
     public static AlwaysFailAppender createAppender(
-        @PluginAttribute("name") @Required(message = "A name for the Appender must be specified") final String name) {
+        @PluginAttribute @Required(message = "A name for the Appender must be specified") final String name) {
         return new AlwaysFailAppender(name);
     }
 
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/BlockingAppender.java b/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/BlockingAppender.java
index 23cd489..922f50b 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/BlockingAppender.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/BlockingAppender.java
@@ -59,7 +59,7 @@
 
     @PluginFactory
     public static BlockingAppender createAppender(
-        @PluginAttribute("name") @Required(message = "A name for the Appender must be specified") final String name) {
+        @PluginAttribute @Required(message = "A name for the Appender must be specified") final String name) {
         return new BlockingAppender(name);
     }
 }
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/DeadlockAppender.java b/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/DeadlockAppender.java
index 34b3b39..9afd483 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/DeadlockAppender.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/DeadlockAppender.java
@@ -69,7 +69,7 @@
 
     @PluginFactory
     public static DeadlockAppender createAppender(
-        @PluginAttribute("name") @Required(message = "A name for the Appender must be specified") final String name) {
+        @PluginAttribute @Required(message = "A name for the Appender must be specified") final String name) {
         return new DeadlockAppender(name);
     }
 
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/FailOnceAppender.java b/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/FailOnceAppender.java
index 8d77914..2a18bc3 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/FailOnceAppender.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/FailOnceAppender.java
@@ -59,7 +59,7 @@
 
     @PluginFactory
     public static FailOnceAppender createAppender(
-        @PluginAttribute("name") @Required(message = "A name for the Appender must be specified") final String name) {
+        @PluginAttribute @Required(message = "A name for the Appender must be specified") final String name) {
         return new FailOnceAppender(name);
     }
 
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/ListAppender.java b/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/ListAppender.java
index 150d010..1f9ec2d 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/ListAppender.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/ListAppender.java
@@ -16,13 +16,6 @@
  */
 package org.apache.logging.log4j.test.appender;
 
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
 import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.Core;
 import org.apache.logging.log4j.core.Filter;
@@ -31,12 +24,19 @@
 import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.appender.AbstractAppender;
 import org.apache.logging.log4j.core.config.Property;
-import org.apache.logging.log4j.plugins.Plugin;
-import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
-import org.apache.logging.log4j.plugins.PluginElement;
-import org.apache.logging.log4j.plugins.validation.constraints.Required;
 import org.apache.logging.log4j.core.impl.MutableLogEvent;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.plugins.PluginAttribute;
+import org.apache.logging.log4j.plugins.PluginElement;
+import org.apache.logging.log4j.plugins.PluginFactory;
+import org.apache.logging.log4j.plugins.validation.constraints.Required;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 /**
  * This appender is primarily used for testing. Use in a real environment is discouraged as the List could eventually
@@ -83,7 +83,7 @@
      *     listAppender.countDownLatch = new CountDownLatch(1);
      *
      *     Logger logger = LogManager.getLogger();
-     *     logger.info("log one event anynchronously");
+     *     logger.info("log one event asynchronously");
      *
      *     // wait for the appender to finish processing this event (wait max 1 second)
      *     listAppender.countDownLatch.await(1, TimeUnit.SECONDS);
@@ -223,49 +223,45 @@
         return new ListAppender(name, filter, layout, newLine, raw);
     }
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static Builder newBuilder() {
         return new Builder();
     }
 
     public static class Builder implements org.apache.logging.log4j.plugins.util.Builder<ListAppender> {
 
-        @PluginBuilderAttribute
-        @Required
         private String name;
-
-        @PluginBuilderAttribute
         private boolean entryPerNewLine;
-
-        @PluginBuilderAttribute
         private boolean raw;
-
-        @PluginElement("Layout")
         private Layout<? extends Serializable> layout;
-
-        @PluginElement("Filter")
         private Filter filter;
 
+        @PluginAttribute
+        @Required
         public Builder setName(final String name) {
             this.name = name;
             return this;
         }
 
+        @PluginAttribute
         public Builder setEntryPerNewLine(final boolean entryPerNewLine) {
             this.entryPerNewLine = entryPerNewLine;
             return this;
         }
 
+        @PluginAttribute
         public Builder setRaw(final boolean raw) {
             this.raw = raw;
             return this;
         }
 
+        @PluginElement
         public Builder setLayout(final Layout<? extends Serializable> layout) {
             this.layout = layout;
             return this;
         }
 
+        @PluginElement
         public Builder setFilter(final Filter filter) {
             this.filter = filter;
             return this;
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/UsesLoggingAppender.java b/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/UsesLoggingAppender.java
index da70fcf..9b4abfd 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/UsesLoggingAppender.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/test/appender/UsesLoggingAppender.java
@@ -45,10 +45,10 @@
 
     @PluginFactory
     public static UsesLoggingAppender createAppender(
-        @PluginAttribute("name") @Required(message = "A name for the Appender must be specified") final String name,
+        @PluginAttribute @Required(message = "A name for the Appender must be specified") final String name,
         @PluginAttribute("ignoreExceptions") final boolean ignore,
-        @PluginElement("Layout") final Layout<?> layout,
-        @PluginElement("Filter") final Filter filter) {
+        @PluginElement final Layout<?> layout,
+        @PluginElement final Filter filter) {
         return new UsesLoggingAppender(name, filter, layout, ignore);
     }
 
diff --git a/log4j-core/src/test/resources/GelfLayoutTest3.xml b/log4j-core/src/test/resources/GelfLayoutTest3.xml
new file mode 100644
index 0000000..fcb23d3
--- /dev/null
+++ b/log4j-core/src/test/resources/GelfLayoutTest3.xml
@@ -0,0 +1,35 @@
+<?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 status="WARN" name="GelfLayoutTest3">
+  <Appenders>
+    <List name="list">
+      <GelfLayout host="myhost" includeThreadContext="true" threadContextIncludes="requestId,loginId">
+        <MessagePattern>%d [%t] %-5p %X{requestId, loginId} %C{1.}.%M:%L - %m%n"</MessagePattern>
+        <KeyValuePair key="foo" value="FOO"/>
+        <KeyValuePair key="runtime" value="$${java:runtime}"/>
+      </GelfLayout>
+    </List>
+  </Appenders>
+
+  <Loggers>
+    <Root level="info">
+      <AppenderRef ref="list"/>
+    </Root>
+  </Loggers>
+</Configuration>
\ No newline at end of file
diff --git a/log4j-core/src/test/resources/log4j-rolling-numbered-gz.xml b/log4j-core/src/test/resources/log4j-rolling-numbered-gz.xml
new file mode 100644
index 0000000..f7aeb13
--- /dev/null
+++ b/log4j-core/src/test/resources/log4j-rolling-numbered-gz.xml
@@ -0,0 +1,59 @@
+<?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 status="WARN" name="XMLConfigTest">
+  <Properties>
+    <Property name="filename">target/rolling1/rolling0-0.log</Property>
+  </Properties>
+  <ThresholdFilter level="debug"/>
+
+  <Appenders>
+    <Console name="STDOUT">
+      <PatternLayout pattern="%m%n"/>
+    </Console>
+    <RollingFile name="RollingFile" fileName="${filename}"
+                 filePattern="target/rolling1/rolling0-%i.log.gz">
+      <PatternLayout>
+        <Pattern>%d %p %C{1.} [%t] %m%n</Pattern>
+      </PatternLayout>
+      <SizeBasedTriggeringPolicy size="500" />
+      <DefaultRolloverStrategy max="7" min="1" fileIndex="min"/>
+    </RollingFile>
+    <List name="List">
+      <ThresholdFilter level="error"/>
+    </List>
+  </Appenders>
+
+  <Loggers>
+    <Logger name="org.apache.logging.log4j.test1" level="debug" additivity="false">
+      <ThreadContextMapFilter>
+        <KeyValuePair key="test" value="123"/>
+      </ThreadContextMapFilter>
+      <AppenderRef ref="STDOUT"/>
+    </Logger>>
+
+    <Logger name="org.apache.logging.log4j.core.appender.rolling" level="debug" additivity="false">
+      <AppenderRef ref="RollingFile"/>
+    </Logger>>
+
+    <Root level="error">
+      <AppenderRef ref="STDOUT"/>
+    </Root>
+  </Loggers>
+
+</Configuration>
\ No newline at end of file
diff --git a/log4j-couchdb/src/main/java/org/apache/logging/log4j/couchdb/CouchDbProvider.java b/log4j-couchdb/src/main/java/org/apache/logging/log4j/couchdb/CouchDbProvider.java
index 621a92d..6eb207e 100644
--- a/log4j-couchdb/src/main/java/org/apache/logging/log4j/couchdb/CouchDbProvider.java
+++ b/log4j-couchdb/src/main/java/org/apache/logging/log4j/couchdb/CouchDbProvider.java
@@ -83,14 +83,14 @@
      */
     @PluginFactory
     public static CouchDbProvider createNoSqlProvider(
-            @PluginAttribute("databaseName") final String databaseName,
-            @PluginAttribute("protocol") String protocol,
-            @PluginAttribute(value = "server", defaultString = "localhost") @ValidHost final String server,
-            @PluginAttribute(value = "port", defaultString = "0") @ValidPort final String port,
-            @PluginAttribute("username") final String username,
-            @PluginAttribute(value = "password", sensitive = true) final String password,
-            @PluginAttribute("factoryClassName") final String factoryClassName,
-            @PluginAttribute("factoryMethodName") final String factoryMethodName) {
+            @PluginAttribute final String databaseName,
+            @PluginAttribute String protocol,
+            @PluginAttribute(defaultString = "localhost") @ValidHost final String server,
+            @PluginAttribute(defaultString = "0") @ValidPort final String port,
+            @PluginAttribute final String username,
+            @PluginAttribute(sensitive = true) final String password,
+            @PluginAttribute final String factoryClassName,
+            @PluginAttribute final String factoryMethodName) {
         CouchDbClient client;
         String description;
         if (Strings.isNotEmpty(factoryClassName) && Strings.isNotEmpty(factoryMethodName)) {
diff --git a/log4j-csv/src/main/java/org/apache/logging/log4j/csv/layout/CsvLogEventLayout.java b/log4j-csv/src/main/java/org/apache/logging/log4j/csv/layout/CsvLogEventLayout.java
index b320052..ce195ed 100644
--- a/log4j-csv/src/main/java/org/apache/logging/log4j/csv/layout/CsvLogEventLayout.java
+++ b/log4j-csv/src/main/java/org/apache/logging/log4j/csv/layout/CsvLogEventLayout.java
@@ -53,16 +53,16 @@
     public static CsvLogEventLayout createLayout(
             // @formatter:off
             @PluginConfiguration final Configuration config,
-            @PluginAttribute(value = "format", defaultString = DEFAULT_FORMAT) final String format,
-            @PluginAttribute("delimiter") final Character delimiter,
-            @PluginAttribute("escape") final Character escape,
-            @PluginAttribute("quote") final Character quote,
-            @PluginAttribute("quoteMode") final QuoteMode quoteMode,
-            @PluginAttribute("nullString") final String nullString,
-            @PluginAttribute("recordSeparator") final String recordSeparator,
-            @PluginAttribute(value = "charset", defaultString = DEFAULT_CHARSET) final Charset charset,
-            @PluginAttribute("header") final String header,
-            @PluginAttribute("footer") final String footer)
+            @PluginAttribute(defaultString = DEFAULT_FORMAT) final String format,
+            @PluginAttribute final Character delimiter,
+            @PluginAttribute final Character escape,
+            @PluginAttribute final Character quote,
+            @PluginAttribute final QuoteMode quoteMode,
+            @PluginAttribute final String nullString,
+            @PluginAttribute final String recordSeparator,
+            @PluginAttribute(defaultString = DEFAULT_CHARSET) final Charset charset,
+            @PluginAttribute final String header,
+            @PluginAttribute final String footer)
             // @formatter:on
     {
 
diff --git a/log4j-csv/src/main/java/org/apache/logging/log4j/csv/layout/CsvParameterLayout.java b/log4j-csv/src/main/java/org/apache/logging/log4j/csv/layout/CsvParameterLayout.java
index a8eaf0a..816271a 100644
--- a/log4j-csv/src/main/java/org/apache/logging/log4j/csv/layout/CsvParameterLayout.java
+++ b/log4j-csv/src/main/java/org/apache/logging/log4j/csv/layout/CsvParameterLayout.java
@@ -62,16 +62,16 @@
     public static AbstractCsvLayout createLayout(
             // @formatter:off
             @PluginConfiguration final Configuration config,
-            @PluginAttribute(value = "format", defaultString = DEFAULT_FORMAT) final String format,
-            @PluginAttribute("delimiter") final Character delimiter,
-            @PluginAttribute("escape") final Character escape,
-            @PluginAttribute("quote") final Character quote,
-            @PluginAttribute("quoteMode") final QuoteMode quoteMode,
-            @PluginAttribute("nullString") final String nullString,
-            @PluginAttribute("recordSeparator") final String recordSeparator,
-            @PluginAttribute(value = "charset", defaultString = DEFAULT_CHARSET) final Charset charset,
-            @PluginAttribute("header") final String header, 
-            @PluginAttribute("footer") final String footer)
+            @PluginAttribute(defaultString = DEFAULT_FORMAT) final String format,
+            @PluginAttribute final Character delimiter,
+            @PluginAttribute final Character escape,
+            @PluginAttribute final Character quote,
+            @PluginAttribute final QuoteMode quoteMode,
+            @PluginAttribute final String nullString,
+            @PluginAttribute final String recordSeparator,
+            @PluginAttribute(defaultString = DEFAULT_CHARSET) final Charset charset,
+            @PluginAttribute final String header,
+            @PluginAttribute final String footer)
             // @formatter:on
     {
 
diff --git a/log4j-csv/src/site/manual/index.md b/log4j-csv/src/site/manual/index.md
index 66fe24f..84fca13 100644
--- a/log4j-csv/src/site/manual/index.md
+++ b/log4j-csv/src/site/manual/index.md
@@ -18,7 +18,7 @@
 
 # Apache Log4j ZeroMQ using JeroMQ module
 
-As of Log4j 2.11.0, ZeroMQ using JeroMQ support has moved from the existing module logj-core to the new module log4j-jeromq.
+As of Log4j 2.11.0, ZeroMQ using JeroMQ support has moved from the existing module log4j-core to the new module log4j-jeromq.
 
 ## Requirements
 
diff --git a/log4j-docker/src/main/java/org/apache/logging/log4j/docker/DockerLookup.java b/log4j-docker/src/main/java/org/apache/logging/log4j/docker/DockerLookup.java
index 8d6255e..cd2c1cb 100644
--- a/log4j-docker/src/main/java/org/apache/logging/log4j/docker/DockerLookup.java
+++ b/log4j-docker/src/main/java/org/apache/logging/log4j/docker/DockerLookup.java
@@ -52,7 +52,7 @@
             baseUri = props.getStringProperty(DOCKER_URI);
         }
         if (baseUri == null) {
-            LOGGER.warn("No Docker URI provided. Docker information is unavailble");
+            LOGGER.warn("No Docker URI provided. Docker information is unavailable");
         }
         Container current = null;
         try {
diff --git a/log4j-docker/src/site/markdown/index.md.vm b/log4j-docker/src/site/markdown/index.md.vm
index e717fb9..969e8e5 100644
--- a/log4j-docker/src/site/markdown/index.md.vm
+++ b/log4j-docker/src/site/markdown/index.md.vm
@@ -25,7 +25,7 @@
 
 $h2 Accessing Docker
 
-The Log4j Docker support requires access to the Docker REST intrerface. In practical terms this means the
+The Log4j Docker support requires access to the Docker REST interface. In practical terms this means the
 application either needs access to unix:///var/run/docker.sock through a volume mount (not recommended),
 bind Docker to another host/port or unix socket. or use a proxy application to provide access. The
 [Log4j Spring Cloud sample application](https://github.com/apache/logging-log4j2/tree/master/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application)
diff --git a/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeAppender.java b/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeAppender.java
index ac9c9a2..e2d4f06 100644
--- a/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeAppender.java
+++ b/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeAppender.java
@@ -185,32 +185,32 @@
      * @return A Flume Avro Appender.
      */
     @PluginFactory
-    public static FlumeAppender createAppender(@PluginElement("Agents") final Agent[] agents,
-                                               @PluginElement("Properties") final Property[] properties,
-                                               @PluginAttribute("hosts") final String hosts,
-                                               @PluginAttribute("embedded") final String embedded,
-                                               @PluginAttribute("type") final String type,
-                                               @PluginAttribute("dataDir") final String dataDir,
+    public static FlumeAppender createAppender(@PluginElement final Agent[] agents,
+                                               @PluginElement final Property[] properties,
+                                               @PluginAttribute final String hosts,
+                                               @PluginAttribute final String embedded,
+                                               @PluginAttribute final String type,
+                                               @PluginAttribute final String dataDir,
                                                @PluginAliases("connectTimeout")
                                                @PluginAttribute("connectTimeoutMillis") final String connectionTimeoutMillis,
                                                @PluginAliases("requestTimeout")
-                                               @PluginAttribute("requestTimeoutMillis") final String requestTimeoutMillis,
-                                               @PluginAttribute("agentRetries") final String agentRetries,
+                                               @PluginAttribute final String requestTimeoutMillis,
+                                               @PluginAttribute final String agentRetries,
                                                @PluginAliases("maxDelay") // deprecated
-                                               @PluginAttribute("maxDelayMillis") final String maxDelayMillis,
-                                               @PluginAttribute("name") final String name,
+                                               @PluginAttribute final String maxDelayMillis,
+                                               @PluginAttribute final String name,
                                                @PluginAttribute("ignoreExceptions") final String ignore,
                                                @PluginAttribute("mdcExcludes") final String excludes,
                                                @PluginAttribute("mdcIncludes") final String includes,
                                                @PluginAttribute("mdcRequired") final String required,
-                                               @PluginAttribute("mdcPrefix") final String mdcPrefix,
-                                               @PluginAttribute("eventPrefix") final String eventPrefix,
+                                               @PluginAttribute final String mdcPrefix,
+                                               @PluginAttribute final String eventPrefix,
                                                @PluginAttribute("compress") final String compressBody,
-                                               @PluginAttribute("batchSize") final String batchSize,
-                                               @PluginAttribute("lockTimeoutRetries") final String lockTimeoutRetries,
-                                               @PluginElement("FlumeEventFactory") final FlumeEventFactory factory,
-                                               @PluginElement("Layout") Layout<? extends Serializable> layout,
-                                               @PluginElement("Filter") final Filter filter) {
+                                               @PluginAttribute final String batchSize,
+                                               @PluginAttribute final String lockTimeoutRetries,
+                                               @PluginElement final FlumeEventFactory factory,
+                                               @PluginElement Layout<? extends Serializable> layout,
+                                               @PluginElement final Filter filter) {
 
         final boolean embed = embedded != null ? Boolean.parseBoolean(embedded) :
             (agents == null || agents.length == 0 || hosts == null || hosts.isEmpty()) && properties != null && properties.length > 0;
diff --git a/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/Log4jEventSource.java b/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/Log4jEventSource.java
index d444db5..7dd573c 100644
--- a/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/Log4jEventSource.java
+++ b/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/Log4jEventSource.java
@@ -58,7 +58,7 @@
         try {
             getChannelProcessor().processEvent(event);
         } catch (final ChannelException ex) {
-            LOGGER.warn("Unabled to process event {}" + event, ex);
+            LOGGER.warn("Unable to process event {}" + event, ex);
             throw ex;
         }
         sourceCounter.incrementAppendAcceptedCount();
diff --git a/log4j-iostreams/src/main/java/org/apache/logging/log4j/io/internal/InternalBufferedInputStream.java b/log4j-iostreams/src/main/java/org/apache/logging/log4j/io/internal/InternalBufferedInputStream.java
index 9f04ed3..bf1490c 100644
--- a/log4j-iostreams/src/main/java/org/apache/logging/log4j/io/internal/InternalBufferedInputStream.java
+++ b/log4j-iostreams/src/main/java/org/apache/logging/log4j/io/internal/InternalBufferedInputStream.java
@@ -28,7 +28,7 @@
 import org.apache.logging.log4j.spi.ExtendedLogger;
 
 /**
- * Internal class that exists primiarly to allow location calculations to work.
+ * Internal class that exists primarily to allow location calculations to work.
  * @since 2.12
  */
 public class InternalBufferedInputStream extends BufferedInputStream {
diff --git a/log4j-iostreams/src/main/java/org/apache/logging/log4j/io/internal/InternalBufferedReader.java b/log4j-iostreams/src/main/java/org/apache/logging/log4j/io/internal/InternalBufferedReader.java
index 90452a4..0379912 100644
--- a/log4j-iostreams/src/main/java/org/apache/logging/log4j/io/internal/InternalBufferedReader.java
+++ b/log4j-iostreams/src/main/java/org/apache/logging/log4j/io/internal/InternalBufferedReader.java
@@ -27,7 +27,7 @@
 import org.apache.logging.log4j.spi.ExtendedLogger;
 
 /**
- * Internal class that exists primiarly to allow location calculations to work.
+ * Internal class that exists primarily to allow location calculations to work.
  * @since 2.12
  */
 public class InternalBufferedReader extends BufferedReader {
diff --git a/log4j-iostreams/src/main/java/org/apache/logging/log4j/io/internal/InternalFilterOutputStream.java b/log4j-iostreams/src/main/java/org/apache/logging/log4j/io/internal/InternalFilterOutputStream.java
index a726818..112e1dd 100644
--- a/log4j-iostreams/src/main/java/org/apache/logging/log4j/io/internal/InternalFilterOutputStream.java
+++ b/log4j-iostreams/src/main/java/org/apache/logging/log4j/io/internal/InternalFilterOutputStream.java
@@ -28,7 +28,7 @@
 import org.apache.logging.log4j.spi.ExtendedLogger;
 
 /**
- * Internal class that exists primiarly to allow location calculations to work.
+ * Internal class that exists primarily to allow location calculations to work.
  *
  * @since 2.12
  */
diff --git a/log4j-iostreams/src/main/java/org/apache/logging/log4j/io/internal/InternalPrintWriter.java b/log4j-iostreams/src/main/java/org/apache/logging/log4j/io/internal/InternalPrintWriter.java
index f8f8c92..d673fc8 100644
--- a/log4j-iostreams/src/main/java/org/apache/logging/log4j/io/internal/InternalPrintWriter.java
+++ b/log4j-iostreams/src/main/java/org/apache/logging/log4j/io/internal/InternalPrintWriter.java
@@ -28,7 +28,7 @@
 import org.apache.logging.log4j.spi.ExtendedLogger;
 
 /**
- * Internal class that exists primiarly to allow location calculations to work.
+ * Internal class that exists primarily to allow location calculations to work.
  *
  * @since 2.12
  */
diff --git a/log4j-iostreams/src/main/java/org/apache/logging/log4j/io/internal/InternalReader.java b/log4j-iostreams/src/main/java/org/apache/logging/log4j/io/internal/InternalReader.java
index 40f9fd1..932ae9b 100644
--- a/log4j-iostreams/src/main/java/org/apache/logging/log4j/io/internal/InternalReader.java
+++ b/log4j-iostreams/src/main/java/org/apache/logging/log4j/io/internal/InternalReader.java
@@ -28,7 +28,7 @@
 import org.apache.logging.log4j.spi.ExtendedLogger;
 
 /**
- * Internal class that exists primiarly to allow location calculations to work.
+ * Internal class that exists primarily to allow location calculations to work.
  *
  * @since 2.12
  */
diff --git a/log4j-iostreams/src/main/java/org/apache/logging/log4j/io/internal/InternalWriter.java b/log4j-iostreams/src/main/java/org/apache/logging/log4j/io/internal/InternalWriter.java
index 11deeab..b117a57 100644
--- a/log4j-iostreams/src/main/java/org/apache/logging/log4j/io/internal/InternalWriter.java
+++ b/log4j-iostreams/src/main/java/org/apache/logging/log4j/io/internal/InternalWriter.java
@@ -26,7 +26,7 @@
 import org.apache.logging.log4j.spi.ExtendedLogger;
 
 /**
- * Internal class that exists primiarly to allow location calculations to work.
+ * Internal class that exists primarily to allow location calculations to work.
  * @since 2.12
  */
 public class InternalWriter extends Writer {
diff --git a/log4j-jdbc-dbcp2/src/main/java/org/apache/logging/log4j/dbcp2/appender/PoolableConnectionFactoryConfig.java b/log4j-jdbc-dbcp2/src/main/java/org/apache/logging/log4j/dbcp2/appender/PoolableConnectionFactoryConfig.java
index 9594d60..01993cf 100644
--- a/log4j-jdbc-dbcp2/src/main/java/org/apache/logging/log4j/dbcp2/appender/PoolableConnectionFactoryConfig.java
+++ b/log4j-jdbc-dbcp2/src/main/java/org/apache/logging/log4j/dbcp2/appender/PoolableConnectionFactoryConfig.java
@@ -17,20 +17,20 @@
 
 package org.apache.logging.log4j.dbcp2.appender;
 
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-
 import org.apache.commons.dbcp2.PoolableConnectionFactory;
 import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
 import org.apache.logging.log4j.core.Core;
 import org.apache.logging.log4j.plugins.Plugin;
 import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
 import org.apache.logging.log4j.plugins.PluginElement;
+import org.apache.logging.log4j.plugins.PluginFactory;
 import org.apache.logging.log4j.status.StatusLogger;
 import org.apache.logging.log4j.util.Strings;
 
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
 /**
  * Configures an Apache Commons DBCP {@link PoolableConnectionFactory}.
  *
@@ -198,7 +198,7 @@
 
     // ALL of these instance variables match DBCP WRT Boolean vs. boolean.
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static Builder newBuilder() {
         return new Builder();
     }
diff --git a/log4j-jdbc-dbcp2/src/main/java/org/apache/logging/log4j/dbcp2/appender/PoolingDriverConnectionSource.java b/log4j-jdbc-dbcp2/src/main/java/org/apache/logging/log4j/dbcp2/appender/PoolingDriverConnectionSource.java
index 0a38866..a8da307 100644
--- a/log4j-jdbc-dbcp2/src/main/java/org/apache/logging/log4j/dbcp2/appender/PoolingDriverConnectionSource.java
+++ b/log4j-jdbc-dbcp2/src/main/java/org/apache/logging/log4j/dbcp2/appender/PoolingDriverConnectionSource.java
@@ -16,11 +16,6 @@
  */
 package org.apache.logging.log4j.dbcp2.appender;
 
-import java.sql.DriverManager;
-import java.sql.SQLException;
-import java.util.Arrays;
-import java.util.concurrent.TimeUnit;
-
 import org.apache.commons.dbcp2.ConnectionFactory;
 import org.apache.commons.dbcp2.DriverManagerConnectionFactory;
 import org.apache.commons.dbcp2.PoolableConnection;
@@ -30,12 +25,17 @@
 import org.apache.commons.pool2.impl.GenericObjectPool;
 import org.apache.logging.log4j.core.Core;
 import org.apache.logging.log4j.core.config.Property;
-import org.apache.logging.log4j.plugins.Plugin;
-import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
-import org.apache.logging.log4j.plugins.PluginElement;
 import org.apache.logging.log4j.jdbc.appender.AbstractDriverManagerConnectionSource;
 import org.apache.logging.log4j.jdbc.appender.ConnectionSource;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
+import org.apache.logging.log4j.plugins.PluginElement;
+import org.apache.logging.log4j.plugins.PluginFactory;
+
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
 
 /**
  * A {@link ConnectionSource} that uses a JDBC connection string, a user name, and a password to call
@@ -95,7 +95,7 @@
     public static final String URL_PREFIX = "jdbc:apache:commons:dbcp:";
 
     // This method is not named newBuilder() to make the compiler happy.
-    @PluginBuilderFactory
+    @PluginFactory
     public static <B extends Builder<B>> B newPoolingDriverConnectionSourceBuilder() {
         return new Builder<B>().asBuilder();
     }
diff --git a/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/ColumnConfig.java b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/ColumnConfig.java
index afe4f4c..16d744c 100644
--- a/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/ColumnConfig.java
+++ b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/ColumnConfig.java
@@ -20,12 +20,12 @@
 import org.apache.logging.log4j.core.Core;
 import org.apache.logging.log4j.core.appender.db.ColumnMapping;
 import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
+import org.apache.logging.log4j.core.layout.PatternLayout;
 import org.apache.logging.log4j.plugins.Plugin;
 import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
-import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
+import org.apache.logging.log4j.plugins.PluginFactory;
 import org.apache.logging.log4j.plugins.validation.constraints.Required;
-import org.apache.logging.log4j.core.layout.PatternLayout;
 import org.apache.logging.log4j.status.StatusLogger;
 import org.apache.logging.log4j.util.Strings;
 
@@ -172,7 +172,7 @@
     }
 
     private static final Logger LOGGER = StatusLogger.getLogger();
-    @PluginBuilderFactory
+    @PluginFactory
     public static Builder newBuilder() {
         return new Builder();
     }
diff --git a/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/DataSourceConnectionSource.java b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/DataSourceConnectionSource.java
index ab39844..496902c 100644
--- a/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/DataSourceConnectionSource.java
+++ b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/DataSourceConnectionSource.java
@@ -64,7 +64,7 @@
      * @return the created connection source.
      */
     @PluginFactory
-    public static DataSourceConnectionSource createConnectionSource(@PluginAttribute("jndiName") final String jndiName) {
+    public static DataSourceConnectionSource createConnectionSource(@PluginAttribute final String jndiName) {
         if (Strings.isEmpty(jndiName)) {
             LOGGER.error("No JNDI name provided.");
             return null;
diff --git a/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/DriverManagerConnectionSource.java b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/DriverManagerConnectionSource.java
index bf506b7..cfc1ff9 100644
--- a/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/DriverManagerConnectionSource.java
+++ b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/DriverManagerConnectionSource.java
@@ -16,12 +16,12 @@
  */
 package org.apache.logging.log4j.jdbc.appender;
 
-import java.sql.DriverManager;
-
 import org.apache.logging.log4j.core.Core;
 import org.apache.logging.log4j.core.config.Property;
 import org.apache.logging.log4j.plugins.Plugin;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
+import org.apache.logging.log4j.plugins.PluginFactory;
+
+import java.sql.DriverManager;
 
 /**
  * A {@link ConnectionSource} that uses a JDBC connection string, a user name, and a password to call
@@ -51,7 +51,7 @@
 
     }
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static <B extends Builder<B>> B newBuilder() {
         return new Builder<B>().asBuilder();
     }
diff --git a/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/JdbcAppender.java b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/JdbcAppender.java
index 61dd796..8ea3bcc 100644
--- a/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/JdbcAppender.java
+++ b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/JdbcAppender.java
@@ -16,10 +16,6 @@
  */
 package org.apache.logging.log4j.jdbc.appender;
 
-import java.io.Serializable;
-import java.sql.PreparedStatement;
-import java.util.Arrays;
-
 import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.Core;
 import org.apache.logging.log4j.core.Filter;
@@ -30,12 +26,16 @@
 import org.apache.logging.log4j.core.config.Property;
 import org.apache.logging.log4j.plugins.Plugin;
 import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
 import org.apache.logging.log4j.plugins.PluginElement;
+import org.apache.logging.log4j.plugins.PluginFactory;
 import org.apache.logging.log4j.plugins.convert.TypeConverter;
 import org.apache.logging.log4j.plugins.validation.constraints.Required;
 import org.apache.logging.log4j.util.Assert;
 
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.util.Arrays;
+
 /**
  * This Appender writes logging events to a relational database using standard JDBC mechanisms. It takes a list of
  * {@link ColumnConfig}s and/or {@link ColumnMapping}s with which it determines how to save the event data into the
@@ -177,7 +177,7 @@
 
     }
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static <B extends Builder<B>> B newBuilder() {
         return new Builder<B>().asBuilder();
     }
diff --git a/log4j-jdbc/src/site/manual/index.md b/log4j-jdbc/src/site/manual/index.md
index 66fe24f..84fca13 100644
--- a/log4j-jdbc/src/site/manual/index.md
+++ b/log4j-jdbc/src/site/manual/index.md
@@ -18,7 +18,7 @@
 
 # Apache Log4j ZeroMQ using JeroMQ module
 
-As of Log4j 2.11.0, ZeroMQ using JeroMQ support has moved from the existing module logj-core to the new module log4j-jeromq.
+As of Log4j 2.11.0, ZeroMQ using JeroMQ support has moved from the existing module log4j-core to the new module log4j-jeromq.
 
 ## Requirements
 
diff --git a/log4j-jeromq/src/main/java/org/apache/logging/log4j/jeromq/appender/JeroMqAppender.java b/log4j-jeromq/src/main/java/org/apache/logging/log4j/jeromq/appender/JeroMqAppender.java
index 424d022..09ce72c 100644
--- a/log4j-jeromq/src/main/java/org/apache/logging/log4j/jeromq/appender/JeroMqAppender.java
+++ b/log4j-jeromq/src/main/java/org/apache/logging/log4j/jeromq/appender/JeroMqAppender.java
@@ -83,33 +83,33 @@
     @PluginFactory
     public static JeroMqAppender createAppender(
             // @formatter:off
-            @Required(message = "No name provided for JeroMqAppender") @PluginAttribute("name") final String name,
-            @PluginElement("Layout") Layout<?> layout,
-            @PluginElement("Filter") final Filter filter,
-            @PluginElement("Properties") final Property[] properties,
+            @Required(message = "No name provided for JeroMqAppender") @PluginAttribute final String name,
+            @PluginElement Layout<?> layout,
+            @PluginElement final Filter filter,
+            @PluginElement final Property[] properties,
             // Super attributes
-            @PluginAttribute("ignoreExceptions") final boolean ignoreExceptions,
+            @PluginAttribute final boolean ignoreExceptions,
             // ZMQ attributes; defaults picked from zmq.Options.
-            @PluginAttribute(value = "affinity", defaultLong = 0) final long affinity,
-            @PluginAttribute(value = "backlog", defaultLong = DEFAULT_BACKLOG) final long backlog,
-            @PluginAttribute(value = "delayAttachOnConnect") final boolean delayAttachOnConnect,
-            @PluginAttribute(value = "identity") final byte[] identity,
-            @PluginAttribute(value = "ipv4Only", defaultBoolean = true) final boolean ipv4Only,
-            @PluginAttribute(value = "linger", defaultLong = -1) final long linger,
-            @PluginAttribute(value = "maxMsgSize", defaultLong = -1) final long maxMsgSize,
-            @PluginAttribute(value = "rcvHwm", defaultLong = DEFAULT_RCV_HWM) final long rcvHwm,
-            @PluginAttribute(value = "receiveBufferSize", defaultLong = 0) final long receiveBufferSize,
-            @PluginAttribute(value = "receiveTimeOut", defaultLong = -1) final int receiveTimeOut,
-            @PluginAttribute(value = "reconnectIVL", defaultLong = DEFAULT_IVL) final long reconnectIVL,
-            @PluginAttribute(value = "reconnectIVLMax", defaultLong = 0) final long reconnectIVLMax,
-            @PluginAttribute(value = "sendBufferSize", defaultLong = 0) final long sendBufferSize,
-            @PluginAttribute(value = "sendTimeOut", defaultLong = -1) final int sendTimeOut,
-            @PluginAttribute(value = "sndHwm", defaultLong = DEFAULT_SND_HWM) final long sndHwm,
-            @PluginAttribute(value = "tcpKeepAlive", defaultInt = -1) final int tcpKeepAlive,
-            @PluginAttribute(value = "tcpKeepAliveCount", defaultLong = -1) final long tcpKeepAliveCount,
-            @PluginAttribute(value = "tcpKeepAliveIdle", defaultLong = -1) final long tcpKeepAliveIdle,
-            @PluginAttribute(value = "tcpKeepAliveInterval", defaultLong = -1) final long tcpKeepAliveInterval,
-            @PluginAttribute(value = "xpubVerbose") final boolean xpubVerbose
+            @PluginAttribute(defaultLong = 0) final long affinity,
+            @PluginAttribute(defaultLong = DEFAULT_BACKLOG) final long backlog,
+            @PluginAttribute final boolean delayAttachOnConnect,
+            @PluginAttribute final byte[] identity,
+            @PluginAttribute(defaultBoolean = true) final boolean ipv4Only,
+            @PluginAttribute(defaultLong = -1) final long linger,
+            @PluginAttribute(defaultLong = -1) final long maxMsgSize,
+            @PluginAttribute(defaultLong = DEFAULT_RCV_HWM) final long rcvHwm,
+            @PluginAttribute(defaultLong = 0) final long receiveBufferSize,
+            @PluginAttribute(defaultLong = -1) final int receiveTimeOut,
+            @PluginAttribute(defaultLong = DEFAULT_IVL) final long reconnectIVL,
+            @PluginAttribute(defaultLong = 0) final long reconnectIVLMax,
+            @PluginAttribute(defaultLong = 0) final long sendBufferSize,
+            @PluginAttribute(defaultLong = -1) final int sendTimeOut,
+            @PluginAttribute(defaultLong = DEFAULT_SND_HWM) final long sndHwm,
+            @PluginAttribute(defaultInt = -1) final int tcpKeepAlive,
+            @PluginAttribute(defaultLong = -1) final long tcpKeepAliveCount,
+            @PluginAttribute(defaultLong = -1) final long tcpKeepAliveIdle,
+            @PluginAttribute(defaultLong = -1) final long tcpKeepAliveInterval,
+            @PluginAttribute final boolean xpubVerbose
             // @formatter:on
     ) {
         if (layout == null) {
diff --git a/log4j-jeromq/src/site/manual/index.md b/log4j-jeromq/src/site/manual/index.md
index 66fe24f..84fca13 100644
--- a/log4j-jeromq/src/site/manual/index.md
+++ b/log4j-jeromq/src/site/manual/index.md
@@ -18,7 +18,7 @@
 
 # Apache Log4j ZeroMQ using JeroMQ module
 
-As of Log4j 2.11.0, ZeroMQ using JeroMQ support has moved from the existing module logj-core to the new module log4j-jeromq.
+As of Log4j 2.11.0, ZeroMQ using JeroMQ support has moved from the existing module log4j-core to the new module log4j-jeromq.
 
 ## Requirements
 
diff --git a/log4j-jms/src/main/java/org/apache/logging/log4j/jms/appender/JmsAppender.java b/log4j-jms/src/main/java/org/apache/logging/log4j/jms/appender/JmsAppender.java
index f6c1819..d7bc0fa 100644
--- a/log4j-jms/src/main/java/org/apache/logging/log4j/jms/appender/JmsAppender.java
+++ b/log4j-jms/src/main/java/org/apache/logging/log4j/jms/appender/JmsAppender.java
@@ -17,27 +17,26 @@
 
 package org.apache.logging.log4j.jms.appender;
 
-import java.io.Serializable;
-import java.util.Properties;
-import java.util.concurrent.TimeUnit;
-
-import javax.jms.JMSException;
-
 import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.Filter;
 import org.apache.logging.log4j.core.Layout;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.appender.AbstractAppender;
 import org.apache.logging.log4j.core.appender.AbstractManager;
-import org.apache.logging.log4j.plugins.Node;
 import org.apache.logging.log4j.core.config.Property;
+import org.apache.logging.log4j.core.net.JndiManager;
+import org.apache.logging.log4j.jms.appender.JmsManager.JmsManagerConfiguration;
+import org.apache.logging.log4j.plugins.Node;
 import org.apache.logging.log4j.plugins.Plugin;
 import org.apache.logging.log4j.plugins.PluginAliases;
 import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
+import org.apache.logging.log4j.plugins.PluginFactory;
 import org.apache.logging.log4j.plugins.validation.constraints.Required;
-import org.apache.logging.log4j.core.net.JndiManager;
-import org.apache.logging.log4j.jms.appender.JmsManager.JmsManagerConfiguration;
+
+import javax.jms.JMSException;
+import java.io.Serializable;
+import java.util.Properties;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Generic JMS Appender plugin for both queues and topics. This Appender replaces the previous split ones. However,
@@ -197,7 +196,7 @@
 
     }
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static Builder newBuilder() {
         return new Builder();
     }
diff --git a/log4j-jms/src/site/manual/index.md b/log4j-jms/src/site/manual/index.md
index 8ef1b47..295c2d5 100644
--- a/log4j-jms/src/site/manual/index.md
+++ b/log4j-jms/src/site/manual/index.md
@@ -18,7 +18,7 @@
 
 # Apache Log4j Java Message Service (JMS) module
 
-As of Log4j 2.11.0, JMS support has moved from the existing module logj-core to the new module log4j-jms.
+As of Log4j 2.11.0, JMS support has moved from the existing module log4j-core to the new module log4j-jms.
 
 ## Requirements
 
diff --git a/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/appender/JpaAppender.java b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/appender/JpaAppender.java
index 82ef8a3..602f6e1 100644
--- a/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/appender/JpaAppender.java
+++ b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/appender/JpaAppender.java
@@ -72,12 +72,12 @@
      */
     @PluginFactory
     public static JpaAppender createAppender(
-            @PluginAttribute("name") final String name,
+            @PluginAttribute final String name,
             @PluginAttribute("ignoreExceptions") final String ignore,
-            @PluginElement("Filter") final Filter filter,
-            @PluginAttribute("bufferSize") final String bufferSize,
-            @PluginAttribute("entityClassName") final String entityClassName,
-            @PluginAttribute("persistenceUnitName") final String persistenceUnitName) {
+            @PluginElement final Filter filter,
+            @PluginAttribute final String bufferSize,
+            @PluginAttribute final String entityClassName,
+            @PluginAttribute final String persistenceUnitName) {
         if (Strings.isEmpty(entityClassName) || Strings.isEmpty(persistenceUnitName)) {
             LOGGER.error("Attributes entityClassName and persistenceUnitName are required for JPA Appender.");
             return null;
diff --git a/log4j-jpa/src/site/manual/index.md b/log4j-jpa/src/site/manual/index.md
index 235dfb8..6b1b12e 100644
--- a/log4j-jpa/src/site/manual/index.md
+++ b/log4j-jpa/src/site/manual/index.md
@@ -18,7 +18,7 @@
 
 # Log4j Java Persistence API module
 
-As of Log4j 2.11.0, JPA support has moved from the existing module logj-core to the new module log4j-jpa.
+As of Log4j 2.11.0, JPA support has moved from the existing module log4j-core to the new module log4j-jpa.
 
 ## Requirements
 
diff --git a/log4j-jul/src/main/java/org/apache/logging/log4j/jul/LogManager.java b/log4j-jul/src/main/java/org/apache/logging/log4j/jul/LogManager.java
index 10f8fdb..ecfdee6 100644
--- a/log4j-jul/src/main/java/org/apache/logging/log4j/jul/LogManager.java
+++ b/log4j-jul/src/main/java/org/apache/logging/log4j/jul/LogManager.java
@@ -41,6 +41,7 @@
 
     private static final org.apache.logging.log4j.Logger LOGGER = StatusLogger.getLogger();
     private final AbstractLoggerAdapter loggerAdapter;
+    private final ThreadLocal<Boolean> recursive = ThreadLocal.withInitial(() -> Boolean.FALSE);
 
     public LogManager() {
         super();
@@ -86,7 +87,16 @@
     @Override
     public Logger getLogger(final String name) {
         LOGGER.trace("Call to LogManager.getLogger({})", name);
-        return loggerAdapter.getLogger(name);
+        if (recursive.get()) {
+            LOGGER.warn("Recursive call to getLogger for {} ignored.", name);
+            return new NoOpLogger(name);
+        }
+        recursive.set(Boolean.TRUE);
+        try {
+            return loggerAdapter.getLogger(name);
+        } finally {
+            recursive.set(Boolean.FALSE);
+        }
     }
 
     @Override
diff --git a/log4j-jul/src/main/java/org/apache/logging/log4j/jul/NoOpLogger.java b/log4j-jul/src/main/java/org/apache/logging/log4j/jul/NoOpLogger.java
new file mode 100644
index 0000000..3c3b158
--- /dev/null
+++ b/log4j-jul/src/main/java/org/apache/logging/log4j/jul/NoOpLogger.java
@@ -0,0 +1,209 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.jul;
+
+import java.util.ResourceBundle;
+import java.util.function.Supplier;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+
+/**
+ * Dummy version of a java.util.Logger.
+ */
+public class NoOpLogger extends Logger {
+
+    protected NoOpLogger(String name) {
+        super(name, null);
+    }
+
+    @Override
+    public void log(LogRecord record) {
+    }
+
+    @Override
+    public void log(Level level, String msg) {
+    }
+
+    @Override
+    public void log(Level level, Supplier<String> msgSupplier) {
+    }
+
+    @Override
+    public void log(Level level, String msg, Object param1) {
+    }
+
+    @Override
+    public void log(Level level, String msg, Object[] params) {
+    }
+
+    @Override
+    public void log(Level level, String msg, Throwable thrown) {
+    }
+
+    @Override
+    public void log(Level level, Throwable thrown, Supplier<String> msgSupplier) {
+    }
+
+    @Override
+    public void logp(Level level, String sourceClass, String sourceMethod, String msg) {
+    }
+
+    @Override
+    public void logp(Level level, String sourceClass, String sourceMethod, Supplier<String> msgSupplier) {
+    }
+
+    @Override
+    public void logp(Level level, String sourceClass, String sourceMethod, String msg, Object param1) {
+    }
+
+    @Override
+    public void logp(Level level, String sourceClass, String sourceMethod, String msg, Object[] params) {
+    }
+
+    @Override
+    public void logp(Level level, String sourceClass, String sourceMethod, String msg, Throwable thrown) {
+    }
+
+    @Override
+    public void logp(Level level, String sourceClass, String sourceMethod, Throwable thrown,
+            Supplier<String> msgSupplier) {
+    }
+
+    @Override
+    public void logrb(Level level, String sourceClass, String sourceMethod, String bundleName, String msg) {
+    }
+
+    @Override
+    public void logrb(Level level, String sourceClass, String sourceMethod, String bundleName, String msg,
+            Object param1) {
+    }
+
+    @Override
+    public void logrb(Level level, String sourceClass, String sourceMethod, String bundleName, String msg,
+            Object[] params) {
+    }
+
+    @Override
+    public void logrb(Level level, String sourceClass, String sourceMethod, ResourceBundle bundle, String msg,
+            Object... params) {
+    }
+
+    @Override
+    public void logrb(Level level, String sourceClass, String sourceMethod, String bundleName, String msg,
+            Throwable thrown) {
+    }
+
+    @Override
+    public void logrb(Level level, String sourceClass, String sourceMethod, ResourceBundle bundle, String msg,
+            Throwable thrown) {
+    }
+
+    @Override
+    public void entering(String sourceClass, String sourceMethod) {
+    }
+
+    @Override
+    public void entering(String sourceClass, String sourceMethod, Object param1) {
+    }
+
+    @Override
+    public void entering(String sourceClass, String sourceMethod, Object[] params) {
+    }
+
+    @Override
+    public void exiting(String sourceClass, String sourceMethod) {
+    }
+
+    @Override
+    public void exiting(String sourceClass, String sourceMethod, Object result) {
+    }
+
+    @Override
+    public void throwing(String sourceClass, String sourceMethod, Throwable thrown) {
+    }
+
+    @Override
+    public void severe(String msg) {
+    }
+
+    @Override
+    public void warning(String msg) {
+    }
+
+    @Override
+    public void info(String msg) {
+    }
+
+    @Override
+    public void config(String msg) {
+    }
+
+    @Override
+    public void fine(String msg) {
+    }
+
+    @Override
+    public void finer(String msg) {
+    }
+
+    @Override
+    public void finest(String msg) {
+    }
+
+    @Override
+    public void severe(Supplier<String> msgSupplier) {
+    }
+
+    @Override
+    public void warning(Supplier<String> msgSupplier) {
+    }
+
+    @Override
+    public void info(Supplier<String> msgSupplier) {
+    }
+
+    @Override
+    public void config(Supplier<String> msgSupplier) {
+    }
+
+    @Override
+    public void fine(Supplier<String> msgSupplier) {
+    }
+
+    @Override
+    public void finer(Supplier<String> msgSupplier) {
+    }
+
+    @Override
+    public void finest(Supplier<String> msgSupplier) {
+    }
+
+    @Override
+    public void setLevel(Level newLevel) throws SecurityException {
+    }
+
+    @Override
+    public Level getLevel() {
+        return Level.OFF;
+    }
+
+    @Override
+    public boolean isLoggable(Level level) {
+        return false;
+    }
+}
diff --git a/log4j-jul/src/site/markdown/index.md b/log4j-jul/src/site/markdown/index.md
index 3e0ff65..683d139 100644
--- a/log4j-jul/src/site/markdown/index.md
+++ b/log4j-jul/src/site/markdown/index.md
@@ -18,7 +18,7 @@
 
 There are two possibilities:
 - Logging Adapter as complete replacement (preferred, but requires JVM start option)
-- Bridge Handler, transfering JDK output to log4j, e.g. useful for webapps
+- Bridge Handler, transferring JDK output to log4j, e.g. useful for webapps
 
 
 # Log4j JDK Logging Adapter
@@ -83,7 +83,7 @@
 
 # Log4j JDK Logging Bridge Handler
 
-The LogManager is not always useable because you have to set a JVM wide effective system
+The LogManager is not always usable because you have to set a JVM wide effective system
 property - e.g. in web servers this is not possible if you are not the administrator.
 
 The [`Log4jBridgeHandler`](apidocs/org/apache/logging/log4j/jul/Log4jBridgeHandler.html) is an
diff --git a/log4j-kafka/src/main/java/org/apache/logging/log4j/kafka/appender/KafkaAppender.java b/log4j-kafka/src/main/java/org/apache/logging/log4j/kafka/appender/KafkaAppender.java
index a0e8c64..36ab5ec 100644
--- a/log4j-kafka/src/main/java/org/apache/logging/log4j/kafka/appender/KafkaAppender.java
+++ b/log4j-kafka/src/main/java/org/apache/logging/log4j/kafka/appender/KafkaAppender.java
@@ -17,23 +17,23 @@
 
 package org.apache.logging.log4j.kafka.appender;
 
-import java.io.Serializable;
-import java.util.Objects;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
 import org.apache.logging.log4j.core.AbstractLifeCycle;
 import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.Filter;
 import org.apache.logging.log4j.core.Layout;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.appender.AbstractAppender;
-import org.apache.logging.log4j.plugins.Node;
 import org.apache.logging.log4j.core.config.Property;
+import org.apache.logging.log4j.plugins.Node;
 import org.apache.logging.log4j.plugins.Plugin;
 import org.apache.logging.log4j.plugins.PluginAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
+import org.apache.logging.log4j.plugins.PluginFactory;
+
+import java.io.Serializable;
+import java.util.Objects;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 /**
  * Sends log events to an Apache Kafka topic.
@@ -50,13 +50,13 @@
     public static class Builder<B extends Builder<B>> extends AbstractAppender.Builder<B>
             implements org.apache.logging.log4j.plugins.util.Builder<KafkaAppender> {
 
-        @PluginAttribute("topic")
+        @PluginAttribute
         private String topic;
 
-        @PluginAttribute("key")
+        @PluginAttribute
         private String key;
 
-        @PluginAttribute(value = "syncSend", defaultBoolean = true)
+        @PluginAttribute(defaultBoolean = true)
         private boolean syncSend;
 
         @PluginAttribute(value = "eventTimestamp", defaultBoolean = true)
@@ -92,6 +92,11 @@
             return asBuilder();
         }
 
+        public B setKey(final String key) {
+            this.key = key;
+            return asBuilder();
+        }
+
         public B setSyncSend(final boolean syncSend) {
             this.syncSend = syncSend;
             return asBuilder();
@@ -108,7 +113,7 @@
      * 
      * @return a builder for a KafkaAppender.
      */
-    @PluginBuilderFactory
+    @PluginFactory
     public static <B extends Builder<B>> B newBuilder() {
         return new Builder<B>().asBuilder();
     }
diff --git a/log4j-kafka/src/site/manual/index.md b/log4j-kafka/src/site/manual/index.md
index d70256a..1438ee1 100644
--- a/log4j-kafka/src/site/manual/index.md
+++ b/log4j-kafka/src/site/manual/index.md
@@ -18,7 +18,7 @@
 
 # Apache Log4j Kafka module
 
-As of Log4j 2.11.0, Kafka support has moved from the existing module logj-core to the new module log4j-kafka.
+As of Log4j 2.11.0, Kafka support has moved from the existing module log4j-core to the new module log4j-kafka.
 
 ## Requirements
 
diff --git a/log4j-kubernetes/pom.xml b/log4j-kubernetes/pom.xml
new file mode 100644
index 0000000..a7c13e0
--- /dev/null
+++ b/log4j-kubernetes/pom.xml
@@ -0,0 +1,206 @@
+<?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/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.logging.log4j</groupId>
+    <artifactId>log4j</artifactId>
+    <version>3.0.0-SNAPSHOT</version>
+    <relativePath>../</relativePath>
+  </parent>
+  <artifactId>log4j-kubernetes</artifactId>
+  <packaging>jar</packaging>
+  <name>Apache Log4j Kubernetes Library</name>
+  <description>Apache Log4j Kubernetes Support</description>
+  <properties>
+    <log4jParentDir>${basedir}/..</log4jParentDir>
+    <docLabel>Log4j Kubernetes Library Documentation</docLabel>
+    <projectDir>/kubernetes</projectDir>
+    <maven.compiler.source>1.8</maven.compiler.source>
+    <maven.compiler.target>1.8</maven.compiler.target>
+    <module.name>org.apache.logging.log4j.kubernetes</module.name>
+  </properties>
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-core</artifactId>
+    </dependency>
+    <!-- Kubernetes Client -->
+    <dependency>
+      <groupId>io.fabric8</groupId>
+      <artifactId>kubernetes-client</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-toolchains-plugin</artifactId>
+        <version>1.1</version>
+        <executions>
+          <execution>
+            <goals>
+              <goal>toolchain</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <toolchains>
+            <jdk>
+              <version>[8, )</version>
+            </jdk>
+          </toolchains>
+        </configuration>
+      </plugin>
+      <!-- Include the standard NOTICE and LICENSE -->
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-remote-resources-plugin</artifactId>
+        <executions>
+          <execution>
+            <goals>
+              <goal>process</goal>
+            </goals>
+            <configuration>
+              <skip>false</skip>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <forkCount>1</forkCount>
+          <reuseForks>false</reuseForks>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <reporting>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-changes-plugin</artifactId>
+        <version>${changes.plugin.version}</version>
+        <reportSets>
+          <reportSet>
+            <reports>
+              <report>changes-report</report>
+            </reports>
+          </reportSet>
+        </reportSets>
+        <configuration>
+          <issueLinkTemplate>%URL%/show_bug.cgi?id=%ISSUE%</issueLinkTemplate>
+          <useJql>true</useJql>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+        <version>${checkstyle.plugin.version}</version>
+        <configuration>
+          <!--<propertiesLocation>${vfs.parent.dir}/checkstyle.properties</propertiesLocation> -->
+          <configLocation>${log4jParentDir}/checkstyle.xml</configLocation>
+          <suppressionsLocation>${log4jParentDir}/checkstyle-suppressions.xml</suppressionsLocation>
+          <enableRulesSummary>false</enableRulesSummary>
+          <propertyExpansion>basedir=${basedir}</propertyExpansion>
+          <propertyExpansion>licensedir=${log4jParentDir}/checkstyle-header.txt</propertyExpansion>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-javadoc-plugin</artifactId>
+        <version>${javadoc.plugin.version}</version>
+        <configuration>
+          <bottom><![CDATA[<p align="center">Copyright &#169; {inceptionYear}-{currentYear} {organizationName}. All Rights Reserved.<br />
+            Apache Logging, Apache Log4j, Log4j, Apache, the Apache feather logo, the Apache Logging project logo,
+            and the Apache Log4j logo are trademarks of The Apache Software Foundation.</p>]]></bottom>
+          <!-- module link generation is completely broken in the javadoc plugin for a multi-module non-aggregating
+               project -->
+          <detectOfflineLinks>false</detectOfflineLinks>
+          <linksource>true</linksource>
+        </configuration>
+        <reportSets>
+          <reportSet>
+            <id>non-aggregate</id>
+            <reports>
+              <report>javadoc</report>
+            </reports>
+          </reportSet>
+        </reportSets>
+      </plugin>
+      <plugin>
+        <groupId>com.github.spotbugs</groupId>
+        <artifactId>spotbugs-maven-plugin</artifactId>
+        <configuration>
+          <fork>true</fork>
+          <jvmArgs>-Duser.language=en</jvmArgs>
+          <threshold>Normal</threshold>
+          <effort>Default</effort>
+          <excludeFilterFile>${log4jParentDir}/spotbugs-exclude-filter.xml</excludeFilterFile>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jxr-plugin</artifactId>
+        <version>${jxr.plugin.version}</version>
+        <reportSets>
+          <reportSet>
+            <id>non-aggregate</id>
+            <reports>
+              <report>jxr</report>
+            </reports>
+          </reportSet>
+          <reportSet>
+            <id>aggregate</id>
+            <reports>
+              <report>aggregate</report>
+            </reports>
+          </reportSet>
+        </reportSets>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-pmd-plugin</artifactId>
+        <version>${pmd.plugin.version}</version>
+        <configuration>
+          <targetJdk>${maven.compiler.target}</targetJdk>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>net.sourceforge.maven-taglib</groupId>
+        <artifactId>maven-taglib-plugin</artifactId>
+        <version>2.4</version>
+      </plugin>
+    </plugins>
+  </reporting>
+</project>
+
diff --git a/log4j-kubernetes/src/main/java/org/apache/logging/log4j/kubernetes/KubernetesClientBuilder.java b/log4j-kubernetes/src/main/java/org/apache/logging/log4j/kubernetes/KubernetesClientBuilder.java
new file mode 100644
index 0000000..414f9e7
--- /dev/null
+++ b/log4j-kubernetes/src/main/java/org/apache/logging/log4j/kubernetes/KubernetesClientBuilder.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.kubernetes;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.status.StatusLogger;
+
+import io.fabric8.kubernetes.client.Config;
+import io.fabric8.kubernetes.client.ConfigBuilder;
+import io.fabric8.kubernetes.client.DefaultKubernetesClient;
+import io.fabric8.kubernetes.client.KubernetesClient;
+
+/**
+ * Builds a Kubernetes Client.
+ */
+public class KubernetesClientBuilder {
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+
+    public KubernetesClient createClient() {
+        return new DefaultKubernetesClient(kubernetesClientConfig());
+    }
+
+    private Config kubernetesClientConfig() {
+        Config base = Config.autoConfigure(null);
+        KubernetesClientProperties props = new KubernetesClientProperties(base);
+        Config properties = new ConfigBuilder(base)
+                .withApiVersion(props.getApiVersion())
+                .withCaCertData(props.getCaCertData())
+                .withCaCertFile(props.getCaCertFile())
+                .withClientCertData(props.getClientCertData())
+                .withClientCertFile(props.getClientCertFile())
+                .withClientKeyAlgo(props.getClientKeyAlgo())
+                .withClientKeyData(props.getClientKeyData())
+                .withClientKeyFile(props.getClientKeyFile())
+                .withClientKeyPassphrase(props.getClientKeyPassphrase())
+                .withConnectionTimeout(props.getConnectionTimeout())
+                .withHttpProxy(props.getHttpProxy())
+                .withHttpsProxy(props.getHttpsProxy())
+                .withMasterUrl(props.getMasterUrl())
+                .withNamespace(props.getNamespace())
+                .withNoProxy(props.getNoProxy())
+                .withPassword(props.getPassword())
+                .withProxyPassword(props.getProxyPassword())
+                .withProxyUsername(props.getProxyUsername())
+                .withRequestTimeout(props.getRequestTimeout())
+                .withRollingTimeout(props.getRollingTimeout())
+                .withTrustCerts(props.isTrustCerts())
+                .withUsername(props.getUsername())
+                .build();
+        return properties;
+    }
+}
diff --git a/log4j-kubernetes/src/main/java/org/apache/logging/log4j/kubernetes/KubernetesClientProperties.java b/log4j-kubernetes/src/main/java/org/apache/logging/log4j/kubernetes/KubernetesClientProperties.java
new file mode 100644
index 0000000..61f50e0
--- /dev/null
+++ b/log4j-kubernetes/src/main/java/org/apache/logging/log4j/kubernetes/KubernetesClientProperties.java
@@ -0,0 +1,191 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.kubernetes;
+
+import java.time.Duration;
+
+import org.apache.logging.log4j.util.PropertiesUtil;
+
+import io.fabric8.kubernetes.client.Config;
+
+/**
+ * Obtains properties used to configure the Kubernetes client.
+ */
+public class KubernetesClientProperties {
+
+    private static final String[] PREFIXES = {"log4j2.kubernetes.client.", "spring.cloud.kubernetes.client."};
+    private static final String API_VERSION = "apiVersion";
+    private static final String CA_CERT_FILE = "caCertFile";
+    private static final String CA_CERT_DATA = "caCertData";
+    private static final String CLIENT_CERT_FILE = "clientCertFile";
+    private static final String CLIENT_CERT_DATA = "clientCertData";
+    private static final String CLIENT_KEY_FILE = "clientKeyFile";
+    private static final String CLIENT_KEY_DATA = "cientKeyData";
+    private static final String CLIENT_KEY_ALGO = "clientKeyAlgo";
+    private static final String CLIENT_KEY_PASSPHRASE = "clientKeyPassphrase";
+    private static final String CONNECTION_TIMEOUT = "connectionTimeout";
+    private static final String HTTP_PROXY = "httpProxy";
+    private static final String HTTPS_PROXY = "httpsProxy";
+    private static final String LOGGING_INTERVAL = "loggingInterval";
+    private static final String MASTER_URL = "masterUrl";
+    private static final String NAMESPACE = "namespace";
+    private static final String NO_PROXY = "noProxy";
+    private static final String PASSWORD = "password";
+    private static final String PROXY_USERNAME = "proxyUsername";
+    private static final String PROXY_PASSWORD = "proxyPassword";
+    private static final String REQUEST_TIMEOUT = "requestTimeout";
+    private static final String ROLLING_TIMEOUT = "rollingTimeout";
+    private static final String TRUST_CERTS = "trustCerts";
+    private static final String USERNAME = "username";
+    private static final String WATCH_RECONNECT_INTERVAL = "watchReconnectInterval";
+    private static final String WATCH_RECONNECT_LIMIT = "watchReconnectLimit";
+
+    private PropertiesUtil props = PropertiesUtil.getProperties();
+    private final Config base;
+
+    public KubernetesClientProperties(Config base) {
+        this.base = base;
+    }
+
+
+    public String getApiVersion() {
+        return props.getStringProperty(PREFIXES, API_VERSION, base::getApiVersion);
+    }
+    public String getCaCertFile() {
+        return props.getStringProperty(PREFIXES, CA_CERT_FILE, base::getCaCertFile);
+    }
+
+    public String getCaCertData() {
+        return props.getStringProperty(PREFIXES, CA_CERT_DATA, base::getCaCertData);
+    }
+
+    public String getClientCertFile() {
+        return props.getStringProperty(PREFIXES, CLIENT_CERT_FILE, base::getClientCertFile);
+    }
+
+    public String getClientCertData() {
+        return props.getStringProperty(PREFIXES, CLIENT_CERT_DATA, base::getClientCertData);
+    }
+
+    public String getClientKeyFile() {
+        return props.getStringProperty(PREFIXES, CLIENT_KEY_FILE, base::getClientKeyFile);
+    }
+
+    public String getClientKeyData() {
+        return props.getStringProperty(PREFIXES, CLIENT_KEY_DATA, base::getClientKeyData);
+    }
+
+    public String getClientKeyAlgo() {
+        return props.getStringProperty(PREFIXES, CLIENT_KEY_ALGO, base::getClientKeyAlgo);
+    }
+
+    public String getClientKeyPassphrase() {
+        return props.getStringProperty(PREFIXES, CLIENT_KEY_PASSPHRASE, base::getClientKeyPassphrase);
+    }
+
+    public int getConnectionTimeout() {
+        Duration timeout = props.getDurationProperty(PREFIXES, CONNECTION_TIMEOUT, null);
+        if (timeout != null) {
+            return (int) timeout.toMillis();
+        }
+        return base.getConnectionTimeout();
+    }
+
+    public String getHttpProxy() {
+        return props.getStringProperty(PREFIXES, HTTP_PROXY, base::getHttpProxy);
+    }
+
+    public String getHttpsProxy() {
+        return props.getStringProperty(PREFIXES, HTTPS_PROXY, base::getHttpsProxy);
+    }
+
+    public int getLoggingInterval() {
+        Duration interval = props.getDurationProperty(PREFIXES, LOGGING_INTERVAL, null);
+        if (interval != null) {
+            return (int) interval.toMillis();
+        }
+        return base.getLoggingInterval();
+    }
+
+    public String getMasterUrl() {
+        return props.getStringProperty(PREFIXES, MASTER_URL, base::getMasterUrl);
+    }
+
+    public String getNamespace() {
+        return props.getStringProperty(PREFIXES, NAMESPACE, base::getNamespace);
+    }
+
+    public String[] getNoProxy() {
+        String result = props.getStringProperty(PREFIXES, NO_PROXY, null);
+        if (result != null) {
+            return result.replace("\\s", "").split(",");
+        }
+        return base.getNoProxy();
+    }
+
+    public String getPassword() {
+        return props.getStringProperty(PREFIXES, PASSWORD, base::getPassword);
+    }
+
+    public String getProxyUsername() {
+        return props.getStringProperty(PREFIXES, PROXY_USERNAME, base::getProxyUsername);
+    }
+
+    public String getProxyPassword() {
+        return props.getStringProperty(PREFIXES, PROXY_PASSWORD, base::getProxyPassword);
+    }
+
+    public int getRequestTimeout() {
+        Duration interval = props.getDurationProperty(PREFIXES, REQUEST_TIMEOUT, null);
+        if (interval != null) {
+            return (int) interval.toMillis();
+        }
+        return base.getRequestTimeout();
+    }
+
+    public long getRollingTimeout() {
+        Duration interval = props.getDurationProperty(PREFIXES, ROLLING_TIMEOUT, null);
+        if (interval != null) {
+            return interval.toMillis();
+        }
+        return base.getRollingTimeout();
+    }
+
+    public Boolean isTrustCerts() {
+        return props.getBooleanProperty(PREFIXES, TRUST_CERTS, base::isTrustCerts);
+    }
+
+    public String getUsername() {
+        return props.getStringProperty(PREFIXES, USERNAME, base::getUsername);
+    }
+
+    public int getWatchReconnectInterval() {
+        Duration interval = props.getDurationProperty(PREFIXES, WATCH_RECONNECT_INTERVAL, null);
+        if (interval != null) {
+            return (int) interval.toMillis();
+        }
+        return base.getWatchReconnectInterval();
+    }
+
+    public int getWatchReconnectLimit() {
+        Duration interval = props.getDurationProperty(PREFIXES, WATCH_RECONNECT_LIMIT, null);
+        if (interval != null) {
+            return (int) interval.toMillis();
+        }
+        return base.getWatchReconnectLimit();
+    }
+}
diff --git a/log4j-kubernetes/src/main/java/org/apache/logging/log4j/kubernetes/KubernetesLookup.java b/log4j-kubernetes/src/main/java/org/apache/logging/log4j/kubernetes/KubernetesLookup.java
new file mode 100644
index 0000000..56d7617
--- /dev/null
+++ b/log4j-kubernetes/src/main/java/org/apache/logging/log4j/kubernetes/KubernetesLookup.java
@@ -0,0 +1,221 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.kubernetes;
+
+import java.net.URL;
+import java.nio.file.Paths;
+import java.util.Map;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.lookup.AbstractLookup;
+import org.apache.logging.log4j.core.lookup.StrLookup;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.LoaderUtil;
+import org.apache.logging.log4j.util.Strings;
+
+import io.fabric8.kubernetes.api.model.Container;
+import io.fabric8.kubernetes.api.model.ContainerStatus;
+import io.fabric8.kubernetes.api.model.Namespace;
+import io.fabric8.kubernetes.api.model.Pod;
+import io.fabric8.kubernetes.client.Config;
+import io.fabric8.kubernetes.client.KubernetesClient;
+
+
+/**
+ * Retrieve various Kubernetes attributes. Supported keys are:
+ *  accountName, containerId, containerName, clusterName, host, hostIp, labels, labels.app,
+ *  labels.podTemplateHash, masterUrl, namespaceId, namespaceName, podId, podIp, podName,
+ *  imageId, imageName.
+ */
+@Plugin(name = "k8s", category = StrLookup.CATEGORY)
+public class KubernetesLookup extends AbstractLookup {
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+    private static final String HOSTNAME = "HOSTNAME";
+    private static final String SPRING_ENVIRONMENT_KEY = "SpringEnvironment";
+
+    private static volatile KubernetesInfo kubernetesInfo;
+    private static Lock initLock = new ReentrantLock();
+    private static boolean isSpringIncluded =
+            LoaderUtil.isClassAvailable("org.apache.logging.log4j.spring.cloud.config.client.SpringEnvironmentHolder");
+
+    private boolean initialize() {
+        if (kubernetesInfo == null || (isSpringIncluded && !kubernetesInfo.isSpringActive)) {
+            initLock.lock();
+            boolean isSpringActive = isSpringActive();
+            if (kubernetesInfo == null || (!kubernetesInfo.isSpringActive && isSpringActive)) {
+                try {
+                    KubernetesClient client = new KubernetesClientBuilder().createClient();
+                    if (client != null) {
+                        KubernetesInfo info = new KubernetesInfo();
+                        info.isSpringActive = isSpringActive;
+                        info.hostName = getHostname();
+                        Pod pod = getCurrentPod(info.hostName, client);
+                        if (pod != null) {
+                            info.app = pod.getMetadata().getLabels().get("app");
+                            final String app = info.app != null ? info.app : "";
+                            info.podTemplateHash = pod.getMetadata().getLabels().get("pod-template-hash");
+                            info.accountName = pod.getSpec().getServiceAccountName();
+                            info.clusterName = pod.getMetadata().getClusterName();
+                            info.hostIp = pod.getStatus().getHostIP();
+                            info.labels = pod.getMetadata().getLabels();
+                            info.podId = pod.getMetadata().getUid();
+                            info.podIp = pod.getStatus().getPodIP();
+                            info.podName = pod.getMetadata().getName();
+                            Container container = pod.getSpec().getContainers().stream()
+                                    .filter(c -> c.getName().equals(app)).findFirst().orElse(null);
+                            if (container != null) {
+                                info.containerName = container.getName();
+                                info.imageName = container.getImage();
+                            }
+                            info.masterUrl = client.getMasterUrl();
+                            info.namespace = pod.getMetadata().getNamespace();
+                            Namespace namespace = client.namespaces().withName(info.namespace).get();
+                            if (namespace != null) {
+                                info.namespaceId = namespace.getMetadata().getUid();
+                            }
+                            ContainerStatus containerStatus = pod.getStatus().getContainerStatuses().stream()
+                                    .filter(cs -> cs.getName().equals(app)).findFirst().orElse(null);
+                            if (containerStatus != null) {
+                                info.containerId = containerStatus.getContainerID();
+                                info.imageId = containerStatus.getImageID();
+                            }
+                            kubernetesInfo = info;
+                        }
+                    }
+                } finally {
+                    initLock.unlock();
+                }
+            }
+        }
+        return kubernetesInfo != null;
+    }
+
+    @Override
+    public String lookup(LogEvent event, String key) {
+        if (!initialize()) {
+            return null;
+        }
+        switch (key) {
+            case "accountName": {
+                return kubernetesInfo.accountName;
+            }
+            case "containerId": {
+                return kubernetesInfo.containerId;
+            }
+            case "containerName": {
+                return kubernetesInfo.containerName;
+            }
+            case "clusterName": {
+                return kubernetesInfo.clusterName;
+            }
+            case "host": {
+                return kubernetesInfo.hostName;
+            }
+            case "hostIp": {
+                return kubernetesInfo.hostIp;
+            }
+            case "labels": {
+                return kubernetesInfo.labels.toString();
+            }
+            case "labels.app": {
+                return kubernetesInfo.app;
+            }
+            case "labels.podTemplateHash": {
+                return kubernetesInfo.podTemplateHash;
+            }
+            case "masterUrl": {
+                return kubernetesInfo.masterUrl.toString();
+            }
+            case "namespaceId": {
+                return kubernetesInfo.namespaceId;
+            }
+            case "namespaceName": {
+                return kubernetesInfo.namespace;
+            }
+            case "podId": {
+                return kubernetesInfo.podId;
+            }
+            case "podIp": {
+                return kubernetesInfo.podIp;
+            }
+            case "podName": {
+                return kubernetesInfo.podName;
+            }
+            case "imageId": {
+                return kubernetesInfo.imageId;
+            }
+            case "imageName": {
+                return kubernetesInfo.imageName;
+            }
+            default:
+                return null;
+        }
+    }
+
+    private String getHostname() {
+        return System.getenv(HOSTNAME);
+    }
+
+    private Pod getCurrentPod(String hostName, KubernetesClient kubernetesClient) {
+        try {
+            if (isServiceAccount() && Strings.isNotBlank(hostName)) {
+                return kubernetesClient.pods().withName(hostName).get();
+            }
+        } catch (Throwable t) {
+            LOGGER.debug("Unable to locate pod with name {}.", hostName);
+        }
+        return null;
+    }
+
+    private boolean isServiceAccount() {
+        return Paths.get(Config.KUBERNETES_SERVICE_ACCOUNT_TOKEN_PATH).toFile().exists()
+                && Paths.get(Config.KUBERNETES_SERVICE_ACCOUNT_CA_CRT_PATH).toFile().exists();
+    }
+
+    private boolean isSpringActive() {
+        return isSpringIncluded && LogManager.getFactory() != null
+            && LogManager.getFactory().hasContext(KubernetesLookup.class.getName(), null, false)
+            && LogManager.getContext(false).getObject(SPRING_ENVIRONMENT_KEY) != null;
+    }
+
+    private static class KubernetesInfo {
+        boolean isSpringActive;
+        String accountName;
+        String app;
+        String clusterName;
+        String containerId;
+        String containerName;
+        String hostName;
+        String hostIp;
+        String imageId;
+        String imageName;
+        Map<String, String> labels;
+        URL masterUrl;
+        String namespace;
+        String namespaceId;
+        String podId;
+        String podIp;
+        String podName;
+        String podTemplateHash;
+    }
+}
diff --git a/log4j-kubernetes/src/site/markdown/index.md.vm b/log4j-kubernetes/src/site/markdown/index.md.vm
new file mode 100644
index 0000000..d51e757
--- /dev/null
+++ b/log4j-kubernetes/src/site/markdown/index.md.vm
@@ -0,0 +1,104 @@
+<!-- vim: set syn=markdown : -->
+<!--
+    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.
+-->
+#set($dollar = '$')
+#set($h1='#')
+#set($h2='##')
+
+$h1 Log4j Kubernetes Support
+
+Log4j supports Kubernetes by providing a Lookup to retrieve container information.
+
+$h2 Accessing Kubernetes
+
+The Log4j Kubernetes support requires access to the Docker REST interface. In many cases the REST service
+can be accessed automatically. If needed the Kubernetes client can be configured any of the standard
+Log4j configuration locations or via the Spring Boot configuration. Note, however, that since Spring Boot
+causes logging to initialize 3 times and since the Spring environment is only available during the last
+Log4j initialization Spring properties will only be available to Log4j in the last initialization.
+
+$h2 Lookup Attributes
+
+Log4j Kubernetes provides access to the following container attributes:
+
+* accountName - The service account name.
+* clusterName - The name of the cluster the application is running in.
+* containerId - The full id assigned to the container.
+* containerName - The name assigned to the container.
+* host - The name of the host.
+* hostIp - The host's ip address.
+* imageId - The id assigned to the image.
+* imageName - The name assigned to the image.
+* labels - All labels formatted in a list.
+* labels.app - The application name.
+* labels.podTemplateHash - The pod's template hash value.
+* masterUrl - The url needed to access the API server.
+* namespaceId - The id of the namespace the various kubernetes components are located within.
+* namespaceName - The namespace the various kubernetes components are located within.
+* podId - The pod's id number.
+* podIp - The pod's ip address.
+* podName - The name of the pod.
+
+#set( $D = '${' )
+#set( $container = 'k8s:containerId}')
+Attributes may be accessed by adding
+```
+$D$container
+```
+to the configuration. Note that kubernetes variables are only resolved once during logging initialization so they
+shouldn't be referenced with more than one '$' character.
+
+$h2 Configuration
+
+Much of the configuration needed to access the Kubernetes API server is provided automatically by Kubernetes.
+However, it is not uncommon to need to provide the url required to access the Kubernetes API server or the
+namespace the application is assigned to. The properties below may either be configured using the Log4j
+variable names and located by Log4j's normal property resolution mechansim or Log4j will resolve the
+spring properties when the application is running in Spring Boot and the Spring Environment has been created.
+Note that Spring Boot initializes logging 3 times and only the last will have a Spring Environment present.
+
+| Log4j Property Name     | Spring Property Name  | Default   | Description |
+|------------------------ |----------------------:|----------:|------------:|
+| log4j2.kubernetes.client.apiVersion | spring.cloud.kubernetes.client.apiVersion | v1 | Kubernetes API Version |
+| log4j2.kubernetes.client.caCertData | spring.cloud.kubernetes.client.caCertData | | Kubernetes API CACertData |
+| log4j2.kubernetes.client.caCertFile | spring.cloud.kubernetes.client.caCertFile | | Kubernetes API CACertFile |
+| log4j2.kubernetes.client.clientCertData | spring.cloud.kubernetes.client.clientCertData | | Kubernetes API ClientCertData |
+| log4j2.kubernetes.client.clientCertFile | spring.cloud.kubernetes.client.clientCertFile | | Kubernetes API ClientCertFile |
+| log4j2.kubernetes.client.clientKeyAlgo | spring.cloud.kubernetes.client.clientKeyAlgo | RSA | Kubernetes API ClientKeyAlgo |
+| log4j2.kubernetes.client.clientKeyData | spring.cloud.kubernetes.client.clientKeyData | | Kubernetes API ClientKeyData |
+| log4j2.kubernetes.client.clientKeyFile | spring.cloud.kubernetes.client.clientKeyFile | | Kubernetes API ClientKeyFile |
+| log4j2.kubernetes.client.clientKeyPassPhrase | spring.cloud.kubernetes.client.clientKeyPassphrase | changeit | Kubernetes API ClientKeyPassphrase |
+| log4j2.kubernetes.client.connectionTimeout | spring.cloud.kubernetes.client.connectionTimeout | 10s | Connection timeout |
+| log4j2.kubernetes.client.httpProxy | spring.cloud.kubernetes.client.http-proxy | | |
+| log4j2.kubernetes.client.httpsProxy | spring.cloud.kubernetes.client.https-proxy | | |
+| log4j2.kubernetes.client.loggingInberval | spring.cloud.kubernetes.client.loggingInterval | 20s | Logging interval |
+| log4j2.kubernetes.client.masterUrl | spring.cloud.kubernetes.client.masterUrl | kubernetes.default.svc | Kubernetes API Master Node URL |
+| log4j2.kubernetes.client.namespacce | spring.cloud.kubernetes.client.namespace | default | Kubernetes Namespace |
+| log4j2.kubernetes.client.noProxy | spring.cloud.kubernetes.client.noProxy | | |
+| log4j2.kubernetes.client.password | spring.cloud.kubernetes.client.password | | Kubernetes API Password |
+| log4j2.kubernetes.client.proxyPassword | spring.cloud.kubernetes.client.proxyPassword | | |
+| log4j2.kubernetes.client.proxyUsername | spring.cloud.kubernetes.client.proxyUsername | | |
+| log4j2.kubernetes.client.requestTimeout | spring.cloud.kubernetes.client.requestTimeout | 10s | Request timeout |
+| log4j2.kubernetes.client.rollingTimeout | spring.cloud.kubernetes.client.rollingTimeout | 900s | Rolling timeout |
+| log4j2.kubernetes.client.trustCerts | spring.cloud.kubernetes.client.trustCerts | false | Kubernetes API Trust Certificates |
+| log4j2.kubernetes.client.username | spring.cloud.kubernetes.client.username | | Kubernetes API Username |
+| log4j2.kubernetes.client.watchReconnectInterval | spring.cloud.kubernetes.client.watchReconnectInterval | 1s | Reconnect Interval |
+| log4j2.kubernetes.client.watchReconnectLimit | spring.cloud.kubernetes.client.watchReconnectLimit | -1 | Reconnect Interval limit retries |
+
+$h2 Requirements
+Log4j Kubernetes requires Log4j Core, Log4j API and a minimum of Java 8.
+For more information, see [Runtime Dependencies](../runtime-dependencies.html).
diff --git a/log4j-kubernetes/src/site/site.xml b/log4j-kubernetes/src/site/site.xml
new file mode 100644
index 0000000..7322f3b
--- /dev/null
+++ b/log4j-kubernetes/src/site/site.xml
@@ -0,0 +1,52 @@
+<!--
+ 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 name="Log4j Docker Support"
+         xmlns="http://maven.apache.org/DECORATION/1.4.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/DECORATION/1.4.0 http://maven.apache.org/xsd/decoration-1.4.0.xsd">
+  <body>
+    <links>
+      <item name="Apache" href="http://www.apache.org/" />
+      <item name="Logging Services" href="http://logging.apache.org/"/>
+      <item name="Log4j" href="../index.html"/>
+    </links>
+
+    <!-- Component-specific reports -->
+    <menu ref="reports"/>
+
+	<!-- Overall Project Info -->
+    <menu name="Log4j Project Information" img="icon-info-sign">
+      <item name="Dependencies" href="../dependencies.html" />
+      <item name="Dependency Convergence" href="../dependency-convergence.html" />
+      <item name="Dependency Management" href="../dependency-management.html" />
+      <item name="Project Team" href="../team-list.html" />
+      <item name="Mailing Lists" href="../mail-lists.html" />
+      <item name="Issue Tracking" href="../issue-tracking.html" />
+      <item name="Project License" href="../license.html" />
+      <item name="Source Repository" href="../source-repository.html" />
+      <item name="Project Summary" href="../project-summary.html" />
+    </menu>
+
+    <menu name="Log4j Project Reports" img="icon-cog">
+      <item name="Changes Report" href="../changes-report.html" />
+      <item name="JIRA Report" href="../jira-report.html" />
+      <item name="Surefire Report" href="../surefire-report.html" />
+      <item name="RAT Report" href="../rat-report.html" />
+    </menu>
+  </body>
+</project>
diff --git a/log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/layout/JsonLayout.java b/log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/layout/JsonLayout.java
index fffacb5..643afee 100644
--- a/log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/layout/JsonLayout.java
+++ b/log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/layout/JsonLayout.java
@@ -16,6 +16,23 @@
  */
 package org.apache.logging.log4j.jackson.json.layout;
 
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonRootName;
+import com.fasterxml.jackson.annotation.JsonUnwrapped;
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.DefaultConfiguration;
+import org.apache.logging.log4j.core.layout.PatternLayout;
+import org.apache.logging.log4j.core.util.KeyValuePair;
+import org.apache.logging.log4j.jackson.AbstractJacksonLayout;
+import org.apache.logging.log4j.jackson.XmlConstants;
+import org.apache.logging.log4j.plugins.Node;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
+import org.apache.logging.log4j.plugins.PluginElement;
+import org.apache.logging.log4j.plugins.PluginFactory;
+
 import java.io.IOException;
 import java.io.Writer;
 import java.nio.charset.Charset;
@@ -23,24 +40,6 @@
 import java.util.HashMap;
 import java.util.Map;
 
-import org.apache.logging.log4j.core.Layout;
-import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.core.config.Configuration;
-import org.apache.logging.log4j.core.config.DefaultConfiguration;
-import org.apache.logging.log4j.plugins.Node;
-import org.apache.logging.log4j.plugins.Plugin;
-import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
-import org.apache.logging.log4j.plugins.PluginElement;
-import org.apache.logging.log4j.core.layout.PatternLayout;
-import org.apache.logging.log4j.core.util.KeyValuePair;
-import org.apache.logging.log4j.jackson.AbstractJacksonLayout;
-import org.apache.logging.log4j.jackson.XmlConstants;
-
-import com.fasterxml.jackson.annotation.JsonAnyGetter;
-import com.fasterxml.jackson.annotation.JsonRootName;
-import com.fasterxml.jackson.annotation.JsonUnwrapped;
-
 /**
  * Appends a series of JSON events as strings serialized as bytes.
  *
@@ -170,7 +169,7 @@
                 DEFAULT_HEADER, DEFAULT_FOOTER, StandardCharsets.UTF_8, true, false, false, null, false);
     }
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static <B extends Builder<B>> B newBuilder() {
         return new Builder<B>().asBuilder();
     }
diff --git a/log4j-layout-jackson-json/src/site/manual/index.md b/log4j-layout-jackson-json/src/site/manual/index.md
index 6cadb78..6459110 100644
--- a/log4j-layout-jackson-json/src/site/manual/index.md
+++ b/log4j-layout-jackson-json/src/site/manual/index.md
@@ -18,7 +18,7 @@
 
 # Apache Log4j Layout for Jackson JSON module
 
-As of Log4j 3.0.0, the layout based on Jackson JSON has moved from the existing module logj-core to the new modules log4j-layout-jackson-json.
+As of Log4j 3.0.0, the layout based on Jackson JSON has moved from the existing module log4j-core to the new modules log4j-layout-jackson-json.
 
 ## Requirements
 
diff --git a/log4j-layout-jackson-xml/pom.xml b/log4j-layout-jackson-xml/pom.xml
index 2f3dbb4..6b039b5 100644
--- a/log4j-layout-jackson-xml/pom.xml
+++ b/log4j-layout-jackson-xml/pom.xml
@@ -35,6 +35,11 @@
       <version>${project.version}</version>
     </dependency>
     <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-1.2-api</artifactId>
+      <optional>true</optional>
+    </dependency>
+    <dependency>
       <groupId>com.fasterxml.jackson.dataformat</groupId>
       <artifactId>jackson-dataformat-xml</artifactId>
     </dependency>
diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/builders/layout/XmlLayoutBuilder.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/builders/layout/XmlLayoutBuilder.java
new file mode 100644
index 0000000..28f0474
--- /dev/null
+++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/builders/layout/XmlLayoutBuilder.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.jackson.xml.builders.layout;
+
+import org.apache.log4j.Layout;
+import org.apache.log4j.bridge.LayoutWrapper;
+import org.apache.log4j.builders.AbstractBuilder;
+import org.apache.log4j.builders.BooleanHolder;
+import org.apache.log4j.builders.Holder;
+import org.apache.log4j.builders.layout.LayoutBuilder;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.xml.XmlConfiguration;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.jackson.xml.layout.XmlLayout;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+
+import java.util.Properties;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.xml.XmlConfiguration.PARAM_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.forEachElement;
+
+/**
+ * Build an XML Layout
+ */
+@Plugin(name = "org.apache.log4j.xml.XMLLayout", category = CATEGORY)
+public class XmlLayoutBuilder extends AbstractBuilder implements LayoutBuilder {
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+
+    private static final String LOCATION_INFO = "LocationInfo";
+    private static final String PROPERTIES = "Properties";
+
+    public XmlLayoutBuilder() {
+    }
+
+    public XmlLayoutBuilder(String prefix, Properties props) {
+        super(prefix, props);
+    }
+
+
+    @Override
+    public Layout parseLayout(Element layoutElement, XmlConfiguration config) {
+        final Holder<Boolean> properties = new BooleanHolder();
+        final Holder<Boolean> locationInfo = new BooleanHolder();
+        forEachElement(layoutElement.getElementsByTagName(PARAM_TAG), (currentElement) -> {
+            if (PROPERTIES.equalsIgnoreCase(currentElement.getAttribute("name"))) {
+                properties.set(Boolean.parseBoolean(currentElement.getAttribute("value")));
+            } else if (LOCATION_INFO.equalsIgnoreCase(currentElement.getAttribute("name"))) {
+                locationInfo.set(Boolean.parseBoolean(currentElement.getAttribute("value")));
+            }
+        });
+        return createLayout(properties.get(), locationInfo.get());
+    }
+
+    @Override
+    public Layout parseLayout(PropertiesConfiguration config) {
+        boolean properties = getBooleanProperty(PROPERTIES);
+        boolean locationInfo = getBooleanProperty(LOCATION_INFO);
+        return createLayout(properties, locationInfo);
+    }
+
+    private Layout createLayout(boolean properties, boolean locationInfo) {
+        return new LayoutWrapper(XmlLayout.newBuilder()
+                .setLocationInfo(locationInfo)
+                .setProperties(properties)
+                .build());
+    }
+}
diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayout.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayout.java
index 2b8326e..54f1ee0 100644
--- a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayout.java
+++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayout.java
@@ -16,23 +16,22 @@
  */
 package org.apache.logging.log4j.jackson.xml.layout;
 
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.util.KeyValuePair;
+import org.apache.logging.log4j.jackson.AbstractJacksonLayout;
+import org.apache.logging.log4j.jackson.XmlConstants;
+import org.apache.logging.log4j.plugins.Node;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.plugins.PluginFactory;
+
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
 import java.util.Map;
 
-import org.apache.logging.log4j.core.Layout;
-import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.core.config.Configuration;
-import org.apache.logging.log4j.plugins.Node;
-import org.apache.logging.log4j.plugins.Plugin;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
-import org.apache.logging.log4j.core.util.KeyValuePair;
-import org.apache.logging.log4j.jackson.AbstractJacksonLayout;
-import org.apache.logging.log4j.jackson.XmlConstants;
-
-import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
-
 /**
  * Appends a series of {@code event} elements as defined in the <a href="log4j.dtd">log4j.dtd</a>.
  *
@@ -102,7 +101,7 @@
         return new XmlLayout(null, false, false, false, false, StandardCharsets.UTF_8, true, false, false, null);
     }
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static <B extends Builder<B>> B newBuilder() {
         return new Builder<B>().asBuilder();
     }
diff --git a/log4j-layout-jackson-xml/src/site/manual/index.md b/log4j-layout-jackson-xml/src/site/manual/index.md
index 216fe05..b46d368 100644
--- a/log4j-layout-jackson-xml/src/site/manual/index.md
+++ b/log4j-layout-jackson-xml/src/site/manual/index.md
@@ -18,7 +18,7 @@
 
 # Apache Log4j Layout for Jackson XML module
 
-As of Log4j 3.0.0, the layout based on Jackson XML has moved from the existing module logj-core to the new modules log4j-layout-jackson-xml.
+As of Log4j 3.0.0, the layout based on Jackson XML has moved from the existing module log4j-core to the new modules log4j-layout-jackson-xml.
 
 ## Requirements
 
diff --git a/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/layout/YamlLayout.java b/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/layout/YamlLayout.java
index 9f09713..585f90f 100644
--- a/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/layout/YamlLayout.java
+++ b/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/layout/YamlLayout.java
@@ -17,26 +17,25 @@
 
 package org.apache.logging.log4j.jackson.yaml.layout;
 
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
-import java.util.Map;
-
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonRootName;
+import com.fasterxml.jackson.annotation.JsonUnwrapped;
 import org.apache.logging.log4j.core.Layout;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.config.Configuration;
 import org.apache.logging.log4j.core.config.DefaultConfiguration;
-import org.apache.logging.log4j.plugins.Node;
-import org.apache.logging.log4j.plugins.Plugin;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
 import org.apache.logging.log4j.core.layout.PatternLayout;
 import org.apache.logging.log4j.core.util.KeyValuePair;
 import org.apache.logging.log4j.jackson.AbstractJacksonLayout;
+import org.apache.logging.log4j.plugins.Node;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.plugins.PluginFactory;
 import org.apache.logging.log4j.util.Strings;
 
-import com.fasterxml.jackson.annotation.JsonAnyGetter;
-import com.fasterxml.jackson.annotation.JsonRootName;
-import com.fasterxml.jackson.annotation.JsonUnwrapped;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * Appends a series of YAML events as strings serialized as bytes.
@@ -111,7 +110,7 @@
                 DEFAULT_FOOTER, StandardCharsets.UTF_8, true, false, false, null);
     }
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static <B extends Builder<B>> B newBuilder() {
         return new Builder<B>().asBuilder();
     }
diff --git a/log4j-layout-jackson-yaml/src/site/manual/index.md b/log4j-layout-jackson-yaml/src/site/manual/index.md
index 83112af..6fb90f1 100644
--- a/log4j-layout-jackson-yaml/src/site/manual/index.md
+++ b/log4j-layout-jackson-yaml/src/site/manual/index.md
@@ -18,7 +18,7 @@
 
 # Apache Log4j Layout for Jackson YAML module
 
-As of Log4j 3.0.0, the layout based on Jackson YAML has moved from the existing module logj-core to the new modules log4j-layout-jackson-yaml.
+As of Log4j 3.0.0, the layout based on Jackson YAML has moved from the existing module log4j-core to the new modules log4j-layout-jackson-yaml.
 
 ## Requirements
 
diff --git a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractJacksonLayout.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractJacksonLayout.java
index 2773fbc..d087a2e 100644
--- a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractJacksonLayout.java
+++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractJacksonLayout.java
@@ -352,7 +352,7 @@
             // This class combines LogEvent with AdditionalFields during serialization
             return createLogEventWithAdditionalFields(event, additionalFieldsMap);
         } else if (event instanceof Message) {
-            // If the LogEvent implements the Messagee interface Jackson will not treat is as a LogEvent.
+            // If the LogEvent implements the Message interface Jackson will not treat is as a LogEvent.
             return new ReadOnlyLogEventWrapper(event);
             // No additional fields, return original object
         }
diff --git a/log4j-layout-jackson/src/site/manual/index.md b/log4j-layout-jackson/src/site/manual/index.md
index b1d22b6..8f3b15d 100644
--- a/log4j-layout-jackson/src/site/manual/index.md
+++ b/log4j-layout-jackson/src/site/manual/index.md
@@ -18,7 +18,7 @@
 
 # Apache Log4j Layout for Jackson module
 
-As of Log4j 3.0.0, common code for layouts based on Jackson have moved from the existing module logj-core to the new modules log4j-layout-jackson.
+As of Log4j 3.0.0, common code for layouts based on Jackson have moved from the existing module log4j-core to the new modules log4j-layout-jackson.
 
 ## Requirements
 
diff --git a/log4j-mongodb2/src/main/java/org/apache/logging/log4j/mongodb2/MongoDbProvider.java b/log4j-mongodb2/src/main/java/org/apache/logging/log4j/mongodb2/MongoDbProvider.java
index f5d3c08..e38f8d1 100644
--- a/log4j-mongodb2/src/main/java/org/apache/logging/log4j/mongodb2/MongoDbProvider.java
+++ b/log4j-mongodb2/src/main/java/org/apache/logging/log4j/mongodb2/MongoDbProvider.java
@@ -16,11 +16,11 @@
  */
 package org.apache.logging.log4j.mongodb2;
 
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.List;
-
+import com.mongodb.DB;
+import com.mongodb.MongoClient;
+import com.mongodb.MongoCredential;
+import com.mongodb.ServerAddress;
+import com.mongodb.WriteConcern;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.Core;
 import org.apache.logging.log4j.core.appender.nosql.NoSqlProvider;
@@ -28,21 +28,20 @@
 import org.apache.logging.log4j.plugins.Plugin;
 import org.apache.logging.log4j.plugins.PluginAliases;
 import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
+import org.apache.logging.log4j.plugins.PluginFactory;
 import org.apache.logging.log4j.plugins.convert.TypeConverters;
 import org.apache.logging.log4j.plugins.validation.constraints.Required;
 import org.apache.logging.log4j.plugins.validation.constraints.ValidHost;
 import org.apache.logging.log4j.plugins.validation.constraints.ValidPort;
 import org.apache.logging.log4j.status.StatusLogger;
-import org.apache.logging.log4j.util.NameUtil;
 import org.apache.logging.log4j.util.LoaderUtil;
+import org.apache.logging.log4j.util.NameUtil;
 import org.apache.logging.log4j.util.Strings;
 
-import com.mongodb.DB;
-import com.mongodb.MongoClient;
-import com.mongodb.MongoCredential;
-import com.mongodb.ServerAddress;
-import com.mongodb.WriteConcern;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * The MongoDB implementation of {@link NoSqlProvider}.
@@ -275,7 +274,7 @@
     private static final int DEFAULT_PORT = 27017;
 
     private static final int DEFAULT_COLLECTION_SIZE = 536870912;
-    @PluginBuilderFactory
+    @PluginFactory
 	public static <B extends Builder<B>> B newBuilder() {
 		return new Builder<B>().asBuilder();
 	}
diff --git a/log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDbProvider.java b/log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDbProvider.java
index f16d2d0..af392c0 100644
--- a/log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDbProvider.java
+++ b/log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDbProvider.java
@@ -16,16 +16,19 @@
  */
 package org.apache.logging.log4j.mongodb3;
 
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-
+import com.mongodb.MongoClient;
+import com.mongodb.MongoClientOptions;
+import com.mongodb.MongoCredential;
+import com.mongodb.ServerAddress;
+import com.mongodb.WriteConcern;
+import com.mongodb.client.MongoDatabase;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.Core;
 import org.apache.logging.log4j.core.appender.nosql.NoSqlProvider;
 import org.apache.logging.log4j.core.filter.AbstractFilterable;
 import org.apache.logging.log4j.plugins.Plugin;
 import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
+import org.apache.logging.log4j.plugins.PluginFactory;
 import org.apache.logging.log4j.plugins.convert.TypeConverters;
 import org.apache.logging.log4j.plugins.validation.constraints.Required;
 import org.apache.logging.log4j.plugins.validation.constraints.ValidHost;
@@ -36,12 +39,8 @@
 import org.apache.logging.log4j.util.Strings;
 import org.bson.codecs.configuration.CodecRegistries;
 
-import com.mongodb.MongoClient;
-import com.mongodb.MongoClientOptions;
-import com.mongodb.MongoCredential;
-import com.mongodb.ServerAddress;
-import com.mongodb.WriteConcern;
-import com.mongodb.client.MongoDatabase;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
 
 /**
  * The MongoDB implementation of {@link NoSqlProvider}.
@@ -291,7 +290,7 @@
 
     private static final Logger LOGGER = StatusLogger.getLogger();
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static <B extends Builder<B>> B newBuilder() {
         return new Builder<B>().asBuilder();
     }
diff --git a/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java b/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java
index 3d09f6b..505732f 100644
--- a/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java
+++ b/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java
@@ -271,7 +271,7 @@
             final String result = baos.toString().substring(
                 12).trim(); // remove the instant then the spaces at start and end, that are non constant
             String expected = "[main] ERROR org.apache.logging.log4j.configuration.CustomConfiguration - Test OK";
-            Assert.assertTrue("Incorrect string. Expected string ends woth: " + expected + " Actual: " + result,
+            Assert.assertTrue("Incorrect string. Expected string ends with: " + expected + " Actual: " + result,
                     result.endsWith(expected));
         } finally {
             System.setOut(bakStream);
diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/LoggingDisabledBenchmark.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/LoggingDisabledBenchmark.java
new file mode 100644
index 0000000..0f8805c
--- /dev/null
+++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/LoggingDisabledBenchmark.java
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.perf.jmh;
+
+import java.io.File;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.TearDown;
+import org.slf4j.LoggerFactory;
+
+//import com.newrelic.api.agent.Trace;
+
+/**
+ * Benchmark logging with logging disabled.
+ * // ============================== HOW TO RUN THIS TEST: ====================================
+ * //
+ * // single thread:
+ * // java -jar log4j-perf/target/benchmarks.jar ".*LoggingDisabledBenchmark.*" -f 1 -wi 5 -i 10
+ * //
+ * // multiple threads (for example, 4 threads):
+ * // java -jar log4j-perf/target/benchmarks.jar ".*LoggingDisabledBenchmark.*" -f 1 -wi 5 -i 10 -t 4 -si true
+ * //
+ * // Usage help:
+ * // java -jar log4j-perf/target/benchmarks.jar -help
+ * //
+ */
+@State(Scope.Thread)
+public class LoggingDisabledBenchmark {
+
+    Logger log4j2Logger;
+    org.slf4j.Logger slf4jLogger;
+    org.apache.log4j.Logger log4j1Logger;
+
+    @Setup
+    public void setUp() throws Exception {
+        System.setProperty("log4j.configurationFile", "log4j2-perf2.xml");
+        System.setProperty("log4j.configuration", "log4j12-perf2.xml");
+        System.setProperty("logback.configurationFile", "logback-perf2.xml");
+
+        deleteLogFiles();
+
+        log4j2Logger = LogManager.getLogger(FileAppenderWithLocationBenchmark.class);
+        slf4jLogger = LoggerFactory.getLogger(FileAppenderWithLocationBenchmark.class);
+        log4j1Logger = org.apache.log4j.Logger.getLogger(FileAppenderWithLocationBenchmark.class);
+    }
+
+    @TearDown
+    public void tearDown() {
+        System.clearProperty("log4j.configurationFile");
+        System.clearProperty("log4j.configuration");
+        System.clearProperty("logback.configurationFile");
+
+        deleteLogFiles();
+    }
+
+    private void deleteLogFiles() {
+        final File logbackFile = new File("target/testlogback.log");
+        logbackFile.delete();
+        final File log4jFile = new File ("target/testlog4j.log");
+        log4jFile.delete();
+        final File log4j2File = new File ("target/testlog4j2.log");
+        log4j2File.delete();
+    }
+
+    @Benchmark
+    @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS)
+    public void baseline() {
+    }
+
+    /*
+      This benchmark tests the overhead of NewRelic on method calls. It is commented out so
+      that we don't have to include the dependency during a "normal" build. Uncomment and add
+      the New Relic Agent client dependency if you would like to test this.
+    @Benchmark
+    @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS)
+    @Trace(dispatcher = true)
+    public void log4j2NewRelic() {
+        log4j2Logger.debug("This won't be logged");
+    } */
+
+    @Benchmark
+    @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS)
+    public void log4j2() {
+        log4j2Logger.debug("This won't be logged");
+    }
+
+    @Benchmark
+    @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS)
+    public void slf4j() {
+        slf4jLogger.debug("This won't be logged");
+    }
+
+    @Benchmark
+    @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS)
+    public void log4j2IsDebugEnabled() {
+        if (log4j2Logger.isDebugEnabled()) {
+            log4j2Logger.debug("This won't be logged");
+        }
+    }
+
+    @Benchmark
+    @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS)
+    public void slf4jIsDebugEnabled() {
+        if (slf4jLogger.isDebugEnabled()) {
+            slf4jLogger.debug("This won't be logged");
+        }
+    }
+
+    @Benchmark
+    @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS)
+    public void log4j1IsDebugEnabled() {
+        if (log4j1Logger.isDebugEnabled()) {
+            log4j1Logger.debug("This won't be logged");
+        }
+    }
+
+}
diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/OutputBenchmark.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/OutputBenchmark.java
new file mode 100644
index 0000000..3aa8a97
--- /dev/null
+++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/OutputBenchmark.java
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+
+package org.apache.logging.log4j.perf.jmh;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.FileHandler;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Group;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.TearDown;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Benchmarks Log4j 2, Log4j 1, Logback and JUL using the DEBUG level which is enabled for this test. The configuration
+ * for each uses a FileAppender
+ */
+// HOW TO RUN THIS TEST
+// java -jar log4j-perf/target/benchmarks.jar ".*OutputBenchmark.*" -f 1 -wi 10 -i 20
+//
+// RUNNING THIS TEST WITH 4 THREADS:
+// java -jar log4j-perf/target/benchmarks.jar ".*OutputBenchmark.*" -f 1 -wi 10 -i 20 -t 4
+@State(Scope.Thread)
+public class OutputBenchmark {
+    public static final String MESSAGE = "This is a debug message";
+
+    Logger log4j2Logger;
+
+
+    @State(Scope.Group)
+    public static class Redirect {
+        PrintStream defaultStream = System.out;
+
+        @Setup
+        public void setUp() throws Exception {
+            PrintStream ps = new PrintStream(new FileOutputStream("target/stdout.log"));
+            System.setOut(ps);
+        }
+
+        @TearDown
+        public void tearDown() {
+            PrintStream ps = System.out;
+            System.setOut(defaultStream);
+            ps.close();
+        }
+    }
+
+    @Setup
+    public void setUp() throws Exception {
+        System.setProperty("log4j.configurationFile", "log4j2-perf3.xml");
+
+        deleteLogFiles();
+
+        log4j2Logger = LogManager.getLogger(OutputBenchmark.class);
+    }
+
+    @TearDown
+    public void tearDown() {
+        System.clearProperty("log4j.configurationFile");
+
+        deleteLogFiles();
+    }
+
+    private void deleteLogFiles() {
+        final File outFile = new File("target/stdout.log");
+        final File log4j2File = new File ("target/testlog4j2.log");
+        log4j2File.delete();
+        outFile.delete();
+    }
+
+    @BenchmarkMode(Mode.Throughput)
+    @OutputTimeUnit(TimeUnit.SECONDS)
+    @Group("console")
+    @Benchmark
+    public void console() {
+        System.out.println(MESSAGE);
+    }
+
+    @BenchmarkMode(Mode.Throughput)
+    @OutputTimeUnit(TimeUnit.SECONDS)
+    @Group("file")
+    @Benchmark
+    public void log4j2File() {
+        log4j2Logger.debug(MESSAGE);
+    }
+
+    @BenchmarkMode(Mode.Throughput)
+    @OutputTimeUnit(TimeUnit.SECONDS)
+    @Group("redirect")
+    @Benchmark
+    public void redirect(Redirect redirect) {
+        System.out.println(MESSAGE);
+    }
+}
diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadsafeDateFormatBenchmark.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadsafeDateFormatBenchmark.java
index 59ac56f..98af16b 100644
--- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadsafeDateFormatBenchmark.java
+++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadsafeDateFormatBenchmark.java
@@ -18,6 +18,8 @@
 package org.apache.logging.log4j.perf.jmh;
 
 import java.text.SimpleDateFormat;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
 import java.util.Date;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
@@ -49,6 +51,7 @@
 public class ThreadsafeDateFormatBenchmark {
 
     private final Date date = new Date();
+    private final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss.SSS");
     private final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm:ss.SSS");
     private final ThreadLocal<SimpleDateFormat> threadLocalSDFormat = new ThreadLocal<SimpleDateFormat>() {
         @Override
@@ -163,6 +166,14 @@
     @Benchmark
     @BenchmarkMode(Mode.SampleTime)
     @OutputTimeUnit(TimeUnit.NANOSECONDS)
+    public String dateTimeFormatter() {
+        final LocalDateTime now = LocalDateTime.now();
+        return dateTimeFormatter.format(now);
+    }
+
+    @Benchmark
+    @BenchmarkMode(Mode.SampleTime)
+    @OutputTimeUnit(TimeUnit.NANOSECONDS)
     public String threadLocalSimpleDateFmt() {
         final long timestamp = System.currentTimeMillis();
         return threadLocalSDFormat.get().format(timestamp);
diff --git a/log4j-perf/src/main/resources/log4j2-perf3.xml b/log4j-perf/src/main/resources/log4j2-perf3.xml
new file mode 100644
index 0000000..1b977e7
--- /dev/null
+++ b/log4j-perf/src/main/resources/log4j2-perf3.xml
@@ -0,0 +1,32 @@
+<?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 name="XMLPerfTest" status="OFF">
+  <Appenders>
+    <File name="TestLogfile" fileName="target/testlog4j2.log" immediateFlush="false">
+      <PatternLayout>
+        <Pattern>%d %5p [%t] %c{1} %X{transactionId} - %m%n</Pattern>
+      </PatternLayout>
+    </File>
+  </Appenders>
+  <Loggers>
+    <Root level="debug">
+      <AppenderRef ref="TestLogfile"/>
+    </Root>
+  </Loggers>
+</Configuration>
diff --git a/log4j-plugins-java9/src/assembly/java9.xml b/log4j-plugins-java9/src/assembly/java9.xml
index 34649d4..249fa86 100644
--- a/log4j-plugins-java9/src/assembly/java9.xml
+++ b/log4j-plugins-java9/src/assembly/java9.xml
@@ -34,6 +34,7 @@
       <excludes>
         <exclude>**/Dummy.class</exclude>
         <exclude>**/PluginService.class</exclude>
+        <exclude>**/Log4jPlugins.class</exclude>
       </excludes>
     </fileSet>
   </fileSets>
diff --git a/log4j-plugins-java9/src/main/java/module-info.java b/log4j-plugins-java9/src/main/java/module-info.java
index 801ee80..896d3e1 100644
--- a/log4j-plugins-java9/src/main/java/module-info.java
+++ b/log4j-plugins-java9/src/main/java/module-info.java
@@ -20,7 +20,15 @@
     exports org.apache.logging.log4j.plugins.processor;
     exports org.apache.logging.log4j.plugins.util;
     exports org.apache.logging.log4j.plugins.validation;
+    exports org.apache.logging.log4j.plugins.validation.constraints;
+    exports org.apache.logging.log4j.plugins.validation.validators;
+    exports org.apache.logging.log4j.plugins.bind;
     exports org.apache.logging.log4j.plugins.inject;
+    exports org.apache.logging.log4j.plugins.name;
+
+    requires org.apache.logging.log4j;
+
+    provides org.apache.logging.log4j.plugins.processor.PluginService with org.apache.logging.log4j.plugins.convert.plugins.Log4jPlugins;
 
     uses org.apache.logging.log4j.plugins.processor.PluginService;
 }
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/bind/Dummy.java
similarity index 68%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/bind/Dummy.java
index 13aaf9c..98f00c7 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/bind/Dummy.java
@@ -14,17 +14,11 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
+package org.apache.logging.log4j.plugins.bind;
 
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-public class ProcessIdUtilTest {
-
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
-    }
+/**
+ * This is a dummy class and is only here to allow module-info.java to compile. It will not
+ * be copied into the log4j-plugins module.
+ */
+public class Dummy {
 }
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/convert/plugins/Log4jPlugins.java
similarity index 69%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/convert/plugins/Log4jPlugins.java
index 13aaf9c..6cdd225 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/convert/plugins/Log4jPlugins.java
@@ -14,17 +14,12 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
+package org.apache.logging.log4j.plugins.convert.plugins;
 
-import org.junit.Test;
+import org.apache.logging.log4j.plugins.processor.PluginService;
 
-import static org.junit.Assert.*;
-
-public class ProcessIdUtilTest {
-
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
-    }
+/**
+ * Class Description goes here.
+ */
+public class Log4jPlugins extends PluginService {
 }
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/name/Dummy.java
similarity index 68%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/name/Dummy.java
index 13aaf9c..853dc00 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/name/Dummy.java
@@ -14,17 +14,11 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
+package org.apache.logging.log4j.plugins.name;
 
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-public class ProcessIdUtilTest {
-
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
-    }
+/**
+ * This is a dummy class and is only here to allow module-info.java to compile. It will not
+ * be copied into the log4j-plugins module.
+ */
+public class Dummy {
 }
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/Dummy.java
similarity index 69%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/Dummy.java
index 13aaf9c..9810d5e 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/Dummy.java
@@ -14,17 +14,11 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
+package org.apache.logging.log4j.plugins.validation.constraints;
 
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-public class ProcessIdUtilTest {
-
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
-    }
+/**
+ * This is a dummy class and is only here to allow module-info.java to compile. It will not
+ * be copied into the log4j-api module.
+ */
+public class Dummy {
 }
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/validation/validators/Dummy.java
similarity index 68%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/validation/validators/Dummy.java
index 13aaf9c..da73052 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/validation/validators/Dummy.java
@@ -14,17 +14,11 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
+package org.apache.logging.log4j.plugins.validation.validators;
 
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-public class ProcessIdUtilTest {
-
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
-    }
+/**
+ * This is a dummy class and is only here to allow module-info.java to compile. It will not
+ * be copied into the log4j-api module.
+ */
+public class Dummy {
 }
diff --git a/log4j-plugins/pom.xml b/log4j-plugins/pom.xml
index 5008c07..c239a76 100644
--- a/log4j-plugins/pom.xml
+++ b/log4j-plugins/pom.xml
@@ -120,6 +120,20 @@
             </configuration>
           </execution>
           <execution>
+            <!-- then do a processing-only pass to generate plugins -->
+            <id>process-plugins</id>
+            <goals>
+              <goal>compile</goal>
+            </goals>
+            <phase>process-classes</phase>
+            <configuration>
+              <excludes>
+                <exclude>module-info.java</exclude>
+              </excludes>
+              <proc>only</proc>
+            </configuration>
+          </execution>
+          <execution>
             <!-- disable annotation processing for first pass -->
             <id>generate-test-plugins</id>
             <phase>generate-test-sources</phase>
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAliases.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAliases.java
index 4dce103..bb3962a 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAliases.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAliases.java
@@ -23,12 +23,16 @@
 import java.lang.annotation.Target;
 
 /**
- * Identifies a list of aliases for a Plugin, PluginAttribute, or PluginBuilderAttribute.
+ * Identifies a list of aliases for an annotated plugin element. This is supported by plugin classes and other element
+ * types supported by the annotations in this package.
  */
 @Documented
 @Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.PARAMETER, ElementType.TYPE, ElementType.FIELD})
+@Target({ElementType.PARAMETER, ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
 public @interface PluginAliases {
 
+    /**
+     * Aliases the annotated element can also be referred to. These aliases are case-insensitive.
+     */
     String[] value();
 }
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAttribute.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAttribute.java
index efc769a..30cccad 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAttribute.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAttribute.java
@@ -16,8 +16,10 @@
  */
 package org.apache.logging.log4j.plugins;
 
-import org.apache.logging.log4j.plugins.inject.InjectionStrategy;
-import org.apache.logging.log4j.plugins.inject.PluginAttributeBuilder;
+import org.apache.logging.log4j.plugins.inject.InjectorStrategy;
+import org.apache.logging.log4j.plugins.inject.PluginAttributeInjector;
+import org.apache.logging.log4j.plugins.name.NameProvider;
+import org.apache.logging.log4j.plugins.name.PluginAttributeNameProvider;
 import org.apache.logging.log4j.util.Strings;
 
 import java.lang.annotation.Documented;
@@ -27,16 +29,24 @@
 import java.lang.annotation.Target;
 
 /**
- * Identifies a Plugin Attribute and its default value. Note that only one of the defaultFoo attributes will be
- * used based on the type this annotation is attached to. Thus, for primitive types, the default<i>Type</i>
- * attribute will be used for some <i>Type</i>. However, for more complex types (including enums), the default
- * string value is used instead and should correspond to the string that would correctly convert to the appropriate
- * enum value using {@link Enum#valueOf(Class, String) Enum.valueOf}.
+ * Identifies a Plugin Attribute along with optional metadata. Plugin attributes can be injected as parameters to
+ * a static {@linkplain PluginFactory factory method}, or as fields and single-parameter methods in a plugin
+ * {@linkplain org.apache.logging.log4j.plugins.util.Builder builder class}.
+ *
+ * <p>Default values may be specified via one of the <code>default<var>Type</var></code> attributes depending on the
+ * annotated type. Unlisted types that are supported by a corresponding
+ * {@link org.apache.logging.log4j.plugins.convert.TypeConverter} may use the {@link #defaultString()} attribute.
+ * When annotating a field, a default value can be specified by the field's initial value instead of using one of the
+ * annotation attributes.</p>
+ *
+ * <p>Plugin attributes with sensitive data such as passwords should specify {@link #sensitive()} to avoid having
+ * their values logged in debug logs.</p>
  */
 @Documented
 @Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.PARAMETER, ElementType.FIELD})
-@InjectionStrategy(PluginAttributeBuilder.class)
+@Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD})
+@InjectorStrategy(PluginAttributeInjector.class)
+@NameProvider(PluginAttributeNameProvider.class)
 public @interface PluginAttribute {
 
     /**
@@ -89,11 +99,18 @@
      */
     String defaultString() default Strings.EMPTY;
 
-    // TODO: could we allow a blank value and infer the attribute name through reflection?
     /**
      * Specifies the name of the attribute (case-insensitive) this annotation corresponds to.
+     * If blank, defaults to using reflection on the annotated element as such:
+     *
+     * <ul>
+     *     <li>Field: uses the field name.</li>
+     *     <li>Method: when named <code>set<var>XYZ</var></code> or <code>with<var>XYZ</var></code>, uses the rest
+     *     (<var>XYZ</var>) of the method name. Otherwise, uses the name of the first parameter.</li>
+     *     <li>Parameter: uses the parameter name.</li>
+     * </ul>
      */
-    String value();
+    String value() default Strings.EMPTY;
 
     /**
      * Indicates that this attribute is a sensitive one that shouldn't be logged directly. Such attributes will instead
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderAttribute.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderAttribute.java
index 36e6ff2..06cb8f0 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderAttribute.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderAttribute.java
@@ -17,8 +17,10 @@
 
 package org.apache.logging.log4j.plugins;
 
-import org.apache.logging.log4j.plugins.inject.InjectionStrategy;
-import org.apache.logging.log4j.plugins.inject.PluginBuilderAttributeBuilder;
+import org.apache.logging.log4j.plugins.inject.InjectorStrategy;
+import org.apache.logging.log4j.plugins.inject.PluginBuilderAttributeInjector;
+import org.apache.logging.log4j.plugins.name.NameProvider;
+import org.apache.logging.log4j.plugins.name.PluginBuilderAttributeNameProvider;
 import org.apache.logging.log4j.util.Strings;
 
 import java.lang.annotation.Documented;
@@ -29,12 +31,15 @@
 
 /**
  * Marks a field as a Plugin Attribute.
+ *
+ * @deprecated use {@link PluginAttribute}
  */
 @Documented
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.TYPE})
-@InjectionStrategy(PluginBuilderAttributeBuilder.class)
-// TODO: this annotation can be combined with @PluginAttribute along with giving it a default value
+@InjectorStrategy(PluginBuilderAttributeInjector.class)
+@NameProvider(PluginBuilderAttributeNameProvider.class)
+@Deprecated
 public @interface PluginBuilderAttribute {
 
     /**
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginElement.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginElement.java
index 919d138..9b333d4 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginElement.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginElement.java
@@ -16,8 +16,11 @@
  */
 package org.apache.logging.log4j.plugins;
 
-import org.apache.logging.log4j.plugins.inject.InjectionStrategy;
-import org.apache.logging.log4j.plugins.inject.PluginElementBuilder;
+import org.apache.logging.log4j.plugins.inject.InjectorStrategy;
+import org.apache.logging.log4j.plugins.inject.PluginElementInjector;
+import org.apache.logging.log4j.plugins.name.NameProvider;
+import org.apache.logging.log4j.plugins.name.PluginElementNameProvider;
+import org.apache.logging.log4j.util.Strings;
 
 import java.lang.annotation.Documented;
 import java.lang.annotation.ElementType;
@@ -26,16 +29,27 @@
 import java.lang.annotation.Target;
 
 /**
- * Identifies a parameter as a Plugin and corresponds with an XML element (or equivalent) in configuration files.
+ * Identifies a Plugin Element which allows for plugins to be configured and injected into another plugin.
+ * Plugin elements can be injected as parameters to a static {@linkplain PluginFactory factory method}, or as fields and
+ * single-parameter methods in a plugin {@linkplain org.apache.logging.log4j.plugins.util.Builder builder class}.
  */
 @Documented
 @Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.PARAMETER, ElementType.FIELD})
-@InjectionStrategy(PluginElementBuilder.class)
+@Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD})
+@InjectorStrategy(PluginElementInjector.class)
+@NameProvider(PluginElementNameProvider.class)
 public @interface PluginElement {
 
     /**
      * Identifies the case-insensitive element name (or attribute name) this corresponds with in a configuration file.
+     * If blank, defaults to using reflection on the annotated element as such:
+     *
+     * <ul>
+     *     <li>Field: uses the field name.</li>
+     *     <li>Method: when named <code>set<var>XYZ</var></code> or <code>with<var>XYZ</var></code>, uses the rest
+     *     (<var>XYZ</var>) of the method name. Otherwise, uses the name of the first parameter.</li>
+     *     <li>Parameter: uses the parameter name.</li>
+     * </ul>
      */
-    String value();
+    String value() default Strings.EMPTY;
 }
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginFactory.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginFactory.java
index b071510..f1d89c6 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginFactory.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginFactory.java
@@ -23,8 +23,13 @@
 import java.lang.annotation.Target;
 
 /**
- * Identifies a Method as the factory to create the plugin. This annotation should only be used on a {@code static}
- * method, and its parameters should be annotated with the appropriate Plugin annotations.
+ * Identifies a static method as a factory to create a plugin or a
+ * {@linkplain org.apache.logging.log4j.plugins.util.Builder builder class} for constructing a plugin.
+ * Factory methods should annotate their parameters with {@link PluginAttribute}, {@link PluginElement},
+ * {@link PluginValue}, or other plugin annotations annotated with
+ * {@link org.apache.logging.log4j.plugins.inject.InjectorStrategy}.
+ * If a factory method returns a builder class, this method should have no arguments; instead, the builder class should
+ * annotate its fields or single-parameter methods to inject plugin configuration data.
  * <p>
  * There can only be one factory method per class.
  * </p>
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginNode.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginNode.java
index 2f5cef3..dcc5b0c 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginNode.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginNode.java
@@ -16,8 +16,8 @@
  */
 package org.apache.logging.log4j.plugins;
 
-import org.apache.logging.log4j.plugins.inject.InjectionStrategy;
-import org.apache.logging.log4j.plugins.inject.PluginNodeBuilder;
+import org.apache.logging.log4j.plugins.inject.InjectorStrategy;
+import org.apache.logging.log4j.plugins.inject.PluginNodeInjector;
 
 import java.lang.annotation.Documented;
 import java.lang.annotation.ElementType;
@@ -26,12 +26,14 @@
 import java.lang.annotation.Target;
 
 /**
- * Identifies a Plugin configuration Node.
+ * Identifies the configuration {@link Node} currently being configured. This can be injected as a parameter to a static
+ * {@linkplain PluginFactory factory method}, or as a field or single-parameter method in a plugin
+ * {@linkplain org.apache.logging.log4j.plugins.util.Builder builder class}.
  */
 @Documented
 @Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.PARAMETER, ElementType.FIELD})
-@InjectionStrategy(PluginNodeBuilder.class)
+@Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD})
+@InjectorStrategy(PluginNodeInjector.class)
 public @interface PluginNode {
     // empty
 }
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginValue.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginValue.java
index 84c4385..a08eaf0 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginValue.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginValue.java
@@ -16,8 +16,10 @@
  */
 package org.apache.logging.log4j.plugins;
 
-import org.apache.logging.log4j.plugins.inject.InjectionStrategy;
-import org.apache.logging.log4j.plugins.inject.PluginValueBuilder;
+import org.apache.logging.log4j.plugins.inject.InjectorStrategy;
+import org.apache.logging.log4j.plugins.inject.PluginValueInjector;
+import org.apache.logging.log4j.plugins.name.NameProvider;
+import org.apache.logging.log4j.plugins.name.PluginValueNameProvider;
 
 import java.lang.annotation.Documented;
 import java.lang.annotation.ElementType;
@@ -26,16 +28,25 @@
 import java.lang.annotation.Target;
 
 /**
- * Identifies a parameter as a value. These correspond with property values generally, but are meant as values to be
- * used as a placeholder value somewhere.
+ * Identifies a Plugin Value and its corresponding attribute alias for configuration formats that don't distinguish
+ * between values and attributes. A value is typically used differently from an attribute in that it is either the
+ * main configuration value required or it is the only value needed to create a plugin. A plugin value can be injected
+ * as a parameter to a static {@linkplain PluginFactory factory method}, or as a field or single-parameter method in a
+ * plugin {@linkplain org.apache.logging.log4j.plugins.util.Builder builder class}.
  *
- * @see org.apache.logging.log4j.core.config.PropertiesPlugin
+ * <p>For example, a Property plugin corresponds to a property entry in a configuration file. The property name is
+ * specified as an attribute, and the property value is specified as a value.</p>
  */
 @Documented
 @Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.PARAMETER, ElementType.FIELD})
-@InjectionStrategy(PluginValueBuilder.class)
+@Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD})
+@InjectorStrategy(PluginValueInjector.class)
+@NameProvider(PluginValueNameProvider.class)
 public @interface PluginValue {
 
-    String value();
+    /**
+     * Specifies the case-insensitive attribute name to use in configuration formats that don't distinguish between
+     * attributes and values. By default, this uses the attribute name {@code value}.
+     */
+    String value() default "value";
 }
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/bind/AbstractConfigurationBinder.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/bind/AbstractConfigurationBinder.java
new file mode 100644
index 0000000..e2a9cfc
--- /dev/null
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/bind/AbstractConfigurationBinder.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+
+package org.apache.logging.log4j.plugins.bind;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.plugins.convert.TypeConverter;
+import org.apache.logging.log4j.plugins.convert.TypeConverterRegistry;
+import org.apache.logging.log4j.plugins.name.AnnotatedElementNameProvider;
+import org.apache.logging.log4j.plugins.validation.ConstraintValidator;
+import org.apache.logging.log4j.plugins.validation.ConstraintValidators;
+import org.apache.logging.log4j.status.StatusLogger;
+
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Type;
+import java.util.Collection;
+import java.util.Objects;
+import java.util.function.Function;
+
+/**
+ * Generic configuration binder for an {@link AnnotatedElement}. This provides automatic
+ * {@linkplain TypeConverter string conversion} and {@linkplain ConstraintValidator constraint validation} support.
+ *
+ * @param <E> element type being bound
+ */
+public abstract class AbstractConfigurationBinder<E extends AnnotatedElement> implements ConfigurationBinder {
+    protected static final Logger LOGGER = StatusLogger.getLogger();
+
+    final E element;
+    final String name;
+    private final Type injectionType;
+    private final Collection<ConstraintValidator<?>> validators;
+
+    AbstractConfigurationBinder(final E element, final Function<E, Type> injectionTypeExtractor) {
+        this.element = Objects.requireNonNull(element);
+        this.name = AnnotatedElementNameProvider.getName(element);
+        Objects.requireNonNull(injectionTypeExtractor);
+        this.injectionType = Objects.requireNonNull(injectionTypeExtractor.apply(element));
+        this.validators = ConstraintValidators.findValidators(element.getAnnotations());
+    }
+
+    @Override
+    public void bindString(final Object factory, final String value) {
+        Object convertedValue = null;
+        if (value != null) {
+            final TypeConverter<?> converter = TypeConverterRegistry.getInstance().findCompatibleConverter(injectionType);
+            try {
+                convertedValue = converter.convert(value);
+            } catch (final Exception e) {
+                throw new ConfigurationBindingException(name, value, e);
+            }
+        }
+        bindObject(factory, convertedValue);
+    }
+
+    void validate(final Object value) {
+        boolean valid = true;
+        for (ConstraintValidator<?> validator : validators) {
+            valid &= validator.isValid(name, value);
+        }
+        // FIXME: this doesn't seem to work properly with primitive types
+//        if (valid && value != null && !TypeUtil.isAssignable(injectionType, value.getClass())) {
+//            LOGGER.error("Cannot bind value of type {} to option {} with type {}", value.getClass(), name, injectionType);
+//            valid = false;
+//        }
+        if (!valid) {
+            throw new ConfigurationBindingException(name, value);
+        }
+    }
+
+}
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/bind/ConfigurationBinder.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/bind/ConfigurationBinder.java
new file mode 100644
index 0000000..d97075c
--- /dev/null
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/bind/ConfigurationBinder.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+
+package org.apache.logging.log4j.plugins.bind;
+
+/**
+ * Strategy to bind and validate an {@linkplain org.apache.logging.log4j.plugins.inject.ConfigurationInjector injected
+ * configuration value} to a {@linkplain org.apache.logging.log4j.plugins.PluginFactory plugin factory}.
+ */
+public interface ConfigurationBinder {
+    /**
+     * Binds an unparsed string value to the given factory.
+     *
+     * @param factory injection factory to bind value to
+     * @param value   string representation of configuration value
+     * @throws ConfigurationBindingException if the given value is invalid
+     */
+    void bindString(final Object factory, final String value);
+
+    /**
+     * Binds an object to the given factory.
+     *
+     * @param factory injection factory to bind value to
+     * @param value   configuration value to bind
+     * @throws ConfigurationBindingException if the given value is invalid
+     */
+    void bindObject(final Object factory, final Object value);
+}
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/bind/ConfigurationBindingException.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/bind/ConfigurationBindingException.java
new file mode 100644
index 0000000..69e9b94
--- /dev/null
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/bind/ConfigurationBindingException.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+
+package org.apache.logging.log4j.plugins.bind;
+
+public class ConfigurationBindingException extends IllegalArgumentException {
+
+    ConfigurationBindingException(final String name, final Object value) {
+        super("Invalid value '" + value + "' for option '" + name + "'");
+    }
+
+    ConfigurationBindingException(final String name, final Object value, final Throwable cause) {
+        super("Unable to set option '" + name + "' to value '" + value + "'", cause);
+    }
+
+    ConfigurationBindingException(final String message, final Throwable cause) {
+        super(message, cause);
+    }
+
+}
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/bind/FactoryMethodBinder.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/bind/FactoryMethodBinder.java
new file mode 100644
index 0000000..7548871
--- /dev/null
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/bind/FactoryMethodBinder.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+
+package org.apache.logging.log4j.plugins.bind;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.BiConsumer;
+
+// TODO: can support constructor factory following same pattern
+public class FactoryMethodBinder {
+
+    private final Method factoryMethod;
+    private final Map<Parameter, ConfigurationBinder> binders = new ConcurrentHashMap<>();
+    private final Map<Parameter, Object> boundParameters = new ConcurrentHashMap<>();
+
+    public FactoryMethodBinder(final Method factoryMethod) {
+        this.factoryMethod = Objects.requireNonNull(factoryMethod);
+        for (final Parameter parameter : factoryMethod.getParameters()) {
+            binders.put(parameter, new ParameterConfigurationBinder(parameter));
+        }
+    }
+
+    public void forEachParameter(final BiConsumer<Parameter, ConfigurationBinder> consumer) {
+        binders.forEach(consumer);
+    }
+
+    public Object invoke() throws Throwable {
+        final Parameter[] parameters = factoryMethod.getParameters();
+        final Object[] args = new Object[parameters.length];
+        for (int i = 0; i < parameters.length; i++) {
+            args[i] = boundParameters.get(parameters[i]);
+        }
+        try {
+            return factoryMethod.invoke(null, args);
+        } catch (final IllegalAccessException e) {
+            throw new ConfigurationBindingException("Cannot access factory method " + factoryMethod, e);
+        } catch (final InvocationTargetException e) {
+            throw e.getCause();
+        }
+    }
+
+    private class ParameterConfigurationBinder extends AbstractConfigurationBinder<Parameter> {
+        private ParameterConfigurationBinder(final Parameter parameter) {
+            super(parameter, Parameter::getParameterizedType);
+        }
+
+        @Override
+        public void bindObject(final Object factory, final Object value) {
+            validate(value);
+            if (value != null) {
+                boundParameters.put(element, value);
+            }
+        }
+    }
+}
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/bind/FieldConfigurationBinder.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/bind/FieldConfigurationBinder.java
new file mode 100644
index 0000000..112d759
--- /dev/null
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/bind/FieldConfigurationBinder.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+
+package org.apache.logging.log4j.plugins.bind;
+
+import java.lang.reflect.Field;
+import java.util.Objects;
+
+public class FieldConfigurationBinder extends AbstractConfigurationBinder<Field> {
+
+    public FieldConfigurationBinder(final Field field) {
+        super(field, Field::getGenericType);
+    }
+
+    @Override
+    public void bindObject(final Object factory, final Object value) {
+        Objects.requireNonNull(factory);
+        // FIXME: if we specify a default field value, @PluginAttribute's defaultType will override that
+        if (value == null) {
+            try {
+                Object defaultValue = element.get(factory);
+                validate(defaultValue);
+                LOGGER.trace("Using default value {} for option {}", defaultValue, name);
+            } catch (final IllegalAccessException e) {
+                throw new ConfigurationBindingException("Unable to validate option " + name, e);
+            }
+        } else {
+            validate(value);
+            try {
+                element.set(factory, value);
+                LOGGER.trace("Using value {} for option {}", value, name);
+            } catch (final IllegalAccessException e) {
+                throw new ConfigurationBindingException(name, value, e);
+            }
+        }
+    }
+
+}
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/bind/MethodConfigurationBinder.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/bind/MethodConfigurationBinder.java
new file mode 100644
index 0000000..0ef7f0f
--- /dev/null
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/bind/MethodConfigurationBinder.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+
+package org.apache.logging.log4j.plugins.bind;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Objects;
+
+public class MethodConfigurationBinder extends AbstractConfigurationBinder<Method> {
+
+    public MethodConfigurationBinder(final Method method) {
+        super(method, m -> m.getGenericParameterTypes()[0]);
+    }
+
+    @Override
+    public void bindObject(final Object factory, final Object value) {
+        Objects.requireNonNull(factory);
+        validate(value);
+        try {
+            element.invoke(factory, value);
+        } catch (final IllegalAccessException e) {
+            throw new ConfigurationBindingException(name, value, e);
+        } catch (final InvocationTargetException e) {
+            throw new ConfigurationBindingException(name, value, e.getCause());
+        }
+    }
+}
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/AbstractConfigurationInjector.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/AbstractConfigurationInjector.java
new file mode 100644
index 0000000..86df282
--- /dev/null
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/AbstractConfigurationInjector.java
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+
+package org.apache.logging.log4j.plugins.inject;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.plugins.Node;
+import org.apache.logging.log4j.plugins.PluginAliases;
+import org.apache.logging.log4j.plugins.bind.ConfigurationBinder;
+import org.apache.logging.log4j.plugins.name.AnnotatedElementNameProvider;
+import org.apache.logging.log4j.status.StatusLogger;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Function;
+
+public abstract class AbstractConfigurationInjector<Ann extends Annotation, Cfg> implements ConfigurationInjector<Ann, Cfg> {
+
+    protected static final Logger LOGGER = StatusLogger.getLogger();
+
+    protected Ann annotation;
+    protected AnnotatedElement annotatedElement;
+    protected Type conversionType;
+    protected String name;
+    protected Collection<String> aliases = Collections.emptyList();
+    protected ConfigurationBinder configurationBinder;
+    protected StringBuilder debugLog;
+    protected Function<String, String> stringSubstitutionStrategy = Function.identity();
+    protected Cfg configuration;
+    protected Node node;
+
+    @Override
+    public ConfigurationInjector<Ann, Cfg> withAnnotation(final Ann annotation) {
+        this.annotation = Objects.requireNonNull(annotation);
+        return this;
+    }
+
+    @Override
+    public ConfigurationInjector<Ann, Cfg> withAnnotatedElement(final AnnotatedElement element) {
+        this.annotatedElement = Objects.requireNonNull(element);
+        withName(AnnotatedElementNameProvider.getName(element));
+        final PluginAliases aliases = element.getAnnotation(PluginAliases.class);
+        if (aliases != null) {
+            withAliases(aliases.value());
+        }
+        return this;
+    }
+
+    @Override
+    public ConfigurationInjector<Ann, Cfg> withConversionType(final Type type) {
+        this.conversionType = Objects.requireNonNull(type);
+        return this;
+    }
+
+    @Override
+    public ConfigurationInjector<Ann, Cfg> withName(final String name) {
+        this.name = Objects.requireNonNull(name);
+        return this;
+    }
+
+    @Override
+    public ConfigurationInjector<Ann, Cfg> withAliases(final String... aliases) {
+        this.aliases = Arrays.asList(aliases);
+        return this;
+    }
+
+    @Override
+    public ConfigurationInjector<Ann, Cfg> withConfigurationBinder(final ConfigurationBinder binder) {
+        this.configurationBinder = binder;
+        return this;
+    }
+
+    @Override
+    public ConfigurationInjector<Ann, Cfg> withDebugLog(final StringBuilder debugLog) {
+        this.debugLog = Objects.requireNonNull(debugLog);
+        return this;
+    }
+
+    @Override
+    public ConfigurationInjector<Ann, Cfg> withStringSubstitutionStrategy(final Function<String, String> strategy) {
+        this.stringSubstitutionStrategy = Objects.requireNonNull(strategy);
+        return this;
+    }
+
+    @Override
+    public ConfigurationInjector<Ann, Cfg> withConfiguration(final Cfg configuration) {
+        this.configuration = Objects.requireNonNull(configuration);
+        return this;
+    }
+
+    @Override
+    public ConfigurationInjector<Ann, Cfg> withNode(final Node node) {
+        this.node = Objects.requireNonNull(node);
+        return this;
+    }
+
+    protected Optional<String> findAndRemoveNodeAttribute() {
+        Objects.requireNonNull(node);
+        Objects.requireNonNull(name);
+        final Map<String, String> attributes = node.getAttributes();
+        for (final String key : attributes.keySet()) {
+            if (key.equalsIgnoreCase(name)) {
+                return Optional.ofNullable(attributes.remove(key));
+            }
+            for (final String alias : aliases) {
+                if (key.equalsIgnoreCase(alias)) {
+                    return Optional.ofNullable(attributes.remove(key));
+                }
+            }
+        }
+        return Optional.empty();
+    }
+
+}
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/AbstractPluginInjectionBuilder.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/AbstractPluginInjectionBuilder.java
deleted file mode 100644
index 569dcef..0000000
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/AbstractPluginInjectionBuilder.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache license, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the license for the specific language governing permissions and
- * limitations under the license.
- */
-
-package org.apache.logging.log4j.plugins.inject;
-
-import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.plugins.Node;
-import org.apache.logging.log4j.plugins.convert.TypeConverters;
-import org.apache.logging.log4j.status.StatusLogger;
-import org.apache.logging.log4j.util.Strings;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Member;
-import java.util.Map;
-import java.util.Objects;
-import java.util.function.Function;
-
-/**
- * Base class for InjectionStrategyBuilder implementations. Provides fields and setters for the builder leaving only
- * {@link PluginInjectionBuilder#build()} to be implemented.
- *
- * @param <Ann> the Plugin annotation type.
- */
-public abstract class AbstractPluginInjectionBuilder<Ann extends Annotation, Cfg> implements PluginInjectionBuilder<Ann, Cfg> {
-
-    /** Status logger. */
-    protected static final Logger LOGGER = StatusLogger.getLogger();
-
-    /**
-     * 
-     */
-    protected final Class<Ann> clazz;
-    /**
-     * 
-     */
-    protected Ann annotation;
-    /**
-     * 
-     */
-    protected String[] aliases;
-    /**
-     * 
-     */
-    protected Class<?> conversionType;
-    /**
-     * 
-     */
-    protected Member member;
-
-    protected Cfg configuration;
-
-    protected Node node;
-
-    protected Function<String, String> stringSubstitutionStrategy;
-
-    protected StringBuilder debugLog;
-
-    /**
-     * This constructor must be overridden by implementation classes as a no-arg constructor.
-     *
-     * @param clazz the annotation class this PluginVisitor is for.
-     */
-    protected AbstractPluginInjectionBuilder(final Class<Ann> clazz) {
-        this.clazz = clazz;
-    }
-
-    @Override
-    public PluginInjectionBuilder<Ann, Cfg> withAnnotation(final Annotation anAnnotation) {
-        final Annotation a = Objects.requireNonNull(anAnnotation, "No annotation was provided");
-        if (this.clazz.isInstance(a)) {
-            this.annotation = clazz.cast(a);
-        }
-        return this;
-    }
-
-    @Override
-    public PluginInjectionBuilder<Ann, Cfg> withAliases(final String... someAliases) {
-        this.aliases = someAliases;
-        return this;
-    }
-
-    @Override
-    public PluginInjectionBuilder<Ann, Cfg> withConversionType(final Class<?> aConversionType) {
-        this.conversionType = Objects.requireNonNull(aConversionType, "No conversion type class was provided");
-        return this;
-    }
-
-    @Override
-    public PluginInjectionBuilder<Ann, Cfg> withMember(final Member aMember) {
-        this.member = aMember;
-        return this;
-    }
-
-    @Override
-    public PluginInjectionBuilder<Ann, Cfg> withConfiguration(final Cfg aConfiguration) {
-        this.configuration = aConfiguration;
-        return this;
-    }
-
-    @Override
-    public PluginInjectionBuilder<Ann, Cfg> withStringSubstitutionStrategy(final Function<String, String> aStringSubstitutionStrategy) {
-        this.stringSubstitutionStrategy = aStringSubstitutionStrategy;
-        return this;
-    }
-
-    @Override
-    public PluginInjectionBuilder<Ann, Cfg> withDebugLog(final StringBuilder aDebugLog) {
-        this.debugLog = aDebugLog;
-        return this;
-    }
-
-    @Override
-    public PluginInjectionBuilder<Ann, Cfg> withConfigurationNode(final Node aNode) {
-        this.node = aNode;
-        return this;
-    }
-
-    /**
-     * Removes an Entry from a given Map using a key name and aliases for that key. Keys are case-insensitive.
-     *
-     * @param attributes the Map to remove an Entry from.
-     * @param name       the key name to look up.
-     * @param aliases    optional aliases of the key name to look up.
-     * @return the value corresponding to the given key or {@code null} if nonexistent.
-     */
-    protected static String removeAttributeValue(final Map<String, String> attributes,
-                                                 final String name,
-                                                 final String... aliases) {
-        for (final Map.Entry<String, String> entry : attributes.entrySet()) {
-            final String key = entry.getKey();
-            final String value = entry.getValue();
-            if (key.equalsIgnoreCase(name)) {
-                attributes.remove(key);
-                return value;
-            }
-            if (aliases != null) {
-                for (final String alias : aliases) {
-                    if (key.equalsIgnoreCase(alias)) {
-                        attributes.remove(key);
-                        return value;
-                    }
-                }
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Converts the given value into the configured type falling back to the provided default value.
-     *
-     * @param value        the value to convert.
-     * @param defaultValue the fallback value to use in case of no value or an error.
-     * @return the converted value whether that be based on the given value or the default value.
-     */
-    protected Object convert(final String value, final Object defaultValue) {
-        if (defaultValue instanceof String) {
-            return TypeConverters.convert(value, this.conversionType, Strings.trimToNull((String) defaultValue));
-        }
-        return TypeConverters.convert(value, this.conversionType, defaultValue);
-    }
-}
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/ConfigurationInjector.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/ConfigurationInjector.java
new file mode 100644
index 0000000..f0db24d
--- /dev/null
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/ConfigurationInjector.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+
+package org.apache.logging.log4j.plugins.inject;
+
+import org.apache.logging.log4j.plugins.Node;
+import org.apache.logging.log4j.plugins.bind.ConfigurationBinder;
+import org.apache.logging.log4j.util.ReflectionUtil;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Type;
+import java.util.Optional;
+import java.util.function.Function;
+
+/**
+ * Strategy builder for injecting configuration data into an {@link AnnotatedElement}. Configuration injection consists
+ * of {@linkplain ConfigurationBinder binding} a {@link Node} and configuration to an annotated element of a
+ * {@linkplain org.apache.logging.log4j.plugins.PluginFactory plugin factory}.
+ *
+ * @param <Ann> plugin annotation this injector uses
+ * @param <Cfg> configuration class
+ */
+public interface ConfigurationInjector<Ann extends Annotation, Cfg> {
+
+    static <Cfg> Optional<ConfigurationInjector<Annotation, Cfg>> forAnnotatedElement(final AnnotatedElement element) {
+        for (final Annotation annotation : element.getAnnotations()) {
+            final InjectorStrategy strategy = annotation.annotationType().getAnnotation(InjectorStrategy.class);
+            if (strategy != null) {
+                @SuppressWarnings("unchecked") final ConfigurationInjector<Annotation, Cfg> injector =
+                        (ConfigurationInjector<Annotation, Cfg>) ReflectionUtil.instantiate(strategy.value());
+                return Optional.of(injector.withAnnotatedElement(element).withAnnotation(annotation));
+            }
+        }
+        return Optional.empty();
+    }
+
+    ConfigurationInjector<Ann, Cfg> withAnnotation(final Ann annotation);
+
+    ConfigurationInjector<Ann, Cfg> withAnnotatedElement(final AnnotatedElement element);
+
+    ConfigurationInjector<Ann, Cfg> withConversionType(final Type type);
+
+    ConfigurationInjector<Ann, Cfg> withName(final String name);
+
+    ConfigurationInjector<Ann, Cfg> withAliases(final String... aliases);
+
+    ConfigurationInjector<Ann, Cfg> withConfigurationBinder(final ConfigurationBinder binder);
+
+    ConfigurationInjector<Ann, Cfg> withDebugLog(final StringBuilder debugLog);
+
+    ConfigurationInjector<Ann, Cfg> withStringSubstitutionStrategy(final Function<String, String> strategy);
+
+    ConfigurationInjector<Ann, Cfg> withConfiguration(final Cfg configuration);
+
+    ConfigurationInjector<Ann, Cfg> withNode(final Node node);
+
+    void inject(final Object factory);
+}
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/InjectionStrategy.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/InjectionStrategy.java
deleted file mode 100644
index ac3c633..0000000
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/InjectionStrategy.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache license, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the license for the specific language governing permissions and
- * limitations under the license.
- */
-
-package org.apache.logging.log4j.plugins.inject;
-
-import java.lang.annotation.Annotation;
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Meta-annotation to denote the class name to use that implements
- * {@link PluginInjectionBuilder} for the annotated annotation.
- */
-@Documented
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.ANNOTATION_TYPE)
-public @interface InjectionStrategy {
-
-    /**
-     * The class to use that implements {@link PluginInjectionBuilder}
-     * for the given annotation. The generic annotation type in {@code PluginInjectionBuilder} should match the
-     * annotation this annotation is applied to.
-     */
-    Class<? extends PluginInjectionBuilder<? extends Annotation, ?>> value();
-}
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderFactory.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/InjectorStrategy.java
similarity index 76%
copy from log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderFactory.java
copy to log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/InjectorStrategy.java
index 4d15caa..66d9507 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderFactory.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/InjectorStrategy.java
@@ -15,21 +15,19 @@
  * limitations under the license.
  */
 
-package org.apache.logging.log4j.plugins;
+package org.apache.logging.log4j.plugins.inject;
 
+import java.lang.annotation.Annotation;
 import java.lang.annotation.Documented;
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
-/**
- * Marks a method as a factory for custom Plugin builders.
- */
 @Documented
 @Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.METHOD)
-// TODO: this can be combined with @PluginFactory as differentiating them by method signature is obvious
-public @interface PluginBuilderFactory {
-    // empty
+@Target(ElementType.ANNOTATION_TYPE)
+// TODO: annotation processor to validate type matches (help avoid runtime errors)
+public @interface InjectorStrategy {
+    Class<? extends ConfigurationInjector<? extends Annotation, ?>> value();
 }
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginAttributeBuilder.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginAttributeBuilder.java
deleted file mode 100644
index 23566dd..0000000
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginAttributeBuilder.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache license, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the license for the specific language governing permissions and
- * limitations under the license.
- */
-
-package org.apache.logging.log4j.plugins.inject;
-
-import org.apache.logging.log4j.plugins.PluginAttribute;
-import org.apache.logging.log4j.util.NameUtil;
-import org.apache.logging.log4j.util.StringBuilders;
-
-import java.util.Map;
-import java.util.function.Function;
-
-/**
- * PluginInjectionBuilder implementation for {@link PluginAttribute}.
- */
-public class PluginAttributeBuilder extends AbstractPluginInjectionBuilder<PluginAttribute, Object> {
-    public PluginAttributeBuilder() {
-        super(PluginAttribute.class);
-    }
-
-    @Override
-    public Object build() {
-        final String name = this.annotation.value();
-        final Map<String, String> attributes = node.getAttributes();
-        final String rawValue = removeAttributeValue(attributes, name, this.aliases);
-        final String replacedValue = stringSubstitutionStrategy.apply(rawValue);
-        final Object defaultValue = findDefaultValue(stringSubstitutionStrategy);
-        final Object value = convert(replacedValue, defaultValue);
-        final Object debugValue = this.annotation.sensitive() ? NameUtil.md5(value + this.getClass().getName()) : value;
-        StringBuilders.appendKeyDqValue(debugLog, name, debugValue);
-        return value;
-    }
-
-    private Object findDefaultValue(Function<String, String> substitutor) {
-        if (this.conversionType == int.class || this.conversionType == Integer.class) {
-            return this.annotation.defaultInt();
-        }
-        if (this.conversionType == long.class || this.conversionType == Long.class) {
-            return this.annotation.defaultLong();
-        }
-        if (this.conversionType == boolean.class || this.conversionType == Boolean.class) {
-            return this.annotation.defaultBoolean();
-        }
-        if (this.conversionType == float.class || this.conversionType == Float.class) {
-            return this.annotation.defaultFloat();
-        }
-        if (this.conversionType == double.class || this.conversionType == Double.class) {
-            return this.annotation.defaultDouble();
-        }
-        if (this.conversionType == byte.class || this.conversionType == Byte.class) {
-            return this.annotation.defaultByte();
-        }
-        if (this.conversionType == char.class || this.conversionType == Character.class) {
-            return this.annotation.defaultChar();
-        }
-        if (this.conversionType == short.class || this.conversionType == Short.class) {
-            return this.annotation.defaultShort();
-        }
-        if (this.conversionType == Class.class) {
-            return this.annotation.defaultClass();
-        }
-        return substitutor.apply(this.annotation.defaultString());
-    }
-}
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginAttributeInjector.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginAttributeInjector.java
new file mode 100644
index 0000000..af1144f
--- /dev/null
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginAttributeInjector.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+
+package org.apache.logging.log4j.plugins.inject;
+
+import org.apache.logging.log4j.plugins.PluginAttribute;
+import org.apache.logging.log4j.util.NameUtil;
+import org.apache.logging.log4j.util.StringBuilders;
+import org.apache.logging.log4j.util.Strings;
+
+import java.lang.reflect.Type;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
+
+public class PluginAttributeInjector extends AbstractConfigurationInjector<PluginAttribute, Object> {
+
+    private static final Map<Type, Function<PluginAttribute, Object>> DEFAULT_VALUE_EXTRACTORS;
+
+    static {
+        final Map<Class<?>, Function<PluginAttribute, Object>> extractors = new ConcurrentHashMap<>();
+        extractors.put(int.class, PluginAttribute::defaultInt);
+        extractors.put(Integer.class, PluginAttribute::defaultInt);
+        extractors.put(long.class, PluginAttribute::defaultLong);
+        extractors.put(Long.class, PluginAttribute::defaultLong);
+        extractors.put(boolean.class, PluginAttribute::defaultBoolean);
+        extractors.put(Boolean.class, PluginAttribute::defaultBoolean);
+        extractors.put(float.class, PluginAttribute::defaultFloat);
+        extractors.put(Float.class, PluginAttribute::defaultFloat);
+        extractors.put(double.class, PluginAttribute::defaultDouble);
+        extractors.put(Double.class, PluginAttribute::defaultDouble);
+        extractors.put(byte.class, PluginAttribute::defaultByte);
+        extractors.put(Byte.class, PluginAttribute::defaultByte);
+        extractors.put(char.class, PluginAttribute::defaultChar);
+        extractors.put(Character.class, PluginAttribute::defaultChar);
+        extractors.put(short.class, PluginAttribute::defaultShort);
+        extractors.put(Short.class, PluginAttribute::defaultShort);
+        extractors.put(Class.class, PluginAttribute::defaultClass);
+        DEFAULT_VALUE_EXTRACTORS = Collections.unmodifiableMap(extractors);
+    }
+
+    @Override
+    public void inject(final Object factory) {
+        final Optional<String> value = findAndRemoveNodeAttribute().map(stringSubstitutionStrategy);
+        if (value.isPresent()) {
+            configurationBinder.bindString(factory, value.get());
+        } else {
+            injectDefaultValue(factory);
+        }
+    }
+
+    private void injectDefaultValue(final Object factory) {
+        final Function<PluginAttribute, Object> extractor = DEFAULT_VALUE_EXTRACTORS.get(conversionType);
+        if (extractor != null) {
+            final Object value = extractor.apply(annotation);
+            debugLog(value);
+            configurationBinder.bindObject(factory, value);
+        } else {
+            final String value = stringSubstitutionStrategy.apply(annotation.defaultString());
+            if (Strings.isNotBlank(value)) {
+                debugLog(value);
+                configurationBinder.bindString(factory, value);
+            }
+        }
+    }
+
+    private void debugLog(final Object value) {
+        final Object debugValue = annotation.sensitive() ? NameUtil.md5(value + getClass().getName()) : value;
+        StringBuilders.appendKeyDqValue(debugLog, name, debugValue);
+    }
+
+}
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginBuilderAttributeBuilder.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginBuilderAttributeBuilder.java
deleted file mode 100644
index 28e6843..0000000
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginBuilderAttributeBuilder.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache license, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the license for the specific language governing permissions and
- * limitations under the license.
- */
-
-package org.apache.logging.log4j.plugins.inject;
-
-import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.util.NameUtil;
-import org.apache.logging.log4j.util.StringBuilders;
-
-import java.util.Map;
-
-/**
- * PluginInjectionBuilder for PluginBuilderAttribute. If {@code null} is returned for the
- * {@link PluginInjectionBuilder#build()}}
- * method, then the default value of the field should remain untouched.
- */
-public class PluginBuilderAttributeBuilder extends AbstractPluginInjectionBuilder<PluginBuilderAttribute, Object> {
-
-    public PluginBuilderAttributeBuilder() {
-        super(PluginBuilderAttribute.class);
-    }
-
-    @Override
-    public Object build() {
-        final String overridden = this.annotation.value();
-        final String name = overridden.isEmpty() ? this.member.getName() : overridden;
-        final Map<String, String> attributes = node.getAttributes();
-        final String rawValue = removeAttributeValue(attributes, name, this.aliases);
-        final String replacedValue = stringSubstitutionStrategy.apply(rawValue);
-        final Object value = convert(replacedValue, null);
-        final Object debugValue = this.annotation.sensitive() ? NameUtil.md5(value + this.getClass().getName()) : value;
-        StringBuilders.appendKeyDqValue(debugLog, name, debugValue);
-        return value;
-    }
-}
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginBuilderAttributeInjector.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginBuilderAttributeInjector.java
new file mode 100644
index 0000000..f1d734d
--- /dev/null
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginBuilderAttributeInjector.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+
+package org.apache.logging.log4j.plugins.inject;
+
+import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
+import org.apache.logging.log4j.util.NameUtil;
+import org.apache.logging.log4j.util.StringBuilders;
+
+import java.util.Optional;
+
+public class PluginBuilderAttributeInjector extends AbstractConfigurationInjector<PluginBuilderAttribute, Object> {
+    @Override
+    public void inject(final Object factory) {
+        final Optional<String> value = findAndRemoveNodeAttribute().map(stringSubstitutionStrategy);
+        if (value.isPresent()) {
+            final String str = value.get();
+            debugLog(str);
+            configurationBinder.bindString(factory, str);
+        } else {
+            debugLog.append(name).append("=null");
+            configurationBinder.bindObject(factory, null);
+        }
+    }
+
+    private void debugLog(final Object value) {
+        final Object debugValue = annotation.sensitive() ? NameUtil.md5(value + getClass().getName()) : value;
+        StringBuilders.appendKeyDqValue(debugLog, name, debugValue);
+    }
+}
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginElementBuilder.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginElementBuilder.java
deleted file mode 100644
index 7f3939a..0000000
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginElementBuilder.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache license, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the license for the specific language governing permissions and
- * limitations under the license.
- */
-
-package org.apache.logging.log4j.plugins.inject;
-
-import org.apache.logging.log4j.plugins.Node;
-import org.apache.logging.log4j.plugins.PluginElement;
-import org.apache.logging.log4j.plugins.util.PluginType;
-
-import java.lang.reflect.Array;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-
-/**
- * PluginInjectionBuilder implementation for {@link PluginElement}. Supports arrays as well as singular values.
- */
-public class PluginElementBuilder extends AbstractPluginInjectionBuilder<PluginElement, Object> {
-    public PluginElementBuilder() {
-        super(PluginElement.class);
-    }
-
-    @Override
-    public Object build() {
-        final String name = this.annotation.value();
-        if (this.conversionType.isArray()) {
-            withConversionType(this.conversionType.getComponentType());
-            final List<Object> values = new ArrayList<>();
-            final Collection<Node> used = new ArrayList<>();
-            debugLog.append("={");
-            boolean first = true;
-            for (final Node child : node.getChildren()) {
-                final PluginType<?> childType = child.getType();
-                if (name.equalsIgnoreCase(childType.getElementName()) ||
-                    this.conversionType.isAssignableFrom(childType.getPluginClass())) {
-                    if (!first) {
-                        debugLog.append(", ");
-                    }
-                    first = false;
-                    used.add(child);
-                    final Object childObject = child.getObject();
-                    if (childObject == null) {
-                        LOGGER.error("Null object returned for {} in {}.", child.getName(), node.getName());
-                        continue;
-                    }
-                    if (childObject.getClass().isArray()) {
-                        debugLog.append(Arrays.toString((Object[]) childObject)).append('}');
-                        node.getChildren().removeAll(used);
-                        return childObject;
-                    }
-                    debugLog.append(child.toString());
-                    values.add(childObject);
-                }
-            }
-            debugLog.append('}');
-            // note that we need to return an empty array instead of null if the types are correct
-            if (!values.isEmpty() && !this.conversionType.isAssignableFrom(values.get(0).getClass())) {
-                LOGGER.error("Attempted to assign attribute {} to list of type {} which is incompatible with {}.",
-                    name, values.get(0).getClass(), this.conversionType);
-                return null;
-            }
-            node.getChildren().removeAll(used);
-            // we need to use reflection here because values.toArray() will cause type errors at runtime
-            final Object[] array = (Object[]) Array.newInstance(this.conversionType, values.size());
-            for (int i = 0; i < array.length; i++) {
-                array[i] = values.get(i);
-            }
-            return array;
-        }
-        final Node namedNode = findNamedNode(name, node.getChildren());
-        if (namedNode == null) {
-            debugLog.append(name).append("=null");
-            return null;
-        }
-        debugLog.append(namedNode.getName()).append('(').append(namedNode.toString()).append(')');
-        node.getChildren().remove(namedNode);
-        return namedNode.getObject();
-    }
-
-    private Node findNamedNode(final String name, final Iterable<Node> children) {
-        for (final Node child : children) {
-            final PluginType<?> childType = child.getType();
-            if (childType == null) {
-                //System.out.println();
-            }
-            if (name.equalsIgnoreCase(childType.getElementName()) ||
-                this.conversionType.isAssignableFrom(childType.getPluginClass())) {
-                // FIXME: check child.getObject() for null?
-                // doing so would be more consistent with the array version
-                return child;
-            }
-        }
-        return null;
-    }
-}
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginElementInjector.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginElementInjector.java
new file mode 100644
index 0000000..21c74be
--- /dev/null
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginElementInjector.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+
+package org.apache.logging.log4j.plugins.inject;
+
+import org.apache.logging.log4j.plugins.Node;
+import org.apache.logging.log4j.plugins.PluginElement;
+import org.apache.logging.log4j.plugins.util.PluginType;
+import org.apache.logging.log4j.plugins.util.TypeUtil;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+
+public class PluginElementInjector extends AbstractConfigurationInjector<PluginElement, Object> {
+    @Override
+    public void inject(final Object factory) {
+        final Optional<Class<?>> componentType = getComponentType(conversionType);
+        if (componentType.isPresent()) {
+            final Class<?> compType = componentType.get();
+            final List<Object> values = new ArrayList<>();
+            final Collection<Node> used = new ArrayList<>();
+            debugLog.append("={");
+            boolean first = true;
+            for (final Node child : node.getChildren()) {
+                final PluginType<?> type = child.getType();
+                if (name.equalsIgnoreCase(type.getElementName()) || compType.isAssignableFrom(type.getPluginClass())) {
+                    if (!first) {
+                        debugLog.append(", ");
+                    }
+                    first = false;
+                    used.add(child);
+                    final Object childObject = child.getObject();
+                    if (childObject == null) {
+                        LOGGER.warn("Skipping null object returned for element {} in node {}", child.getName(), node.getName());
+                    } else if (childObject.getClass().isArray()) {
+                        Object[] children = (Object[]) childObject;
+                        debugLog.append(Arrays.toString(children)).append('}');
+                        node.getChildren().removeAll(used);
+                        configurationBinder.bindObject(factory, children);
+                        return;
+                    } else {
+                        debugLog.append(child.toString());
+                        values.add(childObject);
+                    }
+                }
+            }
+            debugLog.append('}');
+            if (!values.isEmpty() && !TypeUtil.isAssignable(compType, values.get(0).getClass())) {
+                LOGGER.error("Cannot assign element {} a list of {} as it is incompatible with {}", name, values.get(0).getClass(), compType);
+                return;
+            }
+            node.getChildren().removeAll(used);
+            // using List::toArray here would cause type mismatch later on
+            final Object[] vals = (Object[]) Array.newInstance(compType, values.size());
+            for (int i = 0; i < vals.length; i++) {
+                vals[i] = values.get(i);
+            }
+            configurationBinder.bindObject(factory, vals);
+        } else {
+            final Optional<Node> matchingChild = node.getChildren().stream().filter(this::isRequestedNode).findAny();
+            if (matchingChild.isPresent()) {
+                final Node child = matchingChild.get();
+                debugLog.append(child.getName()).append('(').append(child.toString()).append(')');
+                node.getChildren().remove(child);
+                configurationBinder.bindObject(factory, child.getObject());
+            } else {
+                debugLog.append(name).append("=null");
+                configurationBinder.bindObject(factory, null);
+            }
+        }
+    }
+
+    private boolean isRequestedNode(final Node child) {
+        final PluginType<?> type = child.getType();
+        return name.equalsIgnoreCase(type.getElementName()) || TypeUtil.isAssignable(conversionType, type.getPluginClass());
+    }
+
+    private static Optional<Class<?>> getComponentType(final Type type) {
+        if (type instanceof Class<?>) {
+            final Class<?> clazz = (Class<?>) type;
+            if (clazz.isArray()) {
+                return Optional.of(clazz.getComponentType());
+            }
+        }
+        return Optional.empty();
+    }
+}
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginInjectionBuilder.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginInjectionBuilder.java
deleted file mode 100644
index 6dadc77..0000000
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginInjectionBuilder.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache license, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the license for the specific language governing permissions and
- * limitations under the license.
- */
-
-package org.apache.logging.log4j.plugins.inject;
-
-import org.apache.logging.log4j.plugins.Node;
-import org.apache.logging.log4j.plugins.util.Builder;
-import org.apache.logging.log4j.status.StatusLogger;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Member;
-import java.util.Optional;
-import java.util.function.Function;
-
-/**
- * Builder strategy for parsing and injecting a configuration node. Implementations should contain a default constructor
- * and must provide a {@link #build()} implementation. This provides type conversion based on the injection point via
- * {@link org.apache.logging.log4j.plugins.convert.TypeConverters}.
- *
- * @param <Ann> the Annotation type.
- * @param <Cfg> the Configuration type.
- */
-public interface PluginInjectionBuilder<Ann extends Annotation, Cfg> extends Builder<Object> {
-
-    /**
-     * Creates a PluginInjectionBuilder instance for the given annotation class using metadata provided by the annotation's
-     * {@link InjectionStrategy} annotation. This instance must be further populated with
-     * data before being {@linkplain #build() built} to be useful.
-     *
-     * @param injectorType the Plugin annotation class to find a PluginInjectionBuilder for.
-     * @return a PluginInjectionBuilder instance if one could be created or empty.
-     */
-    @SuppressWarnings("unchecked")
-    static <Ann extends Annotation, Cfg> Optional<PluginInjectionBuilder<Ann, Cfg>> findBuilderForInjectionStrategy(final Class<Ann> injectorType) {
-        return Optional.ofNullable(injectorType.getAnnotation(InjectionStrategy.class))
-                .flatMap(type -> {
-                    try {
-                        return Optional.of((PluginInjectionBuilder<Ann, Cfg>) type.value().newInstance());
-                    } catch (final Exception e) {
-                        StatusLogger.getLogger().error("Error loading PluginBuilder [{}] for annotation [{}].", type.value(), injectorType, e);
-                        return Optional.empty();
-                    }
-                });
-    }
-
-    /**
-     * Sets the Annotation to be used for this. If the given Annotation is not compatible with this class's type, then
-     * it is ignored.
-     *
-     * @param annotation the Annotation instance.
-     * @return {@code this}.
-     * @throws NullPointerException if the argument is {@code null}.
-     */
-    PluginInjectionBuilder<Ann, Cfg> withAnnotation(Annotation annotation);
-
-    /**
-     * Sets the list of aliases to use for this injection. No aliases are required, however.
-     *
-     * @param aliases the list of aliases to use.
-     * @return {@code this}.
-     */
-    PluginInjectionBuilder<Ann, Cfg> withAliases(String... aliases);
-
-    /**
-     * Sets the class to convert the plugin value to for injection. This should correspond with a class obtained from
-     * a factory method or builder class field. Not all PluginInjectionBuilder implementations may need this value.
-     *
-     * @param conversionType the type to convert the plugin string to (if applicable).
-     * @return {@code this}.
-     * @throws NullPointerException if the argument is {@code null}.
-     */
-    PluginInjectionBuilder<Ann, Cfg> withConversionType(Class<?> conversionType);
-
-    /**
-     * Sets the Member that this builder is being used for injection upon. For instance, this could be the Field
-     * that is being used for injecting a value, or it could be the factory method being used to inject parameters
-     * into.
-     *
-     * @param member the member this builder is parsing a value for.
-     * @return {@code this}.
-     */
-    PluginInjectionBuilder<Ann, Cfg> withMember(Member member);
-
-    PluginInjectionBuilder<Ann, Cfg> withStringSubstitutionStrategy(Function<String, String> stringSubstitutionStrategy);
-
-    PluginInjectionBuilder<Ann, Cfg> withDebugLog(StringBuilder debugLog);
-
-    PluginInjectionBuilder<Ann, Cfg> withConfiguration(Cfg configuration);
-
-    PluginInjectionBuilder<Ann, Cfg> withConfigurationNode(Node node);
-}
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginNodeBuilder.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginNodeInjector.java
similarity index 67%
rename from log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginNodeBuilder.java
rename to log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginNodeInjector.java
index 3cf2189..23d19ff 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginNodeBuilder.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginNodeInjector.java
@@ -18,22 +18,16 @@
 package org.apache.logging.log4j.plugins.inject;
 
 import org.apache.logging.log4j.plugins.PluginNode;
+import org.apache.logging.log4j.plugins.util.TypeUtil;
 
-/**
- * PluginInjectionBuilder implementation for {@link PluginNode}.
- */
-public class PluginNodeBuilder extends AbstractPluginInjectionBuilder<PluginNode, Object> {
-    public PluginNodeBuilder() {
-        super(PluginNode.class);
-    }
-
+public class PluginNodeInjector extends AbstractConfigurationInjector<PluginNode, Object> {
     @Override
-    public Object build() {
-        if (this.conversionType.isInstance(node)) {
+    public void inject(final Object factory) {
+        if (TypeUtil.isAssignable(conversionType, node.getClass())) {
             debugLog.append("Node=").append(node.getName());
-            return node;
+            configurationBinder.bindObject(factory, node);
+        } else {
+            LOGGER.error("Element with type {} annotated with @PluginNode not compatible with type {}.", conversionType, node.getClass());
         }
-        LOGGER.warn("Variable annotated with @PluginNode is not compatible with the type {}.", node.getClass());
-        return null;
     }
 }
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginValueBuilder.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginValueInjector.java
similarity index 77%
rename from log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginValueBuilder.java
rename to log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginValueInjector.java
index a9e5f0e..8d4cade 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginValueBuilder.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginValueInjector.java
@@ -21,19 +21,11 @@
 import org.apache.logging.log4j.util.StringBuilders;
 import org.apache.logging.log4j.util.Strings;
 
-/**
- * PluginInjectionBuilder implementation for {@link PluginValue}.
- */
-public class PluginValueBuilder extends AbstractPluginInjectionBuilder<PluginValue, Object> {
-    public PluginValueBuilder() {
-        super(PluginValue.class);
-    }
-
+public class PluginValueInjector extends AbstractConfigurationInjector<PluginValue, Object> {
     @Override
-    public Object build() {
-        final String name = this.annotation.value();
+    public void inject(final Object factory) {
         final String elementValue = node.getValue();
-        final String attributeValue = node.getAttributes().get("value");
+        final String attributeValue = node.getAttributes().get(name);
         String rawValue = null; // if neither is specified, return null (LOG4J2-1313)
         if (Strings.isNotEmpty(elementValue)) {
             if (Strings.isNotEmpty(attributeValue)) {
@@ -43,10 +35,10 @@
             }
             rawValue = elementValue;
         } else {
-            rawValue = removeAttributeValue(node.getAttributes(), "value");
+            rawValue = findAndRemoveNodeAttribute().orElse(null);
         }
         final String value = stringSubstitutionStrategy.apply(rawValue);
         StringBuilders.appendKeyDqValue(debugLog, name, value);
-        return value;
+        configurationBinder.bindString(factory, value);
     }
 }
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/package-info.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/package-info.java
index a359ce0..a2afb2b 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/package-info.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/package-info.java
@@ -17,7 +17,7 @@
 
 /**
  * Injection builder classes for parsing data from a {@code Configuration} or {@link org.apache.logging.log4j.plugins.Node}
- * corresponding to an {@link org.apache.logging.log4j.plugins.inject.InjectionStrategy}-annotated annotation.
- * Injection strategies must implement {@link org.apache.logging.log4j.plugins.inject.PluginInjectionBuilder}.
+ * corresponding to an {@link org.apache.logging.log4j.plugins.inject.InjectorStrategy}-annotated annotation.
+ * Injection strategies must implement {@link org.apache.logging.log4j.plugins.inject.ConfigurationInjector}.
  */
 package org.apache.logging.log4j.plugins.inject;
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/name/AnnotatedElementNameProvider.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/name/AnnotatedElementNameProvider.java
new file mode 100644
index 0000000..34349d6
--- /dev/null
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/name/AnnotatedElementNameProvider.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+
+package org.apache.logging.log4j.plugins.name;
+
+import org.apache.logging.log4j.util.ReflectionUtil;
+
+import java.beans.Introspector;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.Optional;
+
+/**
+ * Extracts a specified name for some configurable annotated element. A specified name is one given in a non-empty
+ * string in an annotation as opposed to relying on the default name taken from the annotated element itself.
+ *
+ * @param <A> plugin configuration annotation
+ */
+public interface AnnotatedElementNameProvider<A extends Annotation> {
+
+    static String getName(final AnnotatedElement element) {
+        for (final Annotation annotation : element.getAnnotations()) {
+            final Optional<String> specifiedName = getSpecifiedNameForAnnotation(annotation);
+            if (specifiedName.isPresent()) {
+                return specifiedName.get();
+            }
+        }
+
+        if (element instanceof Field) {
+            return ((Field) element).getName();
+        }
+
+        if (element instanceof Method) {
+            final Method method = (Method) element;
+            final String methodName = method.getName();
+            if (methodName.startsWith("set")) {
+                return Introspector.decapitalize(methodName.substring(3));
+            }
+            if (methodName.startsWith("with")) {
+                return Introspector.decapitalize(methodName.substring(4));
+            }
+            return methodName;
+        }
+
+        if (element instanceof Parameter) {
+            return ((Parameter) element).getName();
+        }
+
+        throw new IllegalArgumentException("Unknown element type for naming: " + element.getClass());
+    }
+
+    static <A extends Annotation> Optional<String> getSpecifiedNameForAnnotation(final A annotation) {
+        return Optional.ofNullable(annotation.annotationType().getAnnotation(NameProvider.class))
+                .map(NameProvider::value)
+                .flatMap(clazz -> {
+                    @SuppressWarnings("unchecked") final AnnotatedElementNameProvider<A> factory =
+                            (AnnotatedElementNameProvider<A>) ReflectionUtil.instantiate(clazz);
+                    return factory.getSpecifiedName(annotation);
+                });
+    }
+
+    /**
+     * Returns the specified name from this annotation if given or {@code Optional.empty()} if none given.
+     *
+     * @param annotation annotation value of configuration element
+     * @return specified name of configuration element or empty if none specified
+     */
+    Optional<String> getSpecifiedName(final A annotation);
+}
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderFactory.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/name/NameProvider.java
similarity index 77%
rename from log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderFactory.java
rename to log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/name/NameProvider.java
index 4d15caa..ac9e643 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderFactory.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/name/NameProvider.java
@@ -15,21 +15,18 @@
  * limitations under the license.
  */
 
-package org.apache.logging.log4j.plugins;
+package org.apache.logging.log4j.plugins.name;
 
+import java.lang.annotation.Annotation;
 import java.lang.annotation.Documented;
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
-/**
- * Marks a method as a factory for custom Plugin builders.
- */
 @Documented
 @Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.METHOD)
-// TODO: this can be combined with @PluginFactory as differentiating them by method signature is obvious
-public @interface PluginBuilderFactory {
-    // empty
+@Target(ElementType.ANNOTATION_TYPE)
+public @interface NameProvider {
+    Class<? extends AnnotatedElementNameProvider<? extends Annotation>> value();
 }
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/name/PluginAttributeNameProvider.java
similarity index 64%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/name/PluginAttributeNameProvider.java
index 13aaf9c..3792a4d 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/name/PluginAttributeNameProvider.java
@@ -14,17 +14,17 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
 
-import org.junit.Test;
+package org.apache.logging.log4j.plugins.name;
 
-import static org.junit.Assert.*;
+import org.apache.logging.log4j.plugins.PluginAttribute;
+import org.apache.logging.log4j.util.Strings;
 
-public class ProcessIdUtilTest {
+import java.util.Optional;
 
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
+public class PluginAttributeNameProvider implements AnnotatedElementNameProvider<PluginAttribute> {
+    @Override
+    public Optional<String> getSpecifiedName(final PluginAttribute annotation) {
+        return Strings.trimToOptional(annotation.value());
     }
 }
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/name/PluginBuilderAttributeNameProvider.java
similarity index 63%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/name/PluginBuilderAttributeNameProvider.java
index 13aaf9c..0c32fe8 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/name/PluginBuilderAttributeNameProvider.java
@@ -14,17 +14,17 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
 
-import org.junit.Test;
+package org.apache.logging.log4j.plugins.name;
 
-import static org.junit.Assert.*;
+import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
+import org.apache.logging.log4j.util.Strings;
 
-public class ProcessIdUtilTest {
+import java.util.Optional;
 
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
+public class PluginBuilderAttributeNameProvider implements AnnotatedElementNameProvider<PluginBuilderAttribute> {
+    @Override
+    public Optional<String> getSpecifiedName(final PluginBuilderAttribute annotation) {
+        return Strings.trimToOptional(annotation.value());
     }
 }
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/name/PluginElementNameProvider.java
similarity index 65%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/name/PluginElementNameProvider.java
index 13aaf9c..53122fb 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/name/PluginElementNameProvider.java
@@ -14,17 +14,17 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
 
-import org.junit.Test;
+package org.apache.logging.log4j.plugins.name;
 
-import static org.junit.Assert.*;
+import org.apache.logging.log4j.plugins.PluginElement;
+import org.apache.logging.log4j.util.Strings;
 
-public class ProcessIdUtilTest {
+import java.util.Optional;
 
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
+public class PluginElementNameProvider implements AnnotatedElementNameProvider<PluginElement> {
+    @Override
+    public Optional<String> getSpecifiedName(final PluginElement annotation) {
+        return Strings.trimToOptional(annotation.value());
     }
 }
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/name/PluginValueNameProvider.java
similarity index 65%
copy from log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
copy to log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/name/PluginValueNameProvider.java
index 13aaf9c..536db27 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/name/PluginValueNameProvider.java
@@ -14,17 +14,17 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.util;
 
-import org.junit.Test;
+package org.apache.logging.log4j.plugins.name;
 
-import static org.junit.Assert.*;
+import org.apache.logging.log4j.plugins.PluginValue;
+import org.apache.logging.log4j.util.Strings;
 
-public class ProcessIdUtilTest {
+import java.util.Optional;
 
-    @Test
-    public void processIdTest() throws Exception {
-        String processId = ProcessIdUtil.getProcessId();
-        assertFalse("ProcessId is default", processId.equals(ProcessIdUtil.DEFAULT_PROCESSID));
+public class PluginValueNameProvider implements AnnotatedElementNameProvider<PluginValue> {
+    @Override
+    public Optional<String> getSpecifiedName(final PluginValue annotation) {
+        return Strings.trimToOptional(annotation.value());
     }
 }
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/package-info.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/package-info.java
index b161185..b515d96 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/package-info.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/package-info.java
@@ -17,5 +17,8 @@
 
 /**
  * Annotations for Log4j 2 plugins.
+ *
+ * @see org.apache.logging.log4j.plugins.Plugin
+ * @see org.apache.logging.log4j.plugins.PluginFactory
  */
 package org.apache.logging.log4j.plugins;
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/TypeUtil.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/TypeUtil.java
index e2bb462..6adf661 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/TypeUtil.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/TypeUtil.java
@@ -18,6 +18,7 @@
 
 import java.lang.reflect.*;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
 
@@ -49,9 +50,7 @@
     public static List<Field> getAllDeclaredFields(Class<?> cls) {
         final List<Field> fields = new ArrayList<>();
         while (cls != null) {
-            for (final Field field : cls.getDeclaredFields()) {
-                fields.add(field);
-            }
+            fields.addAll(Arrays.asList(cls.getDeclaredFields()));
             cls = cls.getSuperclass();
         }
         return fields;
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/Required.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/Required.java
index 9b8a75d..dd0efa8 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/Required.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/Required.java
@@ -29,7 +29,7 @@
  */
 @Documented
 @Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.FIELD, ElementType.PARAMETER})
+@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
 @Constraint(RequiredValidator.class)
 public @interface Required {
 
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/ValidHost.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/ValidHost.java
index 14dd9a8..6a31ef4 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/ValidHost.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/ValidHost.java
@@ -30,7 +30,7 @@
  */
 @Documented
 @Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.FIELD, ElementType.PARAMETER})
+@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
 @Constraint(ValidHostValidator.class)
 public @interface ValidHost {
 
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/ValidPort.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/ValidPort.java
index c4aba16..edb7e72 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/ValidPort.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/ValidPort.java
@@ -29,7 +29,7 @@
  */
 @Documented
 @Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.FIELD, ElementType.PARAMETER})
+@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
 @Constraint(ValidPortValidator.class)
 public @interface ValidPort {
 
diff --git a/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/HostAndPort.java b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/HostAndPort.java
index 626798e..335ea49 100644
--- a/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/HostAndPort.java
+++ b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/HostAndPort.java
@@ -39,8 +39,8 @@
 
     @PluginFactory
     public static HostAndPort createPlugin(
-        @ValidHost(message = "Unit test (host)") @PluginAttribute("host") final String host,
-        @ValidPort(message = "Unit test (port)") @PluginAttribute("port") final int port) {
+        @ValidHost(message = "Unit test (host)") @PluginAttribute final String host,
+        @ValidPort(message = "Unit test (port)") @PluginAttribute final int port) {
         return new HostAndPort(new InetSocketAddress(host, port));
     }
 
diff --git a/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/PluginWithGenericSubclassFoo1Builder.java b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/PluginWithGenericSubclassFoo1Builder.java
index c3fe6c5..0ae991a 100644
--- a/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/PluginWithGenericSubclassFoo1Builder.java
+++ b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/PluginWithGenericSubclassFoo1Builder.java
@@ -16,10 +16,10 @@
  */
 package org.apache.logging.log4j.plugins.validation;
 
-import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
-import org.apache.logging.log4j.plugins.validation.constraints.Required;
 import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.plugins.PluginAttribute;
+import org.apache.logging.log4j.plugins.PluginFactory;
+import org.apache.logging.log4j.plugins.validation.constraints.Required;
 
 @Plugin(name = "PluginWithGenericSubclassFoo1Builder", category = "Test")
 public class PluginWithGenericSubclassFoo1Builder extends AbstractPluginWithGenericBuilder {
@@ -27,12 +27,7 @@
     public static class Builder<B extends Builder<B>> extends AbstractPluginWithGenericBuilder.Builder<B>
             implements org.apache.logging.log4j.plugins.util.Builder<PluginWithGenericSubclassFoo1Builder> {
 
-        @PluginBuilderFactory
-        public static <B extends Builder<B>> B newBuilder() {
-            return new Builder<B>().asBuilder();
-        }
-
-        @PluginBuilderAttribute
+        @PluginAttribute
         @Required(message = "The foo1 given by the builder is null")
         private String foo1;
 
@@ -52,7 +47,7 @@
 
     }
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static <B extends Builder<B>> B newBuilder() {
         return new Builder<B>().asBuilder();
     }
diff --git a/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPlugin.java b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPlugin.java
index 9caf453..eda7145 100644
--- a/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPlugin.java
+++ b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPlugin.java
@@ -16,11 +16,10 @@
  */
 package org.apache.logging.log4j.plugins.validation;
 
+import org.apache.logging.log4j.plugins.Plugin;
 import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
 import org.apache.logging.log4j.plugins.PluginFactory;
 import org.apache.logging.log4j.plugins.validation.constraints.Required;
-import org.apache.logging.log4j.plugins.Plugin;
 
 import java.util.Objects;
 
@@ -46,7 +45,7 @@
         return new ValidatingPlugin(name);
     }
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static Builder newBuilder() {
         return new Builder();
     }
diff --git a/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPluginWithGenericBuilder.java b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPluginWithGenericBuilder.java
index b0bec53..eb9db3f 100644
--- a/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPluginWithGenericBuilder.java
+++ b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPluginWithGenericBuilder.java
@@ -17,9 +17,7 @@
 package org.apache.logging.log4j.plugins.validation;
 
 import org.apache.logging.log4j.plugins.Plugin;
-
-import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
+import org.apache.logging.log4j.plugins.PluginAttribute;
 import org.apache.logging.log4j.plugins.PluginFactory;
 import org.apache.logging.log4j.plugins.validation.constraints.Required;
 
@@ -42,19 +40,13 @@
     }
 
     @PluginFactory
-    public static ValidatingPluginWithGenericBuilder newValidatingPlugin(
-        @Required(message = "The name given by the factory is null") final String name) {
-        return new ValidatingPluginWithGenericBuilder(name);
-    }
-
-    @PluginBuilderFactory
     public static <B extends Builder<B>> B newBuilder() {
         return new Builder<B>().asBuilder();
     }
 
     public static class Builder<B extends Builder<B>> implements org.apache.logging.log4j.plugins.util.Builder<ValidatingPluginWithGenericBuilder> {
 
-        @PluginBuilderAttribute
+        @PluginAttribute
         @Required(message = "The name given by the builder is null")
         private String name;
 
diff --git a/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPluginWithTypedBuilder.java b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPluginWithTypedBuilder.java
index 256181c..fc736b3 100644
--- a/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPluginWithTypedBuilder.java
+++ b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPluginWithTypedBuilder.java
@@ -16,11 +16,10 @@
  */
 package org.apache.logging.log4j.plugins.validation;
 
+import org.apache.logging.log4j.plugins.Plugin;
 import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
 import org.apache.logging.log4j.plugins.PluginFactory;
 import org.apache.logging.log4j.plugins.validation.constraints.Required;
-import org.apache.logging.log4j.plugins.Plugin;
 
 import java.util.Objects;
 
@@ -46,7 +45,7 @@
         return new ValidatingPluginWithTypedBuilder(name);
     }
 
-    @PluginBuilderFactory
+    @PluginFactory
     public static Builder<Integer> newBuilder() {
         return new Builder<>();
     }
diff --git a/log4j-smtp/src/main/java/org/apache/logging/log4j/smtp/appender/SmtpAppender.java b/log4j-smtp/src/main/java/org/apache/logging/log4j/smtp/appender/SmtpAppender.java
index 5c52ae8..c7754da 100644
--- a/log4j-smtp/src/main/java/org/apache/logging/log4j/smtp/appender/SmtpAppender.java
+++ b/log4j-smtp/src/main/java/org/apache/logging/log4j/smtp/appender/SmtpAppender.java
@@ -113,22 +113,22 @@
     @PluginFactory
     public static SmtpAppender createAppender(
             @PluginConfiguration final Configuration config,
-            @PluginAttribute("name") @Required final String name,
-            @PluginAttribute("to") final String to,
-            @PluginAttribute("cc") final String cc,
-            @PluginAttribute("bcc") final String bcc,
-            @PluginAttribute("from") final String from,
-            @PluginAttribute("replyTo") final String replyTo,
-            @PluginAttribute("subject") final String subject,
-            @PluginAttribute("smtpProtocol") final String smtpProtocol,
-            @PluginAttribute("smtpHost") final String smtpHost,
+            @PluginAttribute @Required final String name,
+            @PluginAttribute final String to,
+            @PluginAttribute final String cc,
+            @PluginAttribute final String bcc,
+            @PluginAttribute final String from,
+            @PluginAttribute final String replyTo,
+            @PluginAttribute final String subject,
+            @PluginAttribute final String smtpProtocol,
+            @PluginAttribute final String smtpHost,
             @PluginAttribute(value = "smtpPort", defaultString = "0") @ValidPort final String smtpPortStr,
-            @PluginAttribute("smtpUsername") final String smtpUsername,
-            @PluginAttribute(value = "smtpPassword", sensitive = true) final String smtpPassword,
-            @PluginAttribute("smtpDebug") final String smtpDebug,
+            @PluginAttribute final String smtpUsername,
+            @PluginAttribute(sensitive = true) final String smtpPassword,
+            @PluginAttribute final String smtpDebug,
             @PluginAttribute("bufferSize") final String bufferSizeStr,
-            @PluginElement("Layout") Layout<? extends Serializable> layout,
-            @PluginElement("Filter") Filter filter,
+            @PluginElement Layout<? extends Serializable> layout,
+            @PluginElement Filter filter,
             @PluginAttribute("ignoreExceptions") final String ignore) {
         if (name == null) {
             LOGGER.error("No name provided for SmtpAppender");
diff --git a/log4j-smtp/src/site/manual/index.md b/log4j-smtp/src/site/manual/index.md
index 318d365..6443298 100644
--- a/log4j-smtp/src/site/manual/index.md
+++ b/log4j-smtp/src/site/manual/index.md
@@ -18,7 +18,7 @@
 
 # Apache Log4j Simple Mail Transfer Protocol module
 
-As of Log4j 2.11.0, Simple Mail Transfer Protocol (SMTP) support has moved from the existing module logj-core to the new module log4j-smtp.
+As of Log4j 2.11.0, Simple Mail Transfer Protocol (SMTP) support has moved from the existing module log4j-core to the new module log4j-smtp.
 
 ## Requirements
 
diff --git a/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/Log4j2CloudConfigLoggingSystem.java b/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/Log4j2CloudConfigLoggingSystem.java
index 459be37..8da5bec 100644
--- a/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/Log4j2CloudConfigLoggingSystem.java
+++ b/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/Log4j2CloudConfigLoggingSystem.java
@@ -16,6 +16,7 @@
  */
 package org.apache.logging.log4j.spring.cloud.config.client;
 
+import javax.net.ssl.HttpsURLConnection;
 import java.io.File;
 import java.io.IOException;
 import java.net.URISyntaxException;
@@ -24,10 +25,8 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.Properties;
-import javax.net.ssl.HttpsURLConnection;
 
 import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.config.ConfigurationFactory;
 import org.apache.logging.log4j.core.config.ConfigurationSource;
@@ -36,28 +35,39 @@
 import org.apache.logging.log4j.core.net.ssl.SslConfigurationFactory;
 import org.apache.logging.log4j.core.util.AuthorizationProvider;
 import org.apache.logging.log4j.core.util.FileUtils;
-import org.apache.logging.log4j.status.StatusLogger;
 import org.apache.logging.log4j.util.PropertiesUtil;
 import org.springframework.boot.logging.LogFile;
 import org.springframework.boot.logging.LoggingInitializationContext;
 import org.springframework.boot.logging.log4j2.Log4J2LoggingSystem;
-import org.springframework.core.io.ClassPathResource;
 import org.springframework.util.Assert;
 import org.springframework.util.ClassUtils;
 import org.springframework.util.ResourceUtils;
 
 /**
- *
+ * Override Spring's implementation of the Log4j 2 Logging System to properly support Spring Cloud Config.
  */
 public class Log4j2CloudConfigLoggingSystem extends Log4J2LoggingSystem {
-    private static final String FILE_PROTOCOL = "file";
     private static final String HTTPS = "https";
-    private Logger LOGGER = StatusLogger.getLogger();
+    public static final String ENVIRONMENT_KEY = "SpringEnvironment";
 
     public Log4j2CloudConfigLoggingSystem(ClassLoader loader) {
         super(loader);
     }
 
+    /**
+     * Set the environment into the ExternalContext field so that it can be obtained by SpringLookup when it
+     * is constructed. Spring will replace the ExternalContext field with a String once initialization is
+     * complete.
+     * @param initializationContext The initialization context.
+     * @param configLocation The configuration location.
+     * @param logFile the log file.
+     */
+    @Override
+    public void initialize(LoggingInitializationContext initializationContext, String configLocation, LogFile logFile) {
+        getLoggerContext().putObjectIfAbsent(ENVIRONMENT_KEY, initializationContext.getEnvironment());
+        super.initialize(initializationContext, configLocation, logFile);
+    }
+
     @Override
     protected String[] getStandardConfigLocations() {
         String[] locations = super.getStandardConfigLocations();
@@ -66,7 +76,7 @@
         if (location != null) {
             List<String> list = Arrays.asList(super.getStandardConfigLocations());
             list.add(location);
-            locations = list.toArray(new String[list.size()]);
+            locations = list.toArray(new String[0]);
         }
         return locations;
     }
@@ -103,12 +113,16 @@
         }
     }
 
+    @Override
+    public void cleanUp() {
+        getLoggerContext().removeObject(ENVIRONMENT_KEY);
+        super.cleanUp();
+    }
+
     private ConfigurationSource getConfigurationSource(URL url) throws IOException, URISyntaxException {
         URLConnection urlConnection = url.openConnection();
-        AuthorizationProvider provider = ConfigurationFactory.getAuthorizationProvider();
-        if (provider != null) {
-            provider.addAuthorization(urlConnection);
-        }
+        AuthorizationProvider provider = ConfigurationFactory.authorizationProvider(PropertiesUtil.getProperties());
+        provider.addAuthorization(urlConnection);
         if (url.getProtocol().equals(HTTPS)) {
             SslConfiguration sslConfiguration = SslConfigurationFactory.getSslConfiguration();
             if (sslConfiguration != null) {
diff --git a/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/Log4j2EventListener.java b/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/Log4j2EventListener.java
index 96812d2..eb21607 100644
--- a/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/Log4j2EventListener.java
+++ b/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/Log4j2EventListener.java
@@ -19,7 +19,6 @@
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-
 import org.springframework.cloud.bus.ConditionalOnBusEnabled;
 import org.springframework.cloud.bus.SpringCloudBusClient;
 import org.springframework.cloud.bus.event.RemoteApplicationEvent;
diff --git a/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/SpringEnvironmentHolder.java b/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/SpringEnvironmentHolder.java
new file mode 100644
index 0000000..c633e8a
--- /dev/null
+++ b/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/SpringEnvironmentHolder.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.spring.cloud.config.client;
+
+import org.apache.logging.log4j.LogManager;
+import org.springframework.core.env.Environment;
+
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * Provides access to the Spring Environment.
+ */
+public class SpringEnvironmentHolder {
+
+    private volatile Environment environment;
+    private Lock lock = new ReentrantLock();
+
+
+    protected Environment getEnvironment() {
+        if (environment == null && LogManager.getFactory() != null && LogManager.getFactory().hasContext(SpringEnvironmentHolder.class.getName(), null, false)) {
+            lock.lock();
+            try {
+                if (environment == null) {
+                    Object obj = LogManager.getContext(false).getObject(Log4j2CloudConfigLoggingSystem.ENVIRONMENT_KEY);
+                    environment = obj instanceof Environment ? (Environment) obj : null;
+                }
+            } finally {
+                lock.unlock();
+            }
+        }
+        return environment;
+    }
+}
diff --git a/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/SpringLookup.java b/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/SpringLookup.java
new file mode 100644
index 0000000..076f3b1
--- /dev/null
+++ b/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/SpringLookup.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.spring.cloud.config.client;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.lookup.StrLookup;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.springframework.core.env.Environment;
+
+/**
+ * Lookup for Spring properties.
+ */
+@Plugin(name = "spring", category = StrLookup.CATEGORY)
+public class SpringLookup extends SpringEnvironmentHolder implements StrLookup {
+
+    public SpringLookup() {
+        getEnvironment();
+    }
+
+    @Override
+    public String lookup(String key) {
+        Environment env = getEnvironment();
+        if (env != null) {
+            return env.getProperty(key);
+        }
+        return null;
+    }
+
+    @Override
+    public String lookup(LogEvent event, String key) {
+        return lookup((key));
+    }
+}
diff --git a/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/SpringPropertySource.java b/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/SpringPropertySource.java
new file mode 100644
index 0000000..8ffed65
--- /dev/null
+++ b/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/main/java/org/apache/logging/log4j/spring/cloud/config/client/SpringPropertySource.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.spring.cloud.config.client;
+
+import org.apache.logging.log4j.util.PropertySource;
+import org.springframework.core.env.Environment;
+
+/**
+ * Returns properties from Spring.
+ */
+public class SpringPropertySource extends SpringEnvironmentHolder implements PropertySource {
+
+    /**
+     * System properties take precendence followed by properties in Log4j properties files. Spring properties
+     * follow.
+     * @return This PropertySource's priority.
+     */
+    @Override
+    public int getPriority() {
+        return -50;
+    }
+
+    @Override
+    public String getProperty(String key) {
+        Environment environment = getEnvironment();
+        if (environment != null) {
+            return environment.getProperty(key);
+        }
+        return null;
+    }
+
+    @Override
+    public boolean containsProperty(String key) {
+        Environment environment = getEnvironment();
+        if (environment != null) {
+            return environment.containsProperty(key);
+        }
+        return false;
+    }
+}
diff --git a/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/site/markdown/index.md b/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/site/markdown/index.md
index fee9778..f3bbebd 100644
--- a/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/site/markdown/index.md
+++ b/log4j-spring-cloud-config/log4j-spring-cloud-config-client/src/site/markdown/index.md
@@ -46,16 +46,55 @@
 practices but the application, profile, and label should be specified in the url.
 
 The Spring Cloud Config support also allows connections using TLS and/or basic authentication. When using basic 
-authentication the userid and password may be specified as system properties or in log4j2.component.properties as
+authentication the userid and password may be specified as system properties, log4j2.component.properties or Spring
+Boot's bootstrap.yml. The table below shows the alternate names that may be used to specify the properties. Any of
+the alternatives may be used in any configuration location.
+
+| Property | Alias  | Spring-like alias | Purpose |
+|----------|---------|---------|---------|
+| log4j2.configurationUserName | log4j2.config.username | logging.auth.username | User name for basic authentication |
+| log4j2.configurationPassword | log4j2.config.password | logging.auth.password | Password for basic authentication |
+| log4j2.authorizationProvider | log4j2.config.authorizationProvider | logging.auth.authorizationProvider | Class used to create HTTP Authorization header |
 
 ```
 log4j2.configurationUserName=guest
 log4j2.configurationPassword=guest
 ```
-Note that Log4j currently does not support encrypting the password. 
+As noted above, Log4j supports accessing logging configuration from bootstrap.yml. As an example, to configure reading 
+from a Spring Cloud Configuration service using basic authoriztion you can do:
+```
+spring:
+  application:
+    name: myApp
+  cloud:
+    config:
+      uri: https://spring-configuration-server.mycorp.com
+      username: appuser
+      password: changeme
 
-If more extensive authentication is required an ```AuthorizationProvider``` can be implemented and defined in
-the log4j2.authorizationProvider system property or in log4j2.component.properties.
+logging:
+  config: classpath:log4j2.xml
+  label: ${spring.cloud.config.label}
+
+---
+spring:
+  profiles: dev
+
+logging:
+  config: https://spring-configuration-server.mycorp.com/myApp/default/${logging.label}/log4j2-dev.xml
+  auth:
+    username: appuser
+    password: changeme
+```
+
+Note that Log4j currently does not directly support encrypting the password. However, Log4j does use Spring's 
+standard APIs to access properties in the Spring configuration so any customizations made to Spring's property
+handling would apply to the properties Log4j uses as well.
+
+If more extensive authentication is required an ```AuthorizationProvider``` can be implemented and the fully
+qualified class name in
+the ```log4j2.authorizationProvider``` system property, in log4j2.component.properties or in Spring's bootstrap.yml
+using either the ```log4j2.authorizationProvider``` key or with the key ```logging.auth.authorizationProvider```.
 
 TLS can be enabled by adding the following system properties or defining them in log4j2.component.properties
 
@@ -63,9 +102,9 @@
 | ------------- |-------|:-------------| 
 | log4j2.trustStoreLocation  | Optional | The location of the trust store. If not provided the default trust store will be used.| 
 | log4j2.trustStorePassword  | Optional | Password needed to access the trust store. |
-| log4j2.trustStorePasswordFile | Optinoal | The location of a file that contains the password for the trust store. |
+| log4j2.trustStorePasswordFile | Optional | The location of a file that contains the password for the trust store. |
 | log4j2.trustStorePasswordEnvironmentVariable | Optional | The name of the environment variable that contains the trust store password. |
-| log4j2.trustStorePeyStoreType | Required if keystore location provided | The type of key store.  |
+| log4j2.trustStoreKeyStoreType | Required if keystore location provided | The type of key store.  |
 | log4j2.trustStoreKeyManagerFactoryAlgorithm | Optional | Java cryptographic algorithm. |
 | log4j2.keyStoreLocation | Optional | The location of the key store. If not provided the default key store will be used.|
 | log4j2.keyStorePassword | Optional | Password needed to access the key store. | 
diff --git a/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/Dockerfile b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/Dockerfile
index 89d1ee9..d4402e8 100644
--- a/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/Dockerfile
+++ b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/Dockerfile
@@ -1,3 +1,19 @@
+#
+# 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.
+#
 # Alpine Linux with OpenJDK
 #FROM openjdk:8-jdk-alpine
 FROM openjdk:11-jdk-slim
@@ -13,4 +29,5 @@
 EXPOSE 8080
 
 #CMD java "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005" -jar sampleapp.jar
-CMD java -jar -Xmx2G sampleapp.jar
+ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar -Xmx1G sampleapp.jar"]
+
diff --git a/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/README.md b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/README.md
index 5172881..59311e3 100644
--- a/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/README.md
+++ b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/README.md
@@ -1,8 +1,9 @@
-##Log4j Spring Cloud Sample Application
+#Log4j Spring Cloud Sample Application
 
 This application uses Spring Boot and reads the logging configuration from the companion Spring Cloud Config Server
 project. The log4j2.xml file is located in the config-repo directory in that project.
 
+## Running With Docker
 This sample packages the application in a docker container that is packaged with rabbit-mq (to allow dynamic updates
 from Spring Cloud Config), fluent-bit (to test as a log forwarder), Apache Flume (to test as a log forwarder), and
 Apache Kafka also as a log forwarder. It also installs Socat, a proxy to allow access to the Docker REST API.
@@ -32,5 +33,23 @@
 
 Accessing the log files varies depending on the appending being used. When logging to the console "docker logs" may 
 be used. As configured, Flume will write to files in /var/log/flume, fluent-bit to the standard output of its container.
-Kafka output may be viewed using a tool like [Kafka Tool](http://www.kafkatool.com/).    
+Kafka output may be viewed using a tool like [Kafka Tool](http://www.kafkatool.com/).  
+
+## Running with Kubernetes
+
+This sample has been verified to run in a Docker Desktop for Mac environment with Kubernetes enabled and may run in 
+other Kubernetes environments. 
+
+### Prerequisites
+Note: This guide assumes you already have Docker and Kubernetes installed. Since the same container is used for 
+Kubernetes as with Docker, Java 11 is also required. This implmentation uses an ELK stack which is expected to
+be installed. They can be downloaded individually and started as local applications on the development 
+machine for testing. Logstash should be configured as shown in 
+[Logging in the Cloud](http://logging.apache.org/log4j/2.x/manual/cloud.html).
+
+### Starting the Application   
+Run the ```docker/deploy.sh``` command from the base directory of the log4j-spring-cloud-config-sample-application 
+project. This will build the application and then deploy it to Kubernetes. You should see the start-up logs in Kibana.
+To stop, run the ```docker/undeploy.sh``` script, then run ```docker images``` and perform 
+```docker rmi --force  {image id}``` where image id is the id of the image for the sample application. 
  
diff --git a/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/k8s/deploy.sh b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/k8s/deploy.sh
new file mode 100755
index 0000000..9f67de2
--- /dev/null
+++ b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/k8s/deploy.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env 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.
+#
+
+echo "Building, (re)creating, starting, and attaching to containers for a service."
+
+imageName=sampleapp
+containerName=sampleapp-container
+networkName=docker_sampleapp
+debug_port=5005
+#debug_expose="-p $debug_port:$debug_port"
+exposed_ports="-p 8080:8090 $debug_expose"
+
+mvn clean package -DskipTests=true
+docker build --no-cache -t $imageName -f Dockerfile  .
+
+docker tag $imageName localhost:5000/$imageName
+docker push localhost:5000/$imageName
+kubectl apply -f k8s/sampleapp-deployment.yaml
\ No newline at end of file
diff --git a/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/k8s/sampleapp-deployment.yaml b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/k8s/sampleapp-deployment.yaml
new file mode 100644
index 0000000..fe5d2b7
--- /dev/null
+++ b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/k8s/sampleapp-deployment.yaml
@@ -0,0 +1,44 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: sampleapp
+  labels:
+    app: sampleapp
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: sampleapp
+  template:
+    metadata:
+      labels:
+        app: sampleapp
+    spec:
+      containers:
+        - name: sampleapp
+          image: localhost:5000/sampleapp:latest
+          imagePullPolicy: Always
+          ports:
+            - containerPort: 8080
+            - containerPort: 5005
+          env:
+            - name: JAVA_OPTS
+              value: "-Delastic.search.host=host.docker.internal"
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: sampleapp
+spec:
+  type: NodePort
+  selector:
+    app: sampleapp
+  ports:
+    - protocol: TCP
+      port: 8080
+      nodePort: 30011
+      name: http
+    - protocol: TCP
+      port: 5005
+      nodePort: 30012
+      name: debug
diff --git a/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/k8s/undeploy.sh b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/k8s/undeploy.sh
new file mode 100755
index 0000000..c5255c9
--- /dev/null
+++ b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/k8s/undeploy.sh
@@ -0,0 +1,29 @@
+#!/usr/bin/env 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.
+#
+
+echo "Building, (re)creating, starting, and attaching to containers for a service."
+
+imageName=sampleapp
+containerName=sampleapp-container
+networkName=docker_sampleapp
+
+kubectl delete deploy/$imageName svc/$imageName
+
diff --git a/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/pom.xml b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/pom.xml
index 412ea24..1fd45b4 100644
--- a/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/pom.xml
+++ b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/pom.xml
@@ -92,6 +92,11 @@
       <artifactId>log4j-docker</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-kubernetes</artifactId>
+      <version>${project.version}</version>
+    </dependency>
     <!-- Required for Async Loggers -->
     <dependency>
       <groupId>com.lmax</groupId>
diff --git a/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/src/main/resources/application.yml b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/src/main/resources/application.yml
index 71ca238..7e9838e 100644
--- a/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/src/main/resources/application.yml
+++ b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-application/src/main/resources/application.yml
@@ -27,4 +27,7 @@
     addresses: rabbit
     port: 5672
     username: guest
-    password: guest
\ No newline at end of file
+    password: guest
+
+log4j2:
+  debug: true
\ No newline at end of file
diff --git a/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-server/src/main/config-repo/log4j2.xml b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-server/src/main/config-repo/log4j2.xml
index 84b9673..2e9dcfa 100644
--- a/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-server/src/main/config-repo/log4j2.xml
+++ b/log4j-spring-cloud-config/log4j-spring-cloud-config-samples/log4j-spring-cloud-config-sample-server/src/main/config-repo/log4j2.xml
@@ -1,12 +1,27 @@
 <?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 status="DEBUG" monitorInterval="0">
+  <Properties>
+    <Property name="spring.application.name">sampleapp</Property>
+  </Properties>
   <Appenders>
-    <Console name="console" target="SYSTEM_OUT">
-      <JsonLayout properties="true" compact="true" eventEol="true" stackTraceAsString="true">
-      </JsonLayout>
-    </Console>
-    <Flume name="flume" ignoreExceptions="false" type="Embedded" compress="false">
+    <!--<Flume name="flume" ignoreExceptions="false" type="Embedded" compress="false">
       <Property name="channel.type">memory</Property>
       <Property name="channel.capacity">100000</Property>
       <Property name="channel.transactionCapacity">5000</Property>
@@ -20,6 +35,7 @@
         <KeyValuePair key="containerId" value="\${docker:containerId}"/>
         <KeyValuePair key="containerName" value="\${docker:containerName}"/>
         <KeyValuePair key="imageName" value="\${docker:imageName}"/>
+        <KeyValuePair key="application" value="\$\${lower:\${spring:spring.application.name}}"/>
       </JsonLayout>
     </Flume>
     <Flume name="avro" ignoreExceptions="false" batchSize="1" compress="false">
@@ -28,6 +44,7 @@
         <KeyValuePair key="containerId" value="\${docker:containerId}"/>
         <KeyValuePair key="containerName" value="\${docker:containerName}"/>
         <KeyValuePair key="imageName" value="\${docker:imageName}"/>
+        <KeyValuePair key="application" value="\$\${lower:\${spring:spring.application.name}}"/>
       </JsonLayout>
     </Flume>
     <Flume name="avroSyslog" ignoreExceptions="false" batchSize="100" compress="false">
@@ -38,6 +55,7 @@
           <KeyValuePair key="containerId" value="\${docker:containerId}"/>
           <KeyValuePair key="containerName" value="\${docker:containerName}"/>
           <KeyValuePair key="imageName" value="\${docker:imageName}"/>
+          <KeyValuePair key="application" value="\$\${lower:\${spring:spring.application.name}}"/>
         </LoggerFields>
       </RFC5424Layout>
     </Flume>
@@ -46,6 +64,7 @@
         <KeyValuePair key="containerId" value="\${docker:containerId}"/>
         <KeyValuePair key="containerName" value="\${docker:containerName}"/>
         <KeyValuePair key="imageName" value="\${docker:imageName}"/>
+        <KeyValuePair key="application" value="\$\${lower:\${spring:spring.application.name}}"/>
       </JsonLayout>
       <Property name="bootstrap.servers">host.docker.internal:9092</Property>
     </Kafka>
@@ -54,6 +73,7 @@
         <KeyValuePair key="containerId" value="\${docker:containerId}"/>
         <KeyValuePair key="containerName" value="\${docker:containerName}"/>
         <KeyValuePair key="imageName" value="\${docker:imageName}"/>
+        <KeyValuePair key="application" value="\$\${lower:\${spring:spring.application.name}}"/>
       </JsonLayout>
     </Socket>
     <RollingFile name="RollingFile" fileName="/var/log/sampleapp/app.log"
@@ -62,6 +82,7 @@
         <KeyValuePair key="containerId" value="\${docker:containerId}"/>
         <KeyValuePair key="containerName" value="\${docker:containerName}"/>
         <KeyValuePair key="imageName" value="\${docker:imageName}"/>
+        <KeyValuePair key="application" value="\$\${lower:\${spring:spring.application.name}}"/>
       </JsonLayout>
       <SizeBasedTriggeringPolicy size="10MB" />
       <DefaultRolloverStrategy max="5"/>
@@ -74,24 +95,58 @@
           <KeyValuePair key="containerId" value="\${docker:containerId}"/>
           <KeyValuePair key="containerName" value="\${docker:containerName}"/>
           <KeyValuePair key="imageName" value="\${docker:imageName}"/>
+          <KeyValuePair key="application" value="\$\${lower:\${spring:spring.application.name}}"/>
         </LoggerFields>
       </RFC5424Layout>
       <SizeBasedTriggeringPolicy size="10MB" />
       <DefaultRolloverStrategy max="5"/>
-    </RollingFile>
+    </RollingFile>-->
+    <Socket name="Elastic" host="\${sys:elastic.search.host:-localhost}" port="12222" protocol="tcp" bufferedIo="true" ignoreExceptions="false">
+      <GelfLayout includeStackTrace="true" host="${hostName}" includeThreadContext="true" includeNullDelimiter="true"
+                  compressionType="OFF">
+        <ThreadContextIncludes>requestId,sessionId,loginId,userId,ipAddress,corpAcctNumber,callingHost,ohBehalfOf,onBehalfOfAccount</ThreadContextIncludes>
+        <MessagePattern>%d [%t] %-5p %X{requestId, sessionId, loginId, userId, ipAddress, corpAcctNumber} %C{1.}.%M:%L - %m%n</MessagePattern>
+        <KeyValuePair key="docker.containerId" value="\${docker:containerId:-}"/>
+        <KeyValuePair key="application" value="$\${lower:\${spring:spring.application.name}}"/>
+        <KeyValuePair key="kubernetes.serviceAccountName" value="\${k8s:accountName:-}"/>
+        <KeyValuePair key="kubernetes.containerId" value="\${k8s:containerId:-}"/>
+        <KeyValuePair key="kubernetes.containerName" value="\${k8s:containerName:-}"/>
+        <KeyValuePair key="kubernetes.host" value="\${k8s:host:-}"/>
+        <KeyValuePair key="kubernetes.labels.app" value="\${k8s:labels.app:-}"/>
+        <KeyValuePair key="kubernetes.labels.pod-template-hash" value="\${k8s:labels.podTemplateHash:-}"/>
+        <KeyValuePair key="kubernetes.master_url" value="\${k8s:masterUrl:-}"/>
+        <KeyValuePair key="kubernetes.namespaceId" value="\${k8s:namespaceId:-}"/>
+        <KeyValuePair key="kubernetes.namespaceName" value="\${k8s:namespaceName:-}"/>
+        <KeyValuePair key="kubernetes.podID" value="\${k8s:podId:-}"/>
+        <KeyValuePair key="kubernetes.podIP" value="\${k8s:podIp:-}"/>
+        <KeyValuePair key="kubernetes.podName" value="\${k8s:podName:-}"/>
+        <KeyValuePair key="kubernetes.imageId" value="\${k8s:imageId:-}"/>
+        <KeyValuePair key="kubernetes.imageName" value="\${k8s:imageName:-}"/>
+      </GelfLayout>
+    </Socket>
+    <Console name="Console" target="SYSTEM_OUT">
+      <RFC5424Layout enterpriseNumber="50177" includeMDC="true" mdcId="RequestContext" appName="SalesforceGateway"
+                     mdcPrefix="" newLine="true" mdcIncludes="requestId,sessionId,loginId,userId,ipAddress,corpAcctNumber"/>
+    </Console>
+    <Failover name="log4j" primary="Elastic">
+      <Failovers>
+        <AppenderRef ref="Console"/>
+      </Failovers>
+    </Failover>
   </Appenders>
+
   <Loggers>
     <Logger name="org.apache.kafka" level="warn" additivity="false">
-      <AppenderRef ref="console"/>
+      <AppenderRef ref="log4j"/>
     </Logger>
     <Logger name="org.apache.flume" level="warn" additivity="false">
-      <AppenderRef ref="console"/>
+      <AppenderRef ref="log4j"/>
     </Logger>
     <Logger name="org.apache.avro" level="warn" additivity="false">
-      <AppenderRef ref="console"/>
+      <AppenderRef ref="log4j"/>
     </Logger>
     <Root level="DEBUG">
-      <AppenderRef ref="console"/>
+      <AppenderRef ref="log4j"/>
     </Root>
   </Loggers>
 </Configuration>
\ No newline at end of file
diff --git a/log4j-taglib/src/site/site.xml b/log4j-taglib/src/site/site.xml
index 9ca359b..b201bcc 100644
--- a/log4j-taglib/src/site/site.xml
+++ b/log4j-taglib/src/site/site.xml
@@ -20,14 +20,6 @@
          xmlns="http://maven.apache.org/DECORATION/1.4.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/DECORATION/1.4.0 http://maven.apache.org/xsd/decoration-1.4.0.xsd">
-  <bannerLeft>
-    <name>Logging Services</name>
-    <src>../images/ls-logo.jpg</src>
-    <href>../index.html</href>
-  </bannerLeft>
-  <bannerRight>
-    <src>../images/logo.jpg</src>
-  </bannerRight>
   <body>
     <links>
       <item name="Apache" href="http://www.apache.org/" />
@@ -57,8 +49,5 @@
       <item name="Surefire Report" href="../surefire-report.html" />
       <item name="RAT Report" href="../rat-report.html" />
     </menu>
-    <footer><div class="row span16">Apache Logging, Apache Log4j, Log4j, Apache, the Apache feather logo, and the
-      Apache Logging project logo are trademarks of The Apache Software Foundation.</div>
-    </footer>
   </body>
 </project>
\ No newline at end of file
diff --git a/log4j-web/src/main/java/org/apache/logging/log4j/web/WebLookup.java b/log4j-web/src/main/java/org/apache/logging/log4j/web/WebLookup.java
index 08f2859..1f9ce95 100644
--- a/log4j-web/src/main/java/org/apache/logging/log4j/web/WebLookup.java
+++ b/log4j-web/src/main/java/org/apache/logging/log4j/web/WebLookup.java
@@ -19,6 +19,7 @@
 // this comment if no longer relevant
 
 import java.security.Principal;
+import java.util.Objects;
 import java.util.stream.Stream;
 
 import javax.servlet.ServletContext;
@@ -34,6 +35,7 @@
 
 @Plugin(name = "web", category = "Lookup")
 public class WebLookup extends AbstractLookup {
+    private static final String SESSION_ATTR_PREFIX = "session.attr.";
     private static final String REQUEST_ATTR_PREFIX = "request.attr.";
     private static final String REQUEST_HEADER_PREFIX = "header.";
     private static final String REQUEST_COOKIE_PREFIX = "cookie.";
@@ -91,6 +93,18 @@
                     HttpServletRequest.class.cast(req).getParameter(name) : null;
         }
 
+        if (key.startsWith(SESSION_ATTR_PREFIX)) {
+            final ServletRequest req = getRequest();
+            if (HttpServletRequest.class.isInstance(req)) {
+                final HttpSession session = HttpServletRequest.class.cast(req).getSession(false);
+                if (session != null) {
+                    final String name = key.substring(SESSION_ATTR_PREFIX.length());
+                    return Objects.toString(session.getAttribute(name), null);
+                }
+            }
+            return null;
+        }
+
         if ("request.method".equals(key)) {
             final ServletRequest req = getRequest();
             return HttpServletRequest.class.isInstance(req) ? HttpServletRequest.class.cast(req).getMethod() : null;
diff --git a/log4j-web/src/main/java/org/apache/logging/log4j/web/appender/ServletAppender.java b/log4j-web/src/main/java/org/apache/logging/log4j/web/appender/ServletAppender.java
index 4c6c332..e54004c 100644
--- a/log4j-web/src/main/java/org/apache/logging/log4j/web/appender/ServletAppender.java
+++ b/log4j-web/src/main/java/org/apache/logging/log4j/web/appender/ServletAppender.java
@@ -16,22 +16,21 @@
  */
 package org.apache.logging.log4j.web.appender;
 
-import java.io.Serializable;
-
-import javax.servlet.ServletContext;
-
 import org.apache.logging.log4j.core.Filter;
 import org.apache.logging.log4j.core.Layout;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.appender.AbstractAppender;
 import org.apache.logging.log4j.core.config.Property;
-import org.apache.logging.log4j.plugins.Plugin;
-import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.PluginBuilderFactory;
 import org.apache.logging.log4j.core.layout.AbstractStringLayout;
 import org.apache.logging.log4j.core.layout.PatternLayout;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
+import org.apache.logging.log4j.plugins.PluginFactory;
 import org.apache.logging.log4j.web.WebLoggerContextUtils;
 
+import javax.servlet.ServletContext;
+import java.io.Serializable;
+
 /**
  * Logs using the ServletContext's log method
  */
@@ -84,7 +83,7 @@
 
 	}
     
-    @PluginBuilderFactory
+    @PluginFactory
     public static <B extends Builder<B>> B newBuilder() {
         return new Builder<B>().asBuilder();
     }
diff --git a/log4j-web/src/test/java/org/apache/logging/log4j/web/WebLookupTest.java b/log4j-web/src/test/java/org/apache/logging/log4j/web/WebLookupTest.java
index 7091036..99a3132 100644
--- a/log4j-web/src/test/java/org/apache/logging/log4j/web/WebLookupTest.java
+++ b/log4j-web/src/test/java/org/apache/logging/log4j/web/WebLookupTest.java
@@ -146,6 +146,20 @@
         ContextAnchor.THREAD_CONTEXT.remove();
     }
 
+    @Test
+    public void testSessionAttribute() {
+        final Log4jWebLifeCycle initializer = startInitializer();
+        final MockHttpServletRequest request = new MockHttpServletRequest();
+        request.getSession().setAttribute("foo", "bar");
+        Log4jServletFilter.CURRENT_REQUEST.set(request);
+        final WebLookup lookup = new WebLookup();
+        assertEquals("bar", lookup.lookup(null, "session.attr.foo"));
+        Log4jServletFilter.CURRENT_REQUEST.remove();
+        assertNull(lookup.lookup(null, "session.attr.foo"));
+        initializer.stop();
+        ContextAnchor.THREAD_CONTEXT.remove();
+    }
+
     private Log4jWebLifeCycle startInitializer() {
         ContextAnchor.THREAD_CONTEXT.remove();
         final ServletContext servletContext = new MockServletContext();
diff --git a/pom.xml b/pom.xml
index fe94fb8..115da12 100644
--- a/pom.xml
+++ b/pom.xml
@@ -190,8 +190,9 @@
     <slf4jVersion>1.7.25</slf4jVersion>

     <logbackVersion>1.2.3</logbackVersion>

     <jackson1Version>1.9.13</jackson1Version>

-    <jackson2Version>2.9.9</jackson2Version>

+    <jackson2Version>2.10.1</jackson2Version>

     <springVersion>3.2.18.RELEASE</springVersion>

+    <kubernetes-client.version>4.6.1</kubernetes-client.version>

     <flumeVersion>1.9.0</flumeVersion>

     <disruptorVersion>3.4.2</disruptorVersion>

     <conversantDisruptorVersion>1.2.15</conversantDisruptorVersion>

@@ -220,8 +221,7 @@
     <jxr.plugin.version>2.5</jxr.plugin.version>

     <revapi.plugin.version>0.10.5</revapi.plugin.version>

     <revapi.skip>true</revapi.skip>

-    <!-- Maven site 3.7 uses the wrong stylesheet? -->

-    <site.plugin.version>3.4</site.plugin.version>

+    <site.plugin.version>3.8.2</site.plugin.version>

     <!-- Maven site depends on Velocity and the escaping rules are different in newer versions. -->

     <!-- See https://maven.apache.org/plugins/maven-site-plugin/migrate.html -->

     <velocity.plugin.version>1.5</velocity.plugin.version>

@@ -347,6 +347,11 @@
       </dependency>

       <dependency>

         <groupId>org.apache.logging.log4j</groupId>

+        <artifactId>log4j--1.2-api</artifactId>

+        <version>${project.version}</version>

+      </dependency>

+      <dependency>

+        <groupId>org.apache.logging.log4j</groupId>

         <artifactId>log4j-plugins</artifactId>

         <version>${project.version}</version>

         <type>test-jar</type>

@@ -745,6 +750,11 @@
         <version>${springVersion}</version>

       </dependency>

       <dependency>

+        <groupId>io.fabric8</groupId>

+        <artifactId>kubernetes-client</artifactId>

+        <version>${kubernetes-client.version}</version>

+      </dependency>

+      <dependency>

         <groupId>org.hsqldb</groupId>

         <artifactId>hsqldb</artifactId>

         <version>2.4.1</version>

@@ -953,6 +963,7 @@
             </compilerArguments>

             <compilerId>javac-with-errorprone</compilerId>

             <forceJavacCompilerUse>true</forceJavacCompilerUse>

+            <parameters>true</parameters>

           </configuration>

           <dependencies>

             <dependency>

@@ -1145,16 +1156,29 @@
         </configuration>

       </plugin>

       <plugin>

+        <groupId>org.codehaus.mojo</groupId>

+        <artifactId>build-helper-maven-plugin</artifactId>

+        <version>1.12</version>

+        <executions>

+          <execution>

+            <id>timestamp-property</id>

+            <goals>

+              <goal>timestamp-property</goal>

+            </goals>

+            <phase>pre-site</phase>

+            <configuration>

+              <name>currentYear</name>

+              <pattern>yyyy</pattern>

+            </configuration>

+          </execution>

+        </executions>

+      </plugin>

+      <plugin>

         <groupId>org.apache.maven.plugins</groupId>

         <artifactId>maven-site-plugin</artifactId>

         <version>${site.plugin.version}</version>

         <dependencies>

           <dependency>

-            <groupId>org.apache.velocity</groupId>

-            <artifactId>velocity</artifactId>

-            <version>${velocity.plugin.version}</version>

-          </dependency>

-          <dependency>

             <groupId>org.apache.maven.wagon</groupId>

             <artifactId>wagon-ssh</artifactId>

             <version>3.1.0</version>

@@ -1174,8 +1198,6 @@
           <moduleExcludes>

             <xdoc>navigation.xml,changes.xml</xdoc>

           </moduleExcludes>

-          <templateDirectory>${log4jParentDir}/src/site</templateDirectory>

-          <template>site.vm</template>

           <asciidoc>

             <attributes>

               <!-- copy any site properties wanted in asciidoc files -->

@@ -1264,6 +1286,13 @@
             <!-- Other -->

             <exclude>felix-cache/**</exclude>

             <exclude>RELEASE-NOTES.md</exclude>

+            <exclude>**/*.yml</exclude>

+            <exclude>**/*.yaml</exclude>

+            <exclude>**/*.json</exclude>

+            <excllude>**/images/*.drawio</excllude>

+            <exclude>**/fluent-bit.conf</exclude>

+            <exclude>**/rabbitmq.config</exclude>

+            <exclude>**/MANIFEST.MF</exclude>

           </excludes>

         </configuration>

       </plugin>

@@ -1447,6 +1476,13 @@
             <!-- Other -->

             <exclude>felix-cache/**</exclude>

             <exclude>RELEASE-NOTES.txt</exclude>

+            <exclude>**/*.yml</exclude>

+            <exclude>**/*.yaml</exclude>

+            <exclude>**/*.json</exclude>

+            <excllude>**/images/*.drawio</excllude>

+            <exclude>**/fluent-bit.conf</exclude>

+            <exclude>**/rabbitmq.config</exclude>

+            <exclude>**/MANIFEST.MF</exclude>

           </excludes>

         </configuration>

       </plugin>

@@ -1514,6 +1550,7 @@
     <module>log4j-smtp</module>

     <module>log4j-osgi</module>

     <module>log4j-docker</module>

+    <module>log4j-kubernetes</module>

     <module>log4j-spring-cloud-config</module>

   </modules>

   <profiles>

@@ -1633,6 +1670,13 @@
                 <!-- Other -->

                 <exclude>felix-cache/**</exclude>

                 <exclude>RELEASE-NOTES.md</exclude>

+                <exclude>**/*.yml</exclude>

+                <exclude>**/*.yaml</exclude>

+                <exclude>**/*.json</exclude>

+                <excllude>**/images/*.drawio</excllude>

+                <exclude>**/fluent-bit.conf</exclude>

+                <exclude>**/rabbitmq.config</exclude>

+                <exclude>**/MANIFEST.MF</exclude>

               </excludes>

             </configuration>

             <executions>

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 7fa5f8e..f9bf359 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -31,11 +31,26 @@
          - "remove" - Removed
     -->
     <release version="3.0.0" date="2019-xx-xx" description="GA Release 3.0.0">
+      <actino issue="LOG4J2-2688" dev="rgoers" type="add" due-to="Romain Manni-Bucau">
+        Allow web lookup of session attributes.
+      </actino>
+      <action issue="LOG4J2-2701" dev="rgoers" type="update">
+        Update Jackson from 2.9.x to 2.10.1.
+      </action>
+      <action issue="LOG4J2-2700" dev="mattsicker" type="add">
+        Add support for injecting plugin configuration via builder methods.
+      </action>
+      <action issue="LOG4J2-860" dev="mattsicker" type="update">
+        Unify plugin builders and plugin factories.
+      </action>
+      <action issue="LOG4J2-2690" dev="rgoers" type="update">
+        Locate plugins in modules.
+      </action>
       <action issue="LOG4J2-2617" dev="mattsicker" type="update">
         Fix typo in method MergeStrategy.mergeConfigurations.
       </action>
       <action issue="LOG4J2-2683" dev="mattsicker" type="update">
-        Rename PluginVisitor and related classes to PluginInjectionBuilder.
+        Rename PluginVisitor and related classes to ConfigurationInjectionBuilder.
       </action>
       <action issue="LOG4J2-2523" dev="rgoers" type="update" due-to="Romain Manni-Bucau">
         Allow web lookup to access more information.
@@ -148,6 +163,53 @@
       </action>
     </release>
     <release version="2.13.0" date="2019-MM-DD" description="GA Release 2.13.0">
+      <action issue="LOG4J2-2058" dev="rgoers" type="fix">
+        Prevent recursive calls to java.util.LogManager.getLogger().
+      </action>
+      <action issue="LOG4J2-2725" dev="ckozak" type="fix" due-to="Dzmitry Anikechanka">
+        LOG4J2-2725 - Added try/finally around event.execute() for RingBufferLogEventHandler to clear memory
+        correctly in case of exception/error
+      </action>
+      <action issue="LOG4J2-2635" dev="rgoers" type="fix" due-to="Filipp Gunbin">
+        Wrong java version check in ThreadNameCachingStrategy.
+      </action>
+      <action issue="LOG4J2-2674" dev="rgoers" type="fix" due-to="Anton Korenkov">
+        Use a less confusing name for the CompositeConfiguration source.
+      </action>
+      <action issue="LOG4J2-2732" dev="rgoers" type="add" due-to="Matt Pavlovich">
+        Add ThreadContext.putIfNotNull method.
+      </action>
+      <action issue="LOG4J2-2731" dev="rgoers" type="add">
+        Add a Level Patttern Selector.
+      </action>
+      <action issue="LOG4J2-2727" dev="rogers" type="fix" due-to="Clément Mathieu">
+        Add setKey method to Kafka Appender Builder.
+      </action>
+      <action issue="LOG4J2-2707" dev="rgoers" type="fix" due-to="Christian Frank">
+        ArrayIndexOutOfBoundsException could occur with MAC address longer than 6 bytes.
+      </action>
+      <action issue="LOG4J2-63" dev="rgoers" type="add">
+        Add experimental support for Log4j 1 configuration files.
+      </action>
+      <action issue="LOG4J2-2712" dev="rgoers" type="fix">
+        The rolling file appenders would fail to compress the file after rollover if the file name matched the
+        file pattern.
+      </action>
+      <action issue="LOG4J2-2716" dev="rgoers" type="add">
+        Add the ability to lookup Kubernetes attributes in the Log4j configuration. Allow Log4j properties to
+        be retrieved from the Spring environment if it is available.
+      </action>
+      <action issue="LOG4J2-2710" dev="rgoers" type="add">
+        Allow Spring Boot application properties to be accessed in the Log4j 2 configuration. Add
+        lower and upper case Lookups.
+      </action>
+      <action issue="LOG4J2-2709" dev="rgoers" type="update">
+        Allow message portion of GELF layout to be formatted using a PatternLayout. Allow
+        ThreadContext attributes to be explicitly included or excluded in the GelfLayout.
+      </action>
+      <action issue="LOG4J2-2693" dev="mattsicker" type="fix">
+        @PluginValue does not support attribute names besides "value".
+      </action>
       <action issue="LOG4J-2672" dev="rgoers" type="fix" due-to="Stephen Colebourne">
         Add automatic module names where missing.
       </action>
@@ -157,6 +219,9 @@
       <action issue="LOG4J2-2673" dev="ggregory" type="fix" due-to="Yuichi Sugimura">
         OutputStreamAppender.Builder ignores setFilter().
       </action>
+      <action issue="LOG4J2-2725" dev="ckozak" type="fix" due-to="Dzmitry Anikechanka">
+        Prevent a memory leak when async loggers throw errors.
+      </action>
     </release>
     <release version="2.12.1" date="2019-08-06" description="GA Release 2.12.1">
       <action issue="LOG4J2-1946" dev="rgoers" type="fix" due-to="Igor Perelyotov">
diff --git a/src/site/asciidoc/articles.adoc b/src/site/asciidoc/articles.adoc
index 4b7eb03..95c051c 100644
--- a/src/site/asciidoc/articles.adoc
+++ b/src/site/asciidoc/articles.adoc
@@ -43,8 +43,14 @@
 
 == English
 
-* [Exploring the Secrets of Java Logs: Log4j 2 Log System](https://www.alibabacloud.com/blog/exploring-the-secrets-of-java-logs-log4j-2-log-system_594821)
+* https://www.marcobehler.com/guides/a-guide-to-logging-in-java[A guide to logging in Java]
+(June 23, 2019)
+* https://www.alibabacloud.com/blog/exploring-the-secrets-of-java-logs-log4j-2-log-system_594821[Exploring the Secrets of Java Logs: Log4j 2 Log System]
 (May 17, 2019)
+* https://www.mkyong.com/logging/apache-log4j-2-tutorials/[Apache Log4j 2 Tutorials]
+(March 27, 2019)
+* https://stackify.com/compare-java-logging-frameworks/[Java Logging Frameworks: log4j vs logback vs log4j2]
+(October 30, 2018)
 * https://howtodoinjava.com/log4j2[Log4j2 Tutorial]
 (June 3, 2018)
 * https://crunchify.com/java-how-to-create-your-own-logging-level-in-log4j-configuring-log4j[In Java How to Create your own Logging Level using Log4j (Configuring Log4j 2)]
@@ -59,8 +65,6 @@
 (December 30,2017)
 * https://examples.javacodegeeks.com/enterprise-java/log4j/log4j-2-best-practices-example/[Log4j 2 Best Practices example]
 (November 14, 2017)
-* http://www.baeldung.com/log4j2-appenders-layouts-filters[Intro to Log4j2 - Appenders, Layouts and Filters]
-(November 14, 2017)
 * http://musigma.org/logging/2017/11/06/logging.html[Logging Fundamentals]
 (November 6, 2017)
 * http://www.rationaljava.com/2017/10/allocation-free-logging-with-log4j2.html[Allocation free logging with Log4j2]
diff --git a/src/site/asciidoc/index.adoc b/src/site/asciidoc/index.adoc
index 5e1c80a..5a425d5 100644
--- a/src/site/asciidoc/index.adoc
+++ b/src/site/asciidoc/index.adoc
@@ -35,7 +35,7 @@
 . The Log4j API supports lambda expressions.
 . The Log4j API provides many more logging methods than SLF4J.
 . In addition to the "parameterized logging" format supported by SLF4J, the Log4j API also supports events using
-the java.text.MessageFormat syntax as well printf-sytle messages.
+the java.text.MessageFormat syntax as well printf-style messages.
 . The Log4j API provides a LogManager.shutdown() method. The underlying logging implementation must implement the
 Terminable interface for the method to have effect.
 . Other constructs such as Markers, log Levels, and ThreadContext (aka MDC) are fully supported.
@@ -110,9 +110,16 @@
 
 === Cloud Enabled
 
-Version 2.12.0 introduces support for accessing Dcoker container information via a Lookup and for accessing
-and updating the Log4j configuration through Spring Clooud Configuration. See [Logging in the Cloud](manual/cloud.html)
-for details.
+Version 2.12.0 introduces support for accessing Docker container information via a Lookup and for accessing
+and updating the Log4j configuration through Spring Cloud Configuration. This support was enhanced in
+version 2.13.0 to add support for accessing Spring Boot properties as well as Kubernetes information.
+See link:manual/cloud.html[Logging in the Cloud] for details.
+
+=== Compatible with Log4j 1.x
+
+The Log4j-1.2-api module of Log4j 2 provides compatiblity for applications using the Log4j 1 logging methods. As
+of Log4j 2.13.0 Log4j 2 also provides experimental support for Log4j 1.x configuration files. See
+link:manual/compatiblity.html[Log4j 2 Compatiblity with Log4j 1] for more information.
 
 == Documentation
 
diff --git a/src/site/asciidoc/manual/appenders.adoc b/src/site/asciidoc/manual/appenders.adoc
index 05fb7b9..430d347 100644
--- a/src/site/asciidoc/manual/appenders.adoc
+++ b/src/site/asciidoc/manual/appenders.adoc
@@ -86,7 +86,7 @@
 buffer size must be a power of 2.
 
 When the application is logging faster than the underlying appender can
-keep up with for a long enough time to fill up the queue, the behavious
+keep up with for a long enough time to fill up the queue, the behaviour
 is determined by the
 link:../log4j-core/apidocs/org/apache/logging/log4j/core/async/AsyncQueueFullPolicy.html[`AsyncQueueFullPolicy`].
 
@@ -839,7 +839,7 @@
 == JDBCAppender
 
 As of Log4j 2.11.0, JDBC support has moved from the existing module
-`logj-core` to the new module `log4j-jdbc`.
+`log4j-core` to the new module `log4j-jdbc`.
 
 The JDBCAppender writes log events to a relational database table using
 standard JDBC. It can be configured to obtain JDBC connections using a
@@ -1248,7 +1248,7 @@
 
 [[JMSQueueAppender]] [[JMSTopicAppender]]
 As of Log4j 2.11.0, JPA support has moved from the existing module
-`logj-core` to the new module `log4j-jms`.
+`log4j-core` to the new module `log4j-jms`.
 
 The JMS Appender sends the formatted log event to a JMS Destination.
 
@@ -1377,7 +1377,7 @@
 == JPAAppender
 
 As of Log4j 2.11.0, JPA support has moved from the existing module
-`logj-core` to the new module `log4j-jpa`.
+`log4j-core` to the new module `log4j-jpa`.
 
 The JPAAppender writes log events to a relational database table using
 the Java Persistence API 2.1. It requires the API and a provider
@@ -1636,7 +1636,7 @@
 == KafkaAppender
 
 As of Log4j 2.11.0, https://kafka.apache.org/[Apache Kafka] support has
-moved from the existing module `logj-core` to the new module
+moved from the existing module `log4j-core` to the new module
 `log4j-kafka`.
 
 The KafkaAppender logs events to an https://kafka.apache.org/[Apache
@@ -2844,7 +2844,7 @@
 The DirectWriteRolloverStrategy causes log events to be written directly
 to files represented by the file pattern. With this strategy file
 renames are not performed. If the size-based triggering policy causes
-multiple files to be written durring the specified time period they will
+multiple files to be written during the specified time period they will
 be numbered starting at one and continually incremented until a
 time-based rollover occurs.
 
@@ -3432,7 +3432,7 @@
 attribute view.
 
 |fileGroup |String a|
-File group to define whene action is executed.
+File group to define when action is executed.
 
 Underlying files system shall support
 https://docs.oracle.com/javase/7/docs/api/java/nio/file/attribute/PosixFileAttributeView.html[POSIX]
@@ -3932,7 +3932,7 @@
 == SMTPAppender
 
 As of Log4j 2.11.0, Simple Mail Transfer Protocol (SMTP) support has
-moved from the existing module `logj-core` to the new module
+moved from the existing module `log4j-core` to the new module
 `log4j-smtp`.
 
 Sends an e-mail when a specific logging event occurs, typically on
@@ -4460,7 +4460,7 @@
 == JeroMQAppender
 
 As of Log4j 2.11.0, ZeroMQ/JeroMQ support has moved from the existing
-module `logj-core` to the new module `log4j-jeromq`.
+module `log4j-core` to the new module `log4j-jeromq`.
 
 The ZeroMQ appender uses the https://github.com/zeromq/jeromq[JeroMQ]
 library to send log events to one or more ZeroMQ endpoints.
diff --git a/src/site/asciidoc/manual/async.adoc b/src/site/asciidoc/manual/async.adoc
index 225a789..3b63d62 100644
--- a/src/site/asciidoc/manual/async.adoc
+++ b/src/site/asciidoc/manual/async.adoc
@@ -205,7 +205,7 @@
 system.
 
 When the application is logging faster than the underlying appender can
-keep up with for a long enough time to fill up the queue, the behavious
+keep up with for a long enough time to fill up the queue, the behaviour
 is determined by the
 link:../log4j-core/apidocs/org/apache/logging/log4j/core/async/AsyncQueueFullPolicy.html[AsyncQueueFullPolicy].
 
diff --git a/src/site/asciidoc/manual/configuration.adoc b/src/site/asciidoc/manual/configuration.adoc
index 3ac6ecc..0a466c1 100644
--- a/src/site/asciidoc/manual/configuration.adoc
+++ b/src/site/asciidoc/manual/configuration.adoc
@@ -789,7 +789,7 @@
 with _component.<.identifier>._. The identifier does not have to match
 the name of the component being defined but must uniquely identify all
 the attributes and subcomponents that are part of the component. If the
-list of identifiers is not present the identier must not contain a '.'.
+list of identifiers is not present the identifier must not contain a '.'.
 Each individual component MUST have a "type" attribute specified that
 identifies the component's Plugin type.
 
@@ -899,7 +899,7 @@
 === Configuring Appenders
 
 An appender is configured either using the specific appender plugin's
-name or with an appender element and the type attibute containing the
+name or with an appender element and the type attribute containing the
 appender plugin's name. In addition each appender must have a name
 attribute specified with a value that is unique within the set of
 appenders. The name will be used by loggers to reference the appender as
@@ -1052,7 +1052,7 @@
 `${prefix:name}` where the prefix identifies tells Log4j that variable
 name should be evaluated in a specific context. See the
 link:lookups.html[Lookups] manual page for more details. The contexts
-that are built in to Logj4 are:
+that are built in to Log4j are:
 
 [cols="1m,5"]
 |===
@@ -2021,7 +2021,7 @@
 |[[asyncLoggerRingBufferSize]]log4j2.asyncLoggerRingBufferSize +
 ([[AsyncLogger.RingBufferSize]]AsyncLogger.RingBufferSize)
 |LOG4J_ASYNC_LOGGER_RING_BUFFER_SIZE
-|256 * 1024
+|256 * 1024 or 4 * 1024 in garbage-free mode
 |See
 link:async.html#SysPropsAllAsync[Async Logger System Properties] for
 details.
@@ -2060,7 +2060,7 @@
 |[[asyncLoggerConfigRingBufferSize]]log4j2.asyncLoggerConfigRingBufferSize +
 ([[AsyncLoggerConfig.RingBufferSize]]AsyncLoggerConfig.RingBufferSize)
 |LOG4J_ASYNC_LOGGER_CONFIG_RING_BUFFER_SIZE
-|256 * 1024
+|256 * 1024 or 4 * 1024 in garbage-free mode
 |See
 link:async.html#SysPropsMixedSync-Async[Mixed Async/Synchronous Logger
 System Properties] for details.
@@ -2088,7 +2088,7 @@
 |Default LoggerAdapter to use in the JUL adapter.
 By default, if log4j-core is available, then the class
 `org.apache.logging.log4j.jul .CoreLoggerAdapter` will be used.
-Otherwise, the `ApiLogggerAdapter` will be used. Custom implementations
+Otherwise, the `ApiLoggerAdapter` will be used. Custom implementations
 must provide a public default constructor.
 
 |[[formatMsgAsync]]log4j2.formatMsgAsync +
diff --git a/src/site/asciidoc/manual/extending.adoc b/src/site/asciidoc/manual/extending.adoc
index 7eb0a0a..c68668b 100644
--- a/src/site/asciidoc/manual/extending.adoc
+++ b/src/site/asciidoc/manual/extending.adoc
@@ -173,8 +173,8 @@
 public static class RootLogger extends LoggerConfig {
 
     @PluginFactory
-    public static LoggerConfig createLogger(@PluginAttribute(value = "additivity", defaultBooleanValue = true) boolean additivity,
-                                            @PluginAttribute(value = "level", defaultStringValue = "ERROR") Level level,
+    public static LoggerConfig createLogger(@PluginAttribute(defaultBooleanValue = true) boolean additivity,
+                                            @PluginAttribute(defaultStringValue = "ERROR") Level level,
                                             @PluginElement("AppenderRef") AppenderRef[] refs,
                                             @PluginElement("Filters") Filter filter) {
         List<AppenderRef> appenderRefs = Arrays.asList(refs);
@@ -319,9 +319,9 @@
      * @return The created ThresholdFilter.
      */
     @PluginFactory
-    public static ThresholdFilter createFilter(@PluginAttribute(value = "level", defaultStringValue = "ERROR") Level level,
-                                               @PluginAttribute(value = "onMatch", defaultStringValue = "NEUTRAL") Result onMatch,
-                                               @PluginAttribute(value = "onMismatch", defaultStringValue = "DENY") Result onMismatch) {
+    public static ThresholdFilter createFilter(@PluginAttribute(defaultStringValue = "ERROR") Level level,
+                                               @PluginAttribute(defaultStringValue = "NEUTRAL") Result onMatch,
+                                               @PluginAttribute(defaultStringValue = "DENY") Result onMismatch) {
         return new ThresholdFilter(level, onMatch, onMismatch);
     }
 }
@@ -339,8 +339,8 @@
 as "true" if the toString method renders the values of the attributes
 passed to the Appender.
 
-Appenders must also declare a `@PluginFactory` method or `@PluginFactoryBuilder`
-builder class and method that will create the appender. The example below shows
+Appenders must also declare a `@PluginFactory` method that returns an instance
+of the appender or a builder class used to create the appender. The example below shows
 an Appender named "Stub" that can be used as an initial template.
 
 Most Appenders use Managers. A manager actually "owns" the resources,
@@ -365,16 +365,11 @@
     }
 
     @PluginFactory
-    public static StubAppender createAppender(@PluginAttribute("name") String name,
-                                              @PluginAttribute("ignoreExceptions") boolean ignoreExceptions,
+    public static StubAppender createAppender(@PluginAttribute @Required(message = "No name provided for StubAppender") String name,
+                                              @PluginAttribute boolean ignoreExceptions,
                                               @PluginElement("Layout") Layout layout,
                                               @PluginElement("Filters") Filter filter) {
 
-        if (name == null) {
-            LOGGER.error("No name provided for StubAppender");
-            return null;
-        }
-
         StubManager manager = StubManager.getStubManager(name);
         if (manager == null) {
             return null;
@@ -416,10 +411,10 @@
     }
 
     @PluginFactory
-    public static SampleLayout createLayout(@PluginAttribute("locationInfo") boolean locationInfo,
-                                            @PluginAttribute("properties") boolean properties,
-                                            @PluginAttribute("complete") boolean complete,
-                                            @PluginAttribute(value = "charset", defaultStringValue = "UTF-8") Charset charset) {
+    public static SampleLayout createLayout(@PluginAttribute boolean locationInfo,
+                                            @PluginAttribute boolean properties,
+                                            @PluginAttribute boolean complete,
+                                            @PluginAttribute(defaultStringValue = "UTF-8") Charset charset) {
         return new SampleLayout(locationInfo, properties, complete, charset);
     }
 }
@@ -474,7 +469,7 @@
 an annotated factory method:
 
 * Attribute names don't need to be specified if they match the field
-name.
+name or the method name with `set` or `with` prefixes stripped.
 * Default values can be specified in code rather than through an
 annotation (also allowing a runtime-calculated default value which isn't
 allowed in annotations).
@@ -505,49 +500,45 @@
 
 [source,java]
 ----
-@PluginBuilderFactory
+@PluginFactory
 public static Builder newBuilder() {
     return new Builder();
 }
 
 public static class Builder implements org.apache.logging.log4j.plugins.util.Builder<ListAppender> {
 
-    @PluginBuilderAttribute
-    @Required(message = "No name provided for ListAppender")
     private String name;
-
-    @PluginBuilderAttribute
     private boolean entryPerNewLine;
-
-    @PluginBuilderAttribute
     private boolean raw;
-
-    @PluginElement("Layout")
     private Layout<? extends Serializable> layout;
-
-    @PluginElement("Filter")
     private Filter filter;
 
+    @PluginAttribute
+    @Required(message = "No name provided for ListAppender")
     public Builder setName(final String name) {
         this.name = name;
         return this;
     }
 
+    @PluginAttribute
     public Builder setEntryPerNewLine(final boolean entryPerNewLine) {
         this.entryPerNewLine = entryPerNewLine;
         return this;
     }
 
+    @PluginAttribute
     public Builder setRaw(final boolean raw) {
         this.raw = raw;
         return this;
     }
 
+    @PluginElement
     public Builder setLayout(final Layout<? extends Serializable> layout) {
         this.layout = layout;
         return this;
     }
 
+    @PluginElement
     public Builder setFilter(final Filter filter) {
         this.filter = filter;
         return this;
@@ -560,23 +551,12 @@
 }
 ----
 
-The only difference in annotations is using `@PluginBuilderAttribute`
-instead of `@PluginAttribute` so that default values and reflection can
-be used instead of specifying them in the annotation. Either annotation
-can be used in a builder, but the former is better suited for field
-injection while the latter is better suited for parameter injection.
-Otherwise, the same annotations (`@PluginConfiguration`,
-`@PluginElement`, `@PluginNode`, and `@PluginValue`) are all supported
-on fields. Note that a factory method is still required to supply a
-builder, and this factory method should be annotated with
-`@PluginBuilderFactory`.
-// TODO: this will change with LOG4J2-1188
-
 When plugins are being constructed after a configuration has been
 parsed, a plugin builder will be used if available, otherwise a plugin
 factory method will be used as a fallback. If a plugin contains neither
 factory, then it cannot be used from a configuration file (it can still
 be used programmatically of course).
+// TODO: this will be simplified
 
 Here is an example of using a plugin factory versus a plugin builder
 programmatically:
diff --git a/src/site/asciidoc/manual/layouts.adoc b/src/site/asciidoc/manual/layouts.adoc
index 8f770d6..04386c0 100644
--- a/src/site/asciidoc/manual/layouts.adoc
+++ b/src/site/asciidoc/manual/layouts.adoc
@@ -41,7 +41,7 @@
 == CSV Layouts
 
 As of Log4j 2.11.0, CSV support has moved from the existing module
-`logj-core` to the new module `log4j-csv`.
+`log4j-core` to the new module `log4j-csv`.
 
 This layout creates
 https://en.wikipedia.org/wiki/Comma-separated_values[Comma Separated
@@ -225,13 +225,33 @@
 |boolean
 |Whether to include NULL byte as delimiter after each event (optional, default to false).
 Useful for Graylog GELF TCP input. Cannot be used with compression.
+
+|messagePattern
+|String
+|The pattern to use to format the String. If not supplied only the text derived from the logging
+message will be used. See <<PatternLayout>> for information on the pattern
+strings
+
+|threadContextExcludes
+|String
+|A comma separated list of ThreadContext attributes to exclude when formatting the event. This
+attribute only applies when includeThreadContext="true" is specified. If threadContextIncludes
+are also specified this attribute will be ignored.
+
+|threadContextIncludes
+|String
+|A comma separated list of ThreadContext attributes to include when formatting the event. This
+attribute only applies when includeThreadContext="true" is specified. If threadContextExcludes
+are also specified this attribute will override them. ThreadContext fields specified here that
+have no value will be omitted.
 |===
 
 To include any custom field in the output, use following syntax:
 
 [source,xml]
 ----
-<GelfLayout>
+<GelfLayout includeThreadContext="true" threadContextIncludes="loginId,requestId">
+  <MessagePattern>%d %5p [%t] %c{1} %X{loginId, requestId} - %m%n</MessagePattern>
   <KeyValuePair key="additionalField1" value="constant value"/>
   <KeyValuePair key="additionalField2" value="$${ctx:key}"/>
 </GelfLayout>
@@ -1645,6 +1665,23 @@
 and a set of PatternMatch elements that identify the various patterns
 that can be selected.
 
+[#LevelPatternSelector]
+==== LevelPatternSelector
+
+The LevelPatternSelector selects patterns based on the log level of
+the log event. If the Level in the log event is equal to (ignoring case)
+ the name specified on the PatternMatch key attribute, then
+the pattern specified on that PatternMatch element will be used.
+
+[source,xml]
+----
+<PatternLayout>
+  <MarkerPatternSelector defaultPattern="[%-5level] %c{1.} %msg%n">
+    <PatternMatch key="FLOW" pattern="[%-5level] %c{1.} ====== %C{1.}.%M:%L %msg ======%n"/>
+  </MarkerPatternSelector>
+</PatternLayout>
+----
+
 [#MarkerPatternSelector]
 ==== MarkerPatternSelector
 
@@ -1669,7 +1706,7 @@
 link:../configuration.html#Scripts[Scripts] section of the Configuration
 chapter. The script is passed all the properties configured in the
 Properties section of the configuration, the StrSubstitutor used by the
-Confguration in the "substitutor" vairables, and the log event in the
+Confguration in the "substitutor" variables, and the log event in the
 "logEvent" variable, and is expected to return the value of the
 PatternMatch key that should be used, or null if the default pattern
 should be used.
diff --git a/src/site/asciidoc/manual/logbuilder.adoc b/src/site/asciidoc/manual/logbuilder.adoc
index a7af088..0eba5bb 100644
--- a/src/site/asciidoc/manual/logbuilder.adoc
+++ b/src/site/asciidoc/manual/logbuilder.adoc
@@ -59,7 +59,7 @@
 classes in the log4j-perf project when configured to use 4 threads. The results show that lazily including
 the location information is about 8 times slower than not including location information. While using the
 withLocation method of LogBuilder is about 3 times faster than lazily calculating the location information
-it is still about 2.5 times slower than not including locatoin information.
+it is still about 2.5 times slower than not including location information.
 
 The tests were run on a 2018 MacBook Pro with a 2.9 GHz Intel Core i9 processor with 6 cores, 32 GB of memory
 and 1 TB of SSD storage on Java 11 using Log4j 2.13.0 and Logback 1.2.3.
@@ -73,7 +73,7 @@
 |Logback File|159,116.538 ± 1884.969  ops/s|1,240,438.384 ± 76619.873  ops/s
 |===
 As expected, when using LogBuilder with a call to the withLocation() method logging is much faster when
-location informatoin is used in the output but significantly slower when it is not.
+location information is used in the output but significantly slower when it is not.
 
 Note: Running the tests at various times provides varying results. Although some results have been as much
 as 10% higher all results are generally affected similarly so the comparisons between them stay the same.
\ No newline at end of file
diff --git a/src/site/asciidoc/manual/lookups.adoc b/src/site/asciidoc/manual/lookups.adoc
index bf745c4..5585b1a 100644
--- a/src/site/asciidoc/manual/lookups.adoc
+++ b/src/site/asciidoc/manual/lookups.adoc
@@ -80,7 +80,7 @@
 |containerId
 |The full id assigned to the container.
 
-|containreName
+|containerName
 |The name assigned to the container.
 
 |imageId
@@ -221,6 +221,58 @@
 
 *Java's JMX module is not available on Android or on Google App Engine.*
 
+[#KubernetesLookup]
+== Kubernetes Lookup
+
+The KubernetesLookup can be used to lookup attributes from the Kubernetes environment for the container
+the application is running in.
+
+Log4j Kubernetes provides access to the following container attributes:
+[cols="1m,4a"]
+|===
+|Attribute |Description
+|accountName|The service account name
+|clusterName|The name of the cluster the application is deployed in
+|containerId|>The full id assigned to the container
+|containerName|The name assigned to the container
+|host|The name assigned to the host operating system
+|hostIp|The host's ip address
+|imageId|The id assigned to the container image
+|imageName|The name assigned to the container image
+|labels|All labels formatted in a list
+|labesl.app|The application name
+|labels.podTemplateHash|The pod's template hash value
+|masterUrl|The URL used to access the API server
+|namespaceId|The id of the namespace the various kubernetes components are located within
+|namespaceName|The namespace the various kubernetes components are located within
+|podId|The pod's ip number
+|podIp|The pod's ip address
+|podName|The name of the pod
+
+      <GelfLayout includeStackTrace="true" host="${hostName}" includeThreadContext="true" includeNullDelimiter="true" compressionType="OFF">
+        <ThreadContextIncludes>requestId,sessionId,loginId,userId,ipAddress,callingHost</ThreadContextIncludes>
+        <MessagePattern>%d [%t] %-5p %X{requestId, sessionId, loginId, userId, ipAddress} %C{1.}.%M:%L - %m%n</MessagePattern>
+        <KeyValuePair key="docker.containerId" value="${docker:containerId:-}"/>
+        <KeyValuePair key="application" value="$${lower:${spring:spring.application.name}}"/>
+        <KeyValuePair key="kubernetes.serviceAccountName" value="${k8s:accountName:-}"/>
+        <KeyValuePair key="kubernetes.clusterName" value="${k8s:clusterName:-}/>
+        <KeyValuePair key="kubernetes.containerId" value="${k8s:containerId:-}"/>
+        <KeyValuePair key="kubernetes.containerName" value="${k8s:containerName:-}"/>
+        <KeyValuePair key="kubernetes.host" value="${k8s:host:-}"/>
+        <KeyValuePair key="kubernetes.labels.app" value="${k8s:labels.app:-}"/>
+        <KeyValuePair key="kubernetes.labels.pod-template-hash" value="${k8s:labels.podTemplateHash:-}"/>
+        <KeyValuePair key="kubernetes.master_url" value="${k8s:masterUrl:-}"/>
+        <KeyValuePair key="kubernetes.namespaceId" value="${k8s:namespaceId:-}"/>
+        <KeyValuePair key="kubernetes.namespaceName" value="${k8s:namespaceName:-}"/>
+        <KeyValuePair key="kubernetes.podID" value="${k8s:podId:-}"/>
+        <KeyValuePair key="kubernetes.podIP" value="${k8s:podIp:-}"/>
+        <KeyValuePair key="kubernetes.podName" value="${k8s:podName:-}"/>
+        <KeyValuePair key="kubernetes.imageId" value="${k8s:imageId:-}"/>
+        <KeyValuePair key="kubernetes.imageName" value="${k8s:imageName:-}"/>
+      </GelfLayout>]]></pre>
+
+This Lookup is subject to the configuration requirements listed at link:../log4j-kubernetes/index.html[Log4j Kubernetes Support]
+
 [#Log4jConfigLookup]
 == Log4j Configuration Location Lookup
 
@@ -241,6 +293,21 @@
 </File>
 ----
 
+[#LowerLookup]
+== Lower Lookup
+
+The LowerLookup converts the passed in argument to lower case. Presumably the value will be the
+result of a nested lookup.
+
+[source,xml]
+----
+<File name="Application" fileName="application.log">
+  <PatternLayout>
+    <pattern>%d %p %c{1.} [%t] $${lower:{${spring:spring.application.name}} %m%n</pattern>
+  </PatternLayout>
+</File>
+----
+
 [#AppMainArgsLookup]
 == Main Arguments Lookup (Application)
 
@@ -450,6 +517,23 @@
 </Routing>
 ----
 
+[#SpringLookup]
+== Spring Boot Lookup
+
+The Spring Boot Lookup retrieves the values of Spring properties from the Spring configuration. This Lookup
+will return null values until Spring Boot initializes application logging.
+
+[source,xml]
+----
+<File name="Application" fileName="application.log">
+  <PatternLayout>
+    <pattern>%d %p %c{1.} [%t] $${spring:spring.application.name} %m%n</pattern>
+  </PatternLayout>
+</File>
+----
+
+This Lookup requires log4j-spring-cloud-config-client be included in the application.
+
 [#SystemPropertiesLookup]
 == System Properties Lookup
 
@@ -477,6 +561,21 @@
 </Appenders>
 ----
 
+[#UpperLookup]
+== Upper Lookup
+
+The LowerLookup converts the passed in argument to upper case. Presumably the value will be the
+result of a nested lookup.
+
+[source,xml]
+----
+<File name="Application" fileName="application.log">
+  <PatternLayout>
+    <pattern>%d %p %c{1.} [%t] $${upper:{${spring:spring.application.name}} %m%n</pattern>
+  </PatternLayout>
+</File>
+----
+
 [#WebLookup]
 == Web Lookup
 
@@ -530,6 +629,9 @@
 |session.id
 |Returns the HttpSession id or null if none is started - requires Log4jServletFilter
 
+|session.attr._name_
+|Returns the HttpSession attribute value (using _toString()_ if not null) or null if absent - requires Log4jServletFilter
+
 |contextPath
 |The context path of the web application
 
diff --git a/src/site/asciidoc/manual/plugins.adoc b/src/site/asciidoc/manual/plugins.adoc
index bc0a7e2..694d7bf 100644
--- a/src/site/asciidoc/manual/plugins.adoc
+++ b/src/site/asciidoc/manual/plugins.adoc
@@ -46,7 +46,7 @@
 in your log4j2 configuration file.
 6. Serialized plugin listing files on the classpath. These files were generated by
 the plugin annotation processor in Log4j 2 2.x. These are processed to allow
-compatbility.
+compatibility.
 
 If multiple Plugins specify the same (case-insensitive) `name`, then the
 load order above determines which one will be used. For example, to
@@ -127,18 +127,27 @@
 may simply be referenced in the configuration, provided they are
 appropriate configured to be loaded by the PluginManager.
 
-Every Core plugin must declare a static method annotated with
-`@PluginFactory` or `@PluginBuilderFactory`. The former is used for
-static factory methods that provide all options as method parameters,
-and the latter is used to construct a new `Builder<T>` class whose
-fields are used for injecting attributes and child nodes. To allow the
-`Configuration` to pass the correct parameters to the method, every
-parameter to the method must be annotated as one of the following
-attribute types. Each attribute or element annotation must include the
+Core plugins follow a few simple dependency injection rules for binding
+`Configuration` parameters into a factory entry point. Each plugin must
+declare a static method annotated with `@PluginFactory`.
+This method can either list all options as method parameters, or it can return
+a new `Builder<T>` instance where options are available as either single-argument
+`setFoo` or `withFoo` methods or fields. There are a few different attribute types
+available to denote `Configuration` data that are injected by the plugin
+framework. These are available as annotations that can either be used on the
+method parameters to return an instance of the plugin, or they can be used on the
+returned builder class's methods or fields. Each annotation may include the
 name that must be present in the configuration in order to match the
-configuration item to its respective parameter. For plugin builders, the
-names of the fields will be used by default if no name is specified in
-the annotation. There are dozens of plugins in Log4j Core that can be
+configuration item to its respective parameter. If no name is specified, then
+the name used is as follows:
+
+* When annotated on a parameter, this will use the parameter name.
+* When annotated on a single argument method, if the method name is prefixed by
+  `set` or `with`, this will use the remainder of the method name. Otherwise, the
+  full method name is used.
+* When annotated on a field, this will used the field name.
+
+There are dozens of plugins in Log4j Core that can be
 used as examples for more complex scenarios including hierarchical
 builder classes (e.g., see `FileAppender`). See
 link:extending.html#Plugin_Builders[Extending Log4j with Plugin
@@ -167,7 +176,7 @@
 
 === Constraint Validators
 
-Plugin factory fields and parameters can be automatically validated at
+Plugin factory fields, methods, and parameters can be automatically validated at
 runtime using constraint validators inspired by the
 http://beanvalidation.org/[Bean Validation spec]. The following
 annotations are bundled in Log4j, but custom
diff --git a/src/site/asciidoc/manual/thread-context.adoc b/src/site/asciidoc/manual/thread-context.adoc
index e32cb79..723a121 100644
--- a/src/site/asciidoc/manual/thread-context.adoc
+++ b/src/site/asciidoc/manual/thread-context.adoc
@@ -205,7 +205,7 @@
 === Including the ThreadContext when writing logs
 
 The
-link:../log4j-api/apidocs/org/apache/logging/log4j/core/PatternLayout.html[`PatternLayout`]
+link:../log4j-core/apidocs/org/apache/logging/log4j/core/layout/PatternLayout.html[`PatternLayout`]
 provides mechanisms to print the contents of the
 link:../log4j-api/apidocs/org/apache/logging/log4j/ThreadContext.html[`ThreadContext`]
 Map and Stack.
diff --git a/src/site/asciidoc/manual/usage.adoc b/src/site/asciidoc/manual/usage.adoc
index 513add8..76f1629 100644
--- a/src/site/asciidoc/manual/usage.adoc
+++ b/src/site/asciidoc/manual/usage.adoc
@@ -20,7 +20,7 @@
 [#Static_vs_Non_Static]
 == Static vs Non-Static Loggers
 As with any variable in Java, Loggers may be declared as static variables or class member variables. However,
-there are a few factors to consider when choosing to delare a logger as static vs non-static. Generally, it
+there are a few factors to consider when choosing to declare a logger as static vs non-static. Generally, it
 is better to declare Loggers as static.
 
 1. Instantiation of a new Logger is a fairly expensive operation when using the default ContextSelector,
@@ -194,7 +194,7 @@
 7. Logging is performed in the parent class using the logger of Child. The logger name matches the name of the child
 and so it is printed.
 8. Logging is performed in the parent class using the logger of the Child. Although the method was called against
-the Child instance it is implemented in PArent so that is what appears as the class name.
+the Child instance it is implemented in Parent so that is what appears as the class name.
 9. Logging is performed in Child using the logger in the parent which is set to the child logger, so the name of the
 child is printed as the logger name.
 10. Logging is performed in Child using the logger in the parent, which is set to the child logger. Since
diff --git a/src/site/markdown/manual/cloud.md b/src/site/markdown/manual/cloud.md
index fdde0f8..69020fd 100644
--- a/src/site/markdown/manual/cloud.md
+++ b/src/site/markdown/manual/cloud.md
@@ -21,7 +21,7 @@
 ## The Twelve-Factor Application
 
 The Logging Guidelines for [The Twelve-Factor App](https://12factor.net/logs) state that all logs should be routed 
-unbuffered to stdout. Since this is the least common denominator it is guaranteed to work for all applications. Howeever,
+unbuffered to stdout. Since this is the least common denominator it is guaranteed to work for all applications. However,
 as with any set of general guidelines, choosing the least common denominator approach comes at a cost. Some of the costs
 in Java applications include:
 
@@ -33,10 +33,18 @@
     c. Log from Log4j directly to a logging forwarder or aggregator and bypass the docker logging driver.
 1. When logging to stdout in Docker, log events pass through Java's standard output handling which is then directed 
 to the operating system so that the output can be piped into a file. The overhead of all this is measurably slower
-than just writing directly to a file as can be seen by the performance results below where logging 
-to stdout is anywhere from 20 to 200% slower than logging directly to the file. However, these results alone
-would not be enough to argue against writing to the standard output stream as they only amount to about 20-30 
-microseconds per logging call. 
+than just writing directly to a file as can be seen in these benchmark results where logging 
+to stdout is 16-20 times slower over repeated runs than logging directly to the file. The results below were obtained by 
+running the [Output Benchmark](https://github.com/apache/logging-log4j2/blob/release-2.x/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/OutputBenchmark.java)
+on a 2018 MacBook Pro with a 2.9GHz Intel Core i9 processor and a 1TB SSD.  However, these results alone would not be 
+enough to argue against writing to the standard output stream as they only amount to about 14-25 microseconds 
+per logging call vs 1.5 microseconds when writing to the file. 
+    ```
+        Benchmark                  Mode  Cnt       Score       Error  Units
+        OutputBenchmark.console   thrpt   20   39291.885 ±  3370.066  ops/s
+        OutputBenchmark.file      thrpt   20  654584.309 ± 59399.092  ops/s
+        OutputBenchmark.redirect  thrpt   20   70284.576 ±  7452.167  ops/s
+    ```
 1. When performing audit logging using a framework such as log4j-audit guaranteed delivery of the audit events
 is required. Many of the options for writing the output, including writing to the standard output stream, do
 not guarantee delivery. In these cases the event must be delivered to a "forwarder" that acknowledges receipt
@@ -110,11 +118,88 @@
 
 ![Aggregator](../images/LoggerAggregator.png "Application Logging to an Aggregator via TCP")
 
+## <a name="ELK"></a>Logging using ElasticSearch, Logstash, and Kibana
+
+The following configurations have been tested with an ELK stack and are known to work.
+
+### Log4j Configuration
+Use a socket appender with the GELF layout. Note that if the host name used by the socket appender has more than 
+one ip address associated with its DNS entry the socket appender will fail through them all if needed.
+
+    <Socket name="Elastic" host="${sys:elastic.search.host}" port="12222" protocol="tcp" bufferedIo="true">
+      <GelfLayout includeStackTrace="true" host="${hostName}" includeThreadContext="true" includeNullDelimiter="true"
+                  compressionType="OFF">
+        <ThreadContextIncludes>requestId,sessionId,loginId,userId,ipAddress,callingHost</ThreadContextIncludes>
+        <MessagePattern>%d [%t] %-5p %X{requestId, sessionId, loginId, userId, ipAddress} %C{1.}.%M:%L - %m%n</MessagePattern>
+        <KeyValuePair key="containerId" value="${docker:containerId:-}"/>
+        <KeyValuePair key="application" value="$${lower:${spring:spring.application.name:-spring}}"/>
+        <KeyValuePair key="kubernetes.serviceAccountName" value="${k8s:accountName:-}"/>
+        <KeyValuePair key="kubernetes.containerId" value="${k8s:containerId:-}"/>
+        <KeyValuePair key="kubernetes.containerName" value="${k8s:containerName:-}"/>
+        <KeyValuePair key="kubernetes.host" value="${k8s:host:-}"/>
+        <KeyValuePair key="kubernetes.labels.app" value="${k8s:labels.app:-}"/>
+        <KeyValuePair key="kubernetes.labels.pod-template-hash" value="${k8s:labels.podTemplateHash:-}"/>
+        <KeyValuePair key="kubernetes.master_url" value="${k8s:masterUrl:-}"/>
+        <KeyValuePair key="kubernetes.namespaceId" value="${k8s:namespaceId:-}"/>
+        <KeyValuePair key="kubernetes.namespaceName" value="${k8s:namespaceName:-}"/>
+        <KeyValuePair key="kubernetes.podID" value="${k8s:podId:-}"/>
+        <KeyValuePair key="kubernetes.podIP" value="${k8s:podIp:-}"/>
+        <KeyValuePair key="kubernetes.podName" value="${k8s:podName:-}"/>
+        <KeyValuePair key="kubernetes.imageId" value="${k8s:imageId:-}"/>
+        <KeyValuePair key="kubernetes.imageName" value="${k8s:imageName:-}"/>
+      </GelfLayout>
+    </Socket>
+
+### Logstash Configuration
+
+    input {
+      gelf {
+        host => "localhost"
+        use_tcp => true
+        use_udp => false
+        port => 12222
+        type => "gelf"
+      }
+    }
+
+    filter {
+      # These are GELF/Syslog logging levels as defined in RFC 3164. Map the integer level to its human readable format.
+      translate {
+        field => "[level]"
+        destination => "[levelName]"
+        dictionary => {
+          "0" => "EMERG"
+          "1" => "ALERT"
+          "2" => "CRITICAL"
+          "3" => "ERROR"
+          "4" => "WARN"
+          "5" => "NOTICE"
+          "6" => "INFO"
+          "7" => "DEBUG"
+        }
+      }
+    }
+
+    output {
+      # (Un)comment for debugging purposes
+      # stdout { codec => rubydebug }
+      # Modify the hosts value to reflect where elasticsearch is installed.
+      elasticsearch {
+        hosts => ["http://localhost:9200/"]
+        index => "app-%{application}-%{+YYYY.MM.dd}"
+      }
+    }
+
+### Kibana
+With the above configurations the message field will contain a fully formatted log event just as it would  appear in 
+a file Appender. The ThreadContext attributes, custome fields, thread name, etc. will all be available as attributes
+on each log event that can be used for filtering.
+
 ## Managing Logging Configuration
 
 Spring Boot provides another least common denominator approach to logging configuration. It will let you set the 
 log level for various Loggers within an application which can be dynamically updated via REST endpoints provided 
-by Spring. While this works in a lot of cases it does not support any of the more advanced filtering featurs of 
+by Spring. While this works in a lot of cases it does not support any of the more advanced filtering features of 
 Log4j. For example, since it cannot add or modify any Filters other than the log level of a logger, changes cannot be made to allow 
 all log events for a specific user or customer to temporarily be logged 
 (see [DynamicThresholdFilter](filters.html#DynamicThresholdFilter) or 
@@ -127,7 +212,7 @@
 for changes by using the HTTP "If-Modified-Since" header. A patch has also been integrated into Spring Cloud Config
 starting with versions 2.0.3 and 2.1.1 for it to honor the If-Modified-Since header. In addition, the 
 log4j-spring-cloud-config project will listen for update events published by Spring Cloud Bus and then verify
-that the configuratoin file has been modified, so polling via HTTP is not required.
+that the configuration file has been modified, so polling via HTTP is not required.
 
 Log4j also supports composite configurations. A distributed application spread across microservices could 
 share a common configuration file that could be used to control things like enabling debug logging for a 
@@ -139,21 +224,37 @@
 Further information regarding integration of the log4j-spring-cloud-config-client can be found at 
 [Log4j Spring Cloud Config Client](../log4j-spring-cloud-config/log4j-spring-cloud-config-client/index.html).
 
+## Integration with Spring Boot
+
+Log4j integrates with Spring Boot in 2 ways:
+
+1. A Spring Lookup can be used to access the Spring application configuration from Log4j configuration files.
+2. Log4j will access the Spring configuration when it is trying to resolve log4j system properties.
+
+Both of these require that the log4j-spring-cloud-client jar is included in the application.
+
 ## Integration with Docker
 
 Applications within a Docker container that log using a Docker logging driver can include special 
 attributes in the formatted log event as described at 
 [Customize Log Driver Output](https://docs.docker.com/config/containers/logging/log_tags/). Log4j 
-provides similar functionality via the [Docker Loookup](lookups.html#DockerLookup). More information on
+provides similar functionality via the [Docker Lookup](lookups.html#DockerLookup). More information on
 Log4j's Docker support may also be found at [Log4j-Docker](../log4j-docker/index.html). 
 
+## Integration with Kubernetes
+
+Applications managed by Kubernetes can bypass the Docker/Kubernetes logging infrastructure and log directly to 
+either a sidecar forwarder or a logging aggragator cluster while still including all the kubernetes 
+attributes by using the Log4j 2 [Kubernetes Lookup](lookups.html#KubernetesLookup). More information on
+Log4j's Kubernetes support may also be found at [Log4j-Kubernetes](../log4j-kubernetes/index.html). 
+
 ## Appender Performance
-The numbers in the table below represent how much time in seceonds was required for the application to 
-call logger.debug 100,000 times. These numbers only include the time taken to deliver to the specifcly 
-noted endpoint and many not include the actual time required before they are availble for viewing. All 
+The numbers in the table below represent how much time in seconds was required for the application to 
+call logger.debug 100,000 times. These numbers only include the time taken to deliver to the specifically 
+noted endpoint and many not include the actual time required before they are available for viewing. All 
 measurements were performed on a MacBook Pro with a 2.9GHz Intel Core I9 processor with 6 physical and 12 
 logical cores, 32GB of 2400 MHz DDR4 RAM, and 1TB of Apple SSD storage. The VM used by Docker was managed 
-by VMWare Fusion and had 4 CPUs and 2 GB of RAM. These number should be used for relative perfomance comparisons 
+by VMWare Fusion and had 4 CPUs and 2 GB of RAM. These number should be used for relative performance comparisons 
 as the results on another system may vary considerably.
 
 The sample application used can be found under the log4j-spring-cloud-config/log4j-spring-cloud-config-samples
@@ -211,9 +312,10 @@
 the performance numbers show, so long as the volume of logging is not high enough to fill up the 
 circular buffer the overhead of logging will almost be unnoticeable to the application.
 1. If overall performance is a consideration or you require multiline events such as stack traces
-be processed properly then log via TCP to a companion container that acts as a log forwarder. Use the 
+be processed properly then log via TCP to a companion container that acts as a log forwarder or directly
+to a log aggregator as shown above in [Logging with ELK](#ELK). Use the  
 Log4j Docker Lookup to add the container information to each log event.
-1. Whenvever guaranteed delivery is required use Flume Avro with a batch size of 1 or another Appender such 
+1. Whenever guaranteed delivery is required use Flume Avro with a batch size of 1 or another Appender such 
 as the Kafka Appender with syncSend set to true that only return control after the downstream agent 
 acknowledges receipt of the event. Beware that using an Appender that writes each event individually should 
 be kept to a minimum since it is much slower than sending buffered events. 
diff --git a/src/site/markdown/manual/compatibility.md b/src/site/markdown/manual/compatibility.md
new file mode 100644
index 0000000..69a1b30
--- /dev/null
+++ b/src/site/markdown/manual/compatibility.md
@@ -0,0 +1,94 @@
+<!-- vim: set syn=markdown : -->
+<!--
+ 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.
+-->
+
+# Log4j 2 Compatibility with Log4j 1
+
+## API Compatibility
+
+Log4j 2 provides support for the Log4j 1 logging methods by providing alternate implementations 
+of the classes containing those methods. These classes may be found in the log4j-1.2-api jar 
+distributed with the project. All calls to perform logging will result in the data passed to the logging methods
+to be forwarded to the Log4j2 API where they can be processed by implementations of the Log4j 2 API. 
+
+## Configuration Compatibility
+
+Log4j 2 provides experimental support for Log4j 1 configuration files. Configuration of the Appenders, Layouts 
+and Filters that were provided in the Log4j 1 distribution will be redirected to their Log4j 2 counterparts - 
+with the exception of the implemented Rewrite Policies. This means that although the while the behavior of these 
+components will be similar they may not be exactly the same. For example, the XML generated by the XMLLayout may 
+not exactly match the XML generated by the Log4j 1XMLLayout. 
+
+In addition, Log4j 2 supports custom Log4j 1 Appenders, Filters, and Layouts with some constraints. Since the 
+original Log4j 1 components may not be present in Log4j 2, custom components that extend them will fail. 
+
+As support for Log4j 1 is an experimental feature one of the following steps must be taken to enable it:
+
+1. Set the system property "log4j1.compatibility" to a value of "true". Log4j 2 will then add log4j.properties,
+log4j-test.properties, log4j.xml and log4j-test.xml to the configuration files it searches for on the class path.
+1. Set the Log4j 1 system property "log4j.configuration" to the location of the log4j 1 configuration file. The 
+files must have a file extension of either ".properties" or ".xml".
+
+## Supported Components
+### Appenders
+
+* AsyncAppender
+* ConsoleAppender
+* DailyRollingFileAppender
+* FileAppender
+* NullAppender
+* RewriteAppender (limited)
+* RollingFileAppender
+* SyslogAppender
+
+## Filters
+
+* DenyAllFilter
+* LevelMatchFilter
+* LevelRangeFilter
+* StringMatchFilter
+
+## Layouts
+
+* HtmlLayout
+* PatternLayout
+* SimpleLayout
+* TTCCLayout
+* XmlLayout
+
+## Rewrite Policies
+
+* MapRewritePolicy
+* PropertyRewritePolicy
+
+## Unsupported or Unimplemented Components
+### Appenders
+
+* JDBCAppender (cannot be mapped to Log4j 2's JdbcAppender)
+* JMSAppender 
+* SMTPAppender
+* SocketAppender (Requires the use of the SerializedLayout which is a security risk)
+* SocketHubAppender (Requires the use of the SerializedLayout which is a securiy risk)
+* TelnetAppender (Security risk)
+
+## Rewrite Policies
+
+* ReflectionRewritePolicy
+* Custom rewrite policies since LoggingEvent is currently a no-op.
+
+### Renderers
+Log4j 2 currently will ignore renderers.
\ No newline at end of file
diff --git a/src/site/resources/css/bootstrap.css b/src/site/resources/css/bootstrap.css
deleted file mode 100644
index 3ef47e1..0000000
--- a/src/site/resources/css/bootstrap.css
+++ /dev/null
@@ -1,5893 +0,0 @@
-/*!
- * Bootstrap v2.2.1
- *
- * 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 {
-  width: auto\9;
-  height: auto;
-  max-width: 100%;
-  vertical-align: middle;
-  border: 0;
-  -ms-interpolation-mode: bicubic;
-}
-
-#map_canvas img,
-.google-maps img {
-  max-width: none;
-}
-
-button,
-input,
-select,
-textarea {
-  margin: 0;
-  font-size: 100%;
-  vertical-align: middle;
-}
-
-button,
-input {
-  *overflow: visible;
-  line-height: normal;
-}
-
-button::-moz-focus-inner,
-input::-moz-focus-inner {
-  padding: 0;
-  border: 0;
-}
-
-button,
-html input[type="button"],
-input[type="reset"],
-input[type="submit"] {
-  cursor: pointer;
-  -webkit-appearance: button;
-}
-
-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;
-  line-height: 0;
-  content: "";
-}
-
-.clearfix:after {
-  clear: both;
-}
-
-.hide-text {
-  font: 0/0 a;
-  color: transparent;
-  text-shadow: none;
-  background-color: transparent;
-  border: 0;
-}
-
-.input-block-level {
-  display: block;
-  width: 100%;
-  min-height: 30px;
-  -webkit-box-sizing: border-box;
-     -moz-box-sizing: border-box;
-          box-sizing: border-box;
-}
-
-body {
-  margin: 0;
-  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
-  font-size: 14px;
-  line-height: 20px;
-  color: #333333;
-  background-color: #ffffff;
-}
-
-a {
-  color: #0088cc;
-  text-decoration: none;
-}
-
-a:hover {
-  color: #005580;
-  text-decoration: underline;
-}
-
-.img-rounded {
-  -webkit-border-radius: 6px;
-     -moz-border-radius: 6px;
-          border-radius: 6px;
-}
-
-.img-polaroid {
-  padding: 4px;
-  background-color: #fff;
-  border: 1px solid #ccc;
-  border: 1px solid rgba(0, 0, 0, 0.2);
-  -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
-     -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
-          box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
-}
-
-.img-circle {
-  -webkit-border-radius: 500px;
-     -moz-border-radius: 500px;
-          border-radius: 500px;
-}
-
-.row {
-  margin-left: -20px;
-  *zoom: 1;
-}
-
-.row:before,
-.row:after {
-  display: table;
-  line-height: 0;
-  content: "";
-}
-
-.row:after {
-  clear: both;
-}
-
-[class*="span"] {
-  float: left;
-  min-height: 1px;
-  margin-left: 20px;
-}
-
-.container,
-.navbar-static-top .container,
-.navbar-fixed-top .container,
-.navbar-fixed-bottom .container {
-  width: 940px;
-}
-
-.span12 {
-  width: 940px;
-}
-
-.span11 {
-  width: 860px;
-}
-
-.span10 {
-  width: 780px;
-}
-
-.span9 {
-  width: 700px;
-}
-
-.span8 {
-  width: 620px;
-}
-
-.span7 {
-  width: 540px;
-}
-
-.span6 {
-  width: 460px;
-}
-
-.span5 {
-  width: 380px;
-}
-
-.span4 {
-  width: 300px;
-}
-
-.span3 {
-  width: 220px;
-}
-
-.span2 {
-  width: 140px;
-}
-
-.span1 {
-  width: 60px;
-}
-
-.offset12 {
-  margin-left: 980px;
-}
-
-.offset11 {
-  margin-left: 900px;
-}
-
-.offset10 {
-  margin-left: 820px;
-}
-
-.offset9 {
-  margin-left: 740px;
-}
-
-.offset8 {
-  margin-left: 660px;
-}
-
-.offset7 {
-  margin-left: 580px;
-}
-
-.offset6 {
-  margin-left: 500px;
-}
-
-.offset5 {
-  margin-left: 420px;
-}
-
-.offset4 {
-  margin-left: 340px;
-}
-
-.offset3 {
-  margin-left: 260px;
-}
-
-.offset2 {
-  margin-left: 180px;
-}
-
-.offset1 {
-  margin-left: 100px;
-}
-
-.row-fluid {
-  width: 100%;
-  *zoom: 1;
-}
-
-.row-fluid:before,
-.row-fluid:after {
-  display: table;
-  line-height: 0;
-  content: "";
-}
-
-.row-fluid:after {
-  clear: both;
-}
-
-.row-fluid [class*="span"] {
-  display: block;
-  float: left;
-  width: 100%;
-  min-height: 30px;
-  margin-left: 2.127659574468085%;
-  *margin-left: 2.074468085106383%;
-  -webkit-box-sizing: border-box;
-     -moz-box-sizing: border-box;
-          box-sizing: border-box;
-}
-
-.row-fluid [class*="span"]:first-child {
-  margin-left: 0;
-}
-
-.row-fluid .controls-row [class*="span"] + [class*="span"] {
-  margin-left: 2.127659574468085%;
-}
-
-.row-fluid .span12 {
-  width: 100%;
-  *width: 99.94680851063829%;
-}
-
-.row-fluid .span11 {
-  width: 91.48936170212765%;
-  *width: 91.43617021276594%;
-}
-
-.row-fluid .span10 {
-  width: 82.97872340425532%;
-  *width: 82.92553191489361%;
-}
-
-.row-fluid .span9 {
-  width: 74.46808510638297%;
-  *width: 74.41489361702126%;
-}
-
-.row-fluid .span8 {
-  width: 65.95744680851064%;
-  *width: 65.90425531914893%;
-}
-
-.row-fluid .span7 {
-  width: 57.44680851063829%;
-  *width: 57.39361702127659%;
-}
-
-.row-fluid .span6 {
-  width: 48.93617021276595%;
-  *width: 48.88297872340425%;
-}
-
-.row-fluid .span5 {
-  width: 40.42553191489362%;
-  *width: 40.37234042553192%;
-}
-
-.row-fluid .span4 {
-  width: 31.914893617021278%;
-  *width: 31.861702127659576%;
-}
-
-.row-fluid .span3 {
-  width: 23.404255319148934%;
-  *width: 23.351063829787233%;
-}
-
-.row-fluid .span2 {
-  width: 14.893617021276595%;
-  *width: 14.840425531914894%;
-}
-
-.row-fluid .span1 {
-  width: 6.382978723404255%;
-  *width: 6.329787234042553%;
-}
-
-.row-fluid .offset12 {
-  margin-left: 104.25531914893617%;
-  *margin-left: 104.14893617021275%;
-}
-
-.row-fluid .offset12:first-child {
-  margin-left: 102.12765957446808%;
-  *margin-left: 102.02127659574467%;
-}
-
-.row-fluid .offset11 {
-  margin-left: 95.74468085106382%;
-  *margin-left: 95.6382978723404%;
-}
-
-.row-fluid .offset11:first-child {
-  margin-left: 93.61702127659574%;
-  *margin-left: 93.51063829787232%;
-}
-
-.row-fluid .offset10 {
-  margin-left: 87.23404255319149%;
-  *margin-left: 87.12765957446807%;
-}
-
-.row-fluid .offset10:first-child {
-  margin-left: 85.1063829787234%;
-  *margin-left: 84.99999999999999%;
-}
-
-.row-fluid .offset9 {
-  margin-left: 78.72340425531914%;
-  *margin-left: 78.61702127659572%;
-}
-
-.row-fluid .offset9:first-child {
-  margin-left: 76.59574468085106%;
-  *margin-left: 76.48936170212764%;
-}
-
-.row-fluid .offset8 {
-  margin-left: 70.2127659574468%;
-  *margin-left: 70.10638297872339%;
-}
-
-.row-fluid .offset8:first-child {
-  margin-left: 68.08510638297872%;
-  *margin-left: 67.9787234042553%;
-}
-
-.row-fluid .offset7 {
-  margin-left: 61.70212765957446%;
-  *margin-left: 61.59574468085106%;
-}
-
-.row-fluid .offset7:first-child {
-  margin-left: 59.574468085106375%;
-  *margin-left: 59.46808510638297%;
-}
-
-.row-fluid .offset6 {
-  margin-left: 53.191489361702125%;
-  *margin-left: 53.085106382978715%;
-}
-
-.row-fluid .offset6:first-child {
-  margin-left: 51.063829787234035%;
-  *margin-left: 50.95744680851063%;
-}
-
-.row-fluid .offset5 {
-  margin-left: 44.68085106382979%;
-  *margin-left: 44.57446808510638%;
-}
-
-.row-fluid .offset5:first-child {
-  margin-left: 42.5531914893617%;
-  *margin-left: 42.4468085106383%;
-}
-
-.row-fluid .offset4 {
-  margin-left: 36.170212765957444%;
-  *margin-left: 36.06382978723405%;
-}
-
-.row-fluid .offset4:first-child {
-  margin-left: 34.04255319148936%;
-  *margin-left: 33.93617021276596%;
-}
-
-.row-fluid .offset3 {
-  margin-left: 27.659574468085104%;
-  *margin-left: 27.5531914893617%;
-}
-
-.row-fluid .offset3:first-child {
-  margin-left: 25.53191489361702%;
-  *margin-left: 25.425531914893618%;
-}
-
-.row-fluid .offset2 {
-  margin-left: 19.148936170212764%;
-  *margin-left: 19.04255319148936%;
-}
-
-.row-fluid .offset2:first-child {
-  margin-left: 17.02127659574468%;
-  *margin-left: 16.914893617021278%;
-}
-
-.row-fluid .offset1 {
-  margin-left: 10.638297872340425%;
-  *margin-left: 10.53191489361702%;
-}
-
-.row-fluid .offset1:first-child {
-  margin-left: 8.51063829787234%;
-  *margin-left: 8.404255319148938%;
-}
-
-[class*="span"].hide,
-.row-fluid [class*="span"].hide {
-  display: none;
-}
-
-[class*="span"].pull-right,
-.row-fluid [class*="span"].pull-right {
-  float: right;
-}
-
-.container {
-  margin-right: auto;
-  margin-left: auto;
-  *zoom: 1;
-}
-
-.container:before,
-.container:after {
-  display: table;
-  line-height: 0;
-  content: "";
-}
-
-.container:after {
-  clear: both;
-}
-
-.container-fluid {
-  padding-right: 20px;
-  padding-left: 20px;
-  *zoom: 1;
-}
-
-.container-fluid:before,
-.container-fluid:after {
-  display: table;
-  line-height: 0;
-  content: "";
-}
-
-.container-fluid:after {
-  clear: both;
-}
-
-p {
-  margin: 0 0 10px;
-}
-
-.lead {
-  margin-bottom: 20px;
-  font-size: 21px;
-  font-weight: 200;
-  line-height: 30px;
-}
-
-small {
-  font-size: 85%;
-}
-
-strong {
-  font-weight: bold;
-}
-
-em {
-  font-style: italic;
-}
-
-cite {
-  font-style: normal;
-}
-
-.muted {
-  color: #999999;
-}
-
-.text-warning {
-  color: #c09853;
-}
-
-a.text-warning:hover {
-  color: #a47e3c;
-}
-
-.text-error {
-  color: #b94a48;
-}
-
-a.text-error:hover {
-  color: #953b39;
-}
-
-.text-info {
-  color: #3a87ad;
-}
-
-a.text-info:hover {
-  color: #2d6987;
-}
-
-.text-success {
-  color: #468847;
-}
-
-a.text-success:hover {
-  color: #356635;
-}
-
-h1,
-h2,
-h3,
-h4,
-h5,
-h6 {
-  margin: 10px 0;
-  font-family: inherit;
-  font-weight: bold;
-  line-height: 20px;
-  color: inherit;
-  text-rendering: optimizelegibility;
-}
-
-h1 small,
-h2 small,
-h3 small,
-h4 small,
-h5 small,
-h6 small {
-  font-weight: normal;
-  line-height: 1;
-  color: #999999;
-}
-
-h1,
-h2,
-h3 {
-  line-height: 40px;
-}
-
-h1 {
-  font-size: 38.5px;
-}
-
-h2 {
-  font-size: 31.5px;
-}
-
-h3 {
-  font-size: 24.5px;
-}
-
-h4 {
-  font-size: 17.5px;
-}
-
-h5 {
-  font-size: 14px;
-}
-
-h6 {
-  font-size: 11.9px;
-}
-
-h1 small {
-  font-size: 24.5px;
-}
-
-h2 small {
-  font-size: 17.5px;
-}
-
-h3 small {
-  font-size: 14px;
-}
-
-h4 small {
-  font-size: 14px;
-}
-
-.page-header {
-  padding-bottom: 9px;
-  margin: 20px 0 30px;
-  border-bottom: 1px solid #eeeeee;
-}
-
-ul,
-ol {
-  padding: 0;
-  margin: 0 0 10px 25px;
-}
-
-ul ul,
-ul ol,
-ol ol,
-ol ul {
-  margin-bottom: 0;
-}
-
-li {
-  line-height: 20px;
-}
-
-ul.unstyled,
-ol.unstyled {
-  margin-left: 0;
-  list-style: none;
-}
-
-dl {
-  margin-bottom: 20px;
-}
-
-dt,
-dd {
-  line-height: 20px;
-}
-
-dt {
-  font-weight: bold;
-}
-
-dd {
-  margin-left: 10px;
-}
-
-.dl-horizontal {
-  *zoom: 1;
-}
-
-.dl-horizontal:before,
-.dl-horizontal:after {
-  display: table;
-  line-height: 0;
-  content: "";
-}
-
-.dl-horizontal:after {
-  clear: both;
-}
-
-.dl-horizontal dt {
-  float: left;
-  width: 160px;
-  overflow: hidden;
-  clear: left;
-  text-align: right;
-  text-overflow: ellipsis;
-  white-space: nowrap;
-}
-
-.dl-horizontal dd {
-  margin-left: 180px;
-}
-
-hr {
-  margin: 20px 0;
-  border: 0;
-  border-top: 1px solid #eeeeee;
-  border-bottom: 1px solid #ffffff;
-}
-
-abbr[title],
-abbr[data-original-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 20px;
-  border-left: 5px solid #eeeeee;
-}
-
-blockquote p {
-  margin-bottom: 0;
-  font-size: 16px;
-  font-weight: 300;
-  line-height: 25px;
-}
-
-blockquote small {
-  display: block;
-  line-height: 20px;
-  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;
-}
-
-blockquote.pull-right small:before {
-  content: '';
-}
-
-blockquote.pull-right small:after {
-  content: '\00A0 \2014';
-}
-
-q:before,
-q:after,
-blockquote:before,
-blockquote:after {
-  content: "";
-}
-
-address {
-  display: block;
-  margin-bottom: 20px;
-  font-style: normal;
-  line-height: 20px;
-}
-
-code,
-pre {
-  padding: 0 3px 2px;
-  font-family: Monaco, Menlo, Consolas, "Courier New", monospace;
-  font-size: 12px;
-  color: #333333;
-  -webkit-border-radius: 3px;
-     -moz-border-radius: 3px;
-          border-radius: 3px;
-}
-
-code {
-  padding: 2px 4px;
-  color: #d14; /* FIXME: red? really? */
-  background-color: #f7f7f9;
-  border: 1px solid #e1e1e8;
-}
-
-pre {
-  display: block;
-  padding: 9.5px;
-  margin: 0 0 10px;
-  font-size: 13px;
-  line-height: 20px;
-  word-break: break-all;
-  word-wrap: break-word;
-  white-space: pre;
-  white-space: pre-wrap;
-  background-color: #f5f5f5;
-  border: 1px solid #ccc;
-  border: 1px solid rgba(0, 0, 0, 0.15);
-  -webkit-border-radius: 4px;
-     -moz-border-radius: 4px;
-          border-radius: 4px;
-}
-
-pre.prettyprint {
-  margin-bottom: 20px;
-}
-
-pre code {
-  padding: 0;
-  color: inherit;
-  background-color: transparent;
-  border: 0;
-}
-
-.pre-scrollable {
-  max-height: 340px;
-  overflow-y: scroll;
-}
-
-form {
-  margin: 0 0 20px;
-}
-
-fieldset {
-  padding: 0;
-  margin: 0;
-  border: 0;
-}
-
-legend {
-  display: block;
-  width: 100%;
-  padding: 0;
-  margin-bottom: 20px;
-  font-size: 21px;
-  line-height: 40px;
-  color: #333333;
-  border: 0;
-  border-bottom: 1px solid #e5e5e5;
-}
-
-legend small {
-  font-size: 15px;
-  color: #999999;
-}
-
-label,
-input,
-button,
-select,
-textarea {
-  font-size: 14px;
-  font-weight: normal;
-  line-height: 20px;
-}
-
-input,
-button,
-select,
-textarea {
-  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
-}
-
-label {
-  display: block;
-  margin-bottom: 5px;
-}
-
-select,
-textarea,
-input[type="text"],
-input[type="password"],
-input[type="datetime"],
-input[type="datetime-local"],
-input[type="date"],
-input[type="month"],
-input[type="time"],
-input[type="week"],
-input[type="number"],
-input[type="email"],
-input[type="url"],
-input[type="search"],
-input[type="tel"],
-input[type="color"],
-.uneditable-input {
-  display: inline-block;
-  height: 20px;
-  padding: 4px 6px;
-  margin-bottom: 10px;
-  font-size: 14px;
-  line-height: 20px;
-  color: #555555;
-  vertical-align: middle;
-  -webkit-border-radius: 4px;
-     -moz-border-radius: 4px;
-          border-radius: 4px;
-}
-
-input,
-textarea,
-.uneditable-input {
-  width: 206px;
-}
-
-textarea {
-  height: auto;
-}
-
-textarea,
-input[type="text"],
-input[type="password"],
-input[type="datetime"],
-input[type="datetime-local"],
-input[type="date"],
-input[type="month"],
-input[type="time"],
-input[type="week"],
-input[type="number"],
-input[type="email"],
-input[type="url"],
-input[type="search"],
-input[type="tel"],
-input[type="color"],
-.uneditable-input {
-  background-color: #ffffff;
-  border: 1px solid #cccccc;
-  -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;
-       -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: 4px 0 0;
-  margin-top: 1px \9;
-  *margin-top: 0;
-  line-height: normal;
-  cursor: pointer;
-}
-
-input[type="file"],
-input[type="image"],
-input[type="submit"],
-input[type="reset"],
-input[type="button"],
-input[type="radio"],
-input[type="checkbox"] {
-  width: auto;
-}
-
-select,
-input[type="file"] {
-  height: 30px;
-  /* 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: 30px;
-}
-
-select {
-  width: 220px;
-  background-color: #ffffff;
-  border: 1px solid #cccccc;
-}
-
-select[multiple],
-select[size] {
-  height: auto;
-}
-
-select:focus,
-input[type="file"]:focus,
-input[type="radio"]:focus,
-input[type="checkbox"]:focus {
-  outline: thin dotted #333;
-  outline: 5px auto -webkit-focus-ring-color;
-  outline-offset: -2px;
-}
-
-.uneditable-input,
-.uneditable-textarea {
-  color: #999999;
-  cursor: not-allowed;
-  background-color: #fcfcfc;
-  border-color: #cccccc;
-  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);
-     -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);
-          box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);
-}
-
-.uneditable-input {
-  overflow: hidden;
-  white-space: nowrap;
-}
-
-.uneditable-textarea {
-  width: auto;
-  height: auto;
-}
-
-input:-moz-placeholder,
-textarea:-moz-placeholder {
-  color: #999999;
-}
-
-input:-ms-input-placeholder,
-textarea:-ms-input-placeholder {
-  color: #999999;
-}
-
-input::-webkit-input-placeholder,
-textarea::-webkit-input-placeholder {
-  color: #999999;
-}
-
-.radio,
-.checkbox {
-  min-height: 20px;
-  padding-left: 20px;
-}
-
-.radio input[type="radio"],
-.checkbox input[type="checkbox"] {
-  float: left;
-  margin-left: -20px;
-}
-
-.controls > .radio:first-child,
-.controls > .checkbox:first-child {
-  padding-top: 5px;
-}
-
-.radio.inline,
-.checkbox.inline {
-  display: inline-block;
-  padding-top: 5px;
-  margin-bottom: 0;
-  vertical-align: middle;
-}
-
-.radio.inline + .radio.inline,
-.checkbox.inline + .checkbox.inline {
-  margin-left: 10px;
-}
-
-.input-mini {
-  width: 60px;
-}
-
-.input-small {
-  width: 90px;
-}
-
-.input-medium {
-  width: 150px;
-}
-
-.input-large {
-  width: 210px;
-}
-
-.input-xlarge {
-  width: 270px;
-}
-
-.input-xxlarge {
-  width: 530px;
-}
-
-input[class*="span"],
-select[class*="span"],
-textarea[class*="span"],
-.uneditable-input[class*="span"],
-.row-fluid input[class*="span"],
-.row-fluid select[class*="span"],
-.row-fluid textarea[class*="span"],
-.row-fluid .uneditable-input[class*="span"] {
-  float: none;
-  margin-left: 0;
-}
-
-.input-append input[class*="span"],
-.input-append .uneditable-input[class*="span"],
-.input-prepend input[class*="span"],
-.input-prepend .uneditable-input[class*="span"],
-.row-fluid input[class*="span"],
-.row-fluid select[class*="span"],
-.row-fluid textarea[class*="span"],
-.row-fluid .uneditable-input[class*="span"],
-.row-fluid .input-prepend [class*="span"],
-.row-fluid .input-append [class*="span"] {
-  display: inline-block;
-}
-
-input,
-textarea,
-.uneditable-input {
-  margin-left: 0;
-}
-
-.controls-row [class*="span"] + [class*="span"] {
-  margin-left: 20px;
-}
-
-input.span12,
-textarea.span12,
-.uneditable-input.span12 {
-  width: 926px;
-}
-
-input.span11,
-textarea.span11,
-.uneditable-input.span11 {
-  width: 846px;
-}
-
-input.span10,
-textarea.span10,
-.uneditable-input.span10 {
-  width: 766px;
-}
-
-input.span9,
-textarea.span9,
-.uneditable-input.span9 {
-  width: 686px;
-}
-
-input.span8,
-textarea.span8,
-.uneditable-input.span8 {
-  width: 606px;
-}
-
-input.span7,
-textarea.span7,
-.uneditable-input.span7 {
-  width: 526px;
-}
-
-input.span6,
-textarea.span6,
-.uneditable-input.span6 {
-  width: 446px;
-}
-
-input.span5,
-textarea.span5,
-.uneditable-input.span5 {
-  width: 366px;
-}
-
-input.span4,
-textarea.span4,
-.uneditable-input.span4 {
-  width: 286px;
-}
-
-input.span3,
-textarea.span3,
-.uneditable-input.span3 {
-  width: 206px;
-}
-
-input.span2,
-textarea.span2,
-.uneditable-input.span2 {
-  width: 126px;
-}
-
-input.span1,
-textarea.span1,
-.uneditable-input.span1 {
-  width: 46px;
-}
-
-.controls-row {
-  *zoom: 1;
-}
-
-.controls-row:before,
-.controls-row:after {
-  display: table;
-  line-height: 0;
-  content: "";
-}
-
-.controls-row:after {
-  clear: both;
-}
-
-.controls-row [class*="span"],
-.row-fluid .controls-row [class*="span"] {
-  float: left;
-}
-
-.controls-row .checkbox[class*="span"],
-.controls-row .radio[class*="span"] {
-  padding-top: 5px;
-}
-
-input[disabled],
-select[disabled],
-textarea[disabled],
-input[readonly],
-select[readonly],
-textarea[readonly] {
-  cursor: not-allowed;
-  background-color: #eeeeee;
-}
-
-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;
-}
-
-.control-group.warning input,
-.control-group.warning select,
-.control-group.warning textarea {
-  border-color: #c09853;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-}
-
-.control-group.warning input:focus,
-.control-group.warning select:focus,
-.control-group.warning textarea:focus {
-  border-color: #a47e3c;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e;
-     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e;
-          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e;
-}
-
-.control-group.warning .input-prepend .add-on,
-.control-group.warning .input-append .add-on {
-  color: #c09853;
-  background-color: #fcf8e3;
-  border-color: #c09853;
-}
-
-.control-group.error > label,
-.control-group.error .help-block,
-.control-group.error .help-inline {
-  color: #b94a48;
-}
-
-.control-group.error .checkbox,
-.control-group.error .radio,
-.control-group.error input,
-.control-group.error select,
-.control-group.error textarea {
-  color: #b94a48;
-}
-
-.control-group.error input,
-.control-group.error select,
-.control-group.error textarea {
-  border-color: #b94a48;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-}
-
-.control-group.error input:focus,
-.control-group.error select:focus,
-.control-group.error textarea:focus {
-  border-color: #953b39;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;
-     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;
-          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;
-}
-
-.control-group.error .input-prepend .add-on,
-.control-group.error .input-append .add-on {
-  color: #b94a48;
-  background-color: #f2dede;
-  border-color: #b94a48;
-}
-
-.control-group.success > label,
-.control-group.success .help-block,
-.control-group.success .help-inline {
-  color: #468847;
-}
-
-.control-group.success .checkbox,
-.control-group.success .radio,
-.control-group.success input,
-.control-group.success select,
-.control-group.success textarea {
-  color: #468847;
-}
-
-.control-group.success input,
-.control-group.success select,
-.control-group.success textarea {
-  border-color: #468847;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-}
-
-.control-group.success input:focus,
-.control-group.success select:focus,
-.control-group.success textarea:focus {
-  border-color: #356635;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b;
-     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b;
-          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b;
-}
-
-.control-group.success .input-prepend .add-on,
-.control-group.success .input-append .add-on {
-  color: #468847;
-  background-color: #dff0d8;
-  border-color: #468847;
-}
-
-.control-group.info > label,
-.control-group.info .help-block,
-.control-group.info .help-inline {
-  color: #3a87ad;
-}
-
-.control-group.info .checkbox,
-.control-group.info .radio,
-.control-group.info input,
-.control-group.info select,
-.control-group.info textarea {
-  color: #3a87ad;
-}
-
-.control-group.info input,
-.control-group.info select,
-.control-group.info textarea {
-  border-color: #3a87ad;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-}
-
-.control-group.info input:focus,
-.control-group.info select:focus,
-.control-group.info textarea:focus {
-  border-color: #2d6987;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3;
-     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3;
-          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3;
-}
-
-.control-group.info .input-prepend .add-on,
-.control-group.info .input-append .add-on {
-  color: #3a87ad;
-  background-color: #d9edf7;
-  border-color: #3a87ad;
-}
-
-input:focus: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: 19px 20px 20px;
-  margin-top: 20px;
-  margin-bottom: 20px;
-  background-color: #f5f5f5;
-  border-top: 1px solid #e5e5e5;
-  *zoom: 1;
-}
-
-.form-actions:before,
-.form-actions:after {
-  display: table;
-  line-height: 0;
-  content: "";
-}
-
-.form-actions:after {
-  clear: both;
-}
-
-.help-block,
-.help-inline {
-  color: #595959;
-}
-
-.help-block {
-  display: block;
-  margin-bottom: 10px;
-}
-
-.help-inline {
-  display: inline-block;
-  *display: inline;
-  padding-left: 5px;
-  vertical-align: middle;
-  *zoom: 1;
-}
-
-.input-append,
-.input-prepend {
-  margin-bottom: 5px;
-  font-size: 0;
-  white-space: nowrap;
-}
-
-.input-append input,
-.input-prepend input,
-.input-append select,
-.input-prepend select,
-.input-append .uneditable-input,
-.input-prepend .uneditable-input,
-.input-append .dropdown-menu,
-.input-prepend .dropdown-menu {
-  font-size: 14px;
-}
-
-.input-append input,
-.input-prepend input,
-.input-append select,
-.input-prepend select,
-.input-append .uneditable-input,
-.input-prepend .uneditable-input {
-  position: relative;
-  margin-bottom: 0;
-  *margin-left: 0;
-  vertical-align: top;
-  -webkit-border-radius: 0 4px 4px 0;
-     -moz-border-radius: 0 4px 4px 0;
-          border-radius: 0 4px 4px 0;
-}
-
-.input-append input:focus,
-.input-prepend input:focus,
-.input-append select:focus,
-.input-prepend select:focus,
-.input-append .uneditable-input:focus,
-.input-prepend .uneditable-input:focus {
-  z-index: 2;
-}
-
-.input-append .add-on,
-.input-prepend .add-on {
-  display: inline-block;
-  width: auto;
-  height: 20px;
-  min-width: 16px;
-  padding: 4px 5px;
-  font-size: 14px;
-  font-weight: normal;
-  line-height: 20px;
-  text-align: center;
-  text-shadow: 0 1px 0 #ffffff;
-  background-color: #eeeeee;
-  border: 1px solid #ccc;
-}
-
-.input-append .add-on,
-.input-prepend .add-on,
-.input-append .btn,
-.input-prepend .btn {
-  vertical-align: top;
-  -webkit-border-radius: 0;
-     -moz-border-radius: 0;
-          border-radius: 0;
-}
-
-.input-append .active,
-.input-prepend .active {
-  background-color: #a9dba9;
-  border-color: #46a546;
-}
-
-.input-prepend .add-on,
-.input-prepend .btn {
-  margin-right: -1px;
-}
-
-.input-prepend .add-on:first-child,
-.input-prepend .btn:first-child {
-  -webkit-border-radius: 4px 0 0 4px;
-     -moz-border-radius: 4px 0 0 4px;
-          border-radius: 4px 0 0 4px;
-}
-
-.input-append input,
-.input-append select,
-.input-append .uneditable-input {
-  -webkit-border-radius: 4px 0 0 4px;
-     -moz-border-radius: 4px 0 0 4px;
-          border-radius: 4px 0 0 4px;
-}
-
-.input-append input + .btn-group .btn,
-.input-append select + .btn-group .btn,
-.input-append .uneditable-input + .btn-group .btn {
-  -webkit-border-radius: 0 4px 4px 0;
-     -moz-border-radius: 0 4px 4px 0;
-          border-radius: 0 4px 4px 0;
-}
-
-.input-append .add-on,
-.input-append .btn,
-.input-append .btn-group {
-  margin-left: -1px;
-}
-
-.input-append .add-on:last-child,
-.input-append .btn:last-child {
-  -webkit-border-radius: 0 4px 4px 0;
-     -moz-border-radius: 0 4px 4px 0;
-          border-radius: 0 4px 4px 0;
-}
-
-.input-prepend.input-append input,
-.input-prepend.input-append select,
-.input-prepend.input-append .uneditable-input {
-  -webkit-border-radius: 0;
-     -moz-border-radius: 0;
-          border-radius: 0;
-}
-
-.input-prepend.input-append input + .btn-group .btn,
-.input-prepend.input-append select + .btn-group .btn,
-.input-prepend.input-append .uneditable-input + .btn-group .btn {
-  -webkit-border-radius: 0 4px 4px 0;
-     -moz-border-radius: 0 4px 4px 0;
-          border-radius: 0 4px 4px 0;
-}
-
-.input-prepend.input-append .add-on:first-child,
-.input-prepend.input-append .btn:first-child {
-  margin-right: -1px;
-  -webkit-border-radius: 4px 0 0 4px;
-     -moz-border-radius: 4px 0 0 4px;
-          border-radius: 4px 0 0 4px;
-}
-
-.input-prepend.input-append .add-on:last-child,
-.input-prepend.input-append .btn:last-child {
-  margin-left: -1px;
-  -webkit-border-radius: 0 4px 4px 0;
-     -moz-border-radius: 0 4px 4px 0;
-          border-radius: 0 4px 4px 0;
-}
-
-.input-prepend.input-append .btn-group:first-child {
-  margin-left: 0;
-}
-
-input.search-query {
-  padding-right: 14px;
-  padding-right: 4px \9;
-  padding-left: 14px;
-  padding-left: 4px \9;
-  /* IE7-8 doesn't have border-radius, so don't indent the padding */
-
-  margin-bottom: 0;
-  -webkit-border-radius: 15px;
-     -moz-border-radius: 15px;
-          border-radius: 15px;
-}
-
-/* Allow for input prepend/append in search forms */
-
-.form-search .input-append .search-query,
-.form-search .input-prepend .search-query {
-  -webkit-border-radius: 0;
-     -moz-border-radius: 0;
-          border-radius: 0;
-}
-
-.form-search .input-append .search-query {
-  -webkit-border-radius: 14px 0 0 14px;
-     -moz-border-radius: 14px 0 0 14px;
-          border-radius: 14px 0 0 14px;
-}
-
-.form-search .input-append .btn {
-  -webkit-border-radius: 0 14px 14px 0;
-     -moz-border-radius: 0 14px 14px 0;
-          border-radius: 0 14px 14px 0;
-}
-
-.form-search .input-prepend .search-query {
-  -webkit-border-radius: 0 14px 14px 0;
-     -moz-border-radius: 0 14px 14px 0;
-          border-radius: 0 14px 14px 0;
-}
-
-.form-search .input-prepend .btn {
-  -webkit-border-radius: 14px 0 0 14px;
-     -moz-border-radius: 14px 0 0 14px;
-          border-radius: 14px 0 0 14px;
-}
-
-.form-search input,
-.form-inline input,
-.form-horizontal input,
-.form-search textarea,
-.form-inline textarea,
-.form-horizontal textarea,
-.form-search select,
-.form-inline select,
-.form-horizontal select,
-.form-search .help-inline,
-.form-inline .help-inline,
-.form-horizontal .help-inline,
-.form-search .uneditable-input,
-.form-inline .uneditable-input,
-.form-horizontal .uneditable-input,
-.form-search .input-prepend,
-.form-inline .input-prepend,
-.form-horizontal .input-prepend,
-.form-search .input-append,
-.form-inline .input-append,
-.form-horizontal .input-append {
-  display: inline-block;
-  *display: inline;
-  margin-bottom: 0;
-  vertical-align: middle;
-  *zoom: 1;
-}
-
-.form-search .hide,
-.form-inline .hide,
-.form-horizontal .hide {
-  display: none;
-}
-
-.form-search label,
-.form-inline label,
-.form-search .btn-group,
-.form-inline .btn-group {
-  display: inline-block;
-}
-
-.form-search .input-append,
-.form-inline .input-append,
-.form-search .input-prepend,
-.form-inline .input-prepend {
-  margin-bottom: 0;
-}
-
-.form-search .radio,
-.form-search .checkbox,
-.form-inline .radio,
-.form-inline .checkbox {
-  padding-left: 0;
-  margin-bottom: 0;
-  vertical-align: middle;
-}
-
-.form-search .radio input[type="radio"],
-.form-search .checkbox input[type="checkbox"],
-.form-inline .radio input[type="radio"],
-.form-inline .checkbox input[type="checkbox"] {
-  float: left;
-  margin-right: 3px;
-  margin-left: 0;
-}
-
-.control-group {
-  margin-bottom: 10px;
-}
-
-legend + .control-group {
-  margin-top: 20px;
-  -webkit-margin-top-collapse: separate;
-}
-
-.form-horizontal .control-group {
-  margin-bottom: 20px;
-  *zoom: 1;
-}
-
-.form-horizontal .control-group:before,
-.form-horizontal .control-group:after {
-  display: table;
-  line-height: 0;
-  content: "";
-}
-
-.form-horizontal .control-group:after {
-  clear: both;
-}
-
-.form-horizontal .control-label {
-  float: left;
-  width: 160px;
-  padding-top: 5px;
-  text-align: right;
-}
-
-.form-horizontal .controls {
-  *display: inline-block;
-  *padding-left: 20px;
-  margin-left: 180px;
-  *margin-left: 0;
-}
-
-.form-horizontal .controls:first-child {
-  *padding-left: 180px;
-}
-
-.form-horizontal .help-block {
-  margin-bottom: 0;
-}
-
-.form-horizontal input + .help-block,
-.form-horizontal select + .help-block,
-.form-horizontal textarea + .help-block {
-  margin-top: 10px;
-}
-
-.form-horizontal .form-actions {
-  padding-left: 180px;
-}
-
-table {
-  max-width: 100%;
-  background-color: transparent;
-  border-collapse: collapse;
-  border-spacing: 0;
-}
-
-.table {
-  width: 100%;
-  margin-bottom: 20px;
-}
-
-.table th,
-.table td {
-  padding: 8px;
-  line-height: 20px;
-  text-align: left;
-  vertical-align: top;
-  border-top: 1px solid #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: collapse;
-  border-left: 0;
-  -webkit-border-radius: 4px;
-     -moz-border-radius: 4px;
-          border-radius: 4px;
-}
-
-.table-bordered th,
-.table-bordered td {
-  border-left: 1px solid #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,
-.table-bordered tfoot: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,
-.table-bordered tfoot: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-bordered caption + thead tr:first-child th:first-child,
-.table-bordered caption + tbody tr:first-child td:first-child,
-.table-bordered colgroup + thead tr:first-child th:first-child,
-.table-bordered colgroup + tbody tr:first-child td:first-child {
-  -webkit-border-top-left-radius: 4px;
-          border-top-left-radius: 4px;
-  -moz-border-radius-topleft: 4px;
-}
-
-.table-bordered caption + thead tr:first-child th:last-child,
-.table-bordered caption + tbody tr:first-child td:last-child,
-.table-bordered colgroup + thead tr:first-child th:last-child,
-.table-bordered colgroup + tbody tr:first-child td:last-child {
-  -webkit-border-top-right-radius: 4px;
-          border-top-right-radius: 4px;
-  -moz-border-radius-topright: 4px;
-}
-
-.table-striped tbody tr:nth-child(odd) td,
-.table-striped tbody tr:nth-child(odd) th {
-  background-color: #f9f9f9;
-}
-
-.table-hover tbody tr:hover td,
-.table-hover tbody tr:hover th {
-  background-color: #f5f5f5;
-}
-
-table td[class*="span"],
-table th[class*="span"],
-.row-fluid table td[class*="span"],
-.row-fluid table th[class*="span"] {
-  display: table-cell;
-  float: none;
-  margin-left: 0;
-}
-
-.table td.span1,
-.table th.span1 {
-  float: none;
-  width: 44px;
-  margin-left: 0;
-}
-
-.table td.span2,
-.table th.span2 {
-  float: none;
-  width: 124px;
-  margin-left: 0;
-}
-
-.table td.span3,
-.table th.span3 {
-  float: none;
-  width: 204px;
-  margin-left: 0;
-}
-
-.table td.span4,
-.table th.span4 {
-  float: none;
-  width: 284px;
-  margin-left: 0;
-}
-
-.table td.span5,
-.table th.span5 {
-  float: none;
-  width: 364px;
-  margin-left: 0;
-}
-
-.table td.span6,
-.table th.span6 {
-  float: none;
-  width: 444px;
-  margin-left: 0;
-}
-
-.table td.span7,
-.table th.span7 {
-  float: none;
-  width: 524px;
-  margin-left: 0;
-}
-
-.table td.span8,
-.table th.span8 {
-  float: none;
-  width: 604px;
-  margin-left: 0;
-}
-
-.table td.span9,
-.table th.span9 {
-  float: none;
-  width: 684px;
-  margin-left: 0;
-}
-
-.table td.span10,
-.table th.span10 {
-  float: none;
-  width: 764px;
-  margin-left: 0;
-}
-
-.table td.span11,
-.table th.span11 {
-  float: none;
-  width: 844px;
-  margin-left: 0;
-}
-
-.table td.span12,
-.table th.span12 {
-  float: none;
-  width: 924px;
-  margin-left: 0;
-}
-
-.table tbody tr.success td {
-  background-color: #dff0d8;
-}
-
-.table tbody tr.error td {
-  background-color: #f2dede;
-}
-
-.table tbody tr.warning td {
-  background-color: #fcf8e3;
-}
-
-.table tbody tr.info td {
-  background-color: #d9edf7;
-}
-
-.table-hover tbody tr.success:hover td {
-  background-color: #d0e9c6;
-}
-
-.table-hover tbody tr.error:hover td {
-  background-color: #ebcccc;
-}
-
-.table-hover tbody tr.warning:hover td {
-  background-color: #faf2cc;
-}
-
-.table-hover tbody tr.info:hover td {
-  background-color: #c4e3f3;
-}
-
-[class^="icon-"],
-[class*=" icon-"] {
-  display: inline-block;
-  width: 14px;
-  height: 14px;
-  margin-top: 1px;
-  *margin-right: .3em;
-  line-height: 14px;
-  vertical-align: text-top;
-  background-image: url("../img/glyphicons-halflings.png");
-  background-position: 14px 14px;
-  background-repeat: no-repeat;
-}
-
-/* White icons with optional class, or on hover/active states of certain elements */
-
-.icon-white,
-.nav-pills > .active > a > [class^="icon-"],
-.nav-pills > .active > a > [class*=" icon-"],
-.nav-list > .active > a > [class^="icon-"],
-.nav-list > .active > a > [class*=" icon-"],
-.navbar-inverse .nav > .active > a > [class^="icon-"],
-.navbar-inverse .nav > .active > a > [class*=" icon-"],
-.dropdown-menu > li > a:hover > [class^="icon-"],
-.dropdown-menu > li > a:hover > [class*=" icon-"],
-.dropdown-menu > .active > a > [class^="icon-"],
-.dropdown-menu > .active > a > [class*=" icon-"],
-.dropdown-submenu:hover > a > [class^="icon-"],
-.dropdown-submenu:hover > a > [class*=" icon-"] {
-  background-image: url("../img/glyphicons-halflings-white.png");
-}
-
-.icon-glass {
-  background-position: 0      0;
-}
-
-.icon-music {
-  background-position: -24px 0;
-}
-
-.icon-search {
-  background-position: -48px 0;
-}
-
-.icon-envelope {
-  background-position: -72px 0;
-}
-
-.icon-heart {
-  background-position: -96px 0;
-}
-
-.icon-star {
-  background-position: -120px 0;
-}
-
-.icon-star-empty {
-  background-position: -144px 0;
-}
-
-.icon-user {
-  background-position: -168px 0;
-}
-
-.icon-film {
-  background-position: -192px 0;
-}
-
-.icon-th-large {
-  background-position: -216px 0;
-}
-
-.icon-th {
-  background-position: -240px 0;
-}
-
-.icon-th-list {
-  background-position: -264px 0;
-}
-
-.icon-ok {
-  background-position: -288px 0;
-}
-
-.icon-remove {
-  background-position: -312px 0;
-}
-
-.icon-zoom-in {
-  background-position: -336px 0;
-}
-
-.icon-zoom-out {
-  background-position: -360px 0;
-}
-
-.icon-off {
-  background-position: -384px 0;
-}
-
-.icon-signal {
-  background-position: -408px 0;
-}
-
-.icon-cog {
-  background-position: -432px 0;
-}
-
-.icon-trash {
-  background-position: -456px 0;
-}
-
-.icon-home {
-  background-position: 0 -24px;
-}
-
-.icon-file {
-  background-position: -24px -24px;
-}
-
-.icon-time {
-  background-position: -48px -24px;
-}
-
-.icon-road {
-  background-position: -72px -24px;
-}
-
-.icon-download-alt {
-  background-position: -96px -24px;
-}
-
-.icon-download {
-  background-position: -120px -24px;
-}
-
-.icon-upload {
-  background-position: -144px -24px;
-}
-
-.icon-inbox {
-  background-position: -168px -24px;
-}
-
-.icon-play-circle {
-  background-position: -192px -24px;
-}
-
-.icon-repeat {
-  background-position: -216px -24px;
-}
-
-.icon-refresh {
-  background-position: -240px -24px;
-}
-
-.icon-list-alt {
-  background-position: -264px -24px;
-}
-
-.icon-lock {
-  background-position: -287px -24px;
-}
-
-.icon-flag {
-  background-position: -312px -24px;
-}
-
-.icon-headphones {
-  background-position: -336px -24px;
-}
-
-.icon-volume-off {
-  background-position: -360px -24px;
-}
-
-.icon-volume-down {
-  background-position: -384px -24px;
-}
-
-.icon-volume-up {
-  background-position: -408px -24px;
-}
-
-.icon-qrcode {
-  background-position: -432px -24px;
-}
-
-.icon-barcode {
-  background-position: -456px -24px;
-}
-
-.icon-tag {
-  background-position: 0 -48px;
-}
-
-.icon-tags {
-  background-position: -25px -48px;
-}
-
-.icon-book {
-  background-position: -48px -48px;
-}
-
-.icon-bookmark {
-  background-position: -72px -48px;
-}
-
-.icon-print {
-  background-position: -96px -48px;
-}
-
-.icon-camera {
-  background-position: -120px -48px;
-}
-
-.icon-font {
-  background-position: -144px -48px;
-}
-
-.icon-bold {
-  background-position: -167px -48px;
-}
-
-.icon-italic {
-  background-position: -192px -48px;
-}
-
-.icon-text-height {
-  background-position: -216px -48px;
-}
-
-.icon-text-width {
-  background-position: -240px -48px;
-}
-
-.icon-align-left {
-  background-position: -264px -48px;
-}
-
-.icon-align-center {
-  background-position: -288px -48px;
-}
-
-.icon-align-right {
-  background-position: -312px -48px;
-}
-
-.icon-align-justify {
-  background-position: -336px -48px;
-}
-
-.icon-list {
-  background-position: -360px -48px;
-}
-
-.icon-indent-left {
-  background-position: -384px -48px;
-}
-
-.icon-indent-right {
-  background-position: -408px -48px;
-}
-
-.icon-facetime-video {
-  background-position: -432px -48px;
-}
-
-.icon-picture {
-  background-position: -456px -48px;
-}
-
-.icon-pencil {
-  background-position: 0 -72px;
-}
-
-.icon-map-marker {
-  background-position: -24px -72px;
-}
-
-.icon-adjust {
-  background-position: -48px -72px;
-}
-
-.icon-tint {
-  background-position: -72px -72px;
-}
-
-.icon-edit {
-  background-position: -96px -72px;
-}
-
-.icon-share {
-  background-position: -120px -72px;
-}
-
-.icon-check {
-  background-position: -144px -72px;
-}
-
-.icon-move {
-  background-position: -168px -72px;
-}
-
-.icon-step-backward {
-  background-position: -192px -72px;
-}
-
-.icon-fast-backward {
-  background-position: -216px -72px;
-}
-
-.icon-backward {
-  background-position: -240px -72px;
-}
-
-.icon-play {
-  background-position: -264px -72px;
-}
-
-.icon-pause {
-  background-position: -288px -72px;
-}
-
-.icon-stop {
-  background-position: -312px -72px;
-}
-
-.icon-forward {
-  background-position: -336px -72px;
-}
-
-.icon-fast-forward {
-  background-position: -360px -72px;
-}
-
-.icon-step-forward {
-  background-position: -384px -72px;
-}
-
-.icon-eject {
-  background-position: -408px -72px;
-}
-
-.icon-chevron-left {
-  background-position: -432px -72px;
-}
-
-.icon-chevron-right {
-  background-position: -456px -72px;
-}
-
-.icon-plus-sign {
-  background-position: 0 -96px;
-}
-
-.icon-minus-sign {
-  background-position: -24px -96px;
-}
-
-.icon-remove-sign {
-  background-position: -48px -96px;
-}
-
-.icon-ok-sign {
-  background-position: -72px -96px;
-}
-
-.icon-question-sign {
-  background-position: -96px -96px;
-}
-
-.icon-info-sign {
-  background-position: -120px -96px;
-}
-
-.icon-screenshot {
-  background-position: -144px -96px;
-}
-
-.icon-remove-circle {
-  background-position: -168px -96px;
-}
-
-.icon-ok-circle {
-  background-position: -192px -96px;
-}
-
-.icon-ban-circle {
-  background-position: -216px -96px;
-}
-
-.icon-arrow-left {
-  background-position: -240px -96px;
-}
-
-.icon-arrow-right {
-  background-position: -264px -96px;
-}
-
-.icon-arrow-up {
-  background-position: -289px -96px;
-}
-
-.icon-arrow-down {
-  background-position: -312px -96px;
-}
-
-.icon-share-alt {
-  background-position: -336px -96px;
-}
-
-.icon-resize-full {
-  background-position: -360px -96px;
-}
-
-.icon-resize-small {
-  background-position: -384px -96px;
-}
-
-.icon-plus {
-  background-position: -408px -96px;
-}
-
-.icon-minus {
-  background-position: -433px -96px;
-}
-
-.icon-asterisk {
-  background-position: -456px -96px;
-}
-
-.icon-exclamation-sign {
-  background-position: 0 -120px;
-}
-
-.icon-gift {
-  background-position: -24px -120px;
-}
-
-.icon-leaf {
-  background-position: -48px -120px;
-}
-
-.icon-fire {
-  background-position: -72px -120px;
-}
-
-.icon-eye-open {
-  background-position: -96px -120px;
-}
-
-.icon-eye-close {
-  background-position: -120px -120px;
-}
-
-.icon-warning-sign {
-  background-position: -144px -120px;
-}
-
-.icon-plane {
-  background-position: -168px -120px;
-}
-
-.icon-calendar {
-  background-position: -192px -120px;
-}
-
-.icon-random {
-  width: 16px;
-  background-position: -216px -120px;
-}
-
-.icon-comment {
-  background-position: -240px -120px;
-}
-
-.icon-magnet {
-  background-position: -264px -120px;
-}
-
-.icon-chevron-up {
-  background-position: -288px -120px;
-}
-
-.icon-chevron-down {
-  background-position: -313px -119px;
-}
-
-.icon-retweet {
-  background-position: -336px -120px;
-}
-
-.icon-shopping-cart {
-  background-position: -360px -120px;
-}
-
-.icon-folder-close {
-  background-position: -384px -120px;
-}
-
-.icon-folder-open {
-  width: 16px;
-  background-position: -408px -120px;
-}
-
-.icon-resize-vertical {
-  background-position: -432px -119px;
-}
-
-.icon-resize-horizontal {
-  background-position: -456px -118px;
-}
-
-.icon-hdd {
-  background-position: 0 -144px;
-}
-
-.icon-bullhorn {
-  background-position: -24px -144px;
-}
-
-.icon-bell {
-  background-position: -48px -144px;
-}
-
-.icon-certificate {
-  background-position: -72px -144px;
-}
-
-.icon-thumbs-up {
-  background-position: -96px -144px;
-}
-
-.icon-thumbs-down {
-  background-position: -120px -144px;
-}
-
-.icon-hand-right {
-  background-position: -144px -144px;
-}
-
-.icon-hand-left {
-  background-position: -168px -144px;
-}
-
-.icon-hand-up {
-  background-position: -192px -144px;
-}
-
-.icon-hand-down {
-  background-position: -216px -144px;
-}
-
-.icon-circle-arrow-right {
-  background-position: -240px -144px;
-}
-
-.icon-circle-arrow-left {
-  background-position: -264px -144px;
-}
-
-.icon-circle-arrow-up {
-  background-position: -288px -144px;
-}
-
-.icon-circle-arrow-down {
-  background-position: -312px -144px;
-}
-
-.icon-globe {
-  background-position: -336px -144px;
-}
-
-.icon-wrench {
-  background-position: -360px -144px;
-}
-
-.icon-tasks {
-  background-position: -384px -144px;
-}
-
-.icon-filter {
-  background-position: -408px -144px;
-}
-
-.icon-briefcase {
-  background-position: -432px -144px;
-}
-
-.icon-fullscreen {
-  background-position: -456px -144px;
-}
-
-.dropup,
-.dropdown {
-  position: relative;
-}
-
-.dropdown-toggle {
-  *margin-bottom: -3px;
-}
-
-.dropdown-toggle:active,
-.open .dropdown-toggle {
-  outline: 0;
-}
-
-.caret {
-  display: inline-block;
-  width: 0;
-  height: 0;
-  vertical-align: top;
-  border-top: 4px solid #000000;
-  border-right: 4px solid transparent;
-  border-left: 4px solid transparent;
-  content: "";
-}
-
-.dropdown .caret {
-  margin-top: 8px;
-  margin-left: 2px;
-}
-
-.dropdown-menu {
-  position: absolute;
-  top: 100%;
-  left: 0;
-  z-index: 1000;
-  display: none;
-  float: left;
-  min-width: 160px;
-  padding: 5px 0;
-  margin: 2px 0 0;
-  list-style: none;
-  background-color: #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: 6px;
-     -moz-border-radius: 6px;
-          border-radius: 6px;
-  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
-     -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
-          box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
-  -webkit-background-clip: padding-box;
-     -moz-background-clip: padding;
-          background-clip: padding-box;
-}
-
-.dropdown-menu.pull-right {
-  right: 0;
-  left: auto;
-}
-
-.dropdown-menu .divider {
-  *width: 100%;
-  height: 1px;
-  margin: 9px 1px;
-  *margin: -5px 0 5px;
-  overflow: hidden;
-  background-color: #e5e5e5;
-  border-bottom: 1px solid #ffffff;
-}
-
-.dropdown-menu li > a {
-  display: block;
-  padding: 3px 20px;
-  clear: both;
-  font-weight: normal;
-  line-height: 20px;
-  color: #333333;
-  white-space: nowrap;
-}
-
-.dropdown-menu li > a:hover,
-.dropdown-menu li > a:focus,
-.dropdown-submenu:hover > a {
-  color: #ffffff;
-  text-decoration: none;
-  background-color: #0081c2;
-  background-image: -moz-linear-gradient(top, #0088cc, #0077b3);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3));
-  background-image: -webkit-linear-gradient(top, #0088cc, #0077b3);
-  background-image: -o-linear-gradient(top, #0088cc, #0077b3);
-  background-image: linear-gradient(to bottom, #0088cc, #0077b3);
-  background-repeat: repeat-x;
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0);
-}
-
-.dropdown-menu .active > a,
-.dropdown-menu .active > a:hover {
-  color: #333333;
-  text-decoration: none;
-  background-color: #0081c2;
-  background-image: -moz-linear-gradient(top, #0088cc, #0077b3);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3));
-  background-image: -webkit-linear-gradient(top, #0088cc, #0077b3);
-  background-image: -o-linear-gradient(top, #0088cc, #0077b3);
-  background-image: linear-gradient(to bottom, #0088cc, #0077b3);
-  background-repeat: repeat-x;
-  outline: 0;
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0);
-}
-
-.dropdown-menu .disabled > a,
-.dropdown-menu .disabled > a:hover {
-  color: #999999;
-}
-
-.dropdown-menu .disabled > a:hover {
-  text-decoration: none;
-  cursor: default;
-  background-color: transparent;
-  background-image: none;
-}
-
-.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: "";
-}
-
-.dropup .dropdown-menu,
-.navbar-fixed-bottom .dropdown .dropdown-menu {
-  top: auto;
-  bottom: 100%;
-  margin-bottom: 1px;
-}
-
-.dropdown-submenu {
-  position: relative;
-}
-
-.dropdown-submenu > .dropdown-menu {
-  top: 0;
-  left: 100%;
-  margin-top: -6px;
-  margin-left: -1px;
-  -webkit-border-radius: 0 6px 6px 6px;
-     -moz-border-radius: 0 6px 6px 6px;
-          border-radius: 0 6px 6px 6px;
-}
-
-.dropdown-submenu:hover > .dropdown-menu {
-  display: block;
-}
-
-.dropup .dropdown-submenu > .dropdown-menu {
-  top: auto;
-  bottom: 0;
-  margin-top: 0;
-  margin-bottom: -2px;
-  -webkit-border-radius: 5px 5px 5px 0;
-     -moz-border-radius: 5px 5px 5px 0;
-          border-radius: 5px 5px 5px 0;
-}
-
-.dropdown-submenu > a:after {
-  display: block;
-  float: right;
-  width: 0;
-  height: 0;
-  margin-top: 5px;
-  margin-right: -10px;
-  border-color: transparent;
-  border-left-color: #cccccc;
-  border-style: solid;
-  border-width: 5px 0 5px 5px;
-  content: " ";
-}
-
-.dropdown-submenu:hover > a:after {
-  border-left-color: #ffffff;
-}
-
-.dropdown-submenu.pull-left {
-  float: none;
-}
-
-.dropdown-submenu.pull-left > .dropdown-menu {
-  left: -100%;
-  margin-left: 10px;
-  -webkit-border-radius: 6px 0 6px 6px;
-     -moz-border-radius: 6px 0 6px 6px;
-          border-radius: 6px 0 6px 6px;
-}
-
-.dropdown .dropdown-menu .nav-header {
-  padding-right: 20px;
-  padding-left: 20px;
-}
-
-.typeahead {
-  margin-top: 2px;
-  -webkit-border-radius: 4px;
-     -moz-border-radius: 4px;
-          border-radius: 4px;
-}
-
-.well {
-  min-height: 20px;
-  padding: 19px;
-  margin-bottom: 20px;
-  background-color: #f5f5f5;
-  border: 1px solid #e3e3e3;
-  -webkit-border-radius: 4px;
-     -moz-border-radius: 4px;
-          border-radius: 4px;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
-     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
-          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
-}
-
-.well blockquote {
-  border-color: #ddd;
-  border-color: rgba(0, 0, 0, 0.15);
-}
-
-.well-large {
-  padding: 24px;
-  -webkit-border-radius: 6px;
-     -moz-border-radius: 6px;
-          border-radius: 6px;
-}
-
-.well-small {
-  padding: 9px;
-  -webkit-border-radius: 3px;
-     -moz-border-radius: 3px;
-          border-radius: 3px;
-}
-
-.fade {
-  opacity: 0;
-  -webkit-transition: opacity 0.15s linear;
-     -moz-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;
-       -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: 20px;
-  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 12px;
-  margin-bottom: 0;
-  *margin-left: .3em;
-  font-size: 14px;
-  line-height: 20px;
-  *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: -moz-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(to bottom, #ffffff, #e6e6e6);
-  background-repeat: repeat-x;
-  border: 1px solid #bbbbbb;
-  *border: 0;
-  border-color: #e6e6e6 #e6e6e6 #bfbfbf;
-  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
-  border-bottom-color: #a2a2a2;
-  -webkit-border-radius: 4px;
-     -moz-border-radius: 4px;
-          border-radius: 4px;
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0);
-  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
-  *zoom: 1;
-  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
-     -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
-          box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
-}
-
-.btn:hover,
-.btn:active,
-.btn.active,
-.btn.disabled,
-.btn[disabled] {
-  color: #333333;
-  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;
-       -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: 11px 19px;
-  font-size: 17.5px;
-  -webkit-border-radius: 6px;
-     -moz-border-radius: 6px;
-          border-radius: 6px;
-}
-
-.btn-large [class^="icon-"],
-.btn-large [class*=" icon-"] {
-  margin-top: 2px;
-}
-
-.btn-small {
-  padding: 2px 10px;
-  font-size: 11.9px;
-  -webkit-border-radius: 3px;
-     -moz-border-radius: 3px;
-          border-radius: 3px;
-}
-
-.btn-small [class^="icon-"],
-.btn-small [class*=" icon-"] {
-  margin-top: 0;
-}
-
-.btn-mini {
-  padding: 1px 6px;
-  font-size: 10.5px;
-  -webkit-border-radius: 3px;
-     -moz-border-radius: 3px;
-          border-radius: 3px;
-}
-
-.btn-block {
-  display: block;
-  width: 100%;
-  padding-right: 0;
-  padding-left: 0;
-  -webkit-box-sizing: border-box;
-     -moz-box-sizing: border-box;
-          box-sizing: border-box;
-}
-
-.btn-block + .btn-block {
-  margin-top: 5px;
-}
-
-input[type="submit"].btn-block,
-input[type="reset"].btn-block,
-input[type="button"].btn-block {
-  width: 100%;
-}
-
-.btn-primary.active,
-.btn-warning.active,
-.btn-danger.active,
-.btn-success.active,
-.btn-info.active,
-.btn-inverse.active {
-  color: rgba(255, 255, 255, 0.75);
-}
-
-.btn {
-  border-color: #c5c5c5;
-  border-color: rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.25);
-}
-
-.btn-primary {
-  color: #ffffff;
-  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
-  background-color: #006dcc;
-  *background-color: #0044cc;
-  background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
-  background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
-  background-image: -o-linear-gradient(top, #0088cc, #0044cc);
-  background-image: linear-gradient(to bottom, #0088cc, #0044cc);
-  background-repeat: repeat-x;
-  border-color: #0044cc #0044cc #002a80;
-  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0);
-  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
-}
-
-.btn-primary:hover,
-.btn-primary:active,
-.btn-primary.active,
-.btn-primary.disabled,
-.btn-primary[disabled] {
-  color: #ffffff;
-  background-color: #0044cc;
-  *background-color: #003bb3;
-}
-
-.btn-primary:active,
-.btn-primary.active {
-  background-color: #003399 \9;
-}
-
-.btn-warning {
-  color: #ffffff;
-  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
-  background-color: #faa732;
-  *background-color: #f89406;
-  background-image: -moz-linear-gradient(top, #fbb450, #f89406);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));
-  background-image: -webkit-linear-gradient(top, #fbb450, #f89406);
-  background-image: -o-linear-gradient(top, #fbb450, #f89406);
-  background-image: linear-gradient(to bottom, #fbb450, #f89406);
-  background-repeat: repeat-x;
-  border-color: #f89406 #f89406 #ad6704;
-  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);
-  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
-}
-
-.btn-warning:hover,
-.btn-warning:active,
-.btn-warning.active,
-.btn-warning.disabled,
-.btn-warning[disabled] {
-  color: #ffffff;
-  background-color: #f89406;
-  *background-color: #df8505;
-}
-
-.btn-warning:active,
-.btn-warning.active {
-  background-color: #c67605 \9;
-}
-
-.btn-danger {
-  color: #ffffff;
-  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
-  background-color: #da4f49;
-  *background-color: #bd362f;
-  background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));
-  background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f);
-  background-image: -o-linear-gradient(top, #ee5f5b, #bd362f);
-  background-image: linear-gradient(to bottom, #ee5f5b, #bd362f);
-  background-repeat: repeat-x;
-  border-color: #bd362f #bd362f #802420;
-  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0);
-  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
-}
-
-.btn-danger:hover,
-.btn-danger:active,
-.btn-danger.active,
-.btn-danger.disabled,
-.btn-danger[disabled] {
-  color: #ffffff;
-  background-color: #bd362f;
-  *background-color: #a9302a;
-}
-
-.btn-danger:active,
-.btn-danger.active {
-  background-color: #942a25 \9;
-}
-
-.btn-success {
-  color: #ffffff;
-  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
-  background-color: #5bb75b;
-  *background-color: #51a351;
-  background-image: -moz-linear-gradient(top, #62c462, #51a351);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));
-  background-image: -webkit-linear-gradient(top, #62c462, #51a351);
-  background-image: -o-linear-gradient(top, #62c462, #51a351);
-  background-image: linear-gradient(to bottom, #62c462, #51a351);
-  background-repeat: repeat-x;
-  border-color: #51a351 #51a351 #387038;
-  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0);
-  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
-}
-
-.btn-success:hover,
-.btn-success:active,
-.btn-success.active,
-.btn-success.disabled,
-.btn-success[disabled] {
-  color: #ffffff;
-  background-color: #51a351;
-  *background-color: #499249;
-}
-
-.btn-success:active,
-.btn-success.active {
-  background-color: #408140 \9;
-}
-
-.btn-info {
-  color: #ffffff;
-  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
-  background-color: #49afcd;
-  *background-color: #2f96b4;
-  background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));
-  background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4);
-  background-image: -o-linear-gradient(top, #5bc0de, #2f96b4);
-  background-image: linear-gradient(to bottom, #5bc0de, #2f96b4);
-  background-repeat: repeat-x;
-  border-color: #2f96b4 #2f96b4 #1f6377;
-  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0);
-  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
-}
-
-.btn-info:hover,
-.btn-info:active,
-.btn-info.active,
-.btn-info.disabled,
-.btn-info[disabled] {
-  color: #ffffff;
-  background-color: #2f96b4;
-  *background-color: #2a85a0;
-}
-
-.btn-info:active,
-.btn-info.active {
-  background-color: #24748c \9;
-}
-
-.btn-inverse {
-  color: #ffffff;
-  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
-  background-color: #363636;
-  *background-color: #222222;
-  background-image: -moz-linear-gradient(top, #444444, #222222);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#444444), to(#222222));
-  background-image: -webkit-linear-gradient(top, #444444, #222222);
-  background-image: -o-linear-gradient(top, #444444, #222222);
-  background-image: linear-gradient(to bottom, #444444, #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='#ff444444', endColorstr='#ff222222', GradientType=0);
-  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
-}
-
-.btn-inverse:hover,
-.btn-inverse:active,
-.btn-inverse.active,
-.btn-inverse.disabled,
-.btn-inverse[disabled] {
-  color: #ffffff;
-  background-color: #222222;
-  *background-color: #151515;
-}
-
-.btn-inverse:active,
-.btn-inverse.active {
-  background-color: #080808 \9;
-}
-
-button.btn,
-input[type="submit"].btn {
-  *padding-top: 3px;
-  *padding-bottom: 3px;
-}
-
-button.btn::-moz-focus-inner,
-input[type="submit"].btn::-moz-focus-inner {
-  padding: 0;
-  border: 0;
-}
-
-button.btn.btn-large,
-input[type="submit"].btn.btn-large {
-  *padding-top: 7px;
-  *padding-bottom: 7px;
-}
-
-button.btn.btn-small,
-input[type="submit"].btn.btn-small {
-  *padding-top: 3px;
-  *padding-bottom: 3px;
-}
-
-button.btn.btn-mini,
-input[type="submit"].btn.btn-mini {
-  *padding-top: 1px;
-  *padding-bottom: 1px;
-}
-
-.btn-link,
-.btn-link:active,
-.btn-link[disabled] {
-  background-color: transparent;
-  background-image: none;
-  -webkit-box-shadow: none;
-     -moz-box-shadow: none;
-          box-shadow: none;
-}
-
-.btn-link {
-  color: #0088cc;
-  cursor: pointer;
-  border-color: transparent;
-  -webkit-border-radius: 0;
-     -moz-border-radius: 0;
-          border-radius: 0;
-}
-
-.btn-link:hover {
-  color: #005580;
-  text-decoration: underline;
-  background-color: transparent;
-}
-
-.btn-link[disabled]:hover {
-  color: #333333;
-  text-decoration: none;
-}
-
-.btn-group {
-  position: relative;
-  display: inline-block;
-  *display: inline;
-  *margin-left: .3em;
-  font-size: 0;
-  white-space: nowrap;
-  vertical-align: middle;
-  *zoom: 1;
-}
-
-.btn-group:first-child {
-  *margin-left: 0;
-}
-
-.btn-group + .btn-group {
-  margin-left: 5px;
-}
-
-.btn-toolbar {
-  margin-top: 10px;
-  margin-bottom: 10px;
-  font-size: 0;
-}
-
-.btn-toolbar .btn + .btn,
-.btn-toolbar .btn-group + .btn,
-.btn-toolbar .btn + .btn-group {
-  margin-left: 5px;
-}
-
-.btn-group > .btn {
-  position: relative;
-  -webkit-border-radius: 0;
-     -moz-border-radius: 0;
-          border-radius: 0;
-}
-
-.btn-group > .btn + .btn {
-  margin-left: -1px;
-}
-
-.btn-group > .btn,
-.btn-group > .dropdown-menu {
-  font-size: 14px;
-}
-
-.btn-group > .btn-mini {
-  font-size: 11px;
-}
-
-.btn-group > .btn-small {
-  font-size: 12px;
-}
-
-.btn-group > .btn-large {
-  font-size: 16px;
-}
-
-.btn-group > .btn:first-child {
-  margin-left: 0;
-  -webkit-border-bottom-left-radius: 4px;
-          border-bottom-left-radius: 4px;
-  -webkit-border-top-left-radius: 4px;
-          border-top-left-radius: 4px;
-  -moz-border-radius-bottomleft: 4px;
-  -moz-border-radius-topleft: 4px;
-}
-
-.btn-group > .btn:last-child,
-.btn-group > .dropdown-toggle {
-  -webkit-border-top-right-radius: 4px;
-          border-top-right-radius: 4px;
-  -webkit-border-bottom-right-radius: 4px;
-          border-bottom-right-radius: 4px;
-  -moz-border-radius-topright: 4px;
-  -moz-border-radius-bottomright: 4px;
-}
-
-.btn-group > .btn.large:first-child {
-  margin-left: 0;
-  -webkit-border-bottom-left-radius: 6px;
-          border-bottom-left-radius: 6px;
-  -webkit-border-top-left-radius: 6px;
-          border-top-left-radius: 6px;
-  -moz-border-radius-bottomleft: 6px;
-  -moz-border-radius-topleft: 6px;
-}
-
-.btn-group > .btn.large:last-child,
-.btn-group > .large.dropdown-toggle {
-  -webkit-border-top-right-radius: 6px;
-          border-top-right-radius: 6px;
-  -webkit-border-bottom-right-radius: 6px;
-          border-bottom-right-radius: 6px;
-  -moz-border-radius-topright: 6px;
-  -moz-border-radius-bottomright: 6px;
-}
-
-.btn-group > .btn:hover,
-.btn-group > .btn:focus,
-.btn-group > .btn:active,
-.btn-group > .btn.active {
-  z-index: 2;
-}
-
-.btn-group .dropdown-toggle:active,
-.btn-group.open .dropdown-toggle {
-  outline: 0;
-}
-
-.btn-group > .btn + .dropdown-toggle {
-  *padding-top: 5px;
-  padding-right: 8px;
-  *padding-bottom: 5px;
-  padding-left: 8px;
-  -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
-     -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
-          box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
-}
-
-.btn-group > .btn-mini + .dropdown-toggle {
-  *padding-top: 2px;
-  padding-right: 5px;
-  *padding-bottom: 2px;
-  padding-left: 5px;
-}
-
-.btn-group > .btn-small + .dropdown-toggle {
-  *padding-top: 5px;
-  *padding-bottom: 4px;
-}
-
-.btn-group > .btn-large + .dropdown-toggle {
-  *padding-top: 7px;
-  padding-right: 12px;
-  *padding-bottom: 7px;
-  padding-left: 12px;
-}
-
-.btn-group.open .dropdown-toggle {
-  background-image: none;
-  -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
-     -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
-          box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
-}
-
-.btn-group.open .btn.dropdown-toggle {
-  background-color: #e6e6e6;
-}
-
-.btn-group.open .btn-primary.dropdown-toggle {
-  background-color: #0044cc;
-}
-
-.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: 8px;
-  margin-left: 0;
-}
-
-.btn-mini .caret,
-.btn-small .caret,
-.btn-large .caret {
-  margin-top: 6px;
-}
-
-.btn-large .caret {
-  border-top-width: 5px;
-  border-right-width: 5px;
-  border-left-width: 5px;
-}
-
-.dropup .btn-large .caret {
-  border-bottom-width: 5px;
-}
-
-.btn-primary .caret,
-.btn-warning .caret,
-.btn-danger .caret,
-.btn-info .caret,
-.btn-success .caret,
-.btn-inverse .caret {
-  border-top-color: #ffffff;
-  border-bottom-color: #ffffff;
-}
-
-.btn-group-vertical {
-  display: inline-block;
-  *display: inline;
-  /* IE7 inline-block hack */
-
-  *zoom: 1;
-}
-
-.btn-group-vertical .btn {
-  display: block;
-  float: none;
-  width: 100%;
-  -webkit-border-radius: 0;
-     -moz-border-radius: 0;
-          border-radius: 0;
-}
-
-.btn-group-vertical .btn + .btn {
-  margin-top: -1px;
-  margin-left: 0;
-}
-
-.btn-group-vertical .btn:first-child {
-  -webkit-border-radius: 4px 4px 0 0;
-     -moz-border-radius: 4px 4px 0 0;
-          border-radius: 4px 4px 0 0;
-}
-
-.btn-group-vertical .btn:last-child {
-  -webkit-border-radius: 0 0 4px 4px;
-     -moz-border-radius: 0 0 4px 4px;
-          border-radius: 0 0 4px 4px;
-}
-
-.btn-group-vertical .btn-large:first-child {
-  -webkit-border-radius: 6px 6px 0 0;
-     -moz-border-radius: 6px 6px 0 0;
-          border-radius: 6px 6px 0 0;
-}
-
-.btn-group-vertical .btn-large:last-child {
-  -webkit-border-radius: 0 0 6px 6px;
-     -moz-border-radius: 0 0 6px 6px;
-          border-radius: 0 0 6px 6px;
-}
-
-.alert {
-  padding: 8px 35px 8px 14px;
-  margin-bottom: 20px;
-  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 h4 {
-  margin: 0;
-}
-
-.alert .close {
-  position: relative;
-  top: -2px;
-  right: -21px;
-  line-height: 20px;
-}
-
-.alert-success {
-  color: #468847;
-  background-color: #dff0d8;
-  border-color: #d6e9c6;
-}
-
-.alert-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: 20px;
-  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-header {
-  display: block;
-  padding: 3px 15px;
-  font-size: 11px;
-  font-weight: bold;
-  line-height: 20px;
-  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-"],
-.nav-list [class*=" icon-"] {
-  margin-right: 2px;
-}
-
-.nav-list .divider {
-  *width: 100%;
-  height: 1px;
-  margin: 9px 1px;
-  *margin: -5px 0 5px;
-  overflow: hidden;
-  background-color: #e5e5e5;
-  border-bottom: 1px solid #ffffff;
-}
-
-.nav-tabs,
-.nav-pills {
-  *zoom: 1;
-}
-
-.nav-tabs:before,
-.nav-pills:before,
-.nav-tabs:after,
-.nav-pills:after {
-  display: table;
-  line-height: 0;
-  content: "";
-}
-
-.nav-tabs:after,
-.nav-pills:after {
-  clear: both;
-}
-
-.nav-tabs > li,
-.nav-pills > li {
-  float: left;
-}
-
-.nav-tabs > li > a,
-.nav-pills > li > a {
-  padding-right: 12px;
-  padding-left: 12px;
-  margin-right: 2px;
-  line-height: 14px;
-}
-
-.nav-tabs {
-  border-bottom: 1px solid #ddd;
-}
-
-.nav-tabs > li {
-  margin-bottom: -1px;
-}
-
-.nav-tabs > li > a {
-  padding-top: 8px;
-  padding-bottom: 8px;
-  line-height: 20px;
-  border: 1px solid transparent;
-  -webkit-border-radius: 4px 4px 0 0;
-     -moz-border-radius: 4px 4px 0 0;
-          border-radius: 4px 4px 0 0;
-}
-
-.nav-tabs > li > a:hover {
-  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-top-right-radius: 4px;
-          border-top-right-radius: 4px;
-  -webkit-border-top-left-radius: 4px;
-          border-top-left-radius: 4px;
-  -moz-border-radius-topright: 4px;
-  -moz-border-radius-topleft: 4px;
-}
-
-.nav-tabs.nav-stacked > li:last-child > a {
-  -webkit-border-bottom-right-radius: 4px;
-          border-bottom-right-radius: 4px;
-  -webkit-border-bottom-left-radius: 4px;
-          border-bottom-left-radius: 4px;
-  -moz-border-radius-bottomright: 4px;
-  -moz-border-radius-bottomleft: 4px;
-}
-
-.nav-tabs.nav-stacked > li > a:hover {
-  z-index: 2;
-  border-color: #ddd;
-}
-
-.nav-pills.nav-stacked > li > a {
-  margin-bottom: 3px;
-}
-
-.nav-pills.nav-stacked > li:last-child > a {
-  margin-bottom: 1px;
-}
-
-.nav-tabs .dropdown-menu {
-  -webkit-border-radius: 0 0 6px 6px;
-     -moz-border-radius: 0 0 6px 6px;
-          border-radius: 0 0 6px 6px;
-}
-
-.nav-pills .dropdown-menu {
-  -webkit-border-radius: 6px;
-     -moz-border-radius: 6px;
-          border-radius: 6px;
-}
-
-.nav .dropdown-toggle .caret {
-  margin-top: 6px;
-  border-top-color: #0088cc;
-  border-bottom-color: #0088cc;
-}
-
-.nav .dropdown-toggle:hover .caret {
-  border-top-color: #005580;
-  border-bottom-color: #005580;
-}
-
-/* move down carets for tabs */
-
-.nav-tabs .dropdown-toggle .caret {
-  margin-top: 8px;
-}
-
-.nav .active .dropdown-toggle .caret {
-  border-top-color: #fff;
-  border-bottom-color: #fff;
-}
-
-.nav-tabs .active .dropdown-toggle .caret {
-  border-top-color: #555555;
-  border-bottom-color: #555555;
-}
-
-.nav > .dropdown.active > a:hover {
-  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;
-  line-height: 0;
-  content: "";
-}
-
-.tabbable:after {
-  clear: both;
-}
-
-.tab-content {
-  overflow: auto;
-}
-
-.tabs-below > .nav-tabs,
-.tabs-right > .nav-tabs,
-.tabs-left > .nav-tabs {
-  border-bottom: 0;
-}
-
-.tab-content > .tab-pane,
-.pill-content > .pill-pane {
-  display: none;
-}
-
-.tab-content > .active,
-.pill-content > .active {
-  display: block;
-}
-
-.tabs-below > .nav-tabs {
-  border-top: 1px solid #ddd;
-}
-
-.tabs-below > .nav-tabs > li {
-  margin-top: -1px;
-  margin-bottom: 0;
-}
-
-.tabs-below > .nav-tabs > li > a {
-  -webkit-border-radius: 0 0 4px 4px;
-     -moz-border-radius: 0 0 4px 4px;
-          border-radius: 0 0 4px 4px;
-}
-
-.tabs-below > .nav-tabs > li > a:hover {
-  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;
-}
-
-.nav > .disabled > a {
-  color: #999999;
-}
-
-.nav > .disabled > a:hover {
-  text-decoration: none;
-  cursor: default;
-  background-color: transparent;
-}
-
-.navbar {
-  *position: relative;
-  *z-index: 2;
-  margin-bottom: 20px;
-  overflow: visible;
-  color: #777777;
-}
-
-.navbar-inner {
-  min-height: 40px;
-  padding-right: 20px;
-  padding-left: 20px;
-  background-color: #fafafa;
-  background-image: -moz-linear-gradient(top, #ffffff, #f2f2f2);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f2f2f2));
-  background-image: -webkit-linear-gradient(top, #ffffff, #f2f2f2);
-  background-image: -o-linear-gradient(top, #ffffff, #f2f2f2);
-  background-image: linear-gradient(to bottom, #ffffff, #f2f2f2);
-  background-repeat: repeat-x;
-  border: 1px solid #d4d4d4;
-  -webkit-border-radius: 4px;
-     -moz-border-radius: 4px;
-          border-radius: 4px;
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0);
-  *zoom: 1;
-  -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065);
-     -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065);
-          box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065);
-}
-
-.navbar-inner:before,
-.navbar-inner:after {
-  display: table;
-  line-height: 0;
-  content: "";
-}
-
-.navbar-inner:after {
-  clear: both;
-}
-
-.navbar .container {
-  width: auto;
-}
-
-.nav-collapse.collapse {
-  height: auto;
-  overflow: visible;
-}
-
-.navbar .brand {
-  display: block;
-  float: left;
-  padding: 10px 20px 10px;
-  margin-left: -20px;
-  font-size: 20px;
-  font-weight: 200;
-  color: #777777;
-  text-shadow: 0 1px 0 #ffffff;
-}
-
-.navbar .brand:hover {
-  text-decoration: none;
-}
-
-.navbar-text {
-  margin-bottom: 0;
-  line-height: 40px;
-}
-
-.navbar-link {
-  color: #777777;
-}
-
-.navbar-link:hover {
-  color: #333333;
-}
-
-.navbar .divider-vertical {
-  height: 40px;
-  margin: 0 9px;
-  border-right: 1px solid #ffffff;
-  border-left: 1px solid #f2f2f2;
-}
-
-.navbar .btn,
-.navbar .btn-group {
-  margin-top: 5px;
-}
-
-.navbar .btn-group .btn,
-.navbar .input-prepend .btn,
-.navbar .input-append .btn {
-  margin-top: 0;
-}
-
-.navbar-form {
-  margin-bottom: 0;
-  *zoom: 1;
-}
-
-.navbar-form:before,
-.navbar-form:after {
-  display: table;
-  line-height: 0;
-  content: "";
-}
-
-.navbar-form:after {
-  clear: both;
-}
-
-.navbar-form input,
-.navbar-form select,
-.navbar-form .radio,
-.navbar-form .checkbox {
-  margin-top: 5px;
-}
-
-.navbar-form input,
-.navbar-form select,
-.navbar-form .btn {
-  display: inline-block;
-  margin-bottom: 0;
-}
-
-.navbar-form input[type="image"],
-.navbar-form input[type="checkbox"],
-.navbar-form input[type="radio"] {
-  margin-top: 3px;
-}
-
-.navbar-form .input-append,
-.navbar-form .input-prepend {
-  margin-top: 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: 5px;
-  margin-bottom: 0;
-}
-
-.navbar-search .search-query {
-  padding: 4px 14px;
-  margin-bottom: 0;
-  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
-  font-size: 13px;
-  font-weight: normal;
-  line-height: 1;
-  -webkit-border-radius: 15px;
-     -moz-border-radius: 15px;
-          border-radius: 15px;
-}
-
-.navbar-static-top {
-  position: static;
-  margin-bottom: 0;
-}
-
-.navbar-static-top .navbar-inner {
-  -webkit-border-radius: 0;
-     -moz-border-radius: 0;
-          border-radius: 0;
-}
-
-.navbar-fixed-top,
-.navbar-fixed-bottom {
-  position: fixed;
-  right: 0;
-  left: 0;
-  z-index: 1030;
-  margin-bottom: 0;
-}
-
-.navbar-fixed-top .navbar-inner,
-.navbar-static-top .navbar-inner {
-  border-width: 0 0 1px;
-}
-
-.navbar-fixed-bottom .navbar-inner {
-  border-width: 1px 0 0;
-}
-
-.navbar-fixed-top .navbar-inner,
-.navbar-fixed-bottom .navbar-inner {
-  padding-right: 0;
-  padding-left: 0;
-  -webkit-border-radius: 0;
-     -moz-border-radius: 0;
-          border-radius: 0;
-}
-
-.navbar-static-top .container,
-.navbar-fixed-top .container,
-.navbar-fixed-bottom .container {
-  width: 940px;
-}
-
-.navbar-fixed-top {
-  top: 0;
-}
-
-.navbar-fixed-top .navbar-inner,
-.navbar-static-top .navbar-inner {
-  -webkit-box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1);
-     -moz-box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1);
-          box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1);
-}
-
-.navbar-fixed-bottom {
-  bottom: 0;
-}
-
-.navbar-fixed-bottom .navbar-inner {
-  -webkit-box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1);
-     -moz-box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1);
-          box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1);
-}
-
-.navbar .nav {
-  position: relative;
-  left: 0;
-  display: block;
-  float: left;
-  margin: 0 10px 0 0;
-}
-
-.navbar .nav.pull-right {
-  float: right;
-  margin-right: 0;
-}
-
-.navbar .nav > li {
-  float: left;
-}
-
-.navbar .nav > li > a {
-  float: none;
-  padding: 10px 15px 10px;
-  color: #777777;
-  text-decoration: none;
-  text-shadow: 0 1px 0 #ffffff;
-}
-
-.navbar .nav .dropdown-toggle .caret {
-  margin-top: 8px;
-}
-
-.navbar .nav > li > a:focus,
-.navbar .nav > li > a:hover {
-  color: #333333;
-  text-decoration: none;
-  background-color: transparent;
-}
-
-.navbar .nav > .active > a,
-.navbar .nav > .active > a:hover,
-.navbar .nav > .active > a:focus {
-  color: #555555;
-  text-decoration: none;
-  background-color: #e5e5e5;
-  -webkit-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125);
-     -moz-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125);
-          box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125);
-}
-
-.navbar .btn-navbar {
-  display: none;
-  float: right;
-  padding: 7px 10px;
-  margin-right: 5px;
-  margin-left: 5px;
-  color: #ffffff;
-  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
-  background-color: #ededed;
-  *background-color: #e5e5e5;
-  background-image: -moz-linear-gradient(top, #f2f2f2, #e5e5e5);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f2f2f2), to(#e5e5e5));
-  background-image: -webkit-linear-gradient(top, #f2f2f2, #e5e5e5);
-  background-image: -o-linear-gradient(top, #f2f2f2, #e5e5e5);
-  background-image: linear-gradient(to bottom, #f2f2f2, #e5e5e5);
-  background-repeat: repeat-x;
-  border-color: #e5e5e5 #e5e5e5 #bfbfbf;
-  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2', endColorstr='#ffe5e5e5', GradientType=0);
-  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
-  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);
-     -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);
-          box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);
-}
-
-.navbar .btn-navbar:hover,
-.navbar .btn-navbar:active,
-.navbar .btn-navbar.active,
-.navbar .btn-navbar.disabled,
-.navbar .btn-navbar[disabled] {
-  color: #ffffff;
-  background-color: #e5e5e5;
-  *background-color: #d9d9d9;
-}
-
-.navbar .btn-navbar:active,
-.navbar .btn-navbar.active {
-  background-color: #cccccc \9;
-}
-
-.navbar .btn-navbar .icon-bar {
-  display: block;
-  width: 18px;
-  height: 2px;
-  background-color: #f5f5f5;
-  -webkit-border-radius: 1px;
-     -moz-border-radius: 1px;
-          border-radius: 1px;
-  -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
-     -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
-          box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
-}
-
-.btn-navbar .icon-bar + .icon-bar {
-  margin-top: 3px;
-}
-
-.navbar .nav > li > .dropdown-menu:before {
-  position: absolute;
-  top: -7px;
-  left: 9px;
-  display: inline-block;
-  border-right: 7px solid transparent;
-  border-bottom: 7px solid #ccc;
-  border-left: 7px solid transparent;
-  border-bottom-color: rgba(0, 0, 0, 0.2);
-  content: '';
-}
-
-.navbar .nav > li > .dropdown-menu:after {
-  position: absolute;
-  top: -6px;
-  left: 10px;
-  display: inline-block;
-  border-right: 6px solid transparent;
-  border-bottom: 6px solid #ffffff;
-  border-left: 6px solid transparent;
-  content: '';
-}
-
-.navbar-fixed-bottom .nav > li > .dropdown-menu:before {
-  top: auto;
-  bottom: -7px;
-  border-top: 7px solid #ccc;
-  border-bottom: 0;
-  border-top-color: rgba(0, 0, 0, 0.2);
-}
-
-.navbar-fixed-bottom .nav > li > .dropdown-menu:after {
-  top: auto;
-  bottom: -6px;
-  border-top: 6px solid #ffffff;
-  border-bottom: 0;
-}
-
-.navbar .nav li.dropdown.open > .dropdown-toggle,
-.navbar .nav li.dropdown.active > .dropdown-toggle,
-.navbar .nav li.dropdown.open.active > .dropdown-toggle {
-  color: #555555;
-  background-color: #e5e5e5;
-}
-
-.navbar .nav li.dropdown > .dropdown-toggle .caret {
-  border-top-color: #777777;
-  border-bottom-color: #777777;
-}
-
-.navbar .nav li.dropdown.open > .dropdown-toggle .caret,
-.navbar .nav li.dropdown.active > .dropdown-toggle .caret,
-.navbar .nav li.dropdown.open.active > .dropdown-toggle .caret {
-  border-top-color: #555555;
-  border-bottom-color: #555555;
-}
-
-.navbar .pull-right > li > .dropdown-menu,
-.navbar .nav > li > .dropdown-menu.pull-right {
-  right: 0;
-  left: auto;
-}
-
-.navbar .pull-right > li > .dropdown-menu:before,
-.navbar .nav > li > .dropdown-menu.pull-right:before {
-  right: 12px;
-  left: auto;
-}
-
-.navbar .pull-right > li > .dropdown-menu:after,
-.navbar .nav > li > .dropdown-menu.pull-right:after {
-  right: 13px;
-  left: auto;
-}
-
-.navbar .pull-right > li > .dropdown-menu .dropdown-menu,
-.navbar .nav > li > .dropdown-menu.pull-right .dropdown-menu {
-  right: 100%;
-  left: auto;
-  margin-right: -1px;
-  margin-left: 0;
-  -webkit-border-radius: 6px 0 6px 6px;
-     -moz-border-radius: 6px 0 6px 6px;
-          border-radius: 6px 0 6px 6px;
-}
-
-.navbar-inverse {
-  color: #999999;
-}
-
-.navbar-inverse .navbar-inner {
-  background-color: #1b1b1b;
-  background-image: -moz-linear-gradient(top, #222222, #111111);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#222222), to(#111111));
-  background-image: -webkit-linear-gradient(top, #222222, #111111);
-  background-image: -o-linear-gradient(top, #222222, #111111);
-  background-image: linear-gradient(to bottom, #222222, #111111);
-  background-repeat: repeat-x;
-  border-color: #252525;
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0);
-}
-
-.navbar-inverse .brand,
-.navbar-inverse .nav > li > a {
-  color: #999999;
-  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
-}
-
-.navbar-inverse .brand:hover,
-.navbar-inverse .nav > li > a:hover {
-  color: #ffffff;
-}
-
-.navbar-inverse .nav > li > a:focus,
-.navbar-inverse .nav > li > a:hover {
-  color: #ffffff;
-  background-color: transparent;
-}
-
-.navbar-inverse .nav .active > a,
-.navbar-inverse .nav .active > a:hover,
-.navbar-inverse .nav .active > a:focus {
-  color: #ffffff;
-  background-color: #111111;
-}
-
-.navbar-inverse .navbar-link {
-  color: #999999;
-}
-
-.navbar-inverse .navbar-link:hover {
-  color: #ffffff;
-}
-
-.navbar-inverse .divider-vertical {
-  border-right-color: #222222;
-  border-left-color: #111111;
-}
-
-.navbar-inverse .nav li.dropdown.open > .dropdown-toggle,
-.navbar-inverse .nav li.dropdown.active > .dropdown-toggle,
-.navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle {
-  color: #ffffff;
-  background-color: #111111;
-}
-
-.navbar-inverse .nav li.dropdown > .dropdown-toggle .caret {
-  border-top-color: #999999;
-  border-bottom-color: #999999;
-}
-
-.navbar-inverse .nav li.dropdown.open > .dropdown-toggle .caret,
-.navbar-inverse .nav li.dropdown.active > .dropdown-toggle .caret,
-.navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle .caret {
-  border-top-color: #ffffff;
-  border-bottom-color: #ffffff;
-}
-
-.navbar-inverse .navbar-search .search-query {
-  color: #ffffff;
-  background-color: #515151;
-  border-color: #111111;
-  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);
-     -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);
-          box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);
-  -webkit-transition: none;
-     -moz-transition: none;
-       -o-transition: none;
-          transition: none;
-}
-
-.navbar-inverse .navbar-search .search-query:-moz-placeholder {
-  color: #cccccc;
-}
-
-.navbar-inverse .navbar-search .search-query:-ms-input-placeholder {
-  color: #cccccc;
-}
-
-.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder {
-  color: #cccccc;
-}
-
-.navbar-inverse .navbar-search .search-query:focus,
-.navbar-inverse .navbar-search .search-query.focused {
-  padding: 5px 15px;
-  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-inverse .btn-navbar {
-  color: #ffffff;
-  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
-  background-color: #0e0e0e;
-  *background-color: #040404;
-  background-image: -moz-linear-gradient(top, #151515, #040404);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#151515), to(#040404));
-  background-image: -webkit-linear-gradient(top, #151515, #040404);
-  background-image: -o-linear-gradient(top, #151515, #040404);
-  background-image: linear-gradient(to bottom, #151515, #040404);
-  background-repeat: repeat-x;
-  border-color: #040404 #040404 #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='#ff151515', endColorstr='#ff040404', GradientType=0);
-  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
-}
-
-.navbar-inverse .btn-navbar:hover,
-.navbar-inverse .btn-navbar:active,
-.navbar-inverse .btn-navbar.active,
-.navbar-inverse .btn-navbar.disabled,
-.navbar-inverse .btn-navbar[disabled] {
-  color: #ffffff;
-  background-color: #040404;
-  *background-color: #000000;
-}
-
-.navbar-inverse .btn-navbar:active,
-.navbar-inverse .btn-navbar.active {
-  background-color: #000000 \9;
-}
-
-.breadcrumb {
-  padding: 8px 15px;
-  margin: 0 0 20px;
-  list-style: none;
-  background-color: #f5f5f5;
-  -webkit-border-radius: 4px;
-     -moz-border-radius: 4px;
-          border-radius: 4px;
-}
-
-.breadcrumb li {
-  display: inline-block;
-  *display: inline;
-  text-shadow: 0 1px 0 #ffffff;
-  *zoom: 1;
-}
-
-.breadcrumb .divider {
-  padding: 0 5px;
-  color: #ccc;
-}
-
-.breadcrumb .active {
-  color: #999999;
-}
-
-.pagination {
-  margin: 20px 0;
-}
-
-.pagination ul {
-  display: inline-block;
-  *display: inline;
-  margin-bottom: 0;
-  margin-left: 0;
-  -webkit-border-radius: 4px;
-     -moz-border-radius: 4px;
-          border-radius: 4px;
-  *zoom: 1;
-  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
-     -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
-          box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
-}
-
-.pagination ul > li {
-  display: inline;
-}
-
-.pagination ul > li > a,
-.pagination ul > li > span {
-  float: left;
-  padding: 4px 12px;
-  line-height: 20px;
-  text-decoration: none;
-  background-color: #ffffff;
-  border: 1px solid #dddddd;
-  border-left-width: 0;
-}
-
-.pagination ul > li > a:hover,
-.pagination ul > .active > a,
-.pagination ul > .active > span {
-  background-color: #f5f5f5;
-}
-
-.pagination ul > .active > a,
-.pagination ul > .active > span {
-  color: #999999;
-  cursor: default;
-}
-
-.pagination ul > .disabled > span,
-.pagination ul > .disabled > a,
-.pagination ul > .disabled > a:hover {
-  color: #999999;
-  cursor: default;
-  background-color: transparent;
-}
-
-.pagination ul > li:first-child > a,
-.pagination ul > li:first-child > span {
-  border-left-width: 1px;
-  -webkit-border-bottom-left-radius: 4px;
-          border-bottom-left-radius: 4px;
-  -webkit-border-top-left-radius: 4px;
-          border-top-left-radius: 4px;
-  -moz-border-radius-bottomleft: 4px;
-  -moz-border-radius-topleft: 4px;
-}
-
-.pagination ul > li:last-child > a,
-.pagination ul > li:last-child > span {
-  -webkit-border-top-right-radius: 4px;
-          border-top-right-radius: 4px;
-  -webkit-border-bottom-right-radius: 4px;
-          border-bottom-right-radius: 4px;
-  -moz-border-radius-topright: 4px;
-  -moz-border-radius-bottomright: 4px;
-}
-
-.pagination-centered {
-  text-align: center;
-}
-
-.pagination-right {
-  text-align: right;
-}
-
-.pagination-large ul > li > a,
-.pagination-large ul > li > span {
-  padding: 11px 19px;
-  font-size: 17.5px;
-}
-
-.pagination-large ul > li:first-child > a,
-.pagination-large ul > li:first-child > span {
-  -webkit-border-bottom-left-radius: 6px;
-          border-bottom-left-radius: 6px;
-  -webkit-border-top-left-radius: 6px;
-          border-top-left-radius: 6px;
-  -moz-border-radius-bottomleft: 6px;
-  -moz-border-radius-topleft: 6px;
-}
-
-.pagination-large ul > li:last-child > a,
-.pagination-large ul > li:last-child > span {
-  -webkit-border-top-right-radius: 6px;
-          border-top-right-radius: 6px;
-  -webkit-border-bottom-right-radius: 6px;
-          border-bottom-right-radius: 6px;
-  -moz-border-radius-topright: 6px;
-  -moz-border-radius-bottomright: 6px;
-}
-
-.pagination-mini ul > li:first-child > a,
-.pagination-small ul > li:first-child > a,
-.pagination-mini ul > li:first-child > span,
-.pagination-small ul > li:first-child > span {
-  -webkit-border-bottom-left-radius: 3px;
-          border-bottom-left-radius: 3px;
-  -webkit-border-top-left-radius: 3px;
-          border-top-left-radius: 3px;
-  -moz-border-radius-bottomleft: 3px;
-  -moz-border-radius-topleft: 3px;
-}
-
-.pagination-mini ul > li:last-child > a,
-.pagination-small ul > li:last-child > a,
-.pagination-mini ul > li:last-child > span,
-.pagination-small ul > li:last-child > span {
-  -webkit-border-top-right-radius: 3px;
-          border-top-right-radius: 3px;
-  -webkit-border-bottom-right-radius: 3px;
-          border-bottom-right-radius: 3px;
-  -moz-border-radius-topright: 3px;
-  -moz-border-radius-bottomright: 3px;
-}
-
-.pagination-small ul > li > a,
-.pagination-small ul > li > span {
-  padding: 2px 10px;
-  font-size: 11.9px;
-}
-
-.pagination-mini ul > li > a,
-.pagination-mini ul > li > span {
-  padding: 1px 6px;
-  font-size: 10.5px;
-}
-
-.pager {
-  margin: 20px 0;
-  text-align: center;
-  list-style: none;
-  *zoom: 1;
-}
-
-.pager:before,
-.pager:after {
-  display: table;
-  line-height: 0;
-  content: "";
-}
-
-.pager:after {
-  clear: both;
-}
-
-.pager li {
-  display: inline;
-}
-
-.pager li > a,
-.pager li > span {
-  display: inline-block;
-  padding: 5px 14px;
-  background-color: #fff;
-  border: 1px solid #ddd;
-  -webkit-border-radius: 15px;
-     -moz-border-radius: 15px;
-          border-radius: 15px;
-}
-
-.pager li > a:hover {
-  text-decoration: none;
-  background-color: #f5f5f5;
-}
-
-.pager .next > a,
-.pager .next > span {
-  float: right;
-}
-
-.pager .previous > a,
-.pager .previous > span {
-  float: left;
-}
-
-.pager .disabled > a,
-.pager .disabled > a:hover,
-.pager .disabled > span {
-  color: #999999;
-  cursor: default;
-  background-color: #fff;
-}
-
-.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;
-  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;
-  outline: none;
-  -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;
-       -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-header h3 {
-  margin: 0;
-  line-height: 30px;
-}
-
-.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;
-  line-height: 0;
-  content: "";
-}
-
-.modal-footer:after {
-  clear: both;
-}
-
-.modal-footer .btn + .btn {
-  margin-bottom: 0;
-  margin-left: 5px;
-}
-
-.modal-footer .btn-group .btn + .btn {
-  margin-left: -1px;
-}
-
-.modal-footer .btn-block + .btn-block {
-  margin-left: 0;
-}
-
-.tooltip {
-  position: absolute;
-  z-index: 1030;
-  display: block;
-  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: -3px;
-}
-
-.tooltip.right {
-  margin-left: 3px;
-}
-
-.tooltip.bottom {
-  margin-top: 3px;
-}
-
-.tooltip.left {
-  margin-left: -3px;
-}
-
-.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;
-  border-color: transparent;
-  border-style: solid;
-}
-
-.tooltip.top .tooltip-arrow {
-  bottom: 0;
-  left: 50%;
-  margin-left: -5px;
-  border-top-color: #000000;
-  border-width: 5px 5px 0;
-}
-
-.tooltip.right .tooltip-arrow {
-  top: 50%;
-  left: 0;
-  margin-top: -5px;
-  border-right-color: #000000;
-  border-width: 5px 5px 5px 0;
-}
-
-.tooltip.left .tooltip-arrow {
-  top: 50%;
-  right: 0;
-  margin-top: -5px;
-  border-left-color: #000000;
-  border-width: 5px 0 5px 5px;
-}
-
-.tooltip.bottom .tooltip-arrow {
-  top: 0;
-  left: 50%;
-  margin-left: -5px;
-  border-bottom-color: #000000;
-  border-width: 0 5px 5px;
-}
-
-.popover {
-  position: absolute;
-  top: 0;
-  left: 0;
-  z-index: 1010;
-  display: none;
-  width: 236px;
-  padding: 1px;
-  background-color: #ffffff;
-  border: 1px solid #ccc;
-  border: 1px solid rgba(0, 0, 0, 0.2);
-  -webkit-border-radius: 6px;
-     -moz-border-radius: 6px;
-          border-radius: 6px;
-  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
-     -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
-          box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
-  -webkit-background-clip: padding-box;
-     -moz-background-clip: padding;
-          background-clip: padding-box;
-}
-
-.popover.top {
-  margin-top: -10px;
-}
-
-.popover.right {
-  margin-left: 10px;
-}
-
-.popover.bottom {
-  margin-top: 10px;
-}
-
-.popover.left {
-  margin-left: -10px;
-}
-
-.popover-title {
-  padding: 8px 14px;
-  margin: 0;
-  font-size: 14px;
-  font-weight: normal;
-  line-height: 18px;
-  background-color: #f7f7f7;
-  border-bottom: 1px solid #ebebeb;
-  -webkit-border-radius: 5px 5px 0 0;
-     -moz-border-radius: 5px 5px 0 0;
-          border-radius: 5px 5px 0 0;
-}
-
-.popover-content {
-  padding: 9px 14px;
-}
-
-.popover-content p,
-.popover-content ul,
-.popover-content ol {
-  margin-bottom: 0;
-}
-
-.popover .arrow,
-.popover .arrow:after {
-  position: absolute;
-  display: inline-block;
-  width: 0;
-  height: 0;
-  border-color: transparent;
-  border-style: solid;
-}
-
-.popover .arrow:after {
-  z-index: -1;
-  content: "";
-}
-
-.popover.top .arrow {
-  bottom: -10px;
-  left: 50%;
-  margin-left: -10px;
-  border-top-color: #ffffff;
-  border-width: 10px 10px 0;
-}
-
-.popover.top .arrow:after {
-  bottom: -1px;
-  left: -11px;
-  border-top-color: rgba(0, 0, 0, 0.25);
-  border-width: 11px 11px 0;
-}
-
-.popover.right .arrow {
-  top: 50%;
-  left: -10px;
-  margin-top: -10px;
-  border-right-color: #ffffff;
-  border-width: 10px 10px 10px 0;
-}
-
-.popover.right .arrow:after {
-  bottom: -11px;
-  left: -1px;
-  border-right-color: rgba(0, 0, 0, 0.25);
-  border-width: 11px 11px 11px 0;
-}
-
-.popover.bottom .arrow {
-  top: -10px;
-  left: 50%;
-  margin-left: -10px;
-  border-bottom-color: #ffffff;
-  border-width: 0 10px 10px;
-}
-
-.popover.bottom .arrow:after {
-  top: -1px;
-  left: -11px;
-  border-bottom-color: rgba(0, 0, 0, 0.25);
-  border-width: 0 11px 11px;
-}
-
-.popover.left .arrow {
-  top: 50%;
-  right: -10px;
-  margin-top: -10px;
-  border-left-color: #ffffff;
-  border-width: 10px 0 10px 10px;
-}
-
-.popover.left .arrow:after {
-  right: -1px;
-  bottom: -11px;
-  border-left-color: rgba(0, 0, 0, 0.25);
-  border-width: 11px 0 11px 11px;
-}
-
-.thumbnails {
-  margin-left: -20px;
-  list-style: none;
-  *zoom: 1;
-}
-
-.thumbnails:before,
-.thumbnails:after {
-  display: table;
-  line-height: 0;
-  content: "";
-}
-
-.thumbnails:after {
-  clear: both;
-}
-
-.row-fluid .thumbnails {
-  margin-left: 0;
-}
-
-.thumbnails > li {
-  float: left;
-  margin-bottom: 20px;
-  margin-left: 20px;
-}
-
-.thumbnail {
-  display: block;
-  padding: 4px;
-  line-height: 20px;
-  border: 1px solid #ddd;
-  -webkit-border-radius: 4px;
-     -moz-border-radius: 4px;
-          border-radius: 4px;
-  -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055);
-     -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055);
-          box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055);
-  -webkit-transition: all 0.2s ease-in-out;
-     -moz-transition: all 0.2s ease-in-out;
-       -o-transition: all 0.2s ease-in-out;
-          transition: all 0.2s ease-in-out;
-}
-
-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;
-  color: #555555;
-}
-
-.media,
-.media-body {
-  overflow: hidden;
-  *overflow: visible;
-  zoom: 1;
-}
-
-.media,
-.media .media {
-  margin-top: 15px;
-}
-
-.media:first-child {
-  margin-top: 0;
-}
-
-.media-object {
-  display: block;
-}
-
-.media-heading {
-  margin: 0 0 5px;
-}
-
-.media .pull-left {
-  margin-right: 10px;
-}
-
-.media .pull-right {
-  margin-left: 10px;
-}
-
-.media-list {
-  margin-left: 0;
-  list-style: none;
-}
-
-.label,
-.badge {
-  display: inline-block;
-  padding: 2px 4px;
-  font-size: 11.844px;
-  font-weight: bold;
-  line-height: 14px;
-  color: #ffffff;
-  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
-  white-space: nowrap;
-  vertical-align: baseline;
-  background-color: #999999;
-}
-
-.label {
-  -webkit-border-radius: 3px;
-     -moz-border-radius: 3px;
-          border-radius: 3px;
-}
-
-.badge {
-  padding-right: 9px;
-  padding-left: 9px;
-  -webkit-border-radius: 9px;
-     -moz-border-radius: 9px;
-          border-radius: 9px;
-}
-
-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;
-}
-
-.btn .label,
-.btn .badge {
-  position: relative;
-  top: -1px;
-}
-
-.btn-mini .label,
-.btn-mini .badge {
-  top: 0;
-}
-
-@-webkit-keyframes progress-bar-stripes {
-  from {
-    background-position: 40px 0;
-  }
-  to {
-    background-position: 0 0;
-  }
-}
-
-@-moz-keyframes progress-bar-stripes {
-  from {
-    background-position: 40px 0;
-  }
-  to {
-    background-position: 0 0;
-  }
-}
-
-@-ms-keyframes progress-bar-stripes {
-  from {
-    background-position: 40px 0;
-  }
-  to {
-    background-position: 0 0;
-  }
-}
-
-@-o-keyframes progress-bar-stripes {
-  from {
-    background-position: 0 0;
-  }
-  to {
-    background-position: 40px 0;
-  }
-}
-
-@keyframes progress-bar-stripes {
-  from {
-    background-position: 40px 0;
-  }
-  to {
-    background-position: 0 0;
-  }
-}
-
-.progress {
-  height: 20px;
-  margin-bottom: 20px;
-  overflow: hidden;
-  background-color: #f7f7f7;
-  background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));
-  background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9);
-  background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9);
-  background-image: linear-gradient(to bottom, #f5f5f5, #f9f9f9);
-  background-repeat: repeat-x;
-  -webkit-border-radius: 4px;
-     -moz-border-radius: 4px;
-          border-radius: 4px;
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0);
-  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
-     -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
-          box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
-}
-
-.progress .bar {
-  float: left;
-  width: 0;
-  height: 100%;
-  font-size: 12px;
-  color: #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(to bottom, #149bdf, #0480be);
-  background-repeat: repeat-x;
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0);
-  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
-     -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
-          box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
-  -webkit-box-sizing: border-box;
-     -moz-box-sizing: border-box;
-          box-sizing: border-box;
-  -webkit-transition: width 0.6s ease;
-     -moz-transition: width 0.6s ease;
-       -o-transition: width 0.6s ease;
-          transition: width 0.6s ease;
-}
-
-.progress .bar + .bar {
-  -webkit-box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15);
-     -moz-box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15);
-          box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15);
-}
-
-.progress-striped .bar {
-  background-color: #149bdf;
-  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));
-  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  -webkit-background-size: 40px 40px;
-     -moz-background-size: 40px 40px;
-       -o-background-size: 40px 40px;
-          background-size: 40px 40px;
-}
-
-.progress.active .bar {
-  -webkit-animation: progress-bar-stripes 2s linear infinite;
-     -moz-animation: progress-bar-stripes 2s linear infinite;
-      -ms-animation: progress-bar-stripes 2s linear infinite;
-       -o-animation: progress-bar-stripes 2s linear infinite;
-          animation: progress-bar-stripes 2s linear infinite;
-}
-
-.progress-danger .bar,
-.progress .bar-danger {
-  background-color: #dd514c;
-  background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));
-  background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);
-  background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);
-  background-image: linear-gradient(to bottom, #ee5f5b, #c43c35);
-  background-repeat: repeat-x;
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffc43c35', GradientType=0);
-}
-
-.progress-danger.progress-striped .bar,
-.progress-striped .bar-danger {
-  background-color: #ee5f5b;
-  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));
-  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-}
-
-.progress-success .bar,
-.progress .bar-success {
-  background-color: #5eb95e;
-  background-image: -moz-linear-gradient(top, #62c462, #57a957);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));
-  background-image: -webkit-linear-gradient(top, #62c462, #57a957);
-  background-image: -o-linear-gradient(top, #62c462, #57a957);
-  background-image: linear-gradient(to bottom, #62c462, #57a957);
-  background-repeat: repeat-x;
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff57a957', GradientType=0);
-}
-
-.progress-success.progress-striped .bar,
-.progress-striped .bar-success {
-  background-color: #62c462;
-  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));
-  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-}
-
-.progress-info .bar,
-.progress .bar-info {
-  background-color: #4bb1cf;
-  background-image: -moz-linear-gradient(top, #5bc0de, #339bb9);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));
-  background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9);
-  background-image: -o-linear-gradient(top, #5bc0de, #339bb9);
-  background-image: linear-gradient(to bottom, #5bc0de, #339bb9);
-  background-repeat: repeat-x;
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff339bb9', GradientType=0);
-}
-
-.progress-info.progress-striped .bar,
-.progress-striped .bar-info {
-  background-color: #5bc0de;
-  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));
-  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-}
-
-.progress-warning .bar,
-.progress .bar-warning {
-  background-color: #faa732;
-  background-image: -moz-linear-gradient(top, #fbb450, #f89406);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));
-  background-image: -webkit-linear-gradient(top, #fbb450, #f89406);
-  background-image: -o-linear-gradient(top, #fbb450, #f89406);
-  background-image: linear-gradient(to bottom, #fbb450, #f89406);
-  background-repeat: repeat-x;
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);
-}
-
-.progress-warning.progress-striped .bar,
-.progress-striped .bar-warning {
-  background-color: #fbb450;
-  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));
-  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-}
-
-.accordion {
-  margin-bottom: 20px;
-}
-
-.accordion-group {
-  margin-bottom: 2px;
-  border: 1px solid #e5e5e5;
-  -webkit-border-radius: 4px;
-     -moz-border-radius: 4px;
-          border-radius: 4px;
-}
-
-.accordion-heading {
-  border-bottom: 0;
-}
-
-.accordion-heading .accordion-toggle {
-  display: block;
-  padding: 8px 15px;
-}
-
-.accordion-toggle {
-  cursor: pointer;
-}
-
-.accordion-inner {
-  padding: 9px 15px;
-  border-top: 1px solid #e5e5e5;
-}
-
-.carousel {
-  position: relative;
-  margin-bottom: 20px;
-  line-height: 1;
-}
-
-.carousel-inner {
-  position: relative;
-  width: 100%;
-  overflow: hidden;
-}
-
-.carousel .item {
-  position: relative;
-  display: none;
-  -webkit-transition: 0.6s ease-in-out left;
-     -moz-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: 15px;
-  background: #333333;
-  background: rgba(0, 0, 0, 0.75);
-}
-
-.carousel-caption h4,
-.carousel-caption p {
-  line-height: 20px;
-  color: #ffffff;
-}
-
-.carousel-caption h4 {
-  margin: 0 0 5px;
-}
-
-.carousel-caption p {
-  margin-bottom: 0;
-}
-
-.hero-unit {
-  padding: 60px;
-  margin-bottom: 30px;
-  font-size: 18px;
-  font-weight: 200;
-  line-height: 30px;
-  color: inherit;
-  background-color: #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 li {
-  line-height: 30px;
-}
-
-.pull-right {
-  float: right;
-}
-
-.pull-left {
-  float: left;
-}
-
-.hide {
-  display: none;
-}
-
-.show {
-  display: block;
-}
-
-.invisible {
-  visibility: hidden;
-}
-
-.affix {
-  position: fixed;
-}
diff --git a/src/site/resources/css/bootstrap.min.css b/src/site/resources/css/bootstrap.min.css
deleted file mode 100644
index 43e16d7..0000000
--- a/src/site/resources/css/bootstrap.min.css
+++ /dev/null
@@ -1,9 +0,0 @@
-/*!
- * Bootstrap v2.2.1
- *
- * 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{width:auto\9;height:auto;max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}#map_canvas img,.google-maps img{max-width:none}button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle}button,input{*overflow:visible;line-height:normal}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}button,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}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;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:20px;color:#333;background-color:#fff}a{color:#08c;text-decoration:none}a:hover{color:#005580;text-decoration:underline}.img-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.1);box-shadow:0 1px 3px rgba(0,0,0,0.1)}.img-circle{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px}.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.span12{width:940px}.span11{width:860px}.span10{width:780px}.span9{width:700px}.span8{width:620px}.span7{width:540px}.span6{width:460px}.span5{width:380px}.span4{width:300px}.span3{width:220px}.span2{width:140px}.span1{width:60px}.offset12{margin-left:980px}.offset11{margin-left:900px}.offset10{margin-left:820px}.offset9{margin-left:740px}.offset8{margin-left:660px}.offset7{margin-left:580px}.offset6{margin-left:500px}.offset5{margin-left:420px}.offset4{margin-left:340px}.offset3{margin-left:260px}.offset2{margin-left:180px}.offset1{margin-left:100px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.127659574468085%;*margin-left:2.074468085106383%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.127659574468085%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%}.row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%}.row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%}.row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%}.row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%}.row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%}.row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%}.row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%}.row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%}.row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%}.row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%}.row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%}.row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%}.row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%}.row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%}.row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%}.row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%}.row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%}.row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%}.row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%}.row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%}.row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%}.row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%}.row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%}.row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%}.row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%}.row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%}.row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%}.row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%}.row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%}.row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%}.row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%}.row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%}.row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%}.row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%}[class*="span"].hide,.row-fluid [class*="span"].hide{display:none}[class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right}.container{margin-right:auto;margin-left:auto;*zoom:1}.container:before,.container:after{display:table;line-height:0;content:""}.container:after{clear:both}.container-fluid{padding-right:20px;padding-left:20px;*zoom:1}.container-fluid:before,.container-fluid:after{display:table;line-height:0;content:""}.container-fluid:after{clear:both}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:21px;font-weight:200;line-height:30px}small{font-size:85%}strong{font-weight:bold}em{font-style:italic}cite{font-style:normal}.muted{color:#999}.text-warning{color:#c09853}a.text-warning:hover{color:#a47e3c}.text-error{color:#b94a48}a.text-error:hover{color:#953b39}.text-info{color:#3a87ad}a.text-info:hover{color:#2d6987}.text-success{color:#468847}a.text-success:hover{color:#356635}h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit;text-rendering:optimizelegibility}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#999}h1,h2,h3{line-height:40px}h1{font-size:38.5px}h2{font-size:31.5px}h3{font-size:24.5px}h4{font-size:17.5px}h5{font-size:14px}h6{font-size:11.9px}h1 small{font-size:24.5px}h2 small{font-size:17.5px}h3 small{font-size:14px}h4 small{font-size:14px}.page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eee}ul,ol{padding:0;margin:0 0 10px 25px}ul ul,ul ol,ol ol,ol ul{margin-bottom:0}li{line-height:20px}ul.unstyled,ol.unstyled{margin-left:0;list-style:none}dl{margin-bottom:20px}dt,dd{line-height:20px}dt{font-weight:bold}dd{margin-left:10px}.dl-horizontal{*zoom:1}.dl-horizontal:before,.dl-horizontal:after{display:table;line-height:0;content:""}.dl-horizontal:after{clear:both}.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}hr{margin:20px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{margin-bottom:0;font-size:16px;font-weight:300;line-height:25px}blockquote small{display:block;line-height:20px;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}blockquote.pull-right small:before{content:''}blockquote.pull-right small:after{content:'\00A0 \2014'}q:before,q:after,blockquote:before,blockquote:after{content:""}address{display:block;margin-bottom:20px;font-style:normal;line-height:20px}code,pre{padding:0 3px 2px;font-family:Monaco,Menlo,Consolas,"Courier New",monospace;font-size:12px;color:#333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}code{padding:2px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}pre.prettyprint{margin-bottom:20px}pre code{padding:0;color:inherit;background-color:transparent;border:0}.pre-scrollable{max-height:340px;overflow-y:scroll}form{margin:0 0 20px}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:40px;color:#333;border:0;border-bottom:1px solid #e5e5e5}legend small{font-size:15px;color:#999}label,input,button,select,textarea{font-size:14px;font-weight:normal;line-height:20px}input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}label{display:block;margin-bottom:5px}select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:10px;font-size:14px;line-height:20px;color:#555;vertical-align:middle;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}input,textarea,.uneditable-input{width:206px}textarea{height:auto}textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#fff;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border linear .2s,box-shadow linear .2s;-moz-transition:border linear .2s,box-shadow linear .2s;-o-transition:border linear .2s,box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82,168,236,0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6)}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;*margin-top:0;line-height:normal;cursor:pointer}input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto}select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px}select{width:220px;background-color:#fff;border:1px solid #ccc}select[multiple],select[size]{height:auto}select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.uneditable-input,.uneditable-textarea{color:#999;cursor:not-allowed;background-color:#fcfcfc;border-color:#ccc;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);box-shadow:inset 0 1px 2px rgba(0,0,0,0.025)}.uneditable-input{overflow:hidden;white-space:nowrap}.uneditable-textarea{width:auto;height:auto}input:-moz-placeholder,textarea:-moz-placeholder{color:#999}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999}.radio,.checkbox{min-height:20px;padding-left:20px}.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-20px}.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px}.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle}.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px}.input-mini{width:60px}.input-small{width:90px}.input-medium{width:150px}.input-large{width:210px}.input-xlarge{width:270px}.input-xxlarge{width:530px}input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0}.input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:926px}input.span11,textarea.span11,.uneditable-input.span11{width:846px}input.span10,textarea.span10,.uneditable-input.span10{width:766px}input.span9,textarea.span9,.uneditable-input.span9{width:686px}input.span8,textarea.span8,.uneditable-input.span8{width:606px}input.span7,textarea.span7,.uneditable-input.span7{width:526px}input.span6,textarea.span6,.uneditable-input.span6{width:446px}input.span5,textarea.span5,.uneditable-input.span5{width:366px}input.span4,textarea.span4,.uneditable-input.span4{width:286px}input.span3,textarea.span3,.uneditable-input.span3{width:206px}input.span2,textarea.span2,.uneditable-input.span2{width:126px}input.span1,textarea.span1,.uneditable-input.span1{width:46px}.controls-row{*zoom:1}.controls-row:before,.controls-row:after{display:table;line-height:0;content:""}.controls-row:after{clear:both}.controls-row [class*="span"],.row-fluid .controls-row [class*="span"]{float:left}.controls-row .checkbox[class*="span"],.controls-row .radio[class*="span"]{padding-top:5px}input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eee}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent}.control-group.warning>label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853}.control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853}.control-group.warning input,.control-group.warning select,.control-group.warning textarea{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.control-group.error>label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48}.control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48}.control-group.error input,.control-group.error select,.control-group.error textarea{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.control-group.success>label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847}.control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847}.control-group.success input,.control-group.success select,.control-group.success textarea{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847}.control-group.info>label,.control-group.info .help-block,.control-group.info .help-inline{color:#3a87ad}.control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad}.control-group.info input,.control-group.info select,.control-group.info textarea{border-color:#3a87ad;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.info input:focus,.control-group.info select:focus,.control-group.info textarea:focus{border-color:#2d6987;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3}.control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad}input:focus: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:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1}.form-actions:before,.form-actions:after{display:table;line-height:0;content:""}.form-actions:after{clear:both}.help-block,.help-inline{color:#595959}.help-block{display:block;margin-bottom:10px}.help-inline{display:inline-block;*display:inline;padding-left:5px;vertical-align:middle;*zoom:1}.input-append,.input-prepend{margin-bottom:5px;font-size:0;white-space:nowrap}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input,.input-append .dropdown-menu,.input-prepend .dropdown-menu{font-size:14px}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:top;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2}.input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:14px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #fff;background-color:#eee;border:1px solid #ccc}.input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn{vertical-align:top;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546}.input-prepend .add-on,.input-prepend .btn{margin-right:-1px}.input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input,.input-append select,.input-append .uneditable-input{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input+.btn-group .btn,.input-append select+.btn-group .btn,.input-append .uneditable-input+.btn-group .btn{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append .add-on,.input-append .btn,.input-append .btn-group{margin-left:-1px}.input-append .add-on:last-child,.input-append .btn:last-child{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend.input-append input+.btn-group .btn,.input-prepend.input-append select+.btn-group .btn,.input-prepend.input-append .uneditable-input+.btn-group .btn{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append .btn-group:first-child{margin-left:0}input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.form-search .input-append .search-query,.form-search .input-prepend .search-query{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.form-search .input-append .search-query{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search .input-append .btn{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .search-query{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .btn{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;margin-bottom:0;vertical-align:middle;*zoom:1}.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none}.form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block}.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0}.form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle}.form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0}.control-group{margin-bottom:10px}legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate}.form-horizontal .control-group{margin-bottom:20px;*zoom:1}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;line-height:0;content:""}.form-horizontal .control-group:after{clear:both}.form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right}.form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0}.form-horizontal .controls:first-child{*padding-left:180px}.form-horizontal .help-block{margin-bottom:0}.form-horizontal input+.help-block,.form-horizontal select+.help-block,.form-horizontal textarea+.help-block{margin-top:10px}.form-horizontal .form-actions{padding-left:180px}table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}.table{width:100%;margin-bottom:20px}.table th,.table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #ddd}.table th{font-weight:bold}.table thead th{vertical-align:bottom}.table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0}.table tbody+tbody{border-top:2px solid #ddd}.table-condensed th,.table-condensed td{padding:4px 5px}.table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.table-bordered th,.table-bordered td{border-left:1px solid #ddd}.table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0}.table-bordered thead:first-child tr:first-child th:first-child,.table-bordered tbody:first-child tr:first-child td:first-child{-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,.table-bordered tfoot: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,.table-bordered tfoot: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-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-striped tbody tr:nth-child(odd) td,.table-striped tbody tr:nth-child(odd) th{background-color:#f9f9f9}.table-hover tbody tr:hover td,.table-hover tbody tr:hover th{background-color:#f5f5f5}table td[class*="span"],table th[class*="span"],.row-fluid table td[class*="span"],.row-fluid table th[class*="span"]{display:table-cell;float:none;margin-left:0}.table td.span1,.table th.span1{float:none;width:44px;margin-left:0}.table td.span2,.table th.span2{float:none;width:124px;margin-left:0}.table td.span3,.table th.span3{float:none;width:204px;margin-left:0}.table td.span4,.table th.span4{float:none;width:284px;margin-left:0}.table td.span5,.table th.span5{float:none;width:364px;margin-left:0}.table td.span6,.table th.span6{float:none;width:444px;margin-left:0}.table td.span7,.table th.span7{float:none;width:524px;margin-left:0}.table td.span8,.table th.span8{float:none;width:604px;margin-left:0}.table td.span9,.table th.span9{float:none;width:684px;margin-left:0}.table td.span10,.table th.span10{float:none;width:764px;margin-left:0}.table td.span11,.table th.span11{float:none;width:844px;margin-left:0}.table td.span12,.table th.span12{float:none;width:924px;margin-left:0}.table tbody tr.success td{background-color:#dff0d8}.table tbody tr.error td{background-color:#f2dede}.table tbody tr.warning td{background-color:#fcf8e3}.table tbody tr.info td{background-color:#d9edf7}.table-hover tbody tr.success:hover td{background-color:#d0e9c6}.table-hover tbody tr.error:hover td{background-color:#ebcccc}.table-hover tbody tr.warning:hover td{background-color:#faf2cc}.table-hover tbody tr.info:hover td{background-color:#c4e3f3}[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;margin-top:1px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat}.icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"]{background-image:url("../img/glyphicons-halflings-white.png")}.icon-glass{background-position:0 0}.icon-music{background-position:-24px 0}.icon-search{background-position:-48px 0}.icon-envelope{background-position:-72px 0}.icon-heart{background-position:-96px 0}.icon-star{background-position:-120px 0}.icon-star-empty{background-position:-144px 0}.icon-user{background-position:-168px 0}.icon-film{background-position:-192px 0}.icon-th-large{background-position:-216px 0}.icon-th{background-position:-240px 0}.icon-th-list{background-position:-264px 0}.icon-ok{background-position:-288px 0}.icon-remove{background-position:-312px 0}.icon-zoom-in{background-position:-336px 0}.icon-zoom-out{background-position:-360px 0}.icon-off{background-position:-384px 0}.icon-signal{background-position:-408px 0}.icon-cog{background-position:-432px 0}.icon-trash{background-position:-456px 0}.icon-home{background-position:0 -24px}.icon-file{background-position:-24px -24px}.icon-time{background-position:-48px -24px}.icon-road{background-position:-72px -24px}.icon-download-alt{background-position:-96px -24px}.icon-download{background-position:-120px -24px}.icon-upload{background-position:-144px -24px}.icon-inbox{background-position:-168px -24px}.icon-play-circle{background-position:-192px -24px}.icon-repeat{background-position:-216px -24px}.icon-refresh{background-position:-240px -24px}.icon-list-alt{background-position:-264px -24px}.icon-lock{background-position:-287px -24px}.icon-flag{background-position:-312px -24px}.icon-headphones{background-position:-336px -24px}.icon-volume-off{background-position:-360px -24px}.icon-volume-down{background-position:-384px -24px}.icon-volume-up{background-position:-408px -24px}.icon-qrcode{background-position:-432px -24px}.icon-barcode{background-position:-456px -24px}.icon-tag{background-position:0 -48px}.icon-tags{background-position:-25px -48px}.icon-book{background-position:-48px -48px}.icon-bookmark{background-position:-72px -48px}.icon-print{background-position:-96px -48px}.icon-camera{background-position:-120px -48px}.icon-font{background-position:-144px -48px}.icon-bold{background-position:-167px -48px}.icon-italic{background-position:-192px -48px}.icon-text-height{background-position:-216px -48px}.icon-text-width{background-position:-240px -48px}.icon-align-left{background-position:-264px -48px}.icon-align-center{background-position:-288px -48px}.icon-align-right{background-position:-312px -48px}.icon-align-justify{background-position:-336px -48px}.icon-list{background-position:-360px -48px}.icon-indent-left{background-position:-384px -48px}.icon-indent-right{background-position:-408px -48px}.icon-facetime-video{background-position:-432px -48px}.icon-picture{background-position:-456px -48px}.icon-pencil{background-position:0 -72px}.icon-map-marker{background-position:-24px -72px}.icon-adjust{background-position:-48px -72px}.icon-tint{background-position:-72px -72px}.icon-edit{background-position:-96px -72px}.icon-share{background-position:-120px -72px}.icon-check{background-position:-144px -72px}.icon-move{background-position:-168px -72px}.icon-step-backward{background-position:-192px -72px}.icon-fast-backward{background-position:-216px -72px}.icon-backward{background-position:-240px -72px}.icon-play{background-position:-264px -72px}.icon-pause{background-position:-288px -72px}.icon-stop{background-position:-312px -72px}.icon-forward{background-position:-336px -72px}.icon-fast-forward{background-position:-360px -72px}.icon-step-forward{background-position:-384px -72px}.icon-eject{background-position:-408px -72px}.icon-chevron-left{background-position:-432px -72px}.icon-chevron-right{background-position:-456px -72px}.icon-plus-sign{background-position:0 -96px}.icon-minus-sign{background-position:-24px -96px}.icon-remove-sign{background-position:-48px -96px}.icon-ok-sign{background-position:-72px -96px}.icon-question-sign{background-position:-96px -96px}.icon-info-sign{background-position:-120px -96px}.icon-screenshot{background-position:-144px -96px}.icon-remove-circle{background-position:-168px -96px}.icon-ok-circle{background-position:-192px -96px}.icon-ban-circle{background-position:-216px -96px}.icon-arrow-left{background-position:-240px -96px}.icon-arrow-right{background-position:-264px -96px}.icon-arrow-up{background-position:-289px -96px}.icon-arrow-down{background-position:-312px -96px}.icon-share-alt{background-position:-336px -96px}.icon-resize-full{background-position:-360px -96px}.icon-resize-small{background-position:-384px -96px}.icon-plus{background-position:-408px -96px}.icon-minus{background-position:-433px -96px}.icon-asterisk{background-position:-456px -96px}.icon-exclamation-sign{background-position:0 -120px}.icon-gift{background-position:-24px -120px}.icon-leaf{background-position:-48px -120px}.icon-fire{background-position:-72px -120px}.icon-eye-open{background-position:-96px -120px}.icon-eye-close{background-position:-120px -120px}.icon-warning-sign{background-position:-144px -120px}.icon-plane{background-position:-168px -120px}.icon-calendar{background-position:-192px -120px}.icon-random{width:16px;background-position:-216px -120px}.icon-comment{background-position:-240px -120px}.icon-magnet{background-position:-264px -120px}.icon-chevron-up{background-position:-288px -120px}.icon-chevron-down{background-position:-313px -119px}.icon-retweet{background-position:-336px -120px}.icon-shopping-cart{background-position:-360px -120px}.icon-folder-close{background-position:-384px -120px}.icon-folder-open{width:16px;background-position:-408px -120px}.icon-resize-vertical{background-position:-432px -119px}.icon-resize-horizontal{background-position:-456px -118px}.icon-hdd{background-position:0 -144px}.icon-bullhorn{background-position:-24px -144px}.icon-bell{background-position:-48px -144px}.icon-certificate{background-position:-72px -144px}.icon-thumbs-up{background-position:-96px -144px}.icon-thumbs-down{background-position:-120px -144px}.icon-hand-right{background-position:-144px -144px}.icon-hand-left{background-position:-168px -144px}.icon-hand-up{background-position:-192px -144px}.icon-hand-down{background-position:-216px -144px}.icon-circle-arrow-right{background-position:-240px -144px}.icon-circle-arrow-left{background-position:-264px -144px}.icon-circle-arrow-up{background-position:-288px -144px}.icon-circle-arrow-down{background-position:-312px -144px}.icon-globe{background-position:-336px -144px}.icon-wrench{background-position:-360px -144px}.icon-tasks{background-position:-384px -144px}.icon-filter{background-position:-408px -144px}.icon-briefcase{background-position:-432px -144px}.icon-fullscreen{background-position:-456px -144px}.dropup,.dropdown{position:relative}.dropdown-toggle{*margin-bottom:-3px}.dropdown-toggle:active,.open .dropdown-toggle{outline:0}.caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:""}.dropdown .caret{margin-top:8px;margin-left:2px}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.dropdown-menu li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}.dropdown-menu li>a:hover,.dropdown-menu li>a:focus,.dropdown-submenu:hover>a{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu .active>a,.dropdown-menu .active>a:hover{color:#333;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;outline:0;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu .disabled>a,.dropdown-menu .disabled>a:hover{color:#999}.dropdown-menu .disabled>a:hover{text-decoration:none;cursor:default;background-color:transparent;background-image:none}.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 #000;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}.dropdown-submenu{position:relative}.dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px}.dropdown-submenu:hover>.dropdown-menu{display:block}.dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;-webkit-border-radius:5px 5px 5px 0;-moz-border-radius:5px 5px 5px 0;border-radius:5px 5px 5px 0}.dropdown-submenu>a:after{display:block;float:right;width:0;height:0;margin-top:5px;margin-right:-10px;border-color:transparent;border-left-color:#ccc;border-style:solid;border-width:5px 0 5px 5px;content:" "}.dropdown-submenu:hover>a:after{border-left-color:#fff}.dropdown-submenu.pull-left{float:none}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.dropdown .dropdown-menu .nav-header{padding-right:20px;padding-left:20px}.typeahead{margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.fade{opacity:0;-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-moz-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.collapse.in{height:auto}.close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.btn{display:inline-block;*display:inline;padding:4px 12px;margin-bottom:0;*margin-left:.3em;font-size:14px;line-height:20px;*line-height:20px;color:#333;text-align:center;text-shadow:0 1px 1px rgba(255,255,255,0.75);vertical-align:middle;cursor:pointer;background-color:#f5f5f5;*background-color:#e6e6e6;background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-repeat:repeat-x;border:1px solid #bbb;*border:0;border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);border-bottom-color:#a2a2a2;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);*zoom:1;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn:hover,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333;background-color:#e6e6e6;*background-color:#d9d9d9}.btn:active,.btn.active{background-color:#ccc \9}.btn:first-child{*margin-left:0}.btn:hover{color:#333;text-decoration:none;background-color:#e6e6e6;*background-color:#d9d9d9;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.active,.btn:active{background-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:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-large{padding:11px 19px;font-size:17.5px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.btn-large [class^="icon-"],.btn-large [class*=" icon-"]{margin-top:2px}.btn-small{padding:2px 10px;font-size:11.9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.btn-small [class^="icon-"],.btn-small [class*=" icon-"]{margin-top:0}.btn-mini{padding:1px 6px;font-size:10.5px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255,255,255,0.75)}.btn{border-color:#c5c5c5;border-color:rgba(0,0,0,0.15) rgba(0,0,0,0.15) rgba(0,0,0,0.25)}.btn-primary{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#006dcc;*background-color:#04c;background-image:-moz-linear-gradient(top,#08c,#04c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(to bottom,#08c,#04c);background-repeat:repeat-x;border-color:#04c #04c #002a80;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0044cc',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-primary:hover,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#fff;background-color:#04c;*background-color:#003bb3}.btn-primary:active,.btn-primary.active{background-color:#039 \9}.btn-warning{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#faa732;*background-color:#f89406;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;border-color:#f89406 #f89406 #ad6704;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-warning:hover,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#fff;background-color:#f89406;*background-color:#df8505}.btn-warning:active,.btn-warning.active{background-color:#c67605 \9}.btn-danger{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#da4f49;*background-color:#bd362f;background-image:-moz-linear-gradient(top,#ee5f5b,#bd362f);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#bd362f));background-image:-webkit-linear-gradient(top,#ee5f5b,#bd362f);background-image:-o-linear-gradient(top,#ee5f5b,#bd362f);background-image:linear-gradient(to bottom,#ee5f5b,#bd362f);background-repeat:repeat-x;border-color:#bd362f #bd362f #802420;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffbd362f',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-danger:hover,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#fff;background-color:#bd362f;*background-color:#a9302a}.btn-danger:active,.btn-danger.active{background-color:#942a25 \9}.btn-success{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#5bb75b;*background-color:#51a351;background-image:-moz-linear-gradient(top,#62c462,#51a351);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#51a351));background-image:-webkit-linear-gradient(top,#62c462,#51a351);background-image:-o-linear-gradient(top,#62c462,#51a351);background-image:linear-gradient(to bottom,#62c462,#51a351);background-repeat:repeat-x;border-color:#51a351 #51a351 #387038;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff51a351',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-success:hover,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#fff;background-color:#51a351;*background-color:#499249}.btn-success:active,.btn-success.active{background-color:#408140 \9}.btn-info{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#49afcd;*background-color:#2f96b4;background-image:-moz-linear-gradient(top,#5bc0de,#2f96b4);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#2f96b4));background-image:-webkit-linear-gradient(top,#5bc0de,#2f96b4);background-image:-o-linear-gradient(top,#5bc0de,#2f96b4);background-image:linear-gradient(to bottom,#5bc0de,#2f96b4);background-repeat:repeat-x;border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff2f96b4',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-info:hover,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#fff;background-color:#2f96b4;*background-color:#2a85a0}.btn-info:active,.btn-info.active{background-color:#24748c \9}.btn-inverse{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#363636;*background-color:#222;background-image:-moz-linear-gradient(top,#444,#222);background-image:-webkit-gradient(linear,0 0,0 100%,from(#444),to(#222));background-image:-webkit-linear-gradient(top,#444,#222);background-image:-o-linear-gradient(top,#444,#222);background-image:linear-gradient(to bottom,#444,#222);background-repeat:repeat-x;border-color:#222 #222 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444',endColorstr='#ff222222',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-inverse:hover,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#fff;background-color:#222;*background-color:#151515}.btn-inverse:active,.btn-inverse.active{background-color:#080808 \9}button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0}button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px}button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px}button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px}.btn-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-link{color:#08c;cursor:pointer;border-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-link:hover{color:#005580;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover{color:#333;text-decoration:none}.btn-group{position:relative;display:inline-block;*display:inline;*margin-left:.3em;font-size:0;white-space:nowrap;vertical-align:middle;*zoom:1}.btn-group:first-child{*margin-left:0}.btn-group+.btn-group{margin-left:5px}.btn-toolbar{margin-top:10px;margin-bottom:10px;font-size:0}.btn-toolbar .btn+.btn,.btn-toolbar .btn-group+.btn,.btn-toolbar .btn+.btn-group{margin-left:5px}.btn-group>.btn{position:relative;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group>.btn+.btn{margin-left:-1px}.btn-group>.btn,.btn-group>.dropdown-menu{font-size:14px}.btn-group>.btn-mini{font-size:11px}.btn-group>.btn-small{font-size:12px}.btn-group>.btn-large{font-size:16px}.btn-group>.btn:first-child{margin-left:0;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.btn-group>.btn.large:first-child{margin-left:0;-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{*padding-top:5px;padding-right:8px;*padding-bottom:5px;padding-left:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn-group>.btn-mini+.dropdown-toggle{*padding-top:2px;padding-right:5px;*padding-bottom:2px;padding-left:5px}.btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px}.btn-group>.btn-large+.dropdown-toggle{*padding-top:7px;padding-right:12px;*padding-bottom:7px;padding-left:12px}.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6}.btn-group.open .btn-primary.dropdown-toggle{background-color:#04c}.btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406}.btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f}.btn-group.open .btn-success.dropdown-toggle{background-color:#51a351}.btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4}.btn-group.open .btn-inverse.dropdown-toggle{background-color:#222}.btn .caret{margin-top:8px;margin-left:0}.btn-mini .caret,.btn-small .caret,.btn-large .caret{margin-top:6px}.btn-large .caret{border-top-width:5px;border-right-width:5px;border-left-width:5px}.dropup .btn-large .caret{border-bottom-width:5px}.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#fff;border-bottom-color:#fff}.btn-group-vertical{display:inline-block;*display:inline;*zoom:1}.btn-group-vertical .btn{display:block;float:none;width:100%;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group-vertical .btn+.btn{margin-top:-1px;margin-left:0}.btn-group-vertical .btn:first-child{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.btn-group-vertical .btn:last-child{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.btn-group-vertical .btn-large:first-child{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0}.btn-group-vertical .btn-large:last-child{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.alert{padding:8px 35px 8px 14px;margin-bottom:20px;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 h4{margin:0}.alert .close{position:relative;top:-2px;right:-21px;line-height:20px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-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:20px;margin-left:0;list-style:none}.nav>li>a{display:block}.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>.pull-right{float:right}.nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999;text-shadow:0 1px 0 rgba(255,255,255,0.5);text-transform:uppercase}.nav li+.nav-header{margin-top:9px}.nav-list{padding-right:15px;padding-left:15px;margin-bottom:0}.nav-list>li>a,.nav-list .nav-header{margin-right:-15px;margin-left:-15px;text-shadow:0 1px 0 rgba(255,255,255,0.5)}.nav-list>li>a{padding:3px 15px}.nav-list>.active>a,.nav-list>.active>a:hover{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.2);background-color:#08c}.nav-list [class^="icon-"],.nav-list [class*=" icon-"]{margin-right:2px}.nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.nav-tabs,.nav-pills{*zoom:1}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;line-height:0;content:""}.nav-tabs:after,.nav-pills:after{clear:both}.nav-tabs>li,.nav-pills>li{float:left}.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{margin-bottom:-1px}.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>.active>a,.nav-tabs>.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.nav-pills>.active>a,.nav-pills>.active>a:hover{color:#fff;background-color:#08c}.nav-stacked>li{float:none}.nav-stacked>li>a{margin-right:0}.nav-tabs.nav-stacked{border-bottom:0}.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-topleft:4px}.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomright:4px;-moz-border-radius-bottomleft:4px}.nav-tabs.nav-stacked>li>a:hover{z-index:2;border-color:#ddd}.nav-pills.nav-stacked>li>a{margin-bottom:3px}.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}.nav-tabs .dropdown-menu{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.nav-pills .dropdown-menu{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.nav .dropdown-toggle .caret{margin-top:6px;border-top-color:#08c;border-bottom-color:#08c}.nav .dropdown-toggle:hover .caret{border-top-color:#005580;border-bottom-color:#005580}.nav-tabs .dropdown-toggle .caret{margin-top:8px}.nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.nav-tabs .active .dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.nav>.dropdown.active>a:hover{cursor:pointer}.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover{color:#fff;background-color:#999;border-color:#999}.nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1;filter:alpha(opacity=100)}.tabs-stacked .open>a:hover{border-color:#999}.tabbable{*zoom:1}.tabbable:before,.tabbable:after{display:table;line-height:0;content:""}.tabbable:after{clear:both}.tab-content{overflow:auto}.tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0}.tab-content>.tab-pane,.pill-content>.pill-pane{display:none}.tab-content>.active,.pill-content>.active{display:block}.tabs-below>.nav-tabs{border-top:1px solid #ddd}.tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0}.tabs-below>.nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.tabs-below>.nav-tabs>li>a:hover{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:#eee #ddd #eee #eee}.tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover{border-color:#ddd transparent #ddd #ddd;*border-right-color:#fff}.tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd}.tabs-right>.nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.tabs-right>.nav-tabs>li>a:hover{border-color:#eee #eee #eee #ddd}.tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover{border-color:#ddd #ddd #ddd transparent;*border-left-color:#fff}.nav>.disabled>a{color:#999}.nav>.disabled>a:hover{text-decoration:none;cursor:default;background-color:transparent}.navbar{*position:relative;*z-index:2;margin-bottom:20px;overflow:visible;color:#777}.navbar-inner{min-height:40px;padding-right:20px;padding-left:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top,#fff,#f2f2f2);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#f2f2f2));background-image:-webkit-linear-gradient(top,#fff,#f2f2f2);background-image:-o-linear-gradient(top,#fff,#f2f2f2);background-image:linear-gradient(to bottom,#fff,#f2f2f2);background-repeat:repeat-x;border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff2f2f2',GradientType=0);*zoom:1;-webkit-box-shadow:0 1px 4px rgba(0,0,0,0.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,0.065);box-shadow:0 1px 4px rgba(0,0,0,0.065)}.navbar-inner:before,.navbar-inner:after{display:table;line-height:0;content:""}.navbar-inner:after{clear:both}.navbar .container{width:auto}.nav-collapse.collapse{height:auto;overflow:visible}.navbar .brand{display:block;float:left;padding:10px 20px 10px;margin-left:-20px;font-size:20px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff}.navbar .brand:hover{text-decoration:none}.navbar-text{margin-bottom:0;line-height:40px}.navbar-link{color:#777}.navbar-link:hover{color:#333}.navbar .divider-vertical{height:40px;margin:0 9px;border-right:1px solid #fff;border-left:1px solid #f2f2f2}.navbar .btn,.navbar .btn-group{margin-top:5px}.navbar .btn-group .btn,.navbar .input-prepend .btn,.navbar .input-append .btn{margin-top:0}.navbar-form{margin-bottom:0;*zoom:1}.navbar-form:before,.navbar-form:after{display:table;line-height:0;content:""}.navbar-form:after{clear:both}.navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px}.navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0}.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px}.navbar-form .input-append,.navbar-form .input-prepend{margin-top: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:5px;margin-bottom:0}.navbar-search .search-query{padding:4px 14px;margin-bottom:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.navbar-static-top{position:static;margin-bottom:0}.navbar-static-top .navbar-inner{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border-width:0 0 1px}.navbar-fixed-bottom .navbar-inner{border-width:1px 0 0}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-right:0;padding-left:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.navbar-fixed-top{top:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:0 1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 10px rgba(0,0,0,0.1);box-shadow:0 1px 10px rgba(0,0,0,0.1)}.navbar-fixed-bottom{bottom:0}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:0 -1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,0.1);box-shadow:0 -1px 10px rgba(0,0,0,0.1)}.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}.navbar .nav.pull-right{float:right;margin-right:0}.navbar .nav>li{float:left}.navbar .nav>li>a{float:none;padding:10px 15px 10px;color:#777;text-decoration:none;text-shadow:0 1px 0 #fff}.navbar .nav .dropdown-toggle .caret{margin-top:8px}.navbar .nav>li>a:focus,.navbar .nav>li>a:hover{color:#333;text-decoration:none;background-color:transparent}.navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);box-shadow:inset 0 3px 8px rgba(0,0,0,0.125)}.navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-right:5px;margin-left:5px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#ededed;*background-color:#e5e5e5;background-image:-moz-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f2f2f2),to(#e5e5e5));background-image:-webkit-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-o-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:linear-gradient(to bottom,#f2f2f2,#e5e5e5);background-repeat:repeat-x;border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2',endColorstr='#ffe5e5e5',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075)}.navbar .btn-navbar:hover,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#fff;background-color:#e5e5e5;*background-color:#d9d9d9}.navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#ccc \9}.navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,0.25);-moz-box-shadow:0 1px 0 rgba(0,0,0,0.25);box-shadow:0 1px 0 rgba(0,0,0,0.25)}.btn-navbar .icon-bar+.icon-bar{margin-top:3px}.navbar .nav>li>.dropdown-menu:before{position:absolute;top:-7px;left:9px;display:inline-block;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-left:7px solid transparent;border-bottom-color:rgba(0,0,0,0.2);content:''}.navbar .nav>li>.dropdown-menu:after{position:absolute;top:-6px;left:10px;display:inline-block;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent;content:''}.navbar-fixed-bottom .nav>li>.dropdown-menu:before{top:auto;bottom:-7px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.navbar-fixed-bottom .nav>li>.dropdown-menu:after{top:auto;bottom:-6px;border-top:6px solid #fff;border-bottom:0}.navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{color:#555;background-color:#e5e5e5}.navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777;border-bottom-color:#777}.navbar .nav li.dropdown.open>.dropdown-toggle .caret,.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.navbar .pull-right>li>.dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar .pull-right>li>.dropdown-menu:before,.navbar .nav>li>.dropdown-menu.pull-right:before{right:12px;left:auto}.navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{right:13px;left:auto}.navbar .pull-right>li>.dropdown-menu .dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{right:100%;left:auto;margin-right:-1px;margin-left:0;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.navbar-inverse{color:#999}.navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top,#222,#111);background-image:-webkit-gradient(linear,0 0,0 100%,from(#222),to(#111));background-image:-webkit-linear-gradient(top,#222,#111);background-image:-o-linear-gradient(top,#222,#111);background-image:linear-gradient(to bottom,#222,#111);background-repeat:repeat-x;border-color:#252525;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222',endColorstr='#ff111111',GradientType=0)}.navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover{color:#fff}.navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#fff;background-color:#111}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .divider-vertical{border-right-color:#222;border-left-color:#111}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{color:#fff;background-color:#111}.navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-search .search-query{color:#fff;background-color:#515151;border-color:#111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333;text-shadow:0 1px 0 #fff;background-color:#fff;border:0;outline:0;-webkit-box-shadow:0 0 3px rgba(0,0,0,0.15);-moz-box-shadow:0 0 3px rgba(0,0,0,0.15);box-shadow:0 0 3px rgba(0,0,0,0.15)}.navbar-inverse .btn-navbar{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e0e0e;*background-color:#040404;background-image:-moz-linear-gradient(top,#151515,#040404);background-image:-webkit-gradient(linear,0 0,0 100%,from(#151515),to(#040404));background-image:-webkit-linear-gradient(top,#151515,#040404);background-image:-o-linear-gradient(top,#151515,#040404);background-image:linear-gradient(to bottom,#151515,#040404);background-repeat:repeat-x;border-color:#040404 #040404 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515',endColorstr='#ff040404',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#fff;background-color:#040404;*background-color:#000}.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000 \9}.breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.breadcrumb li{display:inline-block;*display:inline;text-shadow:0 1px 0 #fff;*zoom:1}.breadcrumb .divider{padding:0 5px;color:#ccc}.breadcrumb .active{color:#999}.pagination{margin:20px 0}.pagination ul{display:inline-block;*display:inline;margin-bottom:0;margin-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*zoom:1;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.pagination ul>li{display:inline}.pagination ul>li>a,.pagination ul>li>span{float:left;padding:4px 12px;line-height:20px;text-decoration:none;background-color:#fff;border:1px solid #ddd;border-left-width:0}.pagination ul>li>a:hover,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#f5f5f5}.pagination ul>.active>a,.pagination ul>.active>span{color:#999;cursor:default}.pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover{color:#999;cursor:default;background-color:transparent}.pagination ul>li:first-child>a,.pagination ul>li:first-child>span{border-left-width:1px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.pagination ul>li:last-child>a,.pagination ul>li:last-child>span{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.pagination-centered{text-align:center}.pagination-right{text-align:right}.pagination-large ul>li>a,.pagination-large ul>li>span{padding:11px 19px;font-size:17.5px}.pagination-large ul>li:first-child>a,.pagination-large ul>li:first-child>span{-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.pagination-large ul>li:last-child>a,.pagination-large ul>li:last-child>span{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.pagination-mini ul>li:first-child>a,.pagination-small ul>li:first-child>a,.pagination-mini ul>li:first-child>span,.pagination-small ul>li:first-child>span{-webkit-border-bottom-left-radius:3px;border-bottom-left-radius:3px;-webkit-border-top-left-radius:3px;border-top-left-radius:3px;-moz-border-radius-bottomleft:3px;-moz-border-radius-topleft:3px}.pagination-mini ul>li:last-child>a,.pagination-small ul>li:last-child>a,.pagination-mini ul>li:last-child>span,.pagination-small ul>li:last-child>span{-webkit-border-top-right-radius:3px;border-top-right-radius:3px;-webkit-border-bottom-right-radius:3px;border-bottom-right-radius:3px;-moz-border-radius-topright:3px;-moz-border-radius-bottomright:3px}.pagination-small ul>li>a,.pagination-small ul>li>span{padding:2px 10px;font-size:11.9px}.pagination-mini ul>li>a,.pagination-mini ul>li>span{padding:1px 6px;font-size:10.5px}.pager{margin:20px 0;text-align:center;list-style:none;*zoom:1}.pager:before,.pager:after{display:table;line-height:0;content:""}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.pager li>a:hover{text-decoration:none;background-color:#f5f5f5}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>span{color:#999;cursor:default;background-color:#fff}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop,.modal-backdrop.fade.in{opacity:.8;filter:alpha(opacity=80)}.modal{position:fixed;top:50%;left:50%;z-index:1050;width:560px;margin:-250px 0 0 -280px;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;outline:0;-webkit-box-shadow:0 3px 7px rgba(0,0,0,0.3);-moz-box-shadow:0 3px 7px rgba(0,0,0,0.3);box-shadow:0 3px 7px rgba(0,0,0,0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box}.modal.fade{top:-25%;-webkit-transition:opacity .3s linear,top .3s ease-out;-moz-transition:opacity .3s linear,top .3s ease-out;-o-transition:opacity .3s linear,top .3s ease-out;transition:opacity .3s linear,top .3s ease-out}.modal.fade.in{top:50%}.modal-header{padding:9px 15px;border-bottom:1px solid #eee}.modal-header .close{margin-top:2px}.modal-header h3{margin:0;line-height:30px}.modal-body{max-height:400px;padding:15px;overflow-y:auto}.modal-form{margin-bottom:0}.modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;*zoom:1;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff}.modal-footer:before,.modal-footer:after{display:table;line-height:0;content:""}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.tooltip{position:absolute;z-index:1030;display:block;padding:5px;font-size:11px;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.8;filter:alpha(opacity=80)}.tooltip.top{margin-top:-3px}.tooltip.right{margin-left:3px}.tooltip.bottom{margin-top:3px}.tooltip.left{margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;width:236px;padding:1px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover-content p,.popover-content ul,.popover-content ol{margin-bottom:0}.popover .arrow,.popover .arrow:after{position:absolute;display:inline-block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow:after{z-index:-1;content:""}.popover.top .arrow{bottom:-10px;left:50%;margin-left:-10px;border-top-color:#fff;border-width:10px 10px 0}.popover.top .arrow:after{bottom:-1px;left:-11px;border-top-color:rgba(0,0,0,0.25);border-width:11px 11px 0}.popover.right .arrow{top:50%;left:-10px;margin-top:-10px;border-right-color:#fff;border-width:10px 10px 10px 0}.popover.right .arrow:after{bottom:-11px;left:-1px;border-right-color:rgba(0,0,0,0.25);border-width:11px 11px 11px 0}.popover.bottom .arrow{top:-10px;left:50%;margin-left:-10px;border-bottom-color:#fff;border-width:0 10px 10px}.popover.bottom .arrow:after{top:-1px;left:-11px;border-bottom-color:rgba(0,0,0,0.25);border-width:0 11px 11px}.popover.left .arrow{top:50%;right:-10px;margin-top:-10px;border-left-color:#fff;border-width:10px 0 10px 10px}.popover.left .arrow:after{right:-1px;bottom:-11px;border-left-color:rgba(0,0,0,0.25);border-width:11px 0 11px 11px}.thumbnails{margin-left:-20px;list-style:none;*zoom:1}.thumbnails:before,.thumbnails:after{display:table;line-height:0;content:""}.thumbnails:after{clear:both}.row-fluid .thumbnails{margin-left:0}.thumbnails>li{float:left;margin-bottom:20px;margin-left:20px}.thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.055);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.055);box-shadow:0 1px 3px rgba(0,0,0,0.055);-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}a.thumbnail:hover{border-color:#08c;-webkit-box-shadow:0 1px 4px rgba(0,105,214,0.25);-moz-box-shadow:0 1px 4px rgba(0,105,214,0.25);box-shadow:0 1px 4px rgba(0,105,214,0.25)}.thumbnail>img{display:block;max-width:100%;margin-right:auto;margin-left:auto}.thumbnail .caption{padding:9px;color:#555}.media,.media-body{overflow:hidden;*overflow:visible;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media .pull-left{margin-right:10px}.media .pull-right{margin-left:10px}.media-list{margin-left:0;list-style:none}.label,.badge{display:inline-block;padding:2px 4px;font-size:11.844px;font-weight:bold;line-height:14px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);white-space:nowrap;vertical-align:baseline;background-color:#999}.label{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.badge{padding-right:9px;padding-left:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px}a.label:hover,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.label-important,.badge-important{background-color:#b94a48}.label-important[href],.badge-important[href]{background-color:#953b39}.label-warning,.badge-warning{background-color:#f89406}.label-warning[href],.badge-warning[href]{background-color:#c67605}.label-success,.badge-success{background-color:#468847}.label-success[href],.badge-success[href]{background-color:#356635}.label-info,.badge-info{background-color:#3a87ad}.label-info[href],.badge-info[href]{background-color:#2d6987}.label-inverse,.badge-inverse{background-color:#333}.label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a}.btn .label,.btn .badge{position:relative;top:-1px}.btn-mini .label,.btn-mini .badge{top:0}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f7f7f7;background-image:-moz-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f5f5f5),to(#f9f9f9));background-image:-webkit-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-o-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:linear-gradient(to bottom,#f5f5f5,#f9f9f9);background-repeat:repeat-x;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#fff9f9f9',GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress .bar{float:left;width:0;height:100%;font-size:12px;color:#fff;text-align:center;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top,#149bdf,#0480be);background-image:-webkit-gradient(linear,0 0,0 100%,from(#149bdf),to(#0480be));background-image:-webkit-linear-gradient(top,#149bdf,#0480be);background-image:-o-linear-gradient(top,#149bdf,#0480be);background-image:linear-gradient(to bottom,#149bdf,#0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf',endColorstr='#ff0480be',GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width .6s ease;-moz-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15)}.progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px}.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-danger .bar,.progress .bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top,#ee5f5b,#c43c35);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#c43c35));background-image:-webkit-linear-gradient(top,#ee5f5b,#c43c35);background-image:-o-linear-gradient(top,#ee5f5b,#c43c35);background-image:linear-gradient(to bottom,#ee5f5b,#c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffc43c35',GradientType=0)}.progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-success .bar,.progress .bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top,#62c462,#57a957);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#57a957));background-image:-webkit-linear-gradient(top,#62c462,#57a957);background-image:-o-linear-gradient(top,#62c462,#57a957);background-image:linear-gradient(to bottom,#62c462,#57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff57a957',GradientType=0)}.progress-success.progress-striped .bar,.progress-striped .bar-success{background-color:#62c462;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-info .bar,.progress .bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top,#5bc0de,#339bb9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#339bb9));background-image:-webkit-linear-gradient(top,#5bc0de,#339bb9);background-image:-o-linear-gradient(top,#5bc0de,#339bb9);background-image:linear-gradient(to bottom,#5bc0de,#339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff339bb9',GradientType=0)}.progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-warning .bar,.progress .bar-warning{background-color:#faa732;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0)}.progress-warning.progress-striped .bar,.progress-striped .bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.accordion{margin-bottom:20px}.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.accordion-heading{border-bottom:0}.accordion-heading .accordion-toggle{display:block;padding:8px 15px}.accordion-toggle{cursor:pointer}.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5}.carousel{position:relative;margin-bottom:20px;line-height:1}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel .item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-moz-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel .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:#fff;text-align:center;background:#222;border:3px solid #fff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:.5;filter:alpha(opacity=50)}.carousel-control.right{right:15px;left:auto}.carousel-control:hover{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-caption{position:absolute;right:0;bottom:0;left:0;padding:15px;background:#333;background:rgba(0,0,0,0.75)}.carousel-caption h4,.carousel-caption p{line-height:20px;color:#fff}.carousel-caption h4{margin:0 0 5px}.carousel-caption p{margin-bottom:0}.hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:30px;color:inherit;background-color:#eee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;color:inherit}.hero-unit li{line-height:30px}.pull-right{float:right}.pull-left{float:left}.hide{display:none}.show{display:block}.invisible{visibility:hidden}.affix{position:fixed}
diff --git a/src/site/resources/css/github.css b/src/site/resources/css/github.css
deleted file mode 100644
index de1d2bb..0000000
--- a/src/site/resources/css/github.css
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
-
- github.com style (c) Vasily Polovnyov <vast@whiteants.net>
-
- 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.
-*/
-
-.hljs {
-  display: block;
-  overflow-x: auto;
-  padding: 0.5em;
-  color: #333;
-  background: #f5f5f5;
-}
-
-.hljs-comment,
-.hljs-quote {
-  color: #998;
-  font-style: italic;
-}
-
-.hljs-keyword,
-.hljs-selector-tag,
-.hljs-subst {
-  color: #333;
-  font-weight: bold;
-}
-
-.hljs-number,
-.hljs-literal,
-.hljs-variable,
-.hljs-template-variable,
-.hljs-tag .hljs-attr {
-  color: #008080;
-}
-
-.hljs-string,
-.hljs-doctag {
-  color: #d14;
-}
-
-.hljs-title,
-.hljs-section,
-.hljs-selector-id {
-  color: #900;
-  font-weight: bold;
-}
-
-.hljs-subst {
-  font-weight: normal;
-}
-
-.hljs-type,
-.hljs-class .hljs-title {
-  color: #458;
-  font-weight: bold;
-}
-
-.hljs-tag,
-.hljs-name,
-.hljs-attribute {
-  color: #000080;
-  font-weight: normal;
-}
-
-.hljs-regexp,
-.hljs-link {
-  color: #009926;
-}
-
-.hljs-symbol,
-.hljs-bullet {
-  color: #990073;
-}
-
-.hljs-built_in,
-.hljs-builtin-name {
-  color: #0086b3;
-}
-
-.hljs-meta {
-  color: #999;
-  font-weight: bold;
-}
-
-.hljs-deletion {
-  background: #fdd;
-}
-
-.hljs-addition {
-  background: #dfd;
-}
-
-.hljs-emphasis {
-  font-style: italic;
-}
-
-.hljs-strong {
-  font-weight: bold;
-}
diff --git a/src/site/resources/css/site.css b/src/site/resources/css/site.css
deleted file mode 100644
index 5bda65a..0000000
--- a/src/site/resources/css/site.css
+++ /dev/null
@@ -1,87 +0,0 @@
-/*

- 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.

-*/

-

-div.clear { clear:both; visibility: hidden; }

-div.clear hr { display: none; }

-

-/* Tweaks to the bootstrap theme

---------------------------------- */

-li { line-height: 20px; }

-code { color: #4e648e }

-a code { color: #0088cc }

-dt { margin: 15px 0 5px 0; font-size: 1.2em }

-

-.big-red { font-weight: bold; color: #D14 }

-.big-green { font-weight: bold; color: green }

-

-.layout-table { width: 100%; }

-.sidebar { width: 250px; vertical-align: top; }

-.content { padding-left: 20px; vertical-align: top; }

-

-.sidebar-nav { padding: 9px 0; }

-

-.logo-left { margin: 10px; float: left; height: 100px}

-.logo-center {margin-left: auto; margin-right: auto; display: block; width: 20%}

-.logo-right { margin: 5px; float: right; height: 100px}

-

-.navbar .nav { margin-left: 40px; }

-

-.nav-list { margin-bottom: 15px; }

-.nav-list li { line-height: 16px; }

-.nav-list li.nav-header { color: #333; }

-.nav-list li.nav-header i { margin-right: 5px; }

-

-.nav-list li a { background: no-repeat 16px 9px; padding-left: 34px; }

-.nav-list li.collapsed > a { background-image: url(../images/collapsed.gif) }

-.nav-list li.expanded > a { background-image: url(../images/expanded.gif) }

-

-.nav-list li.expanded ul { list-style: none; margin-left: 0; }

-.nav-list li.expanded li a { display: block; padding: 3px 15px 3px 45px; margin-left: -15px; margin-right: -15px; }

-.nav-list li.expanded li a:hover { text-decoration: none; background-color: #eee; }

-.nav-list li.expanded li.active a { background-color: #08C; color: white }

-

-.nav.nav-tabs { margin-bottom: 8px; }

-

-.content .section { margin-top: 20px; }

-.content .section:first-child { margin-top: 0; }

-.section h2 { margin-bottom: 10px; }

-.section h3 { margin-bottom: 10px; }

-.section h4 { margin-bottom: 10px; }

-

-.footer { background-color: whitesmoke; padding: 15px; margin-top: 15px; text-align: center; border-top: 1px solid #eee; }

-.footer p { font-size: 12px; margin: 0 }

-

-.table-not-wide { width: inherit;}

-.alert-heading { display: block; font-size: 14px; margin-bottom: 6px; font-weight: bold; }

-

-/* Additional styles.

------------------------*/

-

-/* add film icons to youtube and vimeo links (.icon-film) */

-a[href^='https://www.youtube.com/']::before,

-a[href^='https://vimeo.com/']::before {

-    display: inline-block;

-    width: 14px;

-    height: 14px;

-    margin-top: 1px;

-    margin-right: .3em;

-    line-height: 14px;

-    vertical-align: text-top;

-    content: '';

-    /* .icon-film */

-    background: url("../img/glyphicons-halflings.png") no-repeat -192px 0;

-}

diff --git a/src/site/resources/glyphicons-halflings-2-1.zip b/src/site/resources/glyphicons-halflings-2-1.zip
new file mode 100644
index 0000000..974885b
--- /dev/null
+++ b/src/site/resources/glyphicons-halflings-2-1.zip
Binary files differ
diff --git a/src/site/resources/img/glyphicons/book.png b/src/site/resources/img/glyphicons/book.png
new file mode 100644
index 0000000..5fcb05e
--- /dev/null
+++ b/src/site/resources/img/glyphicons/book.png
Binary files differ
diff --git a/src/site/resources/img/glyphicons/cog.png b/src/site/resources/img/glyphicons/cog.png
new file mode 100644
index 0000000..572b300
--- /dev/null
+++ b/src/site/resources/img/glyphicons/cog.png
Binary files differ
diff --git a/src/site/resources/img/glyphicons/home.png b/src/site/resources/img/glyphicons/home.png
new file mode 100644
index 0000000..11f59e9
--- /dev/null
+++ b/src/site/resources/img/glyphicons/home.png
Binary files differ
diff --git a/src/site/resources/img/glyphicons/info.png b/src/site/resources/img/glyphicons/info.png
new file mode 100644
index 0000000..833cdd5
--- /dev/null
+++ b/src/site/resources/img/glyphicons/info.png
Binary files differ
diff --git a/src/site/resources/img/glyphicons/layers.png b/src/site/resources/img/glyphicons/layers.png
new file mode 100644
index 0000000..d157049
--- /dev/null
+++ b/src/site/resources/img/glyphicons/layers.png
Binary files differ
diff --git a/src/site/resources/img/glyphicons/link.png b/src/site/resources/img/glyphicons/link.png
new file mode 100644
index 0000000..18cf1ec
--- /dev/null
+++ b/src/site/resources/img/glyphicons/link.png
Binary files differ
diff --git a/src/site/resources/img/glyphicons/pencil.png b/src/site/resources/img/glyphicons/pencil.png
new file mode 100644
index 0000000..1f5df55
--- /dev/null
+++ b/src/site/resources/img/glyphicons/pencil.png
Binary files differ
diff --git a/src/site/resources/img/glyphicons/tag.png b/src/site/resources/img/glyphicons/tag.png
new file mode 100644
index 0000000..e189be4
--- /dev/null
+++ b/src/site/resources/img/glyphicons/tag.png
Binary files differ
diff --git a/src/site/resources/js/bootstrap.js b/src/site/resources/js/bootstrap.js
deleted file mode 100644
index 7f303eb..0000000
--- a/src/site/resources/js/bootstrap.js
+++ /dev/null
@@ -1,2027 +0,0 @@
-/* ===================================================
- * bootstrap-transition.js v2.1.0
- * 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 otransitionend'
-            ,  '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.1.0
- * 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.1.0
- * 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.1.0
- * 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('.item.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
-      if (this.$element.find('.next, .prev').length && $.support.transition.end) {
-        this.$element.trigger($.support.transition.end)
-        this.cycle()
-      }
-      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('.item.active')
-        , $next = next || $active[type]()
-        , isCycling = this.interval
-        , direction = type == 'next' ? 'left' : 'right'
-        , fallback  = type == 'next' ? 'first' : 'last'
-        , that = this
-        , e = $.Event('slide', {
-            relatedTarget: $next[0]
-          })
-
-      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)
-        , action = typeof option == 'string' ? option : options.slide
-      if (!data) $this.data('carousel', (data = new Carousel(this, options)))
-      if (typeof option == 'number') data.to(option)
-      else if (action) data[action]()
-      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.1.0
- * 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')
-      $.support.transition && 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()
-      $this[$(target).hasClass('in') ? 'addClass' : 'removeClass']('collapsed')
-      $(target).collapse(option)
-    })
-  })
-
-}(window.jQuery);/* ============================================================
- * bootstrap-dropdown.js v2.1.0
- * 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
-        , isActive
-
-      if ($this.is('.disabled, :disabled')) return
-
-      $parent = getParent($this)
-
-      isActive = $parent.hasClass('open')
-
-      clearMenus()
-
-      if (!isActive) {
-        $parent.toggleClass('open')
-        $this.focus()
-      }
-
-      return false
-    }
-
-  , keydown: function (e) {
-      var $this
-        , $items
-        , $active
-        , $parent
-        , isActive
-        , index
-
-      if (!/(38|40|27)/.test(e.keyCode)) return
-
-      $this = $(this)
-
-      e.preventDefault()
-      e.stopPropagation()
-
-      if ($this.is('.disabled, :disabled')) return
-
-      $parent = getParent($this)
-
-      isActive = $parent.hasClass('open')
-
-      if (!isActive || (isActive && e.keyCode == 27)) return $this.click()
-
-      $items = $('[role=menu] li:not(.divider) a', $parent)
-
-      if (!$items.length) return
-
-      index = $items.index($items.filter(':focus'))
-
-      if (e.keyCode == 38 && index > 0) index--                                        // up
-      if (e.keyCode == 40 && index < $items.length - 1) index++                        // down
-      if (!~index) index = 0
-
-      $items
-        .eq(index)
-        .focus()
-    }
-
-  }
-
-  function clearMenus() {
-    getParent($(toggle))
-      .removeClass('open')
-  }
-
-  function getParent($this) {
-    var selector = $this.attr('data-target')
-      , $parent
-
-    if (!selector) {
-      selector = $this.attr('href')
-      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
-    }
-
-    $parent = $(selector)
-    $parent.length || ($parent = $this.parent())
-
-    return $parent
-  }
-
-
-  /* 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 touchstart.dropdown.data-api', clearMenus)
-    $('body')
-      .on('click.dropdown touchstart.dropdown.data-api', '.dropdown', function (e) { e.stopPropagation() })
-      .on('click.dropdown.data-api touchstart.dropdown.data-api'  , toggle, Dropdown.prototype.toggle)
-      .on('keydown.dropdown.data-api touchstart.dropdown.data-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown)
-  })
-
-}(window.jQuery);/* =========================================================
- * bootstrap-modal.js v2.1.0
- * 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 (element, options) {
-    this.options = options
-    this.$element = $(element)
-      .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this))
-    this.options.remote && this.$element.find('.modal-body').load(this.options.remote)
-  }
-
-  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
-
-        this.escape()
-
-        this.backdrop(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')
-            .attr('aria-hidden', false)
-            .focus()
-
-          that.enforceFocus()
-
-          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')
-
-        this.escape()
-
-        $(document).off('focusin.modal')
-
-        this.$element
-          .removeClass('in')
-          .attr('aria-hidden', true)
-
-        $.support.transition && this.$element.hasClass('fade') ?
-          this.hideWithTransition() :
-          this.hideModal()
-      }
-
-    , enforceFocus: function () {
-        var that = this
-        $(document).on('focusin.modal', function (e) {
-          if (that.$element[0] !== e.target && !that.$element.has(e.target).length) {
-            that.$element.focus()
-          }
-        })
-      }
-
-    , escape: function () {
-        var that = this
-        if (this.isShown && this.options.keyboard) {
-          this.$element.on('keyup.dismiss.modal', function ( e ) {
-            e.which == 27 && that.hide()
-          })
-        } else if (!this.isShown) {
-          this.$element.off('keyup.dismiss.modal')
-        }
-      }
-
-    , hideWithTransition: function () {
-        var that = this
-          , timeout = setTimeout(function () {
-              that.$element.off($.support.transition.end)
-              that.hideModal()
-            }, 500)
-
-        this.$element.one($.support.transition.end, function () {
-          clearTimeout(timeout)
-          that.hideModal()
-        })
-      }
-
-    , hideModal: function (that) {
-        this.$element
-          .hide()
-          .trigger('hidden')
-
-        this.backdrop()
-      }
-
-    , removeBackdrop: function () {
-        this.$backdrop.remove()
-        this.$backdrop = null
-      }
-
-    , backdrop: function (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(this.removeBackdrop, this)) :
-            this.removeBackdrop()
-
-        } else if (callback) {
-          callback()
-        }
-      }
-  }
-
-
- /* 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 = $this.attr('href')
-        , $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) //strip for ie7
-        , option = $target.data('modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
-
-      e.preventDefault()
-
-      $target
-        .modal(option)
-        .one('hide', function () {
-          $this.focus()
-        })
-    })
-  })
-
-}(window.jQuery);/* ===========================================================
- * bootstrap-tooltip.js v2.1.0
- * 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 == 'click') {
-        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
-      } else if (this.options.trigger != 'manual') {
-        eventIn = this.options.trigger == 'hover' ? 'mouseenter' : 'focus'
-        eventOut = this.options.trigger == 'hover' ? 'mouseleave' : 'blur'
-        this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
-        this.$element.on(eventOut + '.' + this.type, 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')
-      }
-    }
-
-  , setContent: function () {
-      var $tip = this.tip()
-        , title = this.getTitle()
-
-      $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
-      $tip.removeClass('fade in top bottom left right')
-    }
-
-  , hide: function () {
-      var that = this
-        , $tip = this.tip()
-
-      $tip.removeClass('in')
-
-      function removeWithAnimation() {
-        var timeout = setTimeout(function () {
-          $tip.off($.support.transition.end).remove()
-        }, 500)
-
-        $tip.one($.support.transition.end, function () {
-          clearTimeout(timeout)
-          $tip.remove()
-        })
-      }
-
-      $.support.transition && this.$tip.hasClass('fade') ?
-        removeWithAnimation() :
-        $tip.remove()
-
-      return this
-    }
-
-  , fixTitle: function () {
-      var $e = this.$element
-      if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
-        $e.attr('data-original-title', $e.attr('title') || '').removeAttr('title')
-      }
-    }
-
-  , hasContent: function () {
-      return this.getTitle()
-    }
-
-  , getPosition: function (inside) {
-      return $.extend({}, (inside ? {top: 0, left: 0} : this.$element.offset()), {
-        width: this.$element[0].offsetWidth
-      , height: this.$element[0].offsetHeight
-      })
-    }
-
-  , getTitle: function () {
-      var title
-        , $e = this.$element
-        , o = this.options
-
-      title = $e.attr('data-original-title')
-        || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
-
-      return title
-    }
-
-  , tip: function () {
-      return this.$tip = this.$tip || $(this.options.template)
-    }
-
-  , validate: function () {
-      if (!this.$element[0].parentNode) {
-        this.hide()
-        this.$element = null
-        this.options = null
-      }
-    }
-
-  , enable: function () {
-      this.enabled = true
-    }
-
-  , disable: function () {
-      this.enabled = false
-    }
-
-  , toggleEnabled: function () {
-      this.enabled = !this.enabled
-    }
-
-  , toggle: function () {
-      this[this.tip().hasClass('in') ? 'hide' : 'show']()
-    }
-
-  , destroy: function () {
-      this.hide().$element.off('.' + this.type).removeData(this.type)
-    }
-
-  }
-
-
- /* TOOLTIP PLUGIN DEFINITION
-  * ========================= */
-
-  $.fn.tooltip = function ( option ) {
-    return this.each(function () {
-      var $this = $(this)
-        , data = $this.data('tooltip')
-        , options = typeof option == 'object' && option
-      if (!data) $this.data('tooltip', (data = new Tooltip(this, options)))
-      if (typeof option == 'string') data[option]()
-    })
-  }
-
-  $.fn.tooltip.Constructor = Tooltip
-
-  $.fn.tooltip.defaults = {
-    animation: true
-  , placement: 'top'
-  , selector: false
-  , template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
-  , trigger: 'hover'
-  , title: ''
-  , delay: 0
-  , html: true
-  }
-
-}(window.jQuery);
-/* ===========================================================
- * bootstrap-popover.js v2.1.0
- * http://twitter.github.com/bootstrap/javascript.html#popovers
- * ===========================================================
- * 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 ;_;
-
-
- /* POPOVER PUBLIC CLASS DEFINITION
-  * =============================== */
-
-  var Popover = function (element, options) {
-    this.init('popover', element, options)
-  }
-
-
-  /* NOTE: POPOVER EXTENDS BOOTSTRAP-TOOLTIP.js
-     ========================================== */
-
-  Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype, {
-
-    constructor: Popover
-
-  , setContent: function () {
-      var $tip = this.tip()
-        , title = this.getTitle()
-        , content = this.getContent()
-
-      $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
-      $tip.find('.popover-content > *')[this.options.html ? 'html' : 'text'](content)
-
-      $tip.removeClass('fade top bottom left right in')
-    }
-
-  , hasContent: function () {
-      return this.getTitle() || this.getContent()
-    }
-
-  , getContent: function () {
-      var content
-        , $e = this.$element
-        , o = this.options
-
-      content = $e.attr('data-content')
-        || (typeof o.content == 'function' ? o.content.call($e[0]) :  o.content)
-
-      return content
-    }
-
-  , tip: function () {
-      if (!this.$tip) {
-        this.$tip = $(this.options.template)
-      }
-      return this.$tip
-    }
-
-  , destroy: function () {
-      this.hide().$element.off('.' + this.type).removeData(this.type)
-    }
-
-  })
-
-
- /* POPOVER PLUGIN DEFINITION
-  * ======================= */
-
-  $.fn.popover = function (option) {
-    return this.each(function () {
-      var $this = $(this)
-        , data = $this.data('popover')
-        , options = typeof option == 'object' && option
-      if (!data) $this.data('popover', (data = new Popover(this, options)))
-      if (typeof option == 'string') data[option]()
-    })
-  }
-
-  $.fn.popover.Constructor = Popover
-
-  $.fn.popover.defaults = $.extend({} , $.fn.tooltip.defaults, {
-    placement: 'right'
-  , trigger: 'click'
-  , content: ''
-  , template: '<div class="popover"><div class="arrow"></div><div class="popover-inner"><h3 class="popover-title"></h3><div class="popover-content"><p></p></div></div></div>'
-  })
-
-}(window.jQuery);/* =============================================================
- * bootstrap-scrollspy.js v2.1.0
- * http://twitter.github.com/bootstrap/javascript.html#scrollspy
- * =============================================================
- * 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 ;_;
-
-
- /* SCROLLSPY CLASS DEFINITION
-  * ========================== */
-
-  function ScrollSpy(element, options) {
-    var process = $.proxy(this.process, this)
-      , $element = $(element).is('body') ? $(window) : $(element)
-      , href
-    this.options = $.extend({}, $.fn.scrollspy.defaults, options)
-    this.$scrollElement = $element.on('scroll.scroll-spy.data-api', process)
-    this.selector = (this.options.target
-      || ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
-      || '') + ' .nav li > a'
-    this.$body = $('body')
-    this.refresh()
-    this.process()
-  }
-
-  ScrollSpy.prototype = {
-
-      constructor: ScrollSpy
-
-    , refresh: function () {
-        var self = this
-          , $targets
-
-        this.offsets = $([])
-        this.targets = $([])
-
-        $targets = this.$body
-          .find(this.selector)
-          .map(function () {
-            var $el = $(this)
-              , href = $el.data('target') || $el.attr('href')
-              , $href = /^#\w/.test(href) && $(href)
-            return ( $href
-              && $href.length
-              && [[ $href.position().top, href ]] ) || null
-          })
-          .sort(function (a, b) { return a[0] - b[0] })
-          .each(function () {
-            self.offsets.push(this[0])
-            self.targets.push(this[1])
-          })
-      }
-
-    , process: function () {
-        var scrollTop = this.$scrollElement.scrollTop() + this.options.offset
-          , scrollHeight = this.$scrollElement[0].scrollHeight || this.$body[0].scrollHeight
-          , maxScroll = scrollHeight - this.$scrollElement.height()
-          , offsets = this.offsets
-          , targets = this.targets
-          , activeTarget = this.activeTarget
-          , i
-
-        if (scrollTop >= maxScroll) {
-          return activeTarget != (i = targets.last()[0])
-            && this.activate ( i )
-        }
-
-        for (i = offsets.length; i--;) {
-          activeTarget != targets[i]
-            && scrollTop >= offsets[i]
-            && (!offsets[i + 1] || scrollTop <= offsets[i + 1])
-            && this.activate( targets[i] )
-        }
-      }
-
-    , activate: function (target) {
-        var active
-          , selector
-
-        this.activeTarget = target
-
-        $(this.selector)
-          .parent('.active')
-          .removeClass('active')
-
-        selector = this.selector
-          + '[data-target="' + target + '"],'
-          + this.selector + '[href="' + target + '"]'
-
-        active = $(selector)
-          .parent('li')
-          .addClass('active')
-
-        if (active.parent('.dropdown-menu').length)  {
-          active = active.closest('li.dropdown').addClass('active')
-        }
-
-        active.trigger('activate')
-      }
-
-  }
-
-
- /* SCROLLSPY PLUGIN DEFINITION
-  * =========================== */
-
-  $.fn.scrollspy = function (option) {
-    return this.each(function () {
-      var $this = $(this)
-        , data = $this.data('scrollspy')
-        , options = typeof option == 'object' && option
-      if (!data) $this.data('scrollspy', (data = new ScrollSpy(this, options)))
-      if (typeof option == 'string') data[option]()
-    })
-  }
-
-  $.fn.scrollspy.Constructor = ScrollSpy
-
-  $.fn.scrollspy.defaults = {
-    offset: 10
-  }
-
-
- /* SCROLLSPY DATA-API
-  * ================== */
-
-  $(window).on('load', function () {
-    $('[data-spy="scroll"]').each(function () {
-      var $spy = $(this)
-      $spy.scrollspy($spy.data())
-    })
-  })
-
-}(window.jQuery);/* ========================================================
- * bootstrap-tab.js v2.1.0
- * http://twitter.github.com/bootstrap/javascript.html#tabs
- * ========================================================
- * 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 ;_;
-
-
- /* TAB CLASS DEFINITION
-  * ==================== */
-
-  var Tab = function (element) {
-    this.element = $(element)
-  }
-
-  Tab.prototype = {
-
-    constructor: Tab
-
-  , show: function () {
-      var $this = this.element
-        , $ul = $this.closest('ul:not(.dropdown-menu)')
-        , selector = $this.attr('data-target')
-        , previous
-        , $target
-        , e
-
-      if (!selector) {
-        selector = $this.attr('href')
-        selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
-      }
-
-      if ( $this.parent('li').hasClass('active') ) return
-
-      previous = $ul.find('.active a').last()[0]
-
-      e = $.Event('show', {
-        relatedTarget: previous
-      })
-
-      $this.trigger(e)
-
-      if (e.isDefaultPrevented()) return
-
-      $target = $(selector)
-
-      this.activate($this.parent('li'), $ul)
-      this.activate($target, $target.parent(), function () {
-        $this.trigger({
-          type: 'shown'
-        , relatedTarget: previous
-        })
-      })
-    }
-
-  , activate: function ( element, container, callback) {
-      var $active = container.find('> .active')
-        , transition = callback
-            && $.support.transition
-            && $active.hasClass('fade')
-
-      function next() {
-        $active
-          .removeClass('active')
-          .find('> .dropdown-menu > .active')
-          .removeClass('active')
-
-        element.addClass('active')
-
-        if (transition) {
-          element[0].offsetWidth // reflow for transition
-          element.addClass('in')
-        } else {
-          element.removeClass('fade')
-        }
-
-        if ( element.parent('.dropdown-menu') ) {
-          element.closest('li.dropdown').addClass('active')
-        }
-
-        callback && callback()
-      }
-
-      transition ?
-        $active.one($.support.transition.end, next) :
-        next()
-
-      $active.removeClass('in')
-    }
-  }
-
-
- /* TAB PLUGIN DEFINITION
-  * ===================== */
-
-  $.fn.tab = function ( option ) {
-    return this.each(function () {
-      var $this = $(this)
-        , data = $this.data('tab')
-      if (!data) $this.data('tab', (data = new Tab(this)))
-      if (typeof option == 'string') data[option]()
-    })
-  }
-
-  $.fn.tab.Constructor = Tab
-
-
- /* TAB DATA-API
-  * ============ */
-
-  $(function () {
-    $('body').on('click.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
-      e.preventDefault()
-      $(this).tab('show')
-    })
-  })
-
-}(window.jQuery);/* =============================================================
- * bootstrap-typeahead.js v2.1.0
- * http://twitter.github.com/bootstrap/javascript.html#typeahead
- * =============================================================
- * 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 ;_;
-
-
- /* TYPEAHEAD PUBLIC CLASS DEFINITION
-  * ================================= */
-
-  var Typeahead = function (element, options) {
-    this.$element = $(element)
-    this.options = $.extend({}, $.fn.typeahead.defaults, options)
-    this.matcher = this.options.matcher || this.matcher
-    this.sorter = this.options.sorter || this.sorter
-    this.highlighter = this.options.highlighter || this.highlighter
-    this.updater = this.options.updater || this.updater
-    this.$menu = $(this.options.menu).appendTo('body')
-    this.source = this.options.source
-    this.shown = false
-    this.listen()
-  }
-
-  Typeahead.prototype = {
-
-    constructor: Typeahead
-
-  , select: function () {
-      var val = this.$menu.find('.active').attr('data-value')
-      this.$element
-        .val(this.updater(val))
-        .change()
-      return this.hide()
-    }
-
-  , updater: function (item) {
-      return item
-    }
-
-  , show: function () {
-      var pos = $.extend({}, this.$element.offset(), {
-        height: this.$element[0].offsetHeight
-      })
-
-      this.$menu.css({
-        top: pos.top + pos.height
-      , left: pos.left
-      })
-
-      this.$menu.show()
-      this.shown = true
-      return this
-    }
-
-  , hide: function () {
-      this.$menu.hide()
-      this.shown = false
-      return this
-    }
-
-  , lookup: function (event) {
-      var items
-
-      this.query = this.$element.val()
-
-      if (!this.query || this.query.length < this.options.minLength) {
-        return this.shown ? this.hide() : this
-      }
-
-      items = $.isFunction(this.source) ? this.source(this.query, $.proxy(this.process, this)) : this.source
-
-      return items ? this.process(items) : this
-    }
-
-  , process: function (items) {
-      var that = this
-
-      items = $.grep(items, function (item) {
-        return that.matcher(item)
-      })
-
-      items = this.sorter(items)
-
-      if (!items.length) {
-        return this.shown ? this.hide() : this
-      }
-
-      return this.render(items.slice(0, this.options.items)).show()
-    }
-
-  , matcher: function (item) {
-      return ~item.toLowerCase().indexOf(this.query.toLowerCase())
-    }
-
-  , sorter: function (items) {
-      var beginswith = []
-        , caseSensitive = []
-        , caseInsensitive = []
-        , item
-
-      while (item = items.shift()) {
-        if (!item.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item)
-        else if (~item.indexOf(this.query)) caseSensitive.push(item)
-        else caseInsensitive.push(item)
-      }
-
-      return beginswith.concat(caseSensitive, caseInsensitive)
-    }
-
-  , highlighter: function (item) {
-      var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&')
-      return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) {
-        return '<strong>' + match + '</strong>'
-      })
-    }
-
-  , render: function (items) {
-      var that = this
-
-      items = $(items).map(function (i, item) {
-        i = $(that.options.item).attr('data-value', item)
-        i.find('a').html(that.highlighter(item))
-        return i[0]
-      })
-
-      items.first().addClass('active')
-      this.$menu.html(items)
-      return this
-    }
-
-  , next: function (event) {
-      var active = this.$menu.find('.active').removeClass('active')
-        , next = active.next()
-
-      if (!next.length) {
-        next = $(this.$menu.find('li')[0])
-      }
-
-      next.addClass('active')
-    }
-
-  , prev: function (event) {
-      var active = this.$menu.find('.active').removeClass('active')
-        , prev = active.prev()
-
-      if (!prev.length) {
-        prev = this.$menu.find('li').last()
-      }
-
-      prev.addClass('active')
-    }
-
-  , listen: function () {
-      this.$element
-        .on('blur',     $.proxy(this.blur, this))
-        .on('keypress', $.proxy(this.keypress, this))
-        .on('keyup',    $.proxy(this.keyup, this))
-
-      if ($.browser.webkit || $.browser.msie) {
-        this.$element.on('keydown', $.proxy(this.keydown, this))
-      }
-
-      this.$menu
-        .on('click', $.proxy(this.click, this))
-        .on('mouseenter', 'li', $.proxy(this.mouseenter, this))
-    }
-
-  , move: function (e) {
-      if (!this.shown) return
-
-      switch(e.keyCode) {
-        case 9: // tab
-        case 13: // enter
-        case 27: // escape
-          e.preventDefault()
-          break
-
-        case 38: // up arrow
-          e.preventDefault()
-          this.prev()
-          break
-
-        case 40: // down arrow
-          e.preventDefault()
-          this.next()
-          break
-      }
-
-      e.stopPropagation()
-    }
-
-  , keydown: function (e) {
-      this.suppressKeyPressRepeat = !~$.inArray(e.keyCode, [40,38,9,13,27])
-      this.move(e)
-    }
-
-  , keypress: function (e) {
-      if (this.suppressKeyPressRepeat) return
-      this.move(e)
-    }
-
-  , keyup: function (e) {
-      switch(e.keyCode) {
-        case 40: // down arrow
-        case 38: // up arrow
-          break
-
-        case 9: // tab
-        case 13: // enter
-          if (!this.shown) return
-          this.select()
-          break
-
-        case 27: // escape
-          if (!this.shown) return
-          this.hide()
-          break
-
-        default:
-          this.lookup()
-      }
-
-      e.stopPropagation()
-      e.preventDefault()
-  }
-
-  , blur: function (e) {
-      var that = this
-      setTimeout(function () { that.hide() }, 150)
-    }
-
-  , click: function (e) {
-      e.stopPropagation()
-      e.preventDefault()
-      this.select()
-    }
-
-  , mouseenter: function (e) {
-      this.$menu.find('.active').removeClass('active')
-      $(e.currentTarget).addClass('active')
-    }
-
-  }
-
-
-  /* TYPEAHEAD PLUGIN DEFINITION
-   * =========================== */
-
-  $.fn.typeahead = function (option) {
-    return this.each(function () {
-      var $this = $(this)
-        , data = $this.data('typeahead')
-        , options = typeof option == 'object' && option
-      if (!data) $this.data('typeahead', (data = new Typeahead(this, options)))
-      if (typeof option == 'string') data[option]()
-    })
-  }
-
-  $.fn.typeahead.defaults = {
-    source: []
-  , items: 8
-  , menu: '<ul class="typeahead dropdown-menu"></ul>'
-  , item: '<li><a href="#"></a></li>'
-  , minLength: 1
-  }
-
-  $.fn.typeahead.Constructor = Typeahead
-
-
- /*   TYPEAHEAD DATA-API
-  * ================== */
-
-  $(function () {
-    $('body').on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) {
-      var $this = $(this)
-      if ($this.data('typeahead')) return
-      e.preventDefault()
-      $this.typeahead($this.data())
-    })
-  })
-
-}(window.jQuery);
-/* ==========================================================
- * bootstrap-affix.js v2.1.0
- * http://twitter.github.com/bootstrap/javascript.html#affix
- * ==========================================================
- * 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 ;_;
-
-
- /* AFFIX CLASS DEFINITION
-  * ====================== */
-
-  var Affix = function (element, options) {
-    this.options = $.extend({}, $.fn.affix.defaults, options)
-    this.$window = $(window).on('scroll.affix.data-api', $.proxy(this.checkPosition, this))
-    this.$element = $(element)
-    this.checkPosition()
-  }
-
-  Affix.prototype.checkPosition = function () {
-    if (!this.$element.is(':visible')) return
-
-    var scrollHeight = $(document).height()
-      , scrollTop = this.$window.scrollTop()
-      , position = this.$element.offset()
-      , offset = this.options.offset
-      , offsetBottom = offset.bottom
-      , offsetTop = offset.top
-      , reset = 'affix affix-top affix-bottom'
-      , affix
-
-    if (typeof offset != 'object') offsetBottom = offsetTop = offset
-    if (typeof offsetTop == 'function') offsetTop = offset.top()
-    if (typeof offsetBottom == 'function') offsetBottom = offset.bottom()
-
-    affix = this.unpin != null && (scrollTop + this.unpin <= position.top) ?
-      false    : offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ?
-      'bottom' : offsetTop != null && scrollTop <= offsetTop ?
-      'top'    : false
-
-    if (this.affixed === affix) return
-
-    this.affixed = affix
-    this.unpin = affix == 'bottom' ? position.top - scrollTop : null
-
-    this.$element.removeClass(reset).addClass('affix' + (affix ? '-' + affix : ''))
-  }
-
-
- /* AFFIX PLUGIN DEFINITION
-  * ======================= */
-
-  $.fn.affix = function (option) {
-    return this.each(function () {
-      var $this = $(this)
-        , data = $this.data('affix')
-        , options = typeof option == 'object' && option
-      if (!data) $this.data('affix', (data = new Affix(this, options)))
-      if (typeof option == 'string') data[option]()
-    })
-  }
-
-  $.fn.affix.Constructor = Affix
-
-  $.fn.affix.defaults = {
-    offset: 0
-  }
-
-
- /* AFFIX DATA-API
-  * ============== */
-
-  $(window).on('load', function () {
-    $('[data-spy="affix"]').each(function () {
-      var $spy = $(this)
-        , data = $spy.data()
-
-      data.offset = data.offset || {}
-
-      data.offsetBottom && (data.offset.bottom = data.offsetBottom)
-      data.offsetTop && (data.offset.top = data.offsetTop)
-
-      $spy.affix(data)
-    })
-  })
-
-
-}(window.jQuery);
\ No newline at end of file
diff --git a/src/site/resources/js/bootstrap.min.js b/src/site/resources/js/bootstrap.min.js
deleted file mode 100644
index 66e887b..0000000
--- a/src/site/resources/js/bootstrap.min.js
+++ /dev/null
@@ -1,6 +0,0 @@
-/*!
-* Bootstrap.js by @fat & @mdo
-* Copyright 2012 Twitter, Inc.
-* http://www.apache.org/licenses/LICENSE-2.0.txt
-*/
-!function(e){e(function(){"use strict";e.support.transition=function(){var e=function(){var e=document.createElement("bootstrap"),t={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},n;for(n in t)if(e.style[n]!==undefined)return t[n]}();return e&&{end:e}}()})}(window.jQuery),!function(e){"use strict";var t='[data-dismiss="alert"]',n=function(n){e(n).on("click",t,this.close)};n.prototype.close=function(t){function s(){i.trigger("closed").remove()}var n=e(this),r=n.attr("data-target"),i;r||(r=n.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,"")),i=e(r),t&&t.preventDefault(),i.length||(i=n.hasClass("alert")?n:n.parent()),i.trigger(t=e.Event("close"));if(t.isDefaultPrevented())return;i.removeClass("in"),e.support.transition&&i.hasClass("fade")?i.on(e.support.transition.end,s):s()},e.fn.alert=function(t){return this.each(function(){var r=e(this),i=r.data("alert");i||r.data("alert",i=new n(this)),typeof t=="string"&&i[t].call(r)})},e.fn.alert.Constructor=n,e(function(){e("body").on("click.alert.data-api",t,n.prototype.close)})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.button.defaults,n)};t.prototype.setState=function(e){var t="disabled",n=this.$element,r=n.data(),i=n.is("input")?"val":"html";e+="Text",r.resetText||n.data("resetText",n[i]()),n[i](r[e]||this.options[e]),setTimeout(function(){e=="loadingText"?n.addClass(t).attr(t,t):n.removeClass(t).removeAttr(t)},0)},t.prototype.toggle=function(){var e=this.$element.parent('[data-toggle="buttons-radio"]');e&&e.find(".active").removeClass("active"),this.$element.toggleClass("active")},e.fn.button=function(n){return this.each(function(){var r=e(this),i=r.data("button"),s=typeof n=="object"&&n;i||r.data("button",i=new t(this,s)),n=="toggle"?i.toggle():n&&i.setState(n)})},e.fn.button.defaults={loadingText:"loading..."},e.fn.button.Constructor=t,e(function(){e("body").on("click.button.data-api","[data-toggle^=button]",function(t){var n=e(t.target);n.hasClass("btn")||(n=n.closest(".btn")),n.button("toggle")})})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=n,this.options.slide&&this.slide(this.options.slide),this.options.pause=="hover"&&this.$element.on("mouseenter",e.proxy(this.pause,this)).on("mouseleave",e.proxy(this.cycle,this))};t.prototype={cycle:function(t){return t||(this.paused=!1),this.options.interval&&!this.paused&&(this.interval=setInterval(e.proxy(this.next,this),this.options.interval)),this},to:function(t){var n=this.$element.find(".item.active"),r=n.parent().children(),i=r.index(n),s=this;if(t>r.length-1||t<0)return;return this.sliding?this.$element.one("slid",function(){s.to(t)}):i==t?this.pause().cycle():this.slide(t>i?"next":"prev",e(r[t]))},pause:function(t){return t||(this.paused=!0),this.$element.find(".next, .prev").length&&e.support.transition.end&&(this.$element.trigger(e.support.transition.end),this.cycle()),clearInterval(this.interval),this.interval=null,this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(t,n){var r=this.$element.find(".item.active"),i=n||r[t](),s=this.interval,o=t=="next"?"left":"right",u=t=="next"?"first":"last",a=this,f=e.Event("slide",{relatedTarget:i[0]});this.sliding=!0,s&&this.pause(),i=i.length?i:this.$element.find(".item")[u]();if(i.hasClass("active"))return;if(e.support.transition&&this.$element.hasClass("slide")){this.$element.trigger(f);if(f.isDefaultPrevented())return;i.addClass(t),i[0].offsetWidth,r.addClass(o),i.addClass(o),this.$element.one(e.support.transition.end,function(){i.removeClass([t,o].join(" ")).addClass("active"),r.removeClass(["active",o].join(" ")),a.sliding=!1,setTimeout(function(){a.$element.trigger("slid")},0)})}else{this.$element.trigger(f);if(f.isDefaultPrevented())return;r.removeClass("active"),i.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return s&&this.cycle(),this}},e.fn.carousel=function(n){return this.each(function(){var r=e(this),i=r.data("carousel"),s=e.extend({},e.fn.carousel.defaults,typeof n=="object"&&n),o=typeof n=="string"?n:s.slide;i||r.data("carousel",i=new t(this,s)),typeof n=="number"?i.to(n):o?i[o]():s.interval&&i.cycle()})},e.fn.carousel.defaults={interval:5e3,pause:"hover"},e.fn.carousel.Constructor=t,e(function(){e("body").on("click.carousel.data-api","[data-slide]",function(t){var n=e(this),r,i=e(n.attr("data-target")||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,"")),s=!i.data("modal")&&e.extend({},i.data(),n.data());i.carousel(s),t.preventDefault()})})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.collapse.defaults,n),this.options.parent&&(this.$parent=e(this.options.parent)),this.options.toggle&&this.toggle()};t.prototype={constructor:t,dimension:function(){var e=this.$element.hasClass("width");return e?"width":"height"},show:function(){var t,n,r,i;if(this.transitioning)return;t=this.dimension(),n=e.camelCase(["scroll",t].join("-")),r=this.$parent&&this.$parent.find("> .accordion-group > .in");if(r&&r.length){i=r.data("collapse");if(i&&i.transitioning)return;r.collapse("hide"),i||r.data("collapse",null)}this.$element[t](0),this.transition("addClass",e.Event("show"),"shown"),e.support.transition&&this.$element[t](this.$element[0][n])},hide:function(){var t;if(this.transitioning)return;t=this.dimension(),this.reset(this.$element[t]()),this.transition("removeClass",e.Event("hide"),"hidden"),this.$element[t](0)},reset:function(e){var t=this.dimension();return this.$element.removeClass("collapse")[t](e||"auto")[0].offsetWidth,this.$element[e!==null?"addClass":"removeClass"]("collapse"),this},transition:function(t,n,r){var i=this,s=function(){n.type=="show"&&i.reset(),i.transitioning=0,i.$element.trigger(r)};this.$element.trigger(n);if(n.isDefaultPrevented())return;this.transitioning=1,this.$element[t]("in"),e.support.transition&&this.$element.hasClass("collapse")?this.$element.one(e.support.transition.end,s):s()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}},e.fn.collapse=function(n){return this.each(function(){var r=e(this),i=r.data("collapse"),s=typeof n=="object"&&n;i||r.data("collapse",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.collapse.defaults={toggle:!0},e.fn.collapse.Constructor=t,e(function(){e("body").on("click.collapse.data-api","[data-toggle=collapse]",function(t){var n=e(this),r,i=n.attr("data-target")||t.preventDefault()||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,""),s=e(i).data("collapse")?"toggle":n.data();n[e(i).hasClass("in")?"addClass":"removeClass"]("collapsed"),e(i).collapse(s)})})}(window.jQuery),!function(e){"use strict";function r(){i(e(t)).removeClass("open")}function i(t){var n=t.attr("data-target"),r;return n||(n=t.attr("href"),n=n&&n.replace(/.*(?=#[^\s]*$)/,"")),r=e(n),r.length||(r=t.parent()),r}var t="[data-toggle=dropdown]",n=function(t){var n=e(t).on("click.dropdown.data-api",this.toggle);e("html").on("click.dropdown.data-api",function(){n.parent().removeClass("open")})};n.prototype={constructor:n,toggle:function(t){var n=e(this),s,o;if(n.is(".disabled, :disabled"))return;return s=i(n),o=s.hasClass("open"),r(),o||(s.toggleClass("open"),n.focus()),!1},keydown:function(t){var n,r,s,o,u,a;if(!/(38|40|27)/.test(t.keyCode))return;n=e(this),t.preventDefault(),t.stopPropagation();if(n.is(".disabled, :disabled"))return;o=i(n),u=o.hasClass("open");if(!u||u&&t.keyCode==27)return n.click();r=e("[role=menu] li:not(.divider) a",o);if(!r.length)return;a=r.index(r.filter(":focus")),t.keyCode==38&&a>0&&a--,t.keyCode==40&&a<r.length-1&&a++,~a||(a=0),r.eq(a).focus()}},e.fn.dropdown=function(t){return this.each(function(){var r=e(this),i=r.data("dropdown");i||r.data("dropdown",i=new n(this)),typeof t=="string"&&i[t].call(r)})},e.fn.dropdown.Constructor=n,e(function(){e("html").on("click.dropdown.data-api touchstart.dropdown.data-api",r),e("body").on("click.dropdown touchstart.dropdown.data-api",".dropdown",function(e){e.stopPropagation()}).on("click.dropdown.data-api touchstart.dropdown.data-api",t,n.prototype.toggle).on("keydown.dropdown.data-api touchstart.dropdown.data-api",t+", [role=menu]",n.prototype.keydown)})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.options=n,this.$element=e(t).delegate('[data-dismiss="modal"]',"click.dismiss.modal",e.proxy(this.hide,this)),this.options.remote&&this.$element.find(".modal-body").load(this.options.remote)};t.prototype={constructor:t,toggle:function(){return this[this.isShown?"hide":"show"]()},show:function(){var t=this,n=e.Event("show");this.$element.trigger(n);if(this.isShown||n.isDefaultPrevented())return;e("body").addClass("modal-open"),this.isShown=!0,this.escape(),this.backdrop(function(){var n=e.support.transition&&t.$element.hasClass("fade");t.$element.parent().length||t.$element.appendTo(document.body),t.$element.show(),n&&t.$element[0].offsetWidth,t.$element.addClass("in").attr("aria-hidden",!1).focus(),t.enforceFocus(),n?t.$element.one(e.support.transition.end,function(){t.$element.trigger("shown")}):t.$element.trigger("shown")})},hide:function(t){t&&t.preventDefault();var n=this;t=e.Event("hide"),this.$element.trigger(t);if(!this.isShown||t.isDefaultPrevented())return;this.isShown=!1,e("body").removeClass("modal-open"),this.escape(),e(document).off("focusin.modal"),this.$element.removeClass("in").attr("aria-hidden",!0),e.support.transition&&this.$element.hasClass("fade")?this.hideWithTransition():this.hideModal()},enforceFocus:function(){var t=this;e(document).on("focusin.modal",function(e){t.$element[0]!==e.target&&!t.$element.has(e.target).length&&t.$element.focus()})},escape:function(){var e=this;this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.modal",function(t){t.which==27&&e.hide()}):this.isShown||this.$element.off("keyup.dismiss.modal")},hideWithTransition:function(){var t=this,n=setTimeout(function(){t.$element.off(e.support.transition.end),t.hideModal()},500);this.$element.one(e.support.transition.end,function(){clearTimeout(n),t.hideModal()})},hideModal:function(e){this.$element.hide().trigger("hidden"),this.backdrop()},removeBackdrop:function(){this.$backdrop.remove(),this.$backdrop=null},backdrop:function(t){var n=this,r=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var i=e.support.transition&&r;this.$backdrop=e('<div class="modal-backdrop '+r+'" />').appendTo(document.body),this.options.backdrop!="static"&&this.$backdrop.click(e.proxy(this.hide,this)),i&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),i?this.$backdrop.one(e.support.transition.end,t):t()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),e.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(e.support.transition.end,e.proxy(this.removeBackdrop,this)):this.removeBackdrop()):t&&t()}},e.fn.modal=function(n){return this.each(function(){var r=e(this),i=r.data("modal"),s=e.extend({},e.fn.modal.defaults,r.data(),typeof n=="object"&&n);i||r.data("modal",i=new t(this,s)),typeof n=="string"?i[n]():s.show&&i.show()})},e.fn.modal.defaults={backdrop:!0,keyboard:!0,show:!0},e.fn.modal.Constructor=t,e(function(){e("body").on("click.modal.data-api",'[data-toggle="modal"]',function(t){var n=e(this),r=n.attr("href"),i=e(n.attr("data-target")||r&&r.replace(/.*(?=#[^\s]+$)/,"")),s=i.data("modal")?"toggle":e.extend({remote:!/#/.test(r)&&r},i.data(),n.data());t.preventDefault(),i.modal(s).one("hide",function(){n.focus()})})})}(window.jQuery),!function(e){"use strict";var t=function(e,t){this.init("tooltip",e,t)};t.prototype={constructor:t,init:function(t,n,r){var i,s;this.type=t,this.$element=e(n),this.options=this.getOptions(r),this.enabled=!0,this.options.trigger=="click"?this.$element.on("click."+this.type,this.options.selector,e.proxy(this.toggle,this)):this.options.trigger!="manual"&&(i=this.options.trigger=="hover"?"mouseenter":"focus",s=this.options.trigger=="hover"?"mouseleave":"blur",this.$element.on(i+"."+this.type,this.options.selector,e.proxy(this.enter,this)),this.$element.on(s+"."+this.type,this.options.selector,e.proxy(this.leave,this))),this.options.selector?this._options=e.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},getOptions:function(t){return t=e.extend({},e.fn[this.type].defaults,t,this.$element.data()),t.delay&&typeof t.delay=="number"&&(t.delay={show:t.delay,hide:t.delay}),t},enter:function(t){var n=e(t.currentTarget)[this.type](this._options).data(this.type);if(!n.options.delay||!n.options.delay.show)return n.show();clearTimeout(this.timeout),n.hoverState="in",this.timeout=setTimeout(function(){n.hoverState=="in"&&n.show()},n.options.delay.show)},leave:function(t){var n=e(t.currentTarget)[this.type](this._options).data(this.type);this.timeout&&clearTimeout(this.timeout);if(!n.options.delay||!n.options.delay.hide)return n.hide();n.hoverState="out",this.timeout=setTimeout(function(){n.hoverState=="out"&&n.hide()},n.options.delay.hide)},show:function(){var e,t,n,r,i,s,o;if(this.hasContent()&&this.enabled){e=this.tip(),this.setContent(),this.options.animation&&e.addClass("fade"),s=typeof this.options.placement=="function"?this.options.placement.call(this,e[0],this.$element[0]):this.options.placement,t=/in/.test(s),e.remove().css({top:0,left:0,display:"block"}).appendTo(t?this.$element:document.body),n=this.getPosition(t),r=e[0].offsetWidth,i=e[0].offsetHeight;switch(t?s.split(" ")[1]:s){case"bottom":o={top:n.top+n.height,left:n.left+n.width/2-r/2};break;case"top":o={top:n.top-i,left:n.left+n.width/2-r/2};break;case"left":o={top:n.top+n.height/2-i/2,left:n.left-r};break;case"right":o={top:n.top+n.height/2-i/2,left:n.left+n.width}}e.css(o).addClass(s).addClass("in")}},setContent:function(){var e=this.tip(),t=this.getTitle();e.find(".tooltip-inner")[this.options.html?"html":"text"](t),e.removeClass("fade in top bottom left right")},hide:function(){function r(){var t=setTimeout(function(){n.off(e.support.transition.end).remove()},500);n.one(e.support.transition.end,function(){clearTimeout(t),n.remove()})}var t=this,n=this.tip();return n.removeClass("in"),e.support.transition&&this.$tip.hasClass("fade")?r():n.remove(),this},fixTitle:function(){var e=this.$element;(e.attr("title")||typeof e.attr("data-original-title")!="string")&&e.attr("data-original-title",e.attr("title")||"").removeAttr("title")},hasContent:function(){return this.getTitle()},getPosition:function(t){return e.extend({},t?{top:0,left:0}:this.$element.offset(),{width:this.$element[0].offsetWidth,height:this.$element[0].offsetHeight})},getTitle:function(){var e,t=this.$element,n=this.options;return e=t.attr("data-original-title")||(typeof n.title=="function"?n.title.call(t[0]):n.title),e},tip:function(){return this.$tip=this.$tip||e(this.options.template)},validate:function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled},toggle:function(){this[this.tip().hasClass("in")?"hide":"show"]()},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}},e.fn.tooltip=function(n){return this.each(function(){var r=e(this),i=r.data("tooltip"),s=typeof n=="object"&&n;i||r.data("tooltip",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.tooltip.Constructor=t,e.fn.tooltip.defaults={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover",title:"",delay:0,html:!0}}(window.jQuery),!function(e){"use strict";var t=function(e,t){this.init("popover",e,t)};t.prototype=e.extend({},e.fn.tooltip.Constructor.prototype,{constructor:t,setContent:function(){var e=this.tip(),t=this.getTitle(),n=this.getContent();e.find(".popover-title")[this.options.html?"html":"text"](t),e.find(".popover-content > *")[this.options.html?"html":"text"](n),e.removeClass("fade top bottom left right in")},hasContent:function(){return this.getTitle()||this.getContent()},getContent:function(){var e,t=this.$element,n=this.options;return e=t.attr("data-content")||(typeof n.content=="function"?n.content.call(t[0]):n.content),e},tip:function(){return this.$tip||(this.$tip=e(this.options.template)),this.$tip},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}}),e.fn.popover=function(n){return this.each(function(){var r=e(this),i=r.data("popover"),s=typeof n=="object"&&n;i||r.data("popover",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.popover.Constructor=t,e.fn.popover.defaults=e.extend({},e.fn.tooltip.defaults,{placement:"right",trigger:"click",content:"",template:'<div class="popover"><div class="arrow"></div><div class="popover-inner"><h3 class="popover-title"></h3><div class="popover-content"><p></p></div></div></div>'})}(window.jQuery),!function(e){"use strict";function t(t,n){var r=e.proxy(this.process,this),i=e(t).is("body")?e(window):e(t),s;this.options=e.extend({},e.fn.scrollspy.defaults,n),this.$scrollElement=i.on("scroll.scroll-spy.data-api",r),this.selector=(this.options.target||(s=e(t).attr("href"))&&s.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.$body=e("body"),this.refresh(),this.process()}t.prototype={constructor:t,refresh:function(){var t=this,n;this.offsets=e([]),this.targets=e([]),n=this.$body.find(this.selector).map(function(){var t=e(this),n=t.data("target")||t.attr("href"),r=/^#\w/.test(n)&&e(n);return r&&r.length&&[[r.position().top,n]]||null}).sort(function(e,t){return e[0]-t[0]}).each(function(){t.offsets.push(this[0]),t.targets.push(this[1])})},process:function(){var e=this.$scrollElement.scrollTop()+this.options.offset,t=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,n=t-this.$scrollElement.height(),r=this.offsets,i=this.targets,s=this.activeTarget,o;if(e>=n)return s!=(o=i.last()[0])&&this.activate(o);for(o=r.length;o--;)s!=i[o]&&e>=r[o]&&(!r[o+1]||e<=r[o+1])&&this.activate(i[o])},activate:function(t){var n,r;this.activeTarget=t,e(this.selector).parent(".active").removeClass("active"),r=this.selector+'[data-target="'+t+'"],'+this.selector+'[href="'+t+'"]',n=e(r).parent("li").addClass("active"),n.parent(".dropdown-menu").length&&(n=n.closest("li.dropdown").addClass("active")),n.trigger("activate")}},e.fn.scrollspy=function(n){return this.each(function(){var r=e(this),i=r.data("scrollspy"),s=typeof n=="object"&&n;i||r.data("scrollspy",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.scrollspy.Constructor=t,e.fn.scrollspy.defaults={offset:10},e(window).on("load",function(){e('[data-spy="scroll"]').each(function(){var t=e(this);t.scrollspy(t.data())})})}(window.jQuery),!function(e){"use strict";var t=function(t){this.element=e(t)};t.prototype={constructor:t,show:function(){var t=this.element,n=t.closest("ul:not(.dropdown-menu)"),r=t.attr("data-target"),i,s,o;r||(r=t.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,""));if(t.parent("li").hasClass("active"))return;i=n.find(".active a").last()[0],o=e.Event("show",{relatedTarget:i}),t.trigger(o);if(o.isDefaultPrevented())return;s=e(r),this.activate(t.parent("li"),n),this.activate(s,s.parent(),function(){t.trigger({type:"shown",relatedTarget:i})})},activate:function(t,n,r){function o(){i.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),t.addClass("active"),s?(t[0].offsetWidth,t.addClass("in")):t.removeClass("fade"),t.parent(".dropdown-menu")&&t.closest("li.dropdown").addClass("active"),r&&r()}var i=n.find("> .active"),s=r&&e.support.transition&&i.hasClass("fade");s?i.one(e.support.transition.end,o):o(),i.removeClass("in")}},e.fn.tab=function(n){return this.each(function(){var r=e(this),i=r.data("tab");i||r.data("tab",i=new t(this)),typeof n=="string"&&i[n]()})},e.fn.tab.Constructor=t,e(function(){e("body").on("click.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(t){t.preventDefault(),e(this).tab("show")})})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.typeahead.defaults,n),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.$menu=e(this.options.menu).appendTo("body"),this.source=this.options.source,this.shown=!1,this.listen()};t.prototype={constructor:t,select:function(){var e=this.$menu.find(".active").attr("data-value");return this.$element.val(this.updater(e)).change(),this.hide()},updater:function(e){return e},show:function(){var t=e.extend({},this.$element.offset(),{height:this.$element[0].offsetHeight});return this.$menu.css({top:t.top+t.height,left:t.left}),this.$menu.show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(t){var n;return this.query=this.$element.val(),!this.query||this.query.length<this.options.minLength?this.shown?this.hide():this:(n=e.isFunction(this.source)?this.source(this.query,e.proxy(this.process,this)):this.source,n?this.process(n):this)},process:function(t){var n=this;return t=e.grep(t,function(e){return n.matcher(e)}),t=this.sorter(t),t.length?this.render(t.slice(0,this.options.items)).show():this.shown?this.hide():this},matcher:function(e){return~e.toLowerCase().indexOf(this.query.toLowerCase())},sorter:function(e){var t=[],n=[],r=[],i;while(i=e.shift())i.toLowerCase().indexOf(this.query.toLowerCase())?~i.indexOf(this.query)?n.push(i):r.push(i):t.push(i);return t.concat(n,r)},highlighter:function(e){var t=this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&");return e.replace(new RegExp("("+t+")","ig"),function(e,t){return"<strong>"+t+"</strong>"})},render:function(t){var n=this;return t=e(t).map(function(t,r){return t=e(n.options.item).attr("data-value",r),t.find("a").html(n.highlighter(r)),t[0]}),t.first().addClass("active"),this.$menu.html(t),this},next:function(t){var n=this.$menu.find(".active").removeClass("active"),r=n.next();r.length||(r=e(this.$menu.find("li")[0])),r.addClass("active")},prev:function(e){var t=this.$menu.find(".active").removeClass("active"),n=t.prev();n.length||(n=this.$menu.find("li").last()),n.addClass("active")},listen:function(){this.$element.on("blur",e.proxy(this.blur,this)).on("keypress",e.proxy(this.keypress,this)).on("keyup",e.proxy(this.keyup,this)),(e.browser.webkit||e.browser.msie)&&this.$element.on("keydown",e.proxy(this.keydown,this)),this.$menu.on("click",e.proxy(this.click,this)).on("mouseenter","li",e.proxy(this.mouseenter,this))},move:function(e){if(!this.shown)return;switch(e.keyCode){case 9:case 13:case 27:e.preventDefault();break;case 38:e.preventDefault(),this.prev();break;case 40:e.preventDefault(),this.next()}e.stopPropagation()},keydown:function(t){this.suppressKeyPressRepeat=!~e.inArray(t.keyCode,[40,38,9,13,27]),this.move(t)},keypress:function(e){if(this.suppressKeyPressRepeat)return;this.move(e)},keyup:function(e){switch(e.keyCode){case 40:case 38:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}e.stopPropagation(),e.preventDefault()},blur:function(e){var t=this;setTimeout(function(){t.hide()},150)},click:function(e){e.stopPropagation(),e.preventDefault(),this.select()},mouseenter:function(t){this.$menu.find(".active").removeClass("active"),e(t.currentTarget).addClass("active")}},e.fn.typeahead=function(n){return this.each(function(){var r=e(this),i=r.data("typeahead"),s=typeof n=="object"&&n;i||r.data("typeahead",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.typeahead.defaults={source:[],items:8,menu:'<ul class="typeahead dropdown-menu"></ul>',item:'<li><a href="#"></a></li>',minLength:1},e.fn.typeahead.Constructor=t,e(function(){e("body").on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(t){var n=e(this);if(n.data("typeahead"))return;t.preventDefault(),n.typeahead(n.data())})})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.options=e.extend({},e.fn.affix.defaults,n),this.$window=e(window).on("scroll.affix.data-api",e.proxy(this.checkPosition,this)),this.$element=e(t),this.checkPosition()};t.prototype.checkPosition=function(){if(!this.$element.is(":visible"))return;var t=e(document).height(),n=this.$window.scrollTop(),r=this.$element.offset(),i=this.options.offset,s=i.bottom,o=i.top,u="affix affix-top affix-bottom",a;typeof i!="object"&&(s=o=i),typeof o=="function"&&(o=i.top()),typeof s=="function"&&(s=i.bottom()),a=this.unpin!=null&&n+this.unpin<=r.top?!1:s!=null&&r.top+this.$element.height()>=t-s?"bottom":o!=null&&n<=o?"top":!1;if(this.affixed===a)return;this.affixed=a,this.unpin=a=="bottom"?r.top-n:null,this.$element.removeClass(u).addClass("affix"+(a?"-"+a:""))},e.fn.affix=function(n){return this.each(function(){var r=e(this),i=r.data("affix"),s=typeof n=="object"&&n;i||r.data("affix",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.affix.Constructor=t,e.fn.affix.defaults={offset:0},e(window).on("load",function(){e('[data-spy="affix"]').each(function(){var t=e(this),n=t.data();n.offset=n.offset||{},n.offsetBottom&&(n.offset.bottom=n.offsetBottom),n.offsetTop&&(n.offset.top=n.offsetTop),t.affix(n)})})}(window.jQuery);
\ No newline at end of file
diff --git a/src/site/resources/js/highlight.pack.js b/src/site/resources/js/highlight.pack.js
deleted file mode 100644
index 786b1b1..0000000
--- a/src/site/resources/js/highlight.pack.js
+++ /dev/null
@@ -1,2 +0,0 @@
-/*! highlight.js v9.12.0 | BSD3 License | git.io/hljslicense */
-!function(e){var n="object"==typeof window&&window||"object"==typeof self&&self;"undefined"!=typeof exports?e(exports):n&&(n.hljs=e({}),"function"==typeof define&&define.amd&&define([],function(){return n.hljs}))}(function(e){function n(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function t(e){return e.nodeName.toLowerCase()}function r(e,n){var t=e&&e.exec(n);return t&&0===t.index}function a(e){return k.test(e)}function i(e){var n,t,r,i,o=e.className+" ";if(o+=e.parentNode?e.parentNode.className:"",t=B.exec(o))return w(t[1])?t[1]:"no-highlight";for(o=o.split(/\s+/),n=0,r=o.length;r>n;n++)if(i=o[n],a(i)||w(i))return i}function o(e){var n,t={},r=Array.prototype.slice.call(arguments,1);for(n in e)t[n]=e[n];return r.forEach(function(e){for(n in e)t[n]=e[n]}),t}function u(e){var n=[];return function r(e,a){for(var i=e.firstChild;i;i=i.nextSibling)3===i.nodeType?a+=i.nodeValue.length:1===i.nodeType&&(n.push({event:"start",offset:a,node:i}),a=r(i,a),t(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:a,node:i}));return a}(e,0),n}function c(e,r,a){function i(){return e.length&&r.length?e[0].offset!==r[0].offset?e[0].offset<r[0].offset?e:r:"start"===r[0].event?e:r:e.length?e:r}function o(e){function r(e){return" "+e.nodeName+'="'+n(e.value).replace('"',"&quot;")+'"'}s+="<"+t(e)+E.map.call(e.attributes,r).join("")+">"}function u(e){s+="</"+t(e)+">"}function c(e){("start"===e.event?o:u)(e.node)}for(var l=0,s="",f=[];e.length||r.length;){var g=i();if(s+=n(a.substring(l,g[0].offset)),l=g[0].offset,g===e){f.reverse().forEach(u);do c(g.splice(0,1)[0]),g=i();while(g===e&&g.length&&g[0].offset===l);f.reverse().forEach(o)}else"start"===g[0].event?f.push(g[0].node):f.pop(),c(g.splice(0,1)[0])}return s+n(a.substr(l))}function l(e){return e.v&&!e.cached_variants&&(e.cached_variants=e.v.map(function(n){return o(e,{v:null},n)})),e.cached_variants||e.eW&&[o(e)]||[e]}function s(e){function n(e){return e&&e.source||e}function t(t,r){return new RegExp(n(t),"m"+(e.cI?"i":"")+(r?"g":""))}function r(a,i){if(!a.compiled){if(a.compiled=!0,a.k=a.k||a.bK,a.k){var o={},u=function(n,t){e.cI&&(t=t.toLowerCase()),t.split(" ").forEach(function(e){var t=e.split("|");o[t[0]]=[n,t[1]?Number(t[1]):1]})};"string"==typeof a.k?u("keyword",a.k):x(a.k).forEach(function(e){u(e,a.k[e])}),a.k=o}a.lR=t(a.l||/\w+/,!0),i&&(a.bK&&(a.b="\\b("+a.bK.split(" ").join("|")+")\\b"),a.b||(a.b=/\B|\b/),a.bR=t(a.b),a.e||a.eW||(a.e=/\B|\b/),a.e&&(a.eR=t(a.e)),a.tE=n(a.e)||"",a.eW&&i.tE&&(a.tE+=(a.e?"|":"")+i.tE)),a.i&&(a.iR=t(a.i)),null==a.r&&(a.r=1),a.c||(a.c=[]),a.c=Array.prototype.concat.apply([],a.c.map(function(e){return l("self"===e?a:e)})),a.c.forEach(function(e){r(e,a)}),a.starts&&r(a.starts,i);var c=a.c.map(function(e){return e.bK?"\\.?("+e.b+")\\.?":e.b}).concat([a.tE,a.i]).map(n).filter(Boolean);a.t=c.length?t(c.join("|"),!0):{exec:function(){return null}}}}r(e)}function f(e,t,a,i){function o(e,n){var t,a;for(t=0,a=n.c.length;a>t;t++)if(r(n.c[t].bR,e))return n.c[t]}function u(e,n){if(r(e.eR,n)){for(;e.endsParent&&e.parent;)e=e.parent;return e}return e.eW?u(e.parent,n):void 0}function c(e,n){return!a&&r(n.iR,e)}function l(e,n){var t=N.cI?n[0].toLowerCase():n[0];return e.k.hasOwnProperty(t)&&e.k[t]}function p(e,n,t,r){var a=r?"":I.classPrefix,i='<span class="'+a,o=t?"":C;return i+=e+'">',i+n+o}function h(){var e,t,r,a;if(!E.k)return n(k);for(a="",t=0,E.lR.lastIndex=0,r=E.lR.exec(k);r;)a+=n(k.substring(t,r.index)),e=l(E,r),e?(B+=e[1],a+=p(e[0],n(r[0]))):a+=n(r[0]),t=E.lR.lastIndex,r=E.lR.exec(k);return a+n(k.substr(t))}function d(){var e="string"==typeof E.sL;if(e&&!y[E.sL])return n(k);var t=e?f(E.sL,k,!0,x[E.sL]):g(k,E.sL.length?E.sL:void 0);return E.r>0&&(B+=t.r),e&&(x[E.sL]=t.top),p(t.language,t.value,!1,!0)}function b(){L+=null!=E.sL?d():h(),k=""}function v(e){L+=e.cN?p(e.cN,"",!0):"",E=Object.create(e,{parent:{value:E}})}function m(e,n){if(k+=e,null==n)return b(),0;var t=o(n,E);if(t)return t.skip?k+=n:(t.eB&&(k+=n),b(),t.rB||t.eB||(k=n)),v(t,n),t.rB?0:n.length;var r=u(E,n);if(r){var a=E;a.skip?k+=n:(a.rE||a.eE||(k+=n),b(),a.eE&&(k=n));do E.cN&&(L+=C),E.skip||(B+=E.r),E=E.parent;while(E!==r.parent);return r.starts&&v(r.starts,""),a.rE?0:n.length}if(c(n,E))throw new Error('Illegal lexeme "'+n+'" for mode "'+(E.cN||"<unnamed>")+'"');return k+=n,n.length||1}var N=w(e);if(!N)throw new Error('Unknown language: "'+e+'"');s(N);var R,E=i||N,x={},L="";for(R=E;R!==N;R=R.parent)R.cN&&(L=p(R.cN,"",!0)+L);var k="",B=0;try{for(var M,j,O=0;;){if(E.t.lastIndex=O,M=E.t.exec(t),!M)break;j=m(t.substring(O,M.index),M[0]),O=M.index+j}for(m(t.substr(O)),R=E;R.parent;R=R.parent)R.cN&&(L+=C);return{r:B,value:L,language:e,top:E}}catch(T){if(T.message&&-1!==T.message.indexOf("Illegal"))return{r:0,value:n(t)};throw T}}function g(e,t){t=t||I.languages||x(y);var r={r:0,value:n(e)},a=r;return t.filter(w).forEach(function(n){var t=f(n,e,!1);t.language=n,t.r>a.r&&(a=t),t.r>r.r&&(a=r,r=t)}),a.language&&(r.second_best=a),r}function p(e){return I.tabReplace||I.useBR?e.replace(M,function(e,n){return I.useBR&&"\n"===e?"<br>":I.tabReplace?n.replace(/\t/g,I.tabReplace):""}):e}function h(e,n,t){var r=n?L[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),-1===e.indexOf(r)&&a.push(r),a.join(" ").trim()}function d(e){var n,t,r,o,l,s=i(e);a(s)||(I.useBR?(n=document.createElementNS("http://www.w3.org/1999/xhtml","div"),n.innerHTML=e.innerHTML.replace(/\n/g,"").replace(/<br[ \/]*>/g,"\n")):n=e,l=n.textContent,r=s?f(s,l,!0):g(l),t=u(n),t.length&&(o=document.createElementNS("http://www.w3.org/1999/xhtml","div"),o.innerHTML=r.value,r.value=c(t,u(o),l)),r.value=p(r.value),e.innerHTML=r.value,e.className=h(e.className,s,r.language),e.result={language:r.language,re:r.r},r.second_best&&(e.second_best={language:r.second_best.language,re:r.second_best.r}))}function b(e){I=o(I,e)}function v(){if(!v.called){v.called=!0;var e=document.querySelectorAll("pre code");E.forEach.call(e,d)}}function m(){addEventListener("DOMContentLoaded",v,!1),addEventListener("load",v,!1)}function N(n,t){var r=y[n]=t(e);r.aliases&&r.aliases.forEach(function(e){L[e]=n})}function R(){return x(y)}function w(e){return e=(e||"").toLowerCase(),y[e]||y[L[e]]}var E=[],x=Object.keys,y={},L={},k=/^(no-?highlight|plain|text)$/i,B=/\blang(?:uage)?-([\w-]+)\b/i,M=/((^(<[^>]+>|\t|)+|(?:\n)))/gm,C="</span>",I={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0};return e.highlight=f,e.highlightAuto=g,e.fixMarkup=p,e.highlightBlock=d,e.configure=b,e.initHighlighting=v,e.initHighlightingOnLoad=m,e.registerLanguage=N,e.listLanguages=R,e.getLanguage=w,e.inherit=o,e.IR="[a-zA-Z]\\w*",e.UIR="[a-zA-Z_]\\w*",e.NR="\\b\\d+(\\.\\d+)?",e.CNR="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",e.BNR="\\b(0b[01]+)",e.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",e.BE={b:"\\\\[\\s\\S]",r:0},e.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[e.BE]},e.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[e.BE]},e.PWM={b:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},e.C=function(n,t,r){var a=e.inherit({cN:"comment",b:n,e:t,c:[]},r||{});return a.c.push(e.PWM),a.c.push({cN:"doctag",b:"(?:TODO|FIXME|NOTE|BUG|XXX):",r:0}),a},e.CLCM=e.C("//","$"),e.CBCM=e.C("/\\*","\\*/"),e.HCM=e.C("#","$"),e.NM={cN:"number",b:e.NR,r:0},e.CNM={cN:"number",b:e.CNR,r:0},e.BNM={cN:"number",b:e.BNR,r:0},e.CSSNM={cN:"number",b:e.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0},e.RM={cN:"regexp",b:/\//,e:/\/[gimuy]*/,i:/\n/,c:[e.BE,{b:/\[/,e:/\]/,r:0,c:[e.BE]}]},e.TM={cN:"title",b:e.IR,r:0},e.UTM={cN:"title",b:e.UIR,r:0},e.METHOD_GUARD={b:"\\.\\s*"+e.UIR,r:0},e});hljs.registerLanguage("javascript",function(e){var r="[A-Za-z$_][0-9A-Za-z$_]*",t={keyword:"in of if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const export super debugger as async await static import from as",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document Symbol Set Map WeakSet WeakMap Proxy Reflect Promise"},a={cN:"number",v:[{b:"\\b(0[bB][01]+)"},{b:"\\b(0[oO][0-7]+)"},{b:e.CNR}],r:0},n={cN:"subst",b:"\\$\\{",e:"\\}",k:t,c:[]},c={cN:"string",b:"`",e:"`",c:[e.BE,n]};n.c=[e.ASM,e.QSM,c,a,e.RM];var s=n.c.concat([e.CBCM,e.CLCM]);return{aliases:["js","jsx"],k:t,c:[{cN:"meta",r:10,b:/^\s*['"]use (strict|asm)['"]/},{cN:"meta",b:/^#!/,e:/$/},e.ASM,e.QSM,c,e.CLCM,e.CBCM,a,{b:/[{,]\s*/,r:0,c:[{b:r+"\\s*:",rB:!0,r:0,c:[{cN:"attr",b:r,r:0}]}]},{b:"("+e.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[e.CLCM,e.CBCM,e.RM,{cN:"function",b:"(\\(.*?\\)|"+r+")\\s*=>",rB:!0,e:"\\s*=>",c:[{cN:"params",v:[{b:r},{b:/\(\s*\)/},{b:/\(/,e:/\)/,eB:!0,eE:!0,k:t,c:s}]}]},{b:/</,e:/(\/\w+|\w+\/)>/,sL:"xml",c:[{b:/<\w+\s*\/>/,skip:!0},{b:/<\w+/,e:/(\/\w+|\w+\/)>/,skip:!0,c:[{b:/<\w+\s*\/>/,skip:!0},"self"]}]}],r:0},{cN:"function",bK:"function",e:/\{/,eE:!0,c:[e.inherit(e.TM,{b:r}),{cN:"params",b:/\(/,e:/\)/,eB:!0,eE:!0,c:s}],i:/\[|%/},{b:/\$[(.]/},e.METHOD_GUARD,{cN:"class",bK:"class",e:/[{;=]/,eE:!0,i:/[:"\[\]]/,c:[{bK:"extends"},e.UTM]},{bK:"constructor",e:/\{/,eE:!0}],i:/#(?!!)/}});hljs.registerLanguage("xml",function(s){var e="[A-Za-z0-9\\._:-]+",t={eW:!0,i:/</,r:0,c:[{cN:"attr",b:e,r:0},{b:/=\s*/,r:0,c:[{cN:"string",endsParent:!0,v:[{b:/"/,e:/"/},{b:/'/,e:/'/},{b:/[^\s"'=<>`]+/}]}]}]};return{aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist"],cI:!0,c:[{cN:"meta",b:"<!DOCTYPE",e:">",r:10,c:[{b:"\\[",e:"\\]"}]},s.C("<!--","-->",{r:10}),{b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{b:/<\?(php)?/,e:/\?>/,sL:"php",c:[{b:"/\\*",e:"\\*/",skip:!0}]},{cN:"tag",b:"<style(?=\\s|>|$)",e:">",k:{name:"style"},c:[t],starts:{e:"</style>",rE:!0,sL:["css","xml"]}},{cN:"tag",b:"<script(?=\\s|>|$)",e:">",k:{name:"script"},c:[t],starts:{e:"</script>",rE:!0,sL:["actionscript","javascript","handlebars","xml"]}},{cN:"meta",v:[{b:/<\?xml/,e:/\?>/,r:10},{b:/<\?\w+/,e:/\?>/}]},{cN:"tag",b:"</?",e:"/?>",c:[{cN:"name",b:/[^\/><\s]+/,r:0},t]}]}});hljs.registerLanguage("gradle",function(e){return{cI:!0,k:{keyword:"task project allprojects subprojects artifacts buildscript configurations dependencies repositories sourceSets description delete from into include exclude source classpath destinationDir includes options sourceCompatibility targetCompatibility group flatDir doLast doFirst flatten todir fromdir ant def abstract break case catch continue default do else extends final finally for if implements instanceof native new private protected public return static switch synchronized throw throws transient try volatile while strictfp package import false null super this true antlrtask checkstyle codenarc copy boolean byte char class double float int interface long short void compile runTime file fileTree abs any append asList asWritable call collect compareTo count div dump each eachByte eachFile eachLine every find findAll flatten getAt getErr getIn getOut getText grep immutable inject inspect intersect invokeMethods isCase join leftShift minus multiply newInputStream newOutputStream newPrintWriter newReader newWriter next plus pop power previous print println push putAt read readBytes readLines reverse reverseEach round size sort splitEachLine step subMap times toInteger toList tokenize upto waitForOrKill withPrintWriter withReader withStream withWriter withWriterAppend write writeLine"},c:[e.CLCM,e.CBCM,e.ASM,e.QSM,e.NM,e.RM]}});hljs.registerLanguage("ruby",function(e){var b="[a-zA-Z_]\\w*[!?=]?|[-+~]\\@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?",r={keyword:"and then defined module in return redo if BEGIN retry end for self when next until do begin unless END rescue else break undef not super class case require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor",literal:"true false nil"},c={cN:"doctag",b:"@[A-Za-z]+"},a={b:"#<",e:">"},s=[e.C("#","$",{c:[c]}),e.C("^\\=begin","^\\=end",{c:[c],r:10}),e.C("^__END__","\\n$")],n={cN:"subst",b:"#\\{",e:"}",k:r},t={cN:"string",c:[e.BE,n],v:[{b:/'/,e:/'/},{b:/"/,e:/"/},{b:/`/,e:/`/},{b:"%[qQwWx]?\\(",e:"\\)"},{b:"%[qQwWx]?\\[",e:"\\]"},{b:"%[qQwWx]?{",e:"}"},{b:"%[qQwWx]?<",e:">"},{b:"%[qQwWx]?/",e:"/"},{b:"%[qQwWx]?%",e:"%"},{b:"%[qQwWx]?-",e:"-"},{b:"%[qQwWx]?\\|",e:"\\|"},{b:/\B\?(\\\d{1,3}|\\x[A-Fa-f0-9]{1,2}|\\u[A-Fa-f0-9]{4}|\\?\S)\b/},{b:/<<(-?)\w+$/,e:/^\s*\w+$/}]},i={cN:"params",b:"\\(",e:"\\)",endsParent:!0,k:r},d=[t,a,{cN:"class",bK:"class module",e:"$|;",i:/=/,c:[e.inherit(e.TM,{b:"[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?"}),{b:"<\\s*",c:[{b:"("+e.IR+"::)?"+e.IR}]}].concat(s)},{cN:"function",bK:"def",e:"$|;",c:[e.inherit(e.TM,{b:b}),i].concat(s)},{b:e.IR+"::"},{cN:"symbol",b:e.UIR+"(\\!|\\?)?:",r:0},{cN:"symbol",b:":(?!\\s)",c:[t,{b:b}],r:0},{cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0},{b:"(\\$\\W)|((\\$|\\@\\@?)(\\w+))"},{cN:"params",b:/\|/,e:/\|/,k:r},{b:"("+e.RSR+"|unless)\\s*",k:"unless",c:[a,{cN:"regexp",c:[e.BE,n],i:/\n/,v:[{b:"/",e:"/[a-z]*"},{b:"%r{",e:"}[a-z]*"},{b:"%r\\(",e:"\\)[a-z]*"},{b:"%r!",e:"![a-z]*"},{b:"%r\\[",e:"\\][a-z]*"}]}].concat(s),r:0}].concat(s);n.c=d,i.c=d;var l="[>?]>",o="[\\w#]+\\(\\w+\\):\\d+:\\d+>",u="(\\w+-)?\\d+\\.\\d+\\.\\d(p\\d+)?[^>]+>",w=[{b:/^\s*=>/,starts:{e:"$",c:d}},{cN:"meta",b:"^("+l+"|"+o+"|"+u+")",starts:{e:"$",c:d}}];return{aliases:["rb","gemspec","podspec","thor","irb"],k:r,i:/\/\*/,c:s.concat(w).concat(d)}});hljs.registerLanguage("yaml",function(e){var b="true false yes no null",a="^[ \\-]*",r="[a-zA-Z_][\\w\\-]*",t={cN:"attr",v:[{b:a+r+":"},{b:a+'"'+r+'":'},{b:a+"'"+r+"':"}]},c={cN:"template-variable",v:[{b:"{{",e:"}}"},{b:"%{",e:"}"}]},l={cN:"string",r:0,v:[{b:/'/,e:/'/},{b:/"/,e:/"/},{b:/\S+/}],c:[e.BE,c]};return{cI:!0,aliases:["yml","YAML","yaml"],c:[t,{cN:"meta",b:"^---s*$",r:10},{cN:"string",b:"[\\|>] *$",rE:!0,c:l.c,e:t.v[0].b},{b:"<%[%=-]?",e:"[%-]?%>",sL:"ruby",eB:!0,eE:!0,r:0},{cN:"type",b:"!!"+e.UIR},{cN:"meta",b:"&"+e.UIR+"$"},{cN:"meta",b:"\\*"+e.UIR+"$"},{cN:"bullet",b:"^ *-",r:0},e.HCM,{bK:b,k:{literal:b}},e.CNM,l]}});hljs.registerLanguage("groovy",function(e){return{k:{literal:"true false null",keyword:"byte short char int long boolean float double void def as in assert trait super this abstract static volatile transient public private protected synchronized final class interface enum if else for while switch case break default continue throw throws try catch finally implements extends new import package return instanceof"},c:[e.C("/\\*\\*","\\*/",{r:0,c:[{b:/\w+@/,r:0},{cN:"doctag",b:"@[A-Za-z]+"}]}),e.CLCM,e.CBCM,{cN:"string",b:'"""',e:'"""'},{cN:"string",b:"'''",e:"'''"},{cN:"string",b:"\\$/",e:"/\\$",r:10},e.ASM,{cN:"regexp",b:/~?\/[^\/\n]+\//,c:[e.BE]},e.QSM,{cN:"meta",b:"^#!/usr/bin/env",e:"$",i:"\n"},e.BNM,{cN:"class",bK:"class interface trait enum",e:"{",i:":",c:[{bK:"extends implements"},e.UTM]},e.CNM,{cN:"meta",b:"@[A-Za-z]+"},{cN:"string",b:/[^\?]{0}[A-Za-z0-9_$]+ *:/},{b:/\?/,e:/\:/},{cN:"symbol",b:"^\\s*[A-Za-z0-9_$]+:",r:0}],i:/#|<\//}});hljs.registerLanguage("bash",function(e){var t={cN:"variable",v:[{b:/\$[\w\d#@][\w\d_]*/},{b:/\$\{(.*?)}/}]},s={cN:"string",b:/"/,e:/"/,c:[e.BE,t,{cN:"variable",b:/\$\(/,e:/\)/,c:[e.BE]}]},a={cN:"string",b:/'/,e:/'/};return{aliases:["sh","zsh"],l:/\b-?[a-z\._]+\b/,k:{keyword:"if then else elif fi for while in do done case esac function",literal:"true false",built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp",_:"-ne -eq -lt -gt -f -d -e -s -l -a"},c:[{cN:"meta",b:/^#![^\n]+sh\s*$/,r:10},{cN:"function",b:/\w[\w\d_]*\s*\(\s*\)\s*\{/,rB:!0,c:[e.inherit(e.TM,{b:/\w[\w\d_]*/})],r:0},e.HCM,s,a,t]}});hljs.registerLanguage("kotlin",function(e){var t={keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit initinterface annotation data sealed internal infix operator out by constructor super trait volatile transient native default",built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing",literal:"true false null"},r={cN:"keyword",b:/\b(break|continue|return|this)\b/,starts:{c:[{cN:"symbol",b:/@\w+/}]}},i={cN:"symbol",b:e.UIR+"@"},n={cN:"subst",b:"\\${",e:"}",c:[e.ASM,e.CNM]},a={cN:"variable",b:"\\$"+e.UIR},c={cN:"string",v:[{b:'"""',e:'"""',c:[a,n]},{b:"'",e:"'",i:/\n/,c:[e.BE]},{b:'"',e:'"',i:/\n/,c:[e.BE,a,n]}]},s={cN:"meta",b:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+e.UIR+")?"},o={cN:"meta",b:"@"+e.UIR,c:[{b:/\(/,e:/\)/,c:[e.inherit(c,{cN:"meta-string"})]}]};return{k:t,c:[e.C("/\\*\\*","\\*/",{r:0,c:[{cN:"doctag",b:"@[A-Za-z]+"}]}),e.CLCM,e.CBCM,r,i,s,o,{cN:"function",bK:"fun",e:"[(]|$",rB:!0,eE:!0,k:t,i:/fun\s+(<.*>)?[^\s\(]+(\s+[^\s\(]+)\s*=/,r:5,c:[{b:e.UIR+"\\s*\\(",rB:!0,r:0,c:[e.UTM]},{cN:"type",b:/</,e:/>/,k:"reified",r:0},{cN:"params",b:/\(/,e:/\)/,endsParent:!0,k:t,r:0,c:[{b:/:/,e:/[=,\/]/,eW:!0,c:[{cN:"type",b:e.UIR},e.CLCM,e.CBCM],r:0},e.CLCM,e.CBCM,s,o,c,e.CNM]},e.CBCM]},{cN:"class",bK:"class interface trait",e:/[:\{(]|$/,eE:!0,i:"extends implements",c:[{bK:"public protected internal private constructor"},e.UTM,{cN:"type",b:/</,e:/>/,eB:!0,eE:!0,r:0},{cN:"type",b:/[,:]\s*/,e:/[<\(,]|$/,eB:!0,rE:!0},s,o]},c,{cN:"meta",b:"^#!/usr/bin/env",e:"$",i:"\n"},e.CNM]}});hljs.registerLanguage("json",function(e){var i={literal:"true false null"},n=[e.QSM,e.CNM],r={e:",",eW:!0,eE:!0,c:n,k:i},t={b:"{",e:"}",c:[{cN:"attr",b:/"/,e:/"/,c:[e.BE],i:"\\n"},e.inherit(r,{b:/:/})],i:"\\S"},c={b:"\\[",e:"\\]",c:[e.inherit(r)],i:"\\S"};return n.splice(n.length,0,t,c),{c:n,k:i,i:"\\S"}});hljs.registerLanguage("scala",function(e){var t={cN:"meta",b:"@[A-Za-z]+"},a={cN:"subst",v:[{b:"\\$[A-Za-z0-9_]+"},{b:"\\${",e:"}"}]},r={cN:"string",v:[{b:'"',e:'"',i:"\\n",c:[e.BE]},{b:'"""',e:'"""',r:10},{b:'[a-z]+"',e:'"',i:"\\n",c:[e.BE,a]},{cN:"string",b:'[a-z]+"""',e:'"""',c:[a],r:10}]},c={cN:"symbol",b:"'\\w[\\w\\d_]*(?!')"},i={cN:"type",b:"\\b[A-Z][A-Za-z0-9_]*",r:0},s={cN:"title",b:/[^0-9\n\t "'(),.`{}\[\]:;][^\n\t "'(),.`{}\[\]:;]+|[^0-9\n\t "'(),.`{}\[\]:;=]/,r:0},n={cN:"class",bK:"class object trait type",e:/[:={\[\n;]/,eE:!0,c:[{bK:"extends with",r:10},{b:/\[/,e:/\]/,eB:!0,eE:!0,r:0,c:[i]},{cN:"params",b:/\(/,e:/\)/,eB:!0,eE:!0,r:0,c:[i]},s]},l={cN:"function",bK:"def",e:/[:={\[(\n;]/,eE:!0,c:[s]};return{k:{literal:"true false null",keyword:"type yield lazy override def with val var sealed abstract private trait object if forSome for while throw finally protected extends import final return else break new catch super class case package default try this match continue throws implicit"},c:[e.CLCM,e.CBCM,r,c,i,l,n,e.CNM,t]}});hljs.registerLanguage("java",function(e){var a="[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*",t=a+"(<"+a+"(\\s*,\\s*"+a+")*>)?",r="false synchronized int abstract float private char boolean static null if const for true while long strictfp finally protected import native final void enum else break transient catch instanceof byte super volatile case assert short package default double public try this switch continue throws protected public private module requires exports do",s="\\b(0[bB]([01]+[01_]+[01]+|[01]+)|0[xX]([a-fA-F0-9]+[a-fA-F0-9_]+[a-fA-F0-9]+|[a-fA-F0-9]+)|(([\\d]+[\\d_]+[\\d]+|[\\d]+)(\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))?|\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))([eE][-+]?\\d+)?)[lLfF]?",c={cN:"number",b:s,r:0};return{aliases:["jsp"],k:r,i:/<\/|#/,c:[e.C("/\\*\\*","\\*/",{r:0,c:[{b:/\w+@/,r:0},{cN:"doctag",b:"@[A-Za-z]+"}]}),e.CLCM,e.CBCM,e.ASM,e.QSM,{cN:"class",bK:"class interface",e:/[{;=]/,eE:!0,k:"class interface",i:/[:"\[\]]/,c:[{bK:"extends implements"},e.UTM]},{bK:"new throw return else",r:0},{cN:"function",b:"("+t+"\\s+)+"+e.UIR+"\\s*\\(",rB:!0,e:/[{;=]/,eE:!0,k:r,c:[{b:e.UIR+"\\s*\\(",rB:!0,r:0,c:[e.UTM]},{cN:"params",b:/\(/,e:/\)/,k:r,r:0,c:[e.ASM,e.QSM,e.CNM,e.CBCM]},e.CLCM,e.CBCM]},c,{cN:"meta",b:"@[A-Za-z]+"}]}});hljs.registerLanguage("shell",function(s){return{aliases:["console"],c:[{cN:"meta",b:"^\\s{0,3}[\\w\\d\\[\\]()@-]*[>%$#]",starts:{e:"$",sL:"bash"}}]}});hljs.registerLanguage("sql",function(e){var t=e.C("--","$");return{cI:!0,i:/[<>{}*#]/,c:[{bK:"begin end start commit rollback savepoint lock alter create drop rename call delete do handler insert load replace select truncate update set show pragma grant merge describe use explain help declare prepare execute deallocate release unlock purge reset change stop analyze cache flush optimize repair kill install uninstall checksum restore check backup revoke comment",e:/;/,eW:!0,l:/[\w\.]+/,k:{keyword:"abort abs absolute acc acce accep accept access accessed accessible account acos action activate add addtime admin administer advanced advise aes_decrypt aes_encrypt after agent aggregate ali alia alias allocate allow alter always analyze ancillary and any anydata anydataset anyschema anytype apply archive archived archivelog are as asc ascii asin assembly assertion associate asynchronous at atan atn2 attr attri attrib attribu attribut attribute attributes audit authenticated authentication authid authors auto autoallocate autodblink autoextend automatic availability avg backup badfile basicfile before begin beginning benchmark between bfile bfile_base big bigfile bin binary_double binary_float binlog bit_and bit_count bit_length bit_or bit_xor bitmap blob_base block blocksize body both bound buffer_cache buffer_pool build bulk by byte byteordermark bytes cache caching call calling cancel capacity cascade cascaded case cast catalog category ceil ceiling chain change changed char_base char_length character_length characters characterset charindex charset charsetform charsetid check checksum checksum_agg child choose chr chunk class cleanup clear client clob clob_base clone close cluster_id cluster_probability cluster_set clustering coalesce coercibility col collate collation collect colu colum column column_value columns columns_updated comment commit compact compatibility compiled complete composite_limit compound compress compute concat concat_ws concurrent confirm conn connec connect connect_by_iscycle connect_by_isleaf connect_by_root connect_time connection consider consistent constant constraint constraints constructor container content contents context contributors controlfile conv convert convert_tz corr corr_k corr_s corresponding corruption cos cost count count_big counted covar_pop covar_samp cpu_per_call cpu_per_session crc32 create creation critical cross cube cume_dist curdate current current_date current_time current_timestamp current_user cursor curtime customdatum cycle data database databases datafile datafiles datalength date_add date_cache date_format date_sub dateadd datediff datefromparts datename datepart datetime2fromparts day day_to_second dayname dayofmonth dayofweek dayofyear days db_role_change dbtimezone ddl deallocate declare decode decompose decrement decrypt deduplicate def defa defau defaul default defaults deferred defi defin define degrees delayed delegate delete delete_all delimited demand dense_rank depth dequeue des_decrypt des_encrypt des_key_file desc descr descri describ describe descriptor deterministic diagnostics difference dimension direct_load directory disable disable_all disallow disassociate discardfile disconnect diskgroup distinct distinctrow distribute distributed div do document domain dotnet double downgrade drop dumpfile duplicate duration each edition editionable editions element ellipsis else elsif elt empty enable enable_all enclosed encode encoding encrypt end end-exec endian enforced engine engines enqueue enterprise entityescaping eomonth error errors escaped evalname evaluate event eventdata events except exception exceptions exchange exclude excluding execu execut execute exempt exists exit exp expire explain export export_set extended extent external external_1 external_2 externally extract failed failed_login_attempts failover failure far fast feature_set feature_value fetch field fields file file_name_convert filesystem_like_logging final finish first first_value fixed flash_cache flashback floor flush following follows for forall force form forma format found found_rows freelist freelists freepools fresh from from_base64 from_days ftp full function general generated get get_format get_lock getdate getutcdate global global_name globally go goto grant grants greatest group group_concat group_id grouping grouping_id groups gtid_subtract guarantee guard handler hash hashkeys having hea head headi headin heading heap help hex hierarchy high high_priority hosts hour http id ident_current ident_incr ident_seed identified identity idle_time if ifnull ignore iif ilike ilm immediate import in include including increment index indexes indexing indextype indicator indices inet6_aton inet6_ntoa inet_aton inet_ntoa infile initial initialized initially initrans inmemory inner innodb input insert install instance instantiable instr interface interleaved intersect into invalidate invisible is is_free_lock is_ipv4 is_ipv4_compat is_not is_not_null is_used_lock isdate isnull isolation iterate java join json json_exists keep keep_duplicates key keys kill language large last last_day last_insert_id last_value lax lcase lead leading least leaves left len lenght length less level levels library like like2 like4 likec limit lines link list listagg little ln load load_file lob lobs local localtime localtimestamp locate locator lock locked log log10 log2 logfile logfiles logging logical logical_reads_per_call logoff logon logs long loop low low_priority lower lpad lrtrim ltrim main make_set makedate maketime managed management manual map mapping mask master master_pos_wait match matched materialized max maxextents maximize maxinstances maxlen maxlogfiles maxloghistory maxlogmembers maxsize maxtrans md5 measures median medium member memcompress memory merge microsecond mid migration min minextents minimum mining minus minute minvalue missing mod mode model modification modify module monitoring month months mount move movement multiset mutex name name_const names nan national native natural nav nchar nclob nested never new newline next nextval no no_write_to_binlog noarchivelog noaudit nobadfile nocheck nocompress nocopy nocycle nodelay nodiscardfile noentityescaping noguarantee nokeep nologfile nomapping nomaxvalue nominimize nominvalue nomonitoring none noneditionable nonschema noorder nopr nopro noprom nopromp noprompt norely noresetlogs noreverse normal norowdependencies noschemacheck noswitch not nothing notice notrim novalidate now nowait nth_value nullif nulls num numb numbe nvarchar nvarchar2 object ocicoll ocidate ocidatetime ociduration ociinterval ociloblocator ocinumber ociref ocirefcursor ocirowid ocistring ocitype oct octet_length of off offline offset oid oidindex old on online only opaque open operations operator optimal optimize option optionally or oracle oracle_date oradata ord ordaudio orddicom orddoc order ordimage ordinality ordvideo organization orlany orlvary out outer outfile outline output over overflow overriding package pad parallel parallel_enable parameters parent parse partial partition partitions pascal passing password password_grace_time password_lock_time password_reuse_max password_reuse_time password_verify_function patch path patindex pctincrease pctthreshold pctused pctversion percent percent_rank percentile_cont percentile_disc performance period period_add period_diff permanent physical pi pipe pipelined pivot pluggable plugin policy position post_transaction pow power pragma prebuilt precedes preceding precision prediction prediction_cost prediction_details prediction_probability prediction_set prepare present preserve prior priority private private_sga privileges procedural procedure procedure_analyze processlist profiles project prompt protection public publishingservername purge quarter query quick quiesce quota quotename radians raise rand range rank raw read reads readsize rebuild record records recover recovery recursive recycle redo reduced ref reference referenced references referencing refresh regexp_like register regr_avgx regr_avgy regr_count regr_intercept regr_r2 regr_slope regr_sxx regr_sxy reject rekey relational relative relaylog release release_lock relies_on relocate rely rem remainder rename repair repeat replace replicate replication required reset resetlogs resize resource respect restore restricted result result_cache resumable resume retention return returning returns reuse reverse revoke right rlike role roles rollback rolling rollup round row row_count rowdependencies rowid rownum rows rtrim rules safe salt sample save savepoint sb1 sb2 sb4 scan schema schemacheck scn scope scroll sdo_georaster sdo_topo_geometry search sec_to_time second section securefile security seed segment select self sequence sequential serializable server servererror session session_user sessions_per_user set sets settings sha sha1 sha2 share shared shared_pool short show shrink shutdown si_averagecolor si_colorhistogram si_featurelist si_positionalcolor si_stillimage si_texture siblings sid sign sin size size_t sizes skip slave sleep smalldatetimefromparts smallfile snapshot some soname sort soundex source space sparse spfile split sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_small_result sql_variant_property sqlcode sqldata sqlerror sqlname sqlstate sqrt square standalone standby start starting startup statement static statistics stats_binomial_test stats_crosstab stats_ks_test stats_mode stats_mw_test stats_one_way_anova stats_t_test_ stats_t_test_indep stats_t_test_one stats_t_test_paired stats_wsr_test status std stddev stddev_pop stddev_samp stdev stop storage store stored str str_to_date straight_join strcmp strict string struct stuff style subdate subpartition subpartitions substitutable substr substring subtime subtring_index subtype success sum suspend switch switchoffset switchover sync synchronous synonym sys sys_xmlagg sysasm sysaux sysdate sysdatetimeoffset sysdba sysoper system system_user sysutcdatetime table tables tablespace tan tdo template temporary terminated tertiary_weights test than then thread through tier ties time time_format time_zone timediff timefromparts timeout timestamp timestampadd timestampdiff timezone_abbr timezone_minute timezone_region to to_base64 to_date to_days to_seconds todatetimeoffset trace tracking transaction transactional translate translation treat trigger trigger_nestlevel triggers trim truncate try_cast try_convert try_parse type ub1 ub2 ub4 ucase unarchived unbounded uncompress under undo unhex unicode uniform uninstall union unique unix_timestamp unknown unlimited unlock unpivot unrecoverable unsafe unsigned until untrusted unusable unused update updated upgrade upped upper upsert url urowid usable usage use use_stored_outlines user user_data user_resources users using utc_date utc_timestamp uuid uuid_short validate validate_password_strength validation valist value values var var_samp varcharc vari varia variab variabl variable variables variance varp varraw varrawc varray verify version versions view virtual visible void wait wallet warning warnings week weekday weekofyear wellformed when whene whenev wheneve whenever where while whitespace with within without work wrapped xdb xml xmlagg xmlattributes xmlcast xmlcolattval xmlelement xmlexists xmlforest xmlindex xmlnamespaces xmlpi xmlquery xmlroot xmlschema xmlserialize xmltable xmltype xor year year_to_month years yearweek",literal:"true false null",built_in:"array bigint binary bit blob boolean char character date dec decimal float int int8 integer interval number numeric real record serial serial8 smallint text varchar varying void"},c:[{cN:"string",b:"'",e:"'",c:[e.BE,{b:"''"}]},{cN:"string",b:'"',e:'"',c:[e.BE,{b:'""'}]},{cN:"string",b:"`",e:"`",c:[e.BE]},e.CNM,e.CBCM,t]},e.CBCM,t]}});
\ No newline at end of file
diff --git a/src/site/resources/js/jquery.js b/src/site/resources/js/jquery.js
deleted file mode 100644
index 8ccd0ea..0000000
--- a/src/site/resources/js/jquery.js
+++ /dev/null
@@ -1,9266 +0,0 @@
-/*!
- * jQuery JavaScript Library v1.7.1
- * http://jquery.com/
- *
- * Copyright 2011, John Resig
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * Includes Sizzle.js
- * http://sizzlejs.com/
- * Copyright 2011, The Dojo Foundation
- * Released under the MIT, BSD, and GPL Licenses.
- *
- * Date: Mon Nov 21 21:11:03 2011 -0500
- */
-(function( window, undefined ) {
-
-// Use the correct document accordingly with window argument (sandbox)
-var document = window.document,
-	navigator = window.navigator,
-	location = window.location;
-var jQuery = (function() {
-
-// Define a local copy of jQuery
-var jQuery = function( selector, context ) {
-		// The jQuery object is actually just the init constructor 'enhanced'
-		return new jQuery.fn.init( selector, context, rootjQuery );
-	},
-
-	// Map over jQuery in case of overwrite
-	_jQuery = window.jQuery,
-
-	// Map over the $ in case of overwrite
-	_$ = window.$,
-
-	// A central reference to the root jQuery(document)
-	rootjQuery,
-
-	// A simple way to check for HTML strings or ID strings
-	// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
-	quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,
-
-	// Check if a string has a non-whitespace character in it
-	rnotwhite = /\S/,
-
-	// Used for trimming whitespace
-	trimLeft = /^\s+/,
-	trimRight = /\s+$/,
-
-	// Match a standalone tag
-	rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/,
-
-	// JSON RegExp
-	rvalidchars = /^[\],:{}\s]*$/,
-	rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
-	rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
-	rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
-
-	// Useragent RegExp
-	rwebkit = /(webkit)[ \/]([\w.]+)/,
-	ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/,
-	rmsie = /(msie) ([\w.]+)/,
-	rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/,
-
-	// Matches dashed string for camelizing
-	rdashAlpha = /-([a-z]|[0-9])/ig,
-	rmsPrefix = /^-ms-/,
-
-	// Used by jQuery.camelCase as callback to replace()
-	fcamelCase = function( all, letter ) {
-		return ( letter + "" ).toUpperCase();
-	},
-
-	// Keep a UserAgent string for use with jQuery.browser
-	userAgent = navigator.userAgent,
-
-	// For matching the engine and version of the browser
-	browserMatch,
-
-	// The deferred used on DOM ready
-	readyList,
-
-	// The ready event handler
-	DOMContentLoaded,
-
-	// Save a reference to some core methods
-	toString = Object.prototype.toString,
-	hasOwn = Object.prototype.hasOwnProperty,
-	push = Array.prototype.push,
-	slice = Array.prototype.slice,
-	trim = String.prototype.trim,
-	indexOf = Array.prototype.indexOf,
-
-	// [[Class]] -> type pairs
-	class2type = {};
-
-jQuery.fn = jQuery.prototype = {
-	constructor: jQuery,
-	init: function( selector, context, rootjQuery ) {
-		var match, elem, ret, doc;
-
-		// Handle $(""), $(null), or $(undefined)
-		if ( !selector ) {
-			return this;
-		}
-
-		// Handle $(DOMElement)
-		if ( selector.nodeType ) {
-			this.context = this[0] = selector;
-			this.length = 1;
-			return this;
-		}
-
-		// The body element only exists once, optimize finding it
-		if ( selector === "body" && !context && document.body ) {
-			this.context = document;
-			this[0] = document.body;
-			this.selector = selector;
-			this.length = 1;
-			return this;
-		}
-
-		// Handle HTML strings
-		if ( typeof selector === "string" ) {
-			// Are we dealing with HTML string or an ID?
-			if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
-				// Assume that strings that start and end with <> are HTML and skip the regex check
-				match = [ null, selector, null ];
-
-			} else {
-				match = quickExpr.exec( selector );
-			}
-
-			// Verify a match, and that no context was specified for #id
-			if ( match && (match[1] || !context) ) {
-
-				// HANDLE: $(html) -> $(array)
-				if ( match[1] ) {
-					context = context instanceof jQuery ? context[0] : context;
-					doc = ( context ? context.ownerDocument || context : document );
-
-					// If a single string is passed in and it's a single tag
-					// just do a createElement and skip the rest
-					ret = rsingleTag.exec( selector );
-
-					if ( ret ) {
-						if ( jQuery.isPlainObject( context ) ) {
-							selector = [ document.createElement( ret[1] ) ];
-							jQuery.fn.attr.call( selector, context, true );
-
-						} else {
-							selector = [ doc.createElement( ret[1] ) ];
-						}
-
-					} else {
-						ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
-						selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes;
-					}
-
-					return jQuery.merge( this, selector );
-
-				// HANDLE: $("#id")
-				} else {
-					elem = document.getElementById( match[2] );
-
-					// Check parentNode to catch when Blackberry 4.6 returns
-					// nodes that are no longer in the document #6963
-					if ( elem && elem.parentNode ) {
-						// Handle the case where IE and Opera return items
-						// by name instead of ID
-						if ( elem.id !== match[2] ) {
-							return rootjQuery.find( selector );
-						}
-
-						// Otherwise, we inject the element directly into the jQuery object
-						this.length = 1;
-						this[0] = elem;
-					}
-
-					this.context = document;
-					this.selector = selector;
-					return this;
-				}
-
-			// HANDLE: $(expr, $(...))
-			} else if ( !context || context.jquery ) {
-				return ( context || rootjQuery ).find( selector );
-
-			// HANDLE: $(expr, context)
-			// (which is just equivalent to: $(context).find(expr)
-			} else {
-				return this.constructor( context ).find( selector );
-			}
-
-		// HANDLE: $(function)
-		// Shortcut for document ready
-		} else if ( jQuery.isFunction( selector ) ) {
-			return rootjQuery.ready( selector );
-		}
-
-		if ( selector.selector !== undefined ) {
-			this.selector = selector.selector;
-			this.context = selector.context;
-		}
-
-		return jQuery.makeArray( selector, this );
-	},
-
-	// Start with an empty selector
-	selector: "",
-
-	// The current version of jQuery being used
-	jquery: "1.7.1",
-
-	// The default length of a jQuery object is 0
-	length: 0,
-
-	// The number of elements contained in the matched element set
-	size: function() {
-		return this.length;
-	},
-
-	toArray: function() {
-		return slice.call( this, 0 );
-	},
-
-	// Get the Nth element in the matched element set OR
-	// Get the whole matched element set as a clean array
-	get: function( num ) {
-		return num == null ?
-
-			// Return a 'clean' array
-			this.toArray() :
-
-			// Return just the object
-			( num < 0 ? this[ this.length + num ] : this[ num ] );
-	},
-
-	// Take an array of elements and push it onto the stack
-	// (returning the new matched element set)
-	pushStack: function( elems, name, selector ) {
-		// Build a new jQuery matched element set
-		var ret = this.constructor();
-
-		if ( jQuery.isArray( elems ) ) {
-			push.apply( ret, elems );
-
-		} else {
-			jQuery.merge( ret, elems );
-		}
-
-		// Add the old object onto the stack (as a reference)
-		ret.prevObject = this;
-
-		ret.context = this.context;
-
-		if ( name === "find" ) {
-			ret.selector = this.selector + ( this.selector ? " " : "" ) + selector;
-		} else if ( name ) {
-			ret.selector = this.selector + "." + name + "(" + selector + ")";
-		}
-
-		// Return the newly-formed element set
-		return ret;
-	},
-
-	// Execute a callback for every element in the matched set.
-	// (You can seed the arguments with an array of args, but this is
-	// only used internally.)
-	each: function( callback, args ) {
-		return jQuery.each( this, callback, args );
-	},
-
-	ready: function( fn ) {
-		// Attach the listeners
-		jQuery.bindReady();
-
-		// Add the callback
-		readyList.add( fn );
-
-		return this;
-	},
-
-	eq: function( i ) {
-		i = +i;
-		return i === -1 ?
-			this.slice( i ) :
-			this.slice( i, i + 1 );
-	},
-
-	first: function() {
-		return this.eq( 0 );
-	},
-
-	last: function() {
-		return this.eq( -1 );
-	},
-
-	slice: function() {
-		return this.pushStack( slice.apply( this, arguments ),
-			"slice", slice.call(arguments).join(",") );
-	},
-
-	map: function( callback ) {
-		return this.pushStack( jQuery.map(this, function( elem, i ) {
-			return callback.call( elem, i, elem );
-		}));
-	},
-
-	end: function() {
-		return this.prevObject || this.constructor(null);
-	},
-
-	// For internal use only.
-	// Behaves like an Array's method, not like a jQuery method.
-	push: push,
-	sort: [].sort,
-	splice: [].splice
-};
-
-// Give the init function the jQuery prototype for later instantiation
-jQuery.fn.init.prototype = jQuery.fn;
-
-jQuery.extend = jQuery.fn.extend = function() {
-	var options, name, src, copy, copyIsArray, clone,
-		target = arguments[0] || {},
-		i = 1,
-		length = arguments.length,
-		deep = false;
-
-	// Handle a deep copy situation
-	if ( typeof target === "boolean" ) {
-		deep = target;
-		target = arguments[1] || {};
-		// skip the boolean and the target
-		i = 2;
-	}
-
-	// Handle case when target is a string or something (possible in deep copy)
-	if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
-		target = {};
-	}
-
-	// extend jQuery itself if only one argument is passed
-	if ( length === i ) {
-		target = this;
-		--i;
-	}
-
-	for ( ; i < length; i++ ) {
-		// Only deal with non-null/undefined values
-		if ( (options = arguments[ i ]) != null ) {
-			// Extend the base object
-			for ( name in options ) {
-				src = target[ name ];
-				copy = options[ name ];
-
-				// Prevent never-ending loop
-				if ( target === copy ) {
-					continue;
-				}
-
-				// Recurse if we're merging plain objects or arrays
-				if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
-					if ( copyIsArray ) {
-						copyIsArray = false;
-						clone = src && jQuery.isArray(src) ? src : [];
-
-					} else {
-						clone = src && jQuery.isPlainObject(src) ? src : {};
-					}
-
-					// Never move original objects, clone them
-					target[ name ] = jQuery.extend( deep, clone, copy );
-
-				// Don't bring in undefined values
-				} else if ( copy !== undefined ) {
-					target[ name ] = copy;
-				}
-			}
-		}
-	}
-
-	// Return the modified object
-	return target;
-};
-
-jQuery.extend({
-	noConflict: function( deep ) {
-		if ( window.$ === jQuery ) {
-			window.$ = _$;
-		}
-
-		if ( deep && window.jQuery === jQuery ) {
-			window.jQuery = _jQuery;
-		}
-
-		return jQuery;
-	},
-
-	// Is the DOM ready to be used? Set to true once it occurs.
-	isReady: false,
-
-	// A counter to track how many items to wait for before
-	// the ready event fires. See #6781
-	readyWait: 1,
-
-	// Hold (or release) the ready event
-	holdReady: function( hold ) {
-		if ( hold ) {
-			jQuery.readyWait++;
-		} else {
-			jQuery.ready( true );
-		}
-	},
-
-	// Handle when the DOM is ready
-	ready: function( wait ) {
-		// Either a released hold or an DOMready/load event and not yet ready
-		if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) {
-			// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
-			if ( !document.body ) {
-				return setTimeout( jQuery.ready, 1 );
-			}
-
-			// Remember that the DOM is ready
-			jQuery.isReady = true;
-
-			// If a normal DOM Ready event fired, decrement, and wait if need be
-			if ( wait !== true && --jQuery.readyWait > 0 ) {
-				return;
-			}
-
-			// If there are functions bound, to execute
-			readyList.fireWith( document, [ jQuery ] );
-
-			// Trigger any bound ready events
-			if ( jQuery.fn.trigger ) {
-				jQuery( document ).trigger( "ready" ).off( "ready" );
-			}
-		}
-	},
-
-	bindReady: function() {
-		if ( readyList ) {
-			return;
-		}
-
-		readyList = jQuery.Callbacks( "once memory" );
-
-		// Catch cases where $(document).ready() is called after the
-		// browser event has already occurred.
-		if ( document.readyState === "complete" ) {
-			// Handle it asynchronously to allow scripts the opportunity to delay ready
-			return setTimeout( jQuery.ready, 1 );
-		}
-
-		// Mozilla, Opera and webkit nightlies currently support this event
-		if ( document.addEventListener ) {
-			// Use the handy event callback
-			document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
-
-			// A fallback to window.onload, that will always work
-			window.addEventListener( "load", jQuery.ready, false );
-
-		// If IE event model is used
-		} else if ( document.attachEvent ) {
-			// ensure firing before onload,
-			// maybe late but safe also for iframes
-			document.attachEvent( "onreadystatechange", DOMContentLoaded );
-
-			// A fallback to window.onload, that will always work
-			window.attachEvent( "onload", jQuery.ready );
-
-			// If IE and not a frame
-			// continually check to see if the document is ready
-			var toplevel = false;
-
-			try {
-				toplevel = window.frameElement == null;
-			} catch(e) {}
-
-			if ( document.documentElement.doScroll && toplevel ) {
-				doScrollCheck();
-			}
-		}
-	},
-
-	// See test/unit/core.js for details concerning isFunction.
-	// Since version 1.3, DOM methods and functions like alert
-	// aren't supported. They return false on IE (#2968).
-	isFunction: function( obj ) {
-		return jQuery.type(obj) === "function";
-	},
-
-	isArray: Array.isArray || function( obj ) {
-		return jQuery.type(obj) === "array";
-	},
-
-	// A crude way of determining if an object is a window
-	isWindow: function( obj ) {
-		return obj && typeof obj === "object" && "setInterval" in obj;
-	},
-
-	isNumeric: function( obj ) {
-		return !isNaN( parseFloat(obj) ) && isFinite( obj );
-	},
-
-	type: function( obj ) {
-		return obj == null ?
-			String( obj ) :
-			class2type[ toString.call(obj) ] || "object";
-	},
-
-	isPlainObject: function( obj ) {
-		// Must be an Object.
-		// Because of IE, we also have to check the presence of the constructor property.
-		// Make sure that DOM nodes and window objects don't pass through, as well
-		if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
-			return false;
-		}
-
-		try {
-			// Not own constructor property must be Object
-			if ( obj.constructor &&
-				!hasOwn.call(obj, "constructor") &&
-				!hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
-				return false;
-			}
-		} catch ( e ) {
-			// IE8,9 Will throw exceptions on certain host objects #9897
-			return false;
-		}
-
-		// Own properties are enumerated firstly, so to speed up,
-		// if last one is own, then all properties are own.
-
-		var key;
-		for ( key in obj ) {}
-
-		return key === undefined || hasOwn.call( obj, key );
-	},
-
-	isEmptyObject: function( obj ) {
-		for ( var name in obj ) {
-			return false;
-		}
-		return true;
-	},
-
-	error: function( msg ) {
-		throw new Error( msg );
-	},
-
-	parseJSON: function( data ) {
-		if ( typeof data !== "string" || !data ) {
-			return null;
-		}
-
-		// Make sure leading/trailing whitespace is removed (IE can't handle it)
-		data = jQuery.trim( data );
-
-		// Attempt to parse using the native JSON parser first
-		if ( window.JSON && window.JSON.parse ) {
-			return window.JSON.parse( data );
-		}
-
-		// Make sure the incoming data is actual JSON
-		// Logic borrowed from http://json.org/json2.js
-		if ( rvalidchars.test( data.replace( rvalidescape, "@" )
-			.replace( rvalidtokens, "]" )
-			.replace( rvalidbraces, "")) ) {
-
-			return ( new Function( "return " + data ) )();
-
-		}
-		jQuery.error( "Invalid JSON: " + data );
-	},
-
-	// Cross-browser xml parsing
-	parseXML: function( data ) {
-		var xml, tmp;
-		try {
-			if ( window.DOMParser ) { // Standard
-				tmp = new DOMParser();
-				xml = tmp.parseFromString( data , "text/xml" );
-			} else { // IE
-				xml = new ActiveXObject( "Microsoft.XMLDOM" );
-				xml.async = "false";
-				xml.loadXML( data );
-			}
-		} catch( e ) {
-			xml = undefined;
-		}
-		if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
-			jQuery.error( "Invalid XML: " + data );
-		}
-		return xml;
-	},
-
-	noop: function() {},
-
-	// Evaluates a script in a global context
-	// Workarounds based on findings by Jim Driscoll
-	// http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
-	globalEval: function( data ) {
-		if ( data && rnotwhite.test( data ) ) {
-			// We use execScript on Internet Explorer
-			// We use an anonymous function so that context is window
-			// rather than jQuery in Firefox
-			( window.execScript || function( data ) {
-				window[ "eval" ].call( window, data );
-			} )( data );
-		}
-	},
-
-	// Convert dashed to camelCase; used by the css and data modules
-	// Microsoft forgot to hump their vendor prefix (#9572)
-	camelCase: function( string ) {
-		return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
-	},
-
-	nodeName: function( elem, name ) {
-		return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
-	},
-
-	// args is for internal usage only
-	each: function( object, callback, args ) {
-		var name, i = 0,
-			length = object.length,
-			isObj = length === undefined || jQuery.isFunction( object );
-
-		if ( args ) {
-			if ( isObj ) {
-				for ( name in object ) {
-					if ( callback.apply( object[ name ], args ) === false ) {
-						break;
-					}
-				}
-			} else {
-				for ( ; i < length; ) {
-					if ( callback.apply( object[ i++ ], args ) === false ) {
-						break;
-					}
-				}
-			}
-
-		// A special, fast, case for the most common use of each
-		} else {
-			if ( isObj ) {
-				for ( name in object ) {
-					if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
-						break;
-					}
-				}
-			} else {
-				for ( ; i < length; ) {
-					if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) {
-						break;
-					}
-				}
-			}
-		}
-
-		return object;
-	},
-
-	// Use native String.trim function wherever possible
-	trim: trim ?
-		function( text ) {
-			return text == null ?
-				"" :
-				trim.call( text );
-		} :
-
-		// Otherwise use our own trimming functionality
-		function( text ) {
-			return text == null ?
-				"" :
-				text.toString().replace( trimLeft, "" ).replace( trimRight, "" );
-		},
-
-	// results is for internal usage only
-	makeArray: function( array, results ) {
-		var ret = results || [];
-
-		if ( array != null ) {
-			// The window, strings (and functions) also have 'length'
-			// Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930
-			var type = jQuery.type( array );
-
-			if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) {
-				push.call( ret, array );
-			} else {
-				jQuery.merge( ret, array );
-			}
-		}
-
-		return ret;
-	},
-
-	inArray: function( elem, array, i ) {
-		var len;
-
-		if ( array ) {
-			if ( indexOf ) {
-				return indexOf.call( array, elem, i );
-			}
-
-			len = array.length;
-			i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
-
-			for ( ; i < len; i++ ) {
-				// Skip accessing in sparse arrays
-				if ( i in array && array[ i ] === elem ) {
-					return i;
-				}
-			}
-		}
-
-		return -1;
-	},
-
-	merge: function( first, second ) {
-		var i = first.length,
-			j = 0;
-
-		if ( typeof second.length === "number" ) {
-			for ( var l = second.length; j < l; j++ ) {
-				first[ i++ ] = second[ j ];
-			}
-
-		} else {
-			while ( second[j] !== undefined ) {
-				first[ i++ ] = second[ j++ ];
-			}
-		}
-
-		first.length = i;
-
-		return first;
-	},
-
-	grep: function( elems, callback, inv ) {
-		var ret = [], retVal;
-		inv = !!inv;
-
-		// Go through the array, only saving the items
-		// that pass the validator function
-		for ( var i = 0, length = elems.length; i < length; i++ ) {
-			retVal = !!callback( elems[ i ], i );
-			if ( inv !== retVal ) {
-				ret.push( elems[ i ] );
-			}
-		}
-
-		return ret;
-	},
-
-	// arg is for internal usage only
-	map: function( elems, callback, arg ) {
-		var value, key, ret = [],
-			i = 0,
-			length = elems.length,
-			// jquery objects are treated as arrays
-			isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ;
-
-		// Go through the array, translating each of the items to their
-		if ( isArray ) {
-			for ( ; i < length; i++ ) {
-				value = callback( elems[ i ], i, arg );
-
-				if ( value != null ) {
-					ret[ ret.length ] = value;
-				}
-			}
-
-		// Go through every key on the object,
-		} else {
-			for ( key in elems ) {
-				value = callback( elems[ key ], key, arg );
-
-				if ( value != null ) {
-					ret[ ret.length ] = value;
-				}
-			}
-		}
-
-		// Flatten any nested arrays
-		return ret.concat.apply( [], ret );
-	},
-
-	// A global GUID counter for objects
-	guid: 1,
-
-	// Bind a function to a context, optionally partially applying any
-	// arguments.
-	proxy: function( fn, context ) {
-		if ( typeof context === "string" ) {
-			var tmp = fn[ context ];
-			context = fn;
-			fn = tmp;
-		}
-
-		// Quick check to determine if target is callable, in the spec
-		// this throws a TypeError, but we will just return undefined.
-		if ( !jQuery.isFunction( fn ) ) {
-			return undefined;
-		}
-
-		// Simulated bind
-		var args = slice.call( arguments, 2 ),
-			proxy = function() {
-				return fn.apply( context, args.concat( slice.call( arguments ) ) );
-			};
-
-		// Set the guid of unique handler to the same of original handler, so it can be removed
-		proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;
-
-		return proxy;
-	},
-
-	// Mutifunctional method to get and set values to a collection
-	// The value/s can optionally be executed if it's a function
-	access: function( elems, key, value, exec, fn, pass ) {
-		var length = elems.length;
-
-		// Setting many attributes
-		if ( typeof key === "object" ) {
-			for ( var k in key ) {
-				jQuery.access( elems, k, key[k], exec, fn, value );
-			}
-			return elems;
-		}
-
-		// Setting one attribute
-		if ( value !== undefined ) {
-			// Optionally, function values get executed if exec is true
-			exec = !pass && exec && jQuery.isFunction(value);
-
-			for ( var i = 0; i < length; i++ ) {
-				fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
-			}
-
-			return elems;
-		}
-
-		// Getting an attribute
-		return length ? fn( elems[0], key ) : undefined;
-	},
-
-	now: function() {
-		return ( new Date() ).getTime();
-	},
-
-	// Use of jQuery.browser is frowned upon.
-	// More details: http://docs.jquery.com/Utilities/jQuery.browser
-	uaMatch: function( ua ) {
-		ua = ua.toLowerCase();
-
-		var match = rwebkit.exec( ua ) ||
-			ropera.exec( ua ) ||
-			rmsie.exec( ua ) ||
-			ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) ||
-			[];
-
-		return { browser: match[1] || "", version: match[2] || "0" };
-	},
-
-	sub: function() {
-		function jQuerySub( selector, context ) {
-			return new jQuerySub.fn.init( selector, context );
-		}
-		jQuery.extend( true, jQuerySub, this );
-		jQuerySub.superclass = this;
-		jQuerySub.fn = jQuerySub.prototype = this();
-		jQuerySub.fn.constructor = jQuerySub;
-		jQuerySub.sub = this.sub;
-		jQuerySub.fn.init = function init( selector, context ) {
-			if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
-				context = jQuerySub( context );
-			}
-
-			return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
-		};
-		jQuerySub.fn.init.prototype = jQuerySub.fn;
-		var rootjQuerySub = jQuerySub(document);
-		return jQuerySub;
-	},
-
-	browser: {}
-});
-
-// Populate the class2type map
-jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
-	class2type[ "[object " + name + "]" ] = name.toLowerCase();
-});
-
-browserMatch = jQuery.uaMatch( userAgent );
-if ( browserMatch.browser ) {
-	jQuery.browser[ browserMatch.browser ] = true;
-	jQuery.browser.version = browserMatch.version;
-}
-
-// Deprecated, use jQuery.browser.webkit instead
-if ( jQuery.browser.webkit ) {
-	jQuery.browser.safari = true;
-}
-
-// IE doesn't match non-breaking spaces with \s
-if ( rnotwhite.test( "\xA0" ) ) {
-	trimLeft = /^[\s\xA0]+/;
-	trimRight = /[\s\xA0]+$/;
-}
-
-// All jQuery objects should point back to these
-rootjQuery = jQuery(document);
-
-// Cleanup functions for the document ready method
-if ( document.addEventListener ) {
-	DOMContentLoaded = function() {
-		document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
-		jQuery.ready();
-	};
-
-} else if ( document.attachEvent ) {
-	DOMContentLoaded = function() {
-		// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
-		if ( document.readyState === "complete" ) {
-			document.detachEvent( "onreadystatechange", DOMContentLoaded );
-			jQuery.ready();
-		}
-	};
-}
-
-// The DOM ready check for Internet Explorer
-function doScrollCheck() {
-	if ( jQuery.isReady ) {
-		return;
-	}
-
-	try {
-		// If IE is used, use the trick by Diego Perini
-		// http://javascript.nwbox.com/IEContentLoaded/
-		document.documentElement.doScroll("left");
-	} catch(e) {
-		setTimeout( doScrollCheck, 1 );
-		return;
-	}
-
-	// and execute any waiting functions
-	jQuery.ready();
-}
-
-return jQuery;
-
-})();
-
-
-// String to Object flags format cache
-var flagsCache = {};
-
-// Convert String-formatted flags into Object-formatted ones and store in cache
-function createFlags( flags ) {
-	var object = flagsCache[ flags ] = {},
-		i, length;
-	flags = flags.split( /\s+/ );
-	for ( i = 0, length = flags.length; i < length; i++ ) {
-		object[ flags[i] ] = true;
-	}
-	return object;
-}
-
-/*
- * Create a callback list using the following parameters:
- *
- *	flags:	an optional list of space-separated flags that will change how
- *			the callback list behaves
- *
- * By default a callback list will act like an event callback list and can be
- * "fired" multiple times.
- *
- * Possible flags:
- *
- *	once:			will ensure the callback list can only be fired once (like a Deferred)
- *
- *	memory:			will keep track of previous values and will call any callback added
- *					after the list has been fired right away with the latest "memorized"
- *					values (like a Deferred)
- *
- *	unique:			will ensure a callback can only be added once (no duplicate in the list)
- *
- *	stopOnFalse:	interrupt callings when a callback returns false
- *
- */
-jQuery.Callbacks = function( flags ) {
-
-	// Convert flags from String-formatted to Object-formatted
-	// (we check in cache first)
-	flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {};
-
-	var // Actual callback list
-		list = [],
-		// Stack of fire calls for repeatable lists
-		stack = [],
-		// Last fire value (for non-forgettable lists)
-		memory,
-		// Flag to know if list is currently firing
-		firing,
-		// First callback to fire (used internally by add and fireWith)
-		firingStart,
-		// End of the loop when firing
-		firingLength,
-		// Index of currently firing callback (modified by remove if needed)
-		firingIndex,
-		// Add one or several callbacks to the list
-		add = function( args ) {
-			var i,
-				length,
-				elem,
-				type,
-				actual;
-			for ( i = 0, length = args.length; i < length; i++ ) {
-				elem = args[ i ];
-				type = jQuery.type( elem );
-				if ( type === "array" ) {
-					// Inspect recursively
-					add( elem );
-				} else if ( type === "function" ) {
-					// Add if not in unique mode and callback is not in
-					if ( !flags.unique || !self.has( elem ) ) {
-						list.push( elem );
-					}
-				}
-			}
-		},
-		// Fire callbacks
-		fire = function( context, args ) {
-			args = args || [];
-			memory = !flags.memory || [ context, args ];
-			firing = true;
-			firingIndex = firingStart || 0;
-			firingStart = 0;
-			firingLength = list.length;
-			for ( ; list && firingIndex < firingLength; firingIndex++ ) {
-				if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) {
-					memory = true; // Mark as halted
-					break;
-				}
-			}
-			firing = false;
-			if ( list ) {
-				if ( !flags.once ) {
-					if ( stack && stack.length ) {
-						memory = stack.shift();
-						self.fireWith( memory[ 0 ], memory[ 1 ] );
-					}
-				} else if ( memory === true ) {
-					self.disable();
-				} else {
-					list = [];
-				}
-			}
-		},
-		// Actual Callbacks object
-		self = {
-			// Add a callback or a collection of callbacks to the list
-			add: function() {
-				if ( list ) {
-					var length = list.length;
-					add( arguments );
-					// Do we need to add the callbacks to the
-					// current firing batch?
-					if ( firing ) {
-						firingLength = list.length;
-					// With memory, if we're not firing then
-					// we should call right away, unless previous
-					// firing was halted (stopOnFalse)
-					} else if ( memory && memory !== true ) {
-						firingStart = length;
-						fire( memory[ 0 ], memory[ 1 ] );
-					}
-				}
-				return this;
-			},
-			// Remove a callback from the list
-			remove: function() {
-				if ( list ) {
-					var args = arguments,
-						argIndex = 0,
-						argLength = args.length;
-					for ( ; argIndex < argLength ; argIndex++ ) {
-						for ( var i = 0; i < list.length; i++ ) {
-							if ( args[ argIndex ] === list[ i ] ) {
-								// Handle firingIndex and firingLength
-								if ( firing ) {
-									if ( i <= firingLength ) {
-										firingLength--;
-										if ( i <= firingIndex ) {
-											firingIndex--;
-										}
-									}
-								}
-								// Remove the element
-								list.splice( i--, 1 );
-								// If we have some unicity property then
-								// we only need to do this once
-								if ( flags.unique ) {
-									break;
-								}
-							}
-						}
-					}
-				}
-				return this;
-			},
-			// Control if a given callback is in the list
-			has: function( fn ) {
-				if ( list ) {
-					var i = 0,
-						length = list.length;
-					for ( ; i < length; i++ ) {
-						if ( fn === list[ i ] ) {
-							return true;
-						}
-					}
-				}
-				return false;
-			},
-			// Remove all callbacks from the list
-			empty: function() {
-				list = [];
-				return this;
-			},
-			// Have the list do nothing anymore
-			disable: function() {
-				list = stack = memory = undefined;
-				return this;
-			},
-			// Is it disabled?
-			disabled: function() {
-				return !list;
-			},
-			// Lock the list in its current state
-			lock: function() {
-				stack = undefined;
-				if ( !memory || memory === true ) {
-					self.disable();
-				}
-				return this;
-			},
-			// Is it locked?
-			locked: function() {
-				return !stack;
-			},
-			// Call all callbacks with the given context and arguments
-			fireWith: function( context, args ) {
-				if ( stack ) {
-					if ( firing ) {
-						if ( !flags.once ) {
-							stack.push( [ context, args ] );
-						}
-					} else if ( !( flags.once && memory ) ) {
-						fire( context, args );
-					}
-				}
-				return this;
-			},
-			// Call all the callbacks with the given arguments
-			fire: function() {
-				self.fireWith( this, arguments );
-				return this;
-			},
-			// To know if the callbacks have already been called at least once
-			fired: function() {
-				return !!memory;
-			}
-		};
-
-	return self;
-};
-
-
-
-
-var // Static reference to slice
-	sliceDeferred = [].slice;
-
-jQuery.extend({
-
-	Deferred: function( func ) {
-		var doneList = jQuery.Callbacks( "once memory" ),
-			failList = jQuery.Callbacks( "once memory" ),
-			progressList = jQuery.Callbacks( "memory" ),
-			state = "pending",
-			lists = {
-				resolve: doneList,
-				reject: failList,
-				notify: progressList
-			},
-			promise = {
-				done: doneList.add,
-				fail: failList.add,
-				progress: progressList.add,
-
-				state: function() {
-					return state;
-				},
-
-				// Deprecated
-				isResolved: doneList.fired,
-				isRejected: failList.fired,
-
-				then: function( doneCallbacks, failCallbacks, progressCallbacks ) {
-					deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks );
-					return this;
-				},
-				always: function() {
-					deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments );
-					return this;
-				},
-				pipe: function( fnDone, fnFail, fnProgress ) {
-					return jQuery.Deferred(function( newDefer ) {
-						jQuery.each( {
-							done: [ fnDone, "resolve" ],
-							fail: [ fnFail, "reject" ],
-							progress: [ fnProgress, "notify" ]
-						}, function( handler, data ) {
-							var fn = data[ 0 ],
-								action = data[ 1 ],
-								returned;
-							if ( jQuery.isFunction( fn ) ) {
-								deferred[ handler ](function() {
-									returned = fn.apply( this, arguments );
-									if ( returned && jQuery.isFunction( returned.promise ) ) {
-										returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify );
-									} else {
-										newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] );
-									}
-								});
-							} else {
-								deferred[ handler ]( newDefer[ action ] );
-							}
-						});
-					}).promise();
-				},
-				// Get a promise for this deferred
-				// If obj is provided, the promise aspect is added to the object
-				promise: function( obj ) {
-					if ( obj == null ) {
-						obj = promise;
-					} else {
-						for ( var key in promise ) {
-							obj[ key ] = promise[ key ];
-						}
-					}
-					return obj;
-				}
-			},
-			deferred = promise.promise({}),
-			key;
-
-		for ( key in lists ) {
-			deferred[ key ] = lists[ key ].fire;
-			deferred[ key + "With" ] = lists[ key ].fireWith;
-		}
-
-		// Handle state
-		deferred.done( function() {
-			state = "resolved";
-		}, failList.disable, progressList.lock ).fail( function() {
-			state = "rejected";
-		}, doneList.disable, progressList.lock );
-
-		// Call given func if any
-		if ( func ) {
-			func.call( deferred, deferred );
-		}
-
-		// All done!
-		return deferred;
-	},
-
-	// Deferred helper
-	when: function( firstParam ) {
-		var args = sliceDeferred.call( arguments, 0 ),
-			i = 0,
-			length = args.length,
-			pValues = new Array( length ),
-			count = length,
-			pCount = length,
-			deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ?
-				firstParam :
-				jQuery.Deferred(),
-			promise = deferred.promise();
-		function resolveFunc( i ) {
-			return function( value ) {
-				args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
-				if ( !( --count ) ) {
-					deferred.resolveWith( deferred, args );
-				}
-			};
-		}
-		function progressFunc( i ) {
-			return function( value ) {
-				pValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
-				deferred.notifyWith( promise, pValues );
-			};
-		}
-		if ( length > 1 ) {
-			for ( ; i < length; i++ ) {
-				if ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) {
-					args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) );
-				} else {
-					--count;
-				}
-			}
-			if ( !count ) {
-				deferred.resolveWith( deferred, args );
-			}
-		} else if ( deferred !== firstParam ) {
-			deferred.resolveWith( deferred, length ? [ firstParam ] : [] );
-		}
-		return promise;
-	}
-});
-
-
-
-
-jQuery.support = (function() {
-
-	var support,
-		all,
-		a,
-		select,
-		opt,
-		input,
-		marginDiv,
-		fragment,
-		tds,
-		events,
-		eventName,
-		i,
-		isSupported,
-		div = document.createElement( "div" ),
-		documentElement = document.documentElement;
-
-	// Preliminary tests
-	div.setAttribute("className", "t");
-	div.innerHTML = "   <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
-
-	all = div.getElementsByTagName( "*" );
-	a = div.getElementsByTagName( "a" )[ 0 ];
-
-	// Can't get basic test support
-	if ( !all || !all.length || !a ) {
-		return {};
-	}
-
-	// First batch of supports tests
-	select = document.createElement( "select" );
-	opt = select.appendChild( document.createElement("option") );
-	input = div.getElementsByTagName( "input" )[ 0 ];
-
-	support = {
-		// IE strips leading whitespace when .innerHTML is used
-		leadingWhitespace: ( div.firstChild.nodeType === 3 ),
-
-		// Make sure that tbody elements aren't automatically inserted
-		// IE will insert them into empty tables
-		tbody: !div.getElementsByTagName("tbody").length,
-
-		// Make sure that link elements get serialized correctly by innerHTML
-		// This requires a wrapper element in IE
-		htmlSerialize: !!div.getElementsByTagName("link").length,
-
-		// Get the style information from getAttribute
-		// (IE uses .cssText instead)
-		style: /top/.test( a.getAttribute("style") ),
-
-		// Make sure that URLs aren't manipulated
-		// (IE normalizes it by default)
-		hrefNormalized: ( a.getAttribute("href") === "/a" ),
-
-		// Make sure that element opacity exists
-		// (IE uses filter instead)
-		// Use a regex to work around a WebKit issue. See #5145
-		opacity: /^0.55/.test( a.style.opacity ),
-
-		// Verify style float existence
-		// (IE uses styleFloat instead of cssFloat)
-		cssFloat: !!a.style.cssFloat,
-
-		// Make sure that if no value is specified for a checkbox
-		// that it defaults to "on".
-		// (WebKit defaults to "" instead)
-		checkOn: ( input.value === "on" ),
-
-		// Make sure that a selected-by-default option has a working selected property.
-		// (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
-		optSelected: opt.selected,
-
-		// Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
-		getSetAttribute: div.className !== "t",
-
-		// Tests for enctype support on a form(#6743)
-		enctype: !!document.createElement("form").enctype,
-
-		// Makes sure cloning an html5 element does not cause problems
-		// Where outerHTML is undefined, this still works
-		html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav></:nav>",
-
-		// Will be defined later
-		submitBubbles: true,
-		changeBubbles: true,
-		focusinBubbles: false,
-		deleteExpando: true,
-		noCloneEvent: true,
-		inlineBlockNeedsLayout: false,
-		shrinkWrapBlocks: false,
-		reliableMarginRight: true
-	};
-
-	// Make sure checked status is properly cloned
-	input.checked = true;
-	support.noCloneChecked = input.cloneNode( true ).checked;
-
-	// Make sure that the options inside disabled selects aren't marked as disabled
-	// (WebKit marks them as disabled)
-	select.disabled = true;
-	support.optDisabled = !opt.disabled;
-
-	// Test to see if it's possible to delete an expando from an element
-	// Fails in Internet Explorer
-	try {
-		delete div.test;
-	} catch( e ) {
-		support.deleteExpando = false;
-	}
-
-	if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {
-		div.attachEvent( "onclick", function() {
-			// Cloning a node shouldn't copy over any
-			// bound event handlers (IE does this)
-			support.noCloneEvent = false;
-		});
-		div.cloneNode( true ).fireEvent( "onclick" );
-	}
-
-	// Check if a radio maintains its value
-	// after being appended to the DOM
-	input = document.createElement("input");
-	input.value = "t";
-	input.setAttribute("type", "radio");
-	support.radioValue = input.value === "t";
-
-	input.setAttribute("checked", "checked");
-	div.appendChild( input );
-	fragment = document.createDocumentFragment();
-	fragment.appendChild( div.lastChild );
-
-	// WebKit doesn't clone checked state correctly in fragments
-	support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
-
-	// Check if a disconnected checkbox will retain its checked
-	// value of true after appended to the DOM (IE6/7)
-	support.appendChecked = input.checked;
-
-	fragment.removeChild( input );
-	fragment.appendChild( div );
-
-	div.innerHTML = "";
-
-	// Check if div with explicit width and no margin-right incorrectly
-	// gets computed margin-right based on width of container. For more
-	// info see bug #3333
-	// Fails in WebKit before Feb 2011 nightlies
-	// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
-	if ( window.getComputedStyle ) {
-		marginDiv = document.createElement( "div" );
-		marginDiv.style.width = "0";
-		marginDiv.style.marginRight = "0";
-		div.style.width = "2px";
-		div.appendChild( marginDiv );
-		support.reliableMarginRight =
-			( parseInt( ( window.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0;
-	}
-
-	// Technique from Juriy Zaytsev
-	// http://perfectionkills.com/detecting-event-support-without-browser-sniffing/
-	// We only care about the case where non-standard event systems
-	// are used, namely in IE. Short-circuiting here helps us to
-	// avoid an eval call (in setAttribute) which can cause CSP
-	// to go haywire. See: https://developer.mozilla.org/en/Security/CSP
-	if ( div.attachEvent ) {
-		for( i in {
-			submit: 1,
-			change: 1,
-			focusin: 1
-		}) {
-			eventName = "on" + i;
-			isSupported = ( eventName in div );
-			if ( !isSupported ) {
-				div.setAttribute( eventName, "return;" );
-				isSupported = ( typeof div[ eventName ] === "function" );
-			}
-			support[ i + "Bubbles" ] = isSupported;
-		}
-	}
-
-	fragment.removeChild( div );
-
-	// Null elements to avoid leaks in IE
-	fragment = select = opt = marginDiv = div = input = null;
-
-	// Run tests that need a body at doc ready
-	jQuery(function() {
-		var container, outer, inner, table, td, offsetSupport,
-			conMarginTop, ptlm, vb, style, html,
-			body = document.getElementsByTagName("body")[0];
-
-		if ( !body ) {
-			// Return for frameset docs that don't have a body
-			return;
-		}
-
-		conMarginTop = 1;
-		ptlm = "position:absolute;top:0;left:0;width:1px;height:1px;margin:0;";
-		vb = "visibility:hidden;border:0;";
-		style = "style='" + ptlm + "border:5px solid #000;padding:0;'";
-		html = "<div " + style + "><div></div></div>" +
-			"<table " + style + " cellpadding='0' cellspacing='0'>" +
-			"<tr><td></td></tr></table>";
-
-		container = document.createElement("div");
-		container.style.cssText = vb + "width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px";
-		body.insertBefore( container, body.firstChild );
-
-		// Construct the test element
-		div = document.createElement("div");
-		container.appendChild( div );
-
-		// Check if table cells still have offsetWidth/Height when they are set
-		// to display:none and there are still other visible table cells in a
-		// table row; if so, offsetWidth/Height are not reliable for use when
-		// determining if an element has been hidden directly using
-		// display:none (it is still safe to use offsets if a parent element is
-		// hidden; don safety goggles and see bug #4512 for more information).
-		// (only IE 8 fails this test)
-		div.innerHTML = "<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>";
-		tds = div.getElementsByTagName( "td" );
-		isSupported = ( tds[ 0 ].offsetHeight === 0 );
-
-		tds[ 0 ].style.display = "";
-		tds[ 1 ].style.display = "none";
-
-		// Check if empty table cells still have offsetWidth/Height
-		// (IE <= 8 fail this test)
-		support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
-
-		// Figure out if the W3C box model works as expected
-		div.innerHTML = "";
-		div.style.width = div.style.paddingLeft = "1px";
-		jQuery.boxModel = support.boxModel = div.offsetWidth === 2;
-
-		if ( typeof div.style.zoom !== "undefined" ) {
-			// Check if natively block-level elements act like inline-block
-			// elements when setting their display to 'inline' and giving
-			// them layout
-			// (IE < 8 does this)
-			div.style.display = "inline";
-			div.style.zoom = 1;
-			support.inlineBlockNeedsLayout = ( div.offsetWidth === 2 );
-
-			// Check if elements with layout shrink-wrap their children
-			// (IE 6 does this)
-			div.style.display = "";
-			div.innerHTML = "<div style='width:4px;'></div>";
-			support.shrinkWrapBlocks = ( div.offsetWidth !== 2 );
-		}
-
-		div.style.cssText = ptlm + vb;
-		div.innerHTML = html;
-
-		outer = div.firstChild;
-		inner = outer.firstChild;
-		td = outer.nextSibling.firstChild.firstChild;
-
-		offsetSupport = {
-			doesNotAddBorder: ( inner.offsetTop !== 5 ),
-			doesAddBorderForTableAndCells: ( td.offsetTop === 5 )
-		};
-
-		inner.style.position = "fixed";
-		inner.style.top = "20px";
-
-		// safari subtracts parent border width here which is 5px
-		offsetSupport.fixedPosition = ( inner.offsetTop === 20 || inner.offsetTop === 15 );
-		inner.style.position = inner.style.top = "";
-
-		outer.style.overflow = "hidden";
-		outer.style.position = "relative";
-
-		offsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 );
-		offsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop );
-
-		body.removeChild( container );
-		div  = container = null;
-
-		jQuery.extend( support, offsetSupport );
-	});
-
-	return support;
-})();
-
-
-
-
-var rbrace = /^(?:\{.*\}|\[.*\])$/,
-	rmultiDash = /([A-Z])/g;
-
-jQuery.extend({
-	cache: {},
-
-	// Please use with caution
-	uuid: 0,
-
-	// Unique for each copy of jQuery on the page
-	// Non-digits removed to match rinlinejQuery
-	expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),
-
-	// The following elements throw uncatchable exceptions if you
-	// attempt to add expando properties to them.
-	noData: {
-		"embed": true,
-		// Ban all objects except for Flash (which handle expandos)
-		"object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
-		"applet": true
-	},
-
-	hasData: function( elem ) {
-		elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
-		return !!elem && !isEmptyDataObject( elem );
-	},
-
-	data: function( elem, name, data, pvt /* Internal Use Only */ ) {
-		if ( !jQuery.acceptData( elem ) ) {
-			return;
-		}
-
-		var privateCache, thisCache, ret,
-			internalKey = jQuery.expando,
-			getByName = typeof name === "string",
-
-			// We have to handle DOM nodes and JS objects differently because IE6-7
-			// can't GC object references properly across the DOM-JS boundary
-			isNode = elem.nodeType,
-
-			// Only DOM nodes need the global jQuery cache; JS object data is
-			// attached directly to the object so GC can occur automatically
-			cache = isNode ? jQuery.cache : elem,
-
-			// Only defining an ID for JS objects if its cache already exists allows
-			// the code to shortcut on the same path as a DOM node with no cache
-			id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey,
-			isEvents = name === "events";
-
-		// Avoid doing any more work than we need to when trying to get data on an
-		// object that has no data at all
-		if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) {
-			return;
-		}
-
-		if ( !id ) {
-			// Only DOM nodes need a new unique ID for each element since their data
-			// ends up in the global cache
-			if ( isNode ) {
-				elem[ internalKey ] = id = ++jQuery.uuid;
-			} else {
-				id = internalKey;
-			}
-		}
-
-		if ( !cache[ id ] ) {
-			cache[ id ] = {};
-
-			// Avoids exposing jQuery metadata on plain JS objects when the object
-			// is serialized using JSON.stringify
-			if ( !isNode ) {
-				cache[ id ].toJSON = jQuery.noop;
-			}
-		}
-
-		// An object can be passed to jQuery.data instead of a key/value pair; this gets
-		// shallow copied over onto the existing cache
-		if ( typeof name === "object" || typeof name === "function" ) {
-			if ( pvt ) {
-				cache[ id ] = jQuery.extend( cache[ id ], name );
-			} else {
-				cache[ id ].data = jQuery.extend( cache[ id ].data, name );
-			}
-		}
-
-		privateCache = thisCache = cache[ id ];
-
-		// jQuery data() is stored in a separate object inside the object's internal data
-		// cache in order to avoid key collisions between internal data and user-defined
-		// data.
-		if ( !pvt ) {
-			if ( !thisCache.data ) {
-				thisCache.data = {};
-			}
-
-			thisCache = thisCache.data;
-		}
-
-		if ( data !== undefined ) {
-			thisCache[ jQuery.camelCase( name ) ] = data;
-		}
-
-		// Users should not attempt to inspect the internal events object using jQuery.data,
-		// it is undocumented and subject to change. But does anyone listen? No.
-		if ( isEvents && !thisCache[ name ] ) {
-			return privateCache.events;
-		}
-
-		// Check for both converted-to-camel and non-converted data property names
-		// If a data property was specified
-		if ( getByName ) {
-
-			// First Try to find as-is property data
-			ret = thisCache[ name ];
-
-			// Test for null|undefined property data
-			if ( ret == null ) {
-
-				// Try to find the camelCased property
-				ret = thisCache[ jQuery.camelCase( name ) ];
-			}
-		} else {
-			ret = thisCache;
-		}
-
-		return ret;
-	},
-
-	removeData: function( elem, name, pvt /* Internal Use Only */ ) {
-		if ( !jQuery.acceptData( elem ) ) {
-			return;
-		}
-
-		var thisCache, i, l,
-
-			// Reference to internal data cache key
-			internalKey = jQuery.expando,
-
-			isNode = elem.nodeType,
-
-			// See jQuery.data for more information
-			cache = isNode ? jQuery.cache : elem,
-
-			// See jQuery.data for more information
-			id = isNode ? elem[ internalKey ] : internalKey;
-
-		// If there is already no cache entry for this object, there is no
-		// purpose in continuing
-		if ( !cache[ id ] ) {
-			return;
-		}
-
-		if ( name ) {
-
-			thisCache = pvt ? cache[ id ] : cache[ id ].data;
-
-			if ( thisCache ) {
-
-				// Support array or space separated string names for data keys
-				if ( !jQuery.isArray( name ) ) {
-
-					// try the string as a key before any manipulation
-					if ( name in thisCache ) {
-						name = [ name ];
-					} else {
-
-						// split the camel cased version by spaces unless a key with the spaces exists
-						name = jQuery.camelCase( name );
-						if ( name in thisCache ) {
-							name = [ name ];
-						} else {
-							name = name.split( " " );
-						}
-					}
-				}
-
-				for ( i = 0, l = name.length; i < l; i++ ) {
-					delete thisCache[ name[i] ];
-				}
-
-				// If there is no data left in the cache, we want to continue
-				// and let the cache object itself get destroyed
-				if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {
-					return;
-				}
-			}
-		}
-
-		// See jQuery.data for more information
-		if ( !pvt ) {
-			delete cache[ id ].data;
-
-			// Don't destroy the parent cache unless the internal data object
-			// had been the only thing left in it
-			if ( !isEmptyDataObject(cache[ id ]) ) {
-				return;
-			}
-		}
-
-		// Browsers that fail expando deletion also refuse to delete expandos on
-		// the window, but it will allow it on all other JS objects; other browsers
-		// don't care
-		// Ensure that `cache` is not a window object #10080
-		if ( jQuery.support.deleteExpando || !cache.setInterval ) {
-			delete cache[ id ];
-		} else {
-			cache[ id ] = null;
-		}
-
-		// We destroyed the cache and need to eliminate the expando on the node to avoid
-		// false lookups in the cache for entries that no longer exist
-		if ( isNode ) {
-			// IE does not allow us to delete expando properties from nodes,
-			// nor does it have a removeAttribute function on Document nodes;
-			// we must handle all of these cases
-			if ( jQuery.support.deleteExpando ) {
-				delete elem[ internalKey ];
-			} else if ( elem.removeAttribute ) {
-				elem.removeAttribute( internalKey );
-			} else {
-				elem[ internalKey ] = null;
-			}
-		}
-	},
-
-	// For internal use only.
-	_data: function( elem, name, data ) {
-		return jQuery.data( elem, name, data, true );
-	},
-
-	// A method for determining if a DOM node can handle the data expando
-	acceptData: function( elem ) {
-		if ( elem.nodeName ) {
-			var match = jQuery.noData[ elem.nodeName.toLowerCase() ];
-
-			if ( match ) {
-				return !(match === true || elem.getAttribute("classid") !== match);
-			}
-		}
-
-		return true;
-	}
-});
-
-jQuery.fn.extend({
-	data: function( key, value ) {
-		var parts, attr, name,
-			data = null;
-
-		if ( typeof key === "undefined" ) {
-			if ( this.length ) {
-				data = jQuery.data( this[0] );
-
-				if ( this[0].nodeType === 1 && !jQuery._data( this[0], "parsedAttrs" ) ) {
-					attr = this[0].attributes;
-					for ( var i = 0, l = attr.length; i < l; i++ ) {
-						name = attr[i].name;
-
-						if ( name.indexOf( "data-" ) === 0 ) {
-							name = jQuery.camelCase( name.substring(5) );
-
-							dataAttr( this[0], name, data[ name ] );
-						}
-					}
-					jQuery._data( this[0], "parsedAttrs", true );
-				}
-			}
-
-			return data;
-
-		} else if ( typeof key === "object" ) {
-			return this.each(function() {
-				jQuery.data( this, key );
-			});
-		}
-
-		parts = key.split(".");
-		parts[1] = parts[1] ? "." + parts[1] : "";
-
-		if ( value === undefined ) {
-			data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
-
-			// Try to fetch any internally stored data first
-			if ( data === undefined && this.length ) {
-				data = jQuery.data( this[0], key );
-				data = dataAttr( this[0], key, data );
-			}
-
-			return data === undefined && parts[1] ?
-				this.data( parts[0] ) :
-				data;
-
-		} else {
-			return this.each(function() {
-				var self = jQuery( this ),
-					args = [ parts[0], value ];
-
-				self.triggerHandler( "setData" + parts[1] + "!", args );
-				jQuery.data( this, key, value );
-				self.triggerHandler( "changeData" + parts[1] + "!", args );
-			});
-		}
-	},
-
-	removeData: function( key ) {
-		return this.each(function() {
-			jQuery.removeData( this, key );
-		});
-	}
-});
-
-function dataAttr( elem, key, data ) {
-	// If nothing was found internally, try to fetch any
-	// data from the HTML5 data-* attribute
-	if ( data === undefined && elem.nodeType === 1 ) {
-
-		var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
-
-		data = elem.getAttribute( name );
-
-		if ( typeof data === "string" ) {
-			try {
-				data = data === "true" ? true :
-				data === "false" ? false :
-				data === "null" ? null :
-				jQuery.isNumeric( data ) ? parseFloat( data ) :
-					rbrace.test( data ) ? jQuery.parseJSON( data ) :
-					data;
-			} catch( e ) {}
-
-			// Make sure we set the data so it isn't changed later
-			jQuery.data( elem, key, data );
-
-		} else {
-			data = undefined;
-		}
-	}
-
-	return data;
-}
-
-// checks a cache object for emptiness
-function isEmptyDataObject( obj ) {
-	for ( var name in obj ) {
-
-		// if the public data object is empty, the private is still empty
-		if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
-			continue;
-		}
-		if ( name !== "toJSON" ) {
-			return false;
-		}
-	}
-
-	return true;
-}
-
-
-
-
-function handleQueueMarkDefer( elem, type, src ) {
-	var deferDataKey = type + "defer",
-		queueDataKey = type + "queue",
-		markDataKey = type + "mark",
-		defer = jQuery._data( elem, deferDataKey );
-	if ( defer &&
-		( src === "queue" || !jQuery._data(elem, queueDataKey) ) &&
-		( src === "mark" || !jQuery._data(elem, markDataKey) ) ) {
-		// Give room for hard-coded callbacks to fire first
-		// and eventually mark/queue something else on the element
-		setTimeout( function() {
-			if ( !jQuery._data( elem, queueDataKey ) &&
-				!jQuery._data( elem, markDataKey ) ) {
-				jQuery.removeData( elem, deferDataKey, true );
-				defer.fire();
-			}
-		}, 0 );
-	}
-}
-
-jQuery.extend({
-
-	_mark: function( elem, type ) {
-		if ( elem ) {
-			type = ( type || "fx" ) + "mark";
-			jQuery._data( elem, type, (jQuery._data( elem, type ) || 0) + 1 );
-		}
-	},
-
-	_unmark: function( force, elem, type ) {
-		if ( force !== true ) {
-			type = elem;
-			elem = force;
-			force = false;
-		}
-		if ( elem ) {
-			type = type || "fx";
-			var key = type + "mark",
-				count = force ? 0 : ( (jQuery._data( elem, key ) || 1) - 1 );
-			if ( count ) {
-				jQuery._data( elem, key, count );
-			} else {
-				jQuery.removeData( elem, key, true );
-				handleQueueMarkDefer( elem, type, "mark" );
-			}
-		}
-	},
-
-	queue: function( elem, type, data ) {
-		var q;
-		if ( elem ) {
-			type = ( type || "fx" ) + "queue";
-			q = jQuery._data( elem, type );
-
-			// Speed up dequeue by getting out quickly if this is just a lookup
-			if ( data ) {
-				if ( !q || jQuery.isArray(data) ) {
-					q = jQuery._data( elem, type, jQuery.makeArray(data) );
-				} else {
-					q.push( data );
-				}
-			}
-			return q || [];
-		}
-	},
-
-	dequeue: function( elem, type ) {
-		type = type || "fx";
-
-		var queue = jQuery.queue( elem, type ),
-			fn = queue.shift(),
-			hooks = {};
-
-		// If the fx queue is dequeued, always remove the progress sentinel
-		if ( fn === "inprogress" ) {
-			fn = queue.shift();
-		}
-
-		if ( fn ) {
-			// Add a progress sentinel to prevent the fx queue from being
-			// automatically dequeued
-			if ( type === "fx" ) {
-				queue.unshift( "inprogress" );
-			}
-
-			jQuery._data( elem, type + ".run", hooks );
-			fn.call( elem, function() {
-				jQuery.dequeue( elem, type );
-			}, hooks );
-		}
-
-		if ( !queue.length ) {
-			jQuery.removeData( elem, type + "queue " + type + ".run", true );
-			handleQueueMarkDefer( elem, type, "queue" );
-		}
-	}
-});
-
-jQuery.fn.extend({
-	queue: function( type, data ) {
-		if ( typeof type !== "string" ) {
-			data = type;
-			type = "fx";
-		}
-
-		if ( data === undefined ) {
-			return jQuery.queue( this[0], type );
-		}
-		return this.each(function() {
-			var queue = jQuery.queue( this, type, data );
-
-			if ( type === "fx" && queue[0] !== "inprogress" ) {
-				jQuery.dequeue( this, type );
-			}
-		});
-	},
-	dequeue: function( type ) {
-		return this.each(function() {
-			jQuery.dequeue( this, type );
-		});
-	},
-	// Based off of the plugin by Clint Helfers, with permission.
-	// http://blindsignals.com/index.php/2009/07/jquery-delay/
-	delay: function( time, type ) {
-		time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
-		type = type || "fx";
-
-		return this.queue( type, function( next, hooks ) {
-			var timeout = setTimeout( next, time );
-			hooks.stop = function() {
-				clearTimeout( timeout );
-			};
-		});
-	},
-	clearQueue: function( type ) {
-		return this.queue( type || "fx", [] );
-	},
-	// Get a promise resolved when queues of a certain type
-	// are emptied (fx is the type by default)
-	promise: function( type, object ) {
-		if ( typeof type !== "string" ) {
-			object = type;
-			type = undefined;
-		}
-		type = type || "fx";
-		var defer = jQuery.Deferred(),
-			elements = this,
-			i = elements.length,
-			count = 1,
-			deferDataKey = type + "defer",
-			queueDataKey = type + "queue",
-			markDataKey = type + "mark",
-			tmp;
-		function resolve() {
-			if ( !( --count ) ) {
-				defer.resolveWith( elements, [ elements ] );
-			}
-		}
-		while( i-- ) {
-			if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) ||
-					( jQuery.data( elements[ i ], queueDataKey, undefined, true ) ||
-						jQuery.data( elements[ i ], markDataKey, undefined, true ) ) &&
-					jQuery.data( elements[ i ], deferDataKey, jQuery.Callbacks( "once memory" ), true ) )) {
-				count++;
-				tmp.add( resolve );
-			}
-		}
-		resolve();
-		return defer.promise();
-	}
-});
-
-
-
-
-var rclass = /[\n\t\r]/g,
-	rspace = /\s+/,
-	rreturn = /\r/g,
-	rtype = /^(?:button|input)$/i,
-	rfocusable = /^(?:button|input|object|select|textarea)$/i,
-	rclickable = /^a(?:rea)?$/i,
-	rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
-	getSetAttribute = jQuery.support.getSetAttribute,
-	nodeHook, boolHook, fixSpecified;
-
-jQuery.fn.extend({
-	attr: function( name, value ) {
-		return jQuery.access( this, name, value, true, jQuery.attr );
-	},
-
-	removeAttr: function( name ) {
-		return this.each(function() {
-			jQuery.removeAttr( this, name );
-		});
-	},
-
-	prop: function( name, value ) {
-		return jQuery.access( this, name, value, true, jQuery.prop );
-	},
-
-	removeProp: function( name ) {
-		name = jQuery.propFix[ name ] || name;
-		return this.each(function() {
-			// try/catch handles cases where IE balks (such as removing a property on window)
-			try {
-				this[ name ] = undefined;
-				delete this[ name ];
-			} catch( e ) {}
-		});
-	},
-
-	addClass: function( value ) {
-		var classNames, i, l, elem,
-			setClass, c, cl;
-
-		if ( jQuery.isFunction( value ) ) {
-			return this.each(function( j ) {
-				jQuery( this ).addClass( value.call(this, j, this.className) );
-			});
-		}
-
-		if ( value && typeof value === "string" ) {
-			classNames = value.split( rspace );
-
-			for ( i = 0, l = this.length; i < l; i++ ) {
-				elem = this[ i ];
-
-				if ( elem.nodeType === 1 ) {
-					if ( !elem.className && classNames.length === 1 ) {
-						elem.className = value;
-
-					} else {
-						setClass = " " + elem.className + " ";
-
-						for ( c = 0, cl = classNames.length; c < cl; c++ ) {
-							if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) {
-								setClass += classNames[ c ] + " ";
-							}
-						}
-						elem.className = jQuery.trim( setClass );
-					}
-				}
-			}
-		}
-
-		return this;
-	},
-
-	removeClass: function( value ) {
-		var classNames, i, l, elem, className, c, cl;
-
-		if ( jQuery.isFunction( value ) ) {
-			return this.each(function( j ) {
-				jQuery( this ).removeClass( value.call(this, j, this.className) );
-			});
-		}
-
-		if ( (value && typeof value === "string") || value === undefined ) {
-			classNames = ( value || "" ).split( rspace );
-
-			for ( i = 0, l = this.length; i < l; i++ ) {
-				elem = this[ i ];
-
-				if ( elem.nodeType === 1 && elem.className ) {
-					if ( value ) {
-						className = (" " + elem.className + " ").replace( rclass, " " );
-						for ( c = 0, cl = classNames.length; c < cl; c++ ) {
-							className = className.replace(" " + classNames[ c ] + " ", " ");
-						}
-						elem.className = jQuery.trim( className );
-
-					} else {
-						elem.className = "";
-					}
-				}
-			}
-		}
-
-		return this;
-	},
-
-	toggleClass: function( value, stateVal ) {
-		var type = typeof value,
-			isBool = typeof stateVal === "boolean";
-
-		if ( jQuery.isFunction( value ) ) {
-			return this.each(function( i ) {
-				jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
-			});
-		}
-
-		return this.each(function() {
-			if ( type === "string" ) {
-				// toggle individual class names
-				var className,
-					i = 0,
-					self = jQuery( this ),
-					state = stateVal,
-					classNames = value.split( rspace );
-
-				while ( (className = classNames[ i++ ]) ) {
-					// check each className given, space seperated list
-					state = isBool ? state : !self.hasClass( className );
-					self[ state ? "addClass" : "removeClass" ]( className );
-				}
-
-			} else if ( type === "undefined" || type === "boolean" ) {
-				if ( this.className ) {
-					// store className if set
-					jQuery._data( this, "__className__", this.className );
-				}
-
-				// toggle whole className
-				this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
-			}
-		});
-	},
-
-	hasClass: function( selector ) {
-		var className = " " + selector + " ",
-			i = 0,
-			l = this.length;
-		for ( ; i < l; i++ ) {
-			if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) {
-				return true;
-			}
-		}
-
-		return false;
-	},
-
-	val: function( value ) {
-		var hooks, ret, isFunction,
-			elem = this[0];
-
-		if ( !arguments.length ) {
-			if ( elem ) {
-				hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ];
-
-				if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
-					return ret;
-				}
-
-				ret = elem.value;
-
-				return typeof ret === "string" ?
-					// handle most common string cases
-					ret.replace(rreturn, "") :
-					// handle cases where value is null/undef or number
-					ret == null ? "" : ret;
-			}
-
-			return;
-		}
-
-		isFunction = jQuery.isFunction( value );
-
-		return this.each(function( i ) {
-			var self = jQuery(this), val;
-
-			if ( this.nodeType !== 1 ) {
-				return;
-			}
-
-			if ( isFunction ) {
-				val = value.call( this, i, self.val() );
-			} else {
-				val = value;
-			}
-
-			// Treat null/undefined as ""; convert numbers to string
-			if ( val == null ) {
-				val = "";
-			} else if ( typeof val === "number" ) {
-				val += "";
-			} else if ( jQuery.isArray( val ) ) {
-				val = jQuery.map(val, function ( value ) {
-					return value == null ? "" : value + "";
-				});
-			}
-
-			hooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ];
-
-			// If set returns undefined, fall back to normal setting
-			if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
-				this.value = val;
-			}
-		});
-	}
-});
-
-jQuery.extend({
-	valHooks: {
-		option: {
-			get: function( elem ) {
-				// attributes.value is undefined in Blackberry 4.7 but
-				// uses .value. See #6932
-				var val = elem.attributes.value;
-				return !val || val.specified ? elem.value : elem.text;
-			}
-		},
-		select: {
-			get: function( elem ) {
-				var value, i, max, option,
-					index = elem.selectedIndex,
-					values = [],
-					options = elem.options,
-					one = elem.type === "select-one";
-
-				// Nothing was selected
-				if ( index < 0 ) {
-					return null;
-				}
-
-				// Loop through all the selected options
-				i = one ? index : 0;
-				max = one ? index + 1 : options.length;
-				for ( ; i < max; i++ ) {
-					option = options[ i ];
-
-					// Don't return options that are disabled or in a disabled optgroup
-					if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) &&
-							(!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) {
-
-						// Get the specific value for the option
-						value = jQuery( option ).val();
-
-						// We don't need an array for one selects
-						if ( one ) {
-							return value;
-						}
-
-						// Multi-Selects return an array
-						values.push( value );
-					}
-				}
-
-				// Fixes Bug #2551 -- select.val() broken in IE after form.reset()
-				if ( one && !values.length && options.length ) {
-					return jQuery( options[ index ] ).val();
-				}
-
-				return values;
-			},
-
-			set: function( elem, value ) {
-				var values = jQuery.makeArray( value );
-
-				jQuery(elem).find("option").each(function() {
-					this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
-				});
-
-				if ( !values.length ) {
-					elem.selectedIndex = -1;
-				}
-				return values;
-			}
-		}
-	},
-
-	attrFn: {
-		val: true,
-		css: true,
-		html: true,
-		text: true,
-		data: true,
-		width: true,
-		height: true,
-		offset: true
-	},
-
-	attr: function( elem, name, value, pass ) {
-		var ret, hooks, notxml,
-			nType = elem.nodeType;
-
-		// don't get/set attributes on text, comment and attribute nodes
-		if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
-			return;
-		}
-
-		if ( pass && name in jQuery.attrFn ) {
-			return jQuery( elem )[ name ]( value );
-		}
-
-		// Fallback to prop when attributes are not supported
-		if ( typeof elem.getAttribute === "undefined" ) {
-			return jQuery.prop( elem, name, value );
-		}
-
-		notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
-
-		// All attributes are lowercase
-		// Grab necessary hook if one is defined
-		if ( notxml ) {
-			name = name.toLowerCase();
-			hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
-		}
-
-		if ( value !== undefined ) {
-
-			if ( value === null ) {
-				jQuery.removeAttr( elem, name );
-				return;
-
-			} else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) {
-				return ret;
-
-			} else {
-				elem.setAttribute( name, "" + value );
-				return value;
-			}
-
-		} else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) {
-			return ret;
-
-		} else {
-
-			ret = elem.getAttribute( name );
-
-			// Non-existent attributes return null, we normalize to undefined
-			return ret === null ?
-				undefined :
-				ret;
-		}
-	},
-
-	removeAttr: function( elem, value ) {
-		var propName, attrNames, name, l,
-			i = 0;
-
-		if ( value && elem.nodeType === 1 ) {
-			attrNames = value.toLowerCase().split( rspace );
-			l = attrNames.length;
-
-			for ( ; i < l; i++ ) {
-				name = attrNames[ i ];
-
-				if ( name ) {
-					propName = jQuery.propFix[ name ] || name;
-
-					// See #9699 for explanation of this approach (setting first, then removal)
-					jQuery.attr( elem, name, "" );
-					elem.removeAttribute( getSetAttribute ? name : propName );
-
-					// Set corresponding property to false for boolean attributes
-					if ( rboolean.test( name ) && propName in elem ) {
-						elem[ propName ] = false;
-					}
-				}
-			}
-		}
-	},
-
-	attrHooks: {
-		type: {
-			set: function( elem, value ) {
-				// We can't allow the type property to be changed (since it causes problems in IE)
-				if ( rtype.test( elem.nodeName ) && elem.parentNode ) {
-					jQuery.error( "type property can't be changed" );
-				} else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
-					// Setting the type on a radio button after the value resets the value in IE6-9
-					// Reset value to it's default in case type is set after value
-					// This is for element creation
-					var val = elem.value;
-					elem.setAttribute( "type", value );
-					if ( val ) {
-						elem.value = val;
-					}
-					return value;
-				}
-			}
-		},
-		// Use the value property for back compat
-		// Use the nodeHook for button elements in IE6/7 (#1954)
-		value: {
-			get: function( elem, name ) {
-				if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
-					return nodeHook.get( elem, name );
-				}
-				return name in elem ?
-					elem.value :
-					null;
-			},
-			set: function( elem, value, name ) {
-				if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
-					return nodeHook.set( elem, value, name );
-				}
-				// Does not return so that setAttribute is also used
-				elem.value = value;
-			}
-		}
-	},
-
-	propFix: {
-		tabindex: "tabIndex",
-		readonly: "readOnly",
-		"for": "htmlFor",
-		"class": "className",
-		maxlength: "maxLength",
-		cellspacing: "cellSpacing",
-		cellpadding: "cellPadding",
-		rowspan: "rowSpan",
-		colspan: "colSpan",
-		usemap: "useMap",
-		frameborder: "frameBorder",
-		contenteditable: "contentEditable"
-	},
-
-	prop: function( elem, name, value ) {
-		var ret, hooks, notxml,
-			nType = elem.nodeType;
-
-		// don't get/set properties on text, comment and attribute nodes
-		if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
-			return;
-		}
-
-		notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
-
-		if ( notxml ) {
-			// Fix name and attach hooks
-			name = jQuery.propFix[ name ] || name;
-			hooks = jQuery.propHooks[ name ];
-		}
-
-		if ( value !== undefined ) {
-			if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
-				return ret;
-
-			} else {
-				return ( elem[ name ] = value );
-			}
-
-		} else {
-			if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
-				return ret;
-
-			} else {
-				return elem[ name ];
-			}
-		}
-	},
-
-	propHooks: {
-		tabIndex: {
-			get: function( elem ) {
-				// elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
-				// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
-				var attributeNode = elem.getAttributeNode("tabindex");
-
-				return attributeNode && attributeNode.specified ?
-					parseInt( attributeNode.value, 10 ) :
-					rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
-						0 :
-						undefined;
-			}
-		}
-	}
-});
-
-// Add the tabIndex propHook to attrHooks for back-compat (different case is intentional)
-jQuery.attrHooks.tabindex = jQuery.propHooks.tabIndex;
-
-// Hook for boolean attributes
-boolHook = {
-	get: function( elem, name ) {
-		// Align boolean attributes with corresponding properties
-		// Fall back to attribute presence where some booleans are not supported
-		var attrNode,
-			property = jQuery.prop( elem, name );
-		return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ?
-			name.toLowerCase() :
-			undefined;
-	},
-	set: function( elem, value, name ) {
-		var propName;
-		if ( value === false ) {
-			// Remove boolean attributes when set to false
-			jQuery.removeAttr( elem, name );
-		} else {
-			// value is true since we know at this point it's type boolean and not false
-			// Set boolean attributes to the same name and set the DOM property
-			propName = jQuery.propFix[ name ] || name;
-			if ( propName in elem ) {
-				// Only set the IDL specifically if it already exists on the element
-				elem[ propName ] = true;
-			}
-
-			elem.setAttribute( name, name.toLowerCase() );
-		}
-		return name;
-	}
-};
-
-// IE6/7 do not support getting/setting some attributes with get/setAttribute
-if ( !getSetAttribute ) {
-
-	fixSpecified = {
-		name: true,
-		id: true
-	};
-
-	// Use this for any attribute in IE6/7
-	// This fixes almost every IE6/7 issue
-	nodeHook = jQuery.valHooks.button = {
-		get: function( elem, name ) {
-			var ret;
-			ret = elem.getAttributeNode( name );
-			return ret && ( fixSpecified[ name ] ? ret.nodeValue !== "" : ret.specified ) ?
-				ret.nodeValue :
-				undefined;
-		},
-		set: function( elem, value, name ) {
-			// Set the existing or create a new attribute node
-			var ret = elem.getAttributeNode( name );
-			if ( !ret ) {
-				ret = document.createAttribute( name );
-				elem.setAttributeNode( ret );
-			}
-			return ( ret.nodeValue = value + "" );
-		}
-	};
-
-	// Apply the nodeHook to tabindex
-	jQuery.attrHooks.tabindex.set = nodeHook.set;
-
-	// Set width and height to auto instead of 0 on empty string( Bug #8150 )
-	// This is for removals
-	jQuery.each([ "width", "height" ], function( i, name ) {
-		jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
-			set: function( elem, value ) {
-				if ( value === "" ) {
-					elem.setAttribute( name, "auto" );
-					return value;
-				}
-			}
-		});
-	});
-
-	// Set contenteditable to false on removals(#10429)
-	// Setting to empty string throws an error as an invalid value
-	jQuery.attrHooks.contenteditable = {
-		get: nodeHook.get,
-		set: function( elem, value, name ) {
-			if ( value === "" ) {
-				value = "false";
-			}
-			nodeHook.set( elem, value, name );
-		}
-	};
-}
-
-
-// Some attributes require a special call on IE
-if ( !jQuery.support.hrefNormalized ) {
-	jQuery.each([ "href", "src", "width", "height" ], function( i, name ) {
-		jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
-			get: function( elem ) {
-				var ret = elem.getAttribute( name, 2 );
-				return ret === null ? undefined : ret;
-			}
-		});
-	});
-}
-
-if ( !jQuery.support.style ) {
-	jQuery.attrHooks.style = {
-		get: function( elem ) {
-			// Return undefined in the case of empty string
-			// Normalize to lowercase since IE uppercases css property names
-			return elem.style.cssText.toLowerCase() || undefined;
-		},
-		set: function( elem, value ) {
-			return ( elem.style.cssText = "" + value );
-		}
-	};
-}
-
-// Safari mis-reports the default selected property of an option
-// Accessing the parent's selectedIndex property fixes it
-if ( !jQuery.support.optSelected ) {
-	jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {
-		get: function( elem ) {
-			var parent = elem.parentNode;
-
-			if ( parent ) {
-				parent.selectedIndex;
-
-				// Make sure that it also works with optgroups, see #5701
-				if ( parent.parentNode ) {
-					parent.parentNode.selectedIndex;
-				}
-			}
-			return null;
-		}
-	});
-}
-
-// IE6/7 call enctype encoding
-if ( !jQuery.support.enctype ) {
-	jQuery.propFix.enctype = "encoding";
-}
-
-// Radios and checkboxes getter/setter
-if ( !jQuery.support.checkOn ) {
-	jQuery.each([ "radio", "checkbox" ], function() {
-		jQuery.valHooks[ this ] = {
-			get: function( elem ) {
-				// Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
-				return elem.getAttribute("value") === null ? "on" : elem.value;
-			}
-		};
-	});
-}
-jQuery.each([ "radio", "checkbox" ], function() {
-	jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {
-		set: function( elem, value ) {
-			if ( jQuery.isArray( value ) ) {
-				return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
-			}
-		}
-	});
-});
-
-
-
-
-var rformElems = /^(?:textarea|input|select)$/i,
-	rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/,
-	rhoverHack = /\bhover(\.\S+)?\b/,
-	rkeyEvent = /^key/,
-	rmouseEvent = /^(?:mouse|contextmenu)|click/,
-	rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
-	rquickIs = /^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,
-	quickParse = function( selector ) {
-		var quick = rquickIs.exec( selector );
-		if ( quick ) {
-			//   0  1    2   3
-			// [ _, tag, id, class ]
-			quick[1] = ( quick[1] || "" ).toLowerCase();
-			quick[3] = quick[3] && new RegExp( "(?:^|\\s)" + quick[3] + "(?:\\s|$)" );
-		}
-		return quick;
-	},
-	quickIs = function( elem, m ) {
-		var attrs = elem.attributes || {};
-		return (
-			(!m[1] || elem.nodeName.toLowerCase() === m[1]) &&
-			(!m[2] || (attrs.id || {}).value === m[2]) &&
-			(!m[3] || m[3].test( (attrs[ "class" ] || {}).value ))
-		);
-	},
-	hoverHack = function( events ) {
-		return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" );
-	};
-
-/*
- * Helper functions for managing events -- not part of the public interface.
- * Props to Dean Edwards' addEvent library for many of the ideas.
- */
-jQuery.event = {
-
-	add: function( elem, types, handler, data, selector ) {
-
-		var elemData, eventHandle, events,
-			t, tns, type, namespaces, handleObj,
-			handleObjIn, quick, handlers, special;
-
-		// Don't attach events to noData or text/comment nodes (allow plain objects tho)
-		if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) {
-			return;
-		}
-
-		// Caller can pass in an object of custom data in lieu of the handler
-		if ( handler.handler ) {
-			handleObjIn = handler;
-			handler = handleObjIn.handler;
-		}
-
-		// Make sure that the handler has a unique ID, used to find/remove it later
-		if ( !handler.guid ) {
-			handler.guid = jQuery.guid++;
-		}
-
-		// Init the element's event structure and main handler, if this is the first
-		events = elemData.events;
-		if ( !events ) {
-			elemData.events = events = {};
-		}
-		eventHandle = elemData.handle;
-		if ( !eventHandle ) {
-			elemData.handle = eventHandle = function( e ) {
-				// Discard the second event of a jQuery.event.trigger() and
-				// when an event is called after a page has unloaded
-				return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ?
-					jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
-					undefined;
-			};
-			// Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
-			eventHandle.elem = elem;
-		}
-
-		// Handle multiple events separated by a space
-		// jQuery(...).bind("mouseover mouseout", fn);
-		types = jQuery.trim( hoverHack(types) ).split( " " );
-		for ( t = 0; t < types.length; t++ ) {
-
-			tns = rtypenamespace.exec( types[t] ) || [];
-			type = tns[1];
-			namespaces = ( tns[2] || "" ).split( "." ).sort();
-
-			// If event changes its type, use the special event handlers for the changed type
-			special = jQuery.event.special[ type ] || {};
-
-			// If selector defined, determine special event api type, otherwise given type
-			type = ( selector ? special.delegateType : special.bindType ) || type;
-
-			// Update special based on newly reset type
-			special = jQuery.event.special[ type ] || {};
-
-			// handleObj is passed to all event handlers
-			handleObj = jQuery.extend({
-				type: type,
-				origType: tns[1],
-				data: data,
-				handler: handler,
-				guid: handler.guid,
-				selector: selector,
-				quick: quickParse( selector ),
-				namespace: namespaces.join(".")
-			}, handleObjIn );
-
-			// Init the event handler queue if we're the first
-			handlers = events[ type ];
-			if ( !handlers ) {
-				handlers = events[ type ] = [];
-				handlers.delegateCount = 0;
-
-				// Only use addEventListener/attachEvent if the special events handler returns false
-				if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
-					// Bind the global event handler to the element
-					if ( elem.addEventListener ) {
-						elem.addEventListener( type, eventHandle, false );
-
-					} else if ( elem.attachEvent ) {
-						elem.attachEvent( "on" + type, eventHandle );
-					}
-				}
-			}
-
-			if ( special.add ) {
-				special.add.call( elem, handleObj );
-
-				if ( !handleObj.handler.guid ) {
-					handleObj.handler.guid = handler.guid;
-				}
-			}
-
-			// Add to the element's handler list, delegates in front
-			if ( selector ) {
-				handlers.splice( handlers.delegateCount++, 0, handleObj );
-			} else {
-				handlers.push( handleObj );
-			}
-
-			// Keep track of which events have ever been used, for event optimization
-			jQuery.event.global[ type ] = true;
-		}
-
-		// Nullify elem to prevent memory leaks in IE
-		elem = null;
-	},
-
-	global: {},
-
-	// Detach an event or set of events from an element
-	remove: function( elem, types, handler, selector, mappedTypes ) {
-
-		var elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
-			t, tns, type, origType, namespaces, origCount,
-			j, events, special, handle, eventType, handleObj;
-
-		if ( !elemData || !(events = elemData.events) ) {
-			return;
-		}
-
-		// Once for each type.namespace in types; type may be omitted
-		types = jQuery.trim( hoverHack( types || "" ) ).split(" ");
-		for ( t = 0; t < types.length; t++ ) {
-			tns = rtypenamespace.exec( types[t] ) || [];
-			type = origType = tns[1];
-			namespaces = tns[2];
-
-			// Unbind all events (on this namespace, if provided) for the element
-			if ( !type ) {
-				for ( type in events ) {
-					jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
-				}
-				continue;
-			}
-
-			special = jQuery.event.special[ type ] || {};
-			type = ( selector? special.delegateType : special.bindType ) || type;
-			eventType = events[ type ] || [];
-			origCount = eventType.length;
-			namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.)?") + "(\\.|$)") : null;
-
-			// Remove matching events
-			for ( j = 0; j < eventType.length; j++ ) {
-				handleObj = eventType[ j ];
-
-				if ( ( mappedTypes || origType === handleObj.origType ) &&
-					 ( !handler || handler.guid === handleObj.guid ) &&
-					 ( !namespaces || namespaces.test( handleObj.namespace ) ) &&
-					 ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
-					eventType.splice( j--, 1 );
-
-					if ( handleObj.selector ) {
-						eventType.delegateCount--;
-					}
-					if ( special.remove ) {
-						special.remove.call( elem, handleObj );
-					}
-				}
-			}
-
-			// Remove generic event handler if we removed something and no more handlers exist
-			// (avoids potential for endless recursion during removal of special event handlers)
-			if ( eventType.length === 0 && origCount !== eventType.length ) {
-				if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
-					jQuery.removeEvent( elem, type, elemData.handle );
-				}
-
-				delete events[ type ];
-			}
-		}
-
-		// Remove the expando if it's no longer used
-		if ( jQuery.isEmptyObject( events ) ) {
-			handle = elemData.handle;
-			if ( handle ) {
-				handle.elem = null;
-			}
-
-			// removeData also checks for emptiness and clears the expando if empty
-			// so use it instead of delete
-			jQuery.removeData( elem, [ "events", "handle" ], true );
-		}
-	},
-
-	// Events that are safe to short-circuit if no handlers are attached.
-	// Native DOM events should not be added, they may have inline handlers.
-	customEvent: {
-		"getData": true,
-		"setData": true,
-		"changeData": true
-	},
-
-	trigger: function( event, data, elem, onlyHandlers ) {
-		// Don't do events on text and comment nodes
-		if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) {
-			return;
-		}
-
-		// Event object or event type
-		var type = event.type || event,
-			namespaces = [],
-			cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType;
-
-		// focus/blur morphs to focusin/out; ensure we're not firing them right now
-		if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
-			return;
-		}
-
-		if ( type.indexOf( "!" ) >= 0 ) {
-			// Exclusive events trigger only for the exact event (no namespaces)
-			type = type.slice(0, -1);
-			exclusive = true;
-		}
-
-		if ( type.indexOf( "." ) >= 0 ) {
-			// Namespaced trigger; create a regexp to match event type in handle()
-			namespaces = type.split(".");
-			type = namespaces.shift();
-			namespaces.sort();
-		}
-
-		if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) {
-			// No jQuery handlers for this event type, and it can't have inline handlers
-			return;
-		}
-
-		// Caller can pass in an Event, Object, or just an event type string
-		event = typeof event === "object" ?
-			// jQuery.Event object
-			event[ jQuery.expando ] ? event :
-			// Object literal
-			new jQuery.Event( type, event ) :
-			// Just the event type (string)
-			new jQuery.Event( type );
-
-		event.type = type;
-		event.isTrigger = true;
-		event.exclusive = exclusive;
-		event.namespace = namespaces.join( "." );
-		event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)") : null;
-		ontype = type.indexOf( ":" ) < 0 ? "on" + type : "";
-
-		// Handle a global trigger
-		if ( !elem ) {
-
-			// TODO: Stop taunting the data cache; remove global events and always attach to document
-			cache = jQuery.cache;
-			for ( i in cache ) {
-				if ( cache[ i ].events && cache[ i ].events[ type ] ) {
-					jQuery.event.trigger( event, data, cache[ i ].handle.elem, true );
-				}
-			}
-			return;
-		}
-
-		// Clean up the event in case it is being reused
-		event.result = undefined;
-		if ( !event.target ) {
-			event.target = elem;
-		}
-
-		// Clone any incoming data and prepend the event, creating the handler arg list
-		data = data != null ? jQuery.makeArray( data ) : [];
-		data.unshift( event );
-
-		// Allow special events to draw outside the lines
-		special = jQuery.event.special[ type ] || {};
-		if ( special.trigger && special.trigger.apply( elem, data ) === false ) {
-			return;
-		}
-
-		// Determine event propagation path in advance, per W3C events spec (#9951)
-		// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
-		eventPath = [[ elem, special.bindType || type ]];
-		if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
-
-			bubbleType = special.delegateType || type;
-			cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode;
-			old = null;
-			for ( ; cur; cur = cur.parentNode ) {
-				eventPath.push([ cur, bubbleType ]);
-				old = cur;
-			}
-
-			// Only add window if we got to document (e.g., not plain obj or detached DOM)
-			if ( old && old === elem.ownerDocument ) {
-				eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]);
-			}
-		}
-
-		// Fire handlers on the event path
-		for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) {
-
-			cur = eventPath[i][0];
-			event.type = eventPath[i][1];
-
-			handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
-			if ( handle ) {
-				handle.apply( cur, data );
-			}
-			// Note that this is a bare JS function and not a jQuery handler
-			handle = ontype && cur[ ontype ];
-			if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) {
-				event.preventDefault();
-			}
-		}
-		event.type = type;
-
-		// If nobody prevented the default action, do it now
-		if ( !onlyHandlers && !event.isDefaultPrevented() ) {
-
-			if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) &&
-				!(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
-
-				// Call a native DOM method on the target with the same name name as the event.
-				// Can't use an .isFunction() check here because IE6/7 fails that test.
-				// Don't do default actions on window, that's where global variables be (#6170)
-				// IE<9 dies on focus/blur to hidden element (#1486)
-				if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) {
-
-					// Don't re-trigger an onFOO event when we call its FOO() method
-					old = elem[ ontype ];
-
-					if ( old ) {
-						elem[ ontype ] = null;
-					}
-
-					// Prevent re-triggering of the same event, since we already bubbled it above
-					jQuery.event.triggered = type;
-					elem[ type ]();
-					jQuery.event.triggered = undefined;
-
-					if ( old ) {
-						elem[ ontype ] = old;
-					}
-				}
-			}
-		}
-
-		return event.result;
-	},
-
-	dispatch: function( event ) {
-
-		// Make a writable jQuery.Event from the native event object
-		event = jQuery.event.fix( event || window.event );
-
-		var handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []),
-			delegateCount = handlers.delegateCount,
-			args = [].slice.call( arguments, 0 ),
-			run_all = !event.exclusive && !event.namespace,
-			handlerQueue = [],
-			i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related;
-
-		// Use the fix-ed jQuery.Event rather than the (read-only) native event
-		args[0] = event;
-		event.delegateTarget = this;
-
-		// Determine handlers that should run if there are delegated events
-		// Avoid disabled elements in IE (#6911) and non-left-click bubbling in Firefox (#3861)
-		if ( delegateCount && !event.target.disabled && !(event.button && event.type === "click") ) {
-
-			// Pregenerate a single jQuery object for reuse with .is()
-			jqcur = jQuery(this);
-			jqcur.context = this.ownerDocument || this;
-
-			for ( cur = event.target; cur != this; cur = cur.parentNode || this ) {
-				selMatch = {};
-				matches = [];
-				jqcur[0] = cur;
-				for ( i = 0; i < delegateCount; i++ ) {
-					handleObj = handlers[ i ];
-					sel = handleObj.selector;
-
-					if ( selMatch[ sel ] === undefined ) {
-						selMatch[ sel ] = (
-							handleObj.quick ? quickIs( cur, handleObj.quick ) : jqcur.is( sel )
-						);
-					}
-					if ( selMatch[ sel ] ) {
-						matches.push( handleObj );
-					}
-				}
-				if ( matches.length ) {
-					handlerQueue.push({ elem: cur, matches: matches });
-				}
-			}
-		}
-
-		// Add the remaining (directly-bound) handlers
-		if ( handlers.length > delegateCount ) {
-			handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) });
-		}
-
-		// Run delegates first; they may want to stop propagation beneath us
-		for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) {
-			matched = handlerQueue[ i ];
-			event.currentTarget = matched.elem;
-
-			for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) {
-				handleObj = matched.matches[ j ];
-
-				// Triggered event must either 1) be non-exclusive and have no namespace, or
-				// 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
-				if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) {
-
-					event.data = handleObj.data;
-					event.handleObj = handleObj;
-
-					ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
-							.apply( matched.elem, args );
-
-					if ( ret !== undefined ) {
-						event.result = ret;
-						if ( ret === false ) {
-							event.preventDefault();
-							event.stopPropagation();
-						}
-					}
-				}
-			}
-		}
-
-		return event.result;
-	},
-
-	// Includes some event props shared by KeyEvent and MouseEvent
-	// *** attrChange attrName relatedNode srcElement  are not normalized, non-W3C, deprecated, will be removed in 1.8 ***
-	props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
-
-	fixHooks: {},
-
-	keyHooks: {
-		props: "char charCode key keyCode".split(" "),
-		filter: function( event, original ) {
-
-			// Add which for key events
-			if ( event.which == null ) {
-				event.which = original.charCode != null ? original.charCode : original.keyCode;
-			}
-
-			return event;
-		}
-	},
-
-	mouseHooks: {
-		props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
-		filter: function( event, original ) {
-			var eventDoc, doc, body,
-				button = original.button,
-				fromElement = original.fromElement;
-
-			// Calculate pageX/Y if missing and clientX/Y available
-			if ( event.pageX == null && original.clientX != null ) {
-				eventDoc = event.target.ownerDocument || document;
-				doc = eventDoc.documentElement;
-				body = eventDoc.body;
-
-				event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
-				event.pageY = original.clientY + ( doc && doc.scrollTop  || body && body.scrollTop  || 0 ) - ( doc && doc.clientTop  || body && body.clientTop  || 0 );
-			}
-
-			// Add relatedTarget, if necessary
-			if ( !event.relatedTarget && fromElement ) {
-				event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
-			}
-
-			// Add which for click: 1 === left; 2 === middle; 3 === right
-			// Note: button is not normalized, so don't use it
-			if ( !event.which && button !== undefined ) {
-				event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
-			}
-
-			return event;
-		}
-	},
-
-	fix: function( event ) {
-		if ( event[ jQuery.expando ] ) {
-			return event;
-		}
-
-		// Create a writable copy of the event object and normalize some properties
-		var i, prop,
-			originalEvent = event,
-			fixHook = jQuery.event.fixHooks[ event.type ] || {},
-			copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
-
-		event = jQuery.Event( originalEvent );
-
-		for ( i = copy.length; i; ) {
-			prop = copy[ --i ];
-			event[ prop ] = originalEvent[ prop ];
-		}
-
-		// Fix target property, if necessary (#1925, IE 6/7/8 & Safari2)
-		if ( !event.target ) {
-			event.target = originalEvent.srcElement || document;
-		}
-
-		// Target should not be a text node (#504, Safari)
-		if ( event.target.nodeType === 3 ) {
-			event.target = event.target.parentNode;
-		}
-
-		// For mouse/key events; add metaKey if it's not there (#3368, IE6/7/8)
-		if ( event.metaKey === undefined ) {
-			event.metaKey = event.ctrlKey;
-		}
-
-		return fixHook.filter? fixHook.filter( event, originalEvent ) : event;
-	},
-
-	special: {
-		ready: {
-			// Make sure the ready event is setup
-			setup: jQuery.bindReady
-		},
-
-		load: {
-			// Prevent triggered image.load events from bubbling to window.load
-			noBubble: true
-		},
-
-		focus: {
-			delegateType: "focusin"
-		},
-		blur: {
-			delegateType: "focusout"
-		},
-
-		beforeunload: {
-			setup: function( data, namespaces, eventHandle ) {
-				// We only want to do this special case on windows
-				if ( jQuery.isWindow( this ) ) {
-					this.onbeforeunload = eventHandle;
-				}
-			},
-
-			teardown: function( namespaces, eventHandle ) {
-				if ( this.onbeforeunload === eventHandle ) {
-					this.onbeforeunload = null;
-				}
-			}
-		}
-	},
-
-	simulate: function( type, elem, event, bubble ) {
-		// Piggyback on a donor event to simulate a different one.
-		// Fake originalEvent to avoid donor's stopPropagation, but if the
-		// simulated event prevents default then we do the same on the donor.
-		var e = jQuery.extend(
-			new jQuery.Event(),
-			event,
-			{ type: type,
-				isSimulated: true,
-				originalEvent: {}
-			}
-		);
-		if ( bubble ) {
-			jQuery.event.trigger( e, null, elem );
-		} else {
-			jQuery.event.dispatch.call( elem, e );
-		}
-		if ( e.isDefaultPrevented() ) {
-			event.preventDefault();
-		}
-	}
-};
-
-// Some plugins are using, but it's undocumented/deprecated and will be removed.
-// The 1.7 special event interface should provide all the hooks needed now.
-jQuery.event.handle = jQuery.event.dispatch;
-
-jQuery.removeEvent = document.removeEventListener ?
-	function( elem, type, handle ) {
-		if ( elem.removeEventListener ) {
-			elem.removeEventListener( type, handle, false );
-		}
-	} :
-	function( elem, type, handle ) {
-		if ( elem.detachEvent ) {
-			elem.detachEvent( "on" + type, handle );
-		}
-	};
-
-jQuery.Event = function( src, props ) {
-	// Allow instantiation without the 'new' keyword
-	if ( !(this instanceof jQuery.Event) ) {
-		return new jQuery.Event( src, props );
-	}
-
-	// Event object
-	if ( src && src.type ) {
-		this.originalEvent = src;
-		this.type = src.type;
-
-		// Events bubbling up the document may have been marked as prevented
-		// by a handler lower down the tree; reflect the correct value.
-		this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false ||
-			src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;
-
-	// Event type
-	} else {
-		this.type = src;
-	}
-
-	// Put explicitly provided properties onto the event object
-	if ( props ) {
-		jQuery.extend( this, props );
-	}
-
-	// Create a timestamp if incoming event doesn't have one
-	this.timeStamp = src && src.timeStamp || jQuery.now();
-
-	// Mark it as fixed
-	this[ jQuery.expando ] = true;
-};
-
-function returnFalse() {
-	return false;
-}
-function returnTrue() {
-	return true;
-}
-
-// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
-// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
-jQuery.Event.prototype = {
-	preventDefault: function() {
-		this.isDefaultPrevented = returnTrue;
-
-		var e = this.originalEvent;
-		if ( !e ) {
-			return;
-		}
-
-		// if preventDefault exists run it on the original event
-		if ( e.preventDefault ) {
-			e.preventDefault();
-
-		// otherwise set the returnValue property of the original event to false (IE)
-		} else {
-			e.returnValue = false;
-		}
-	},
-	stopPropagation: function() {
-		this.isPropagationStopped = returnTrue;
-
-		var e = this.originalEvent;
-		if ( !e ) {
-			return;
-		}
-		// if stopPropagation exists run it on the original event
-		if ( e.stopPropagation ) {
-			e.stopPropagation();
-		}
-		// otherwise set the cancelBubble property of the original event to true (IE)
-		e.cancelBubble = true;
-	},
-	stopImmediatePropagation: function() {
-		this.isImmediatePropagationStopped = returnTrue;
-		this.stopPropagation();
-	},
-	isDefaultPrevented: returnFalse,
-	isPropagationStopped: returnFalse,
-	isImmediatePropagationStopped: returnFalse
-};
-
-// Create mouseenter/leave events using mouseover/out and event-time checks
-jQuery.each({
-	mouseenter: "mouseover",
-	mouseleave: "mouseout"
-}, function( orig, fix ) {
-	jQuery.event.special[ orig ] = {
-		delegateType: fix,
-		bindType: fix,
-
-		handle: function( event ) {
-			var target = this,
-				related = event.relatedTarget,
-				handleObj = event.handleObj,
-				selector = handleObj.selector,
-				ret;
-
-			// For mousenter/leave call the handler if related is outside the target.
-			// NB: No relatedTarget if the mouse left/entered the browser window
-			if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
-				event.type = handleObj.origType;
-				ret = handleObj.handler.apply( this, arguments );
-				event.type = fix;
-			}
-			return ret;
-		}
-	};
-});
-
-// IE submit delegation
-if ( !jQuery.support.submitBubbles ) {
-
-	jQuery.event.special.submit = {
-		setup: function() {
-			// Only need this for delegated form submit events
-			if ( jQuery.nodeName( this, "form" ) ) {
-				return false;
-			}
-
-			// Lazy-add a submit handler when a descendant form may potentially be submitted
-			jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
-				// Node name check avoids a VML-related crash in IE (#9807)
-				var elem = e.target,
-					form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
-				if ( form && !form._submit_attached ) {
-					jQuery.event.add( form, "submit._submit", function( event ) {
-						// If form was submitted by the user, bubble the event up the tree
-						if ( this.parentNode && !event.isTrigger ) {
-							jQuery.event.simulate( "submit", this.parentNode, event, true );
-						}
-					});
-					form._submit_attached = true;
-				}
-			});
-			// return undefined since we don't need an event listener
-		},
-
-		teardown: function() {
-			// Only need this for delegated form submit events
-			if ( jQuery.nodeName( this, "form" ) ) {
-				return false;
-			}
-
-			// Remove delegated handlers; cleanData eventually reaps submit handlers attached above
-			jQuery.event.remove( this, "._submit" );
-		}
-	};
-}
-
-// IE change delegation and checkbox/radio fix
-if ( !jQuery.support.changeBubbles ) {
-
-	jQuery.event.special.change = {
-
-		setup: function() {
-
-			if ( rformElems.test( this.nodeName ) ) {
-				// IE doesn't fire change on a check/radio until blur; trigger it on click
-				// after a propertychange. Eat the blur-change in special.change.handle.
-				// This still fires onchange a second time for check/radio after blur.
-				if ( this.type === "checkbox" || this.type === "radio" ) {
-					jQuery.event.add( this, "propertychange._change", function( event ) {
-						if ( event.originalEvent.propertyName === "checked" ) {
-							this._just_changed = true;
-						}
-					});
-					jQuery.event.add( this, "click._change", function( event ) {
-						if ( this._just_changed && !event.isTrigger ) {
-							this._just_changed = false;
-							jQuery.event.simulate( "change", this, event, true );
-						}
-					});
-				}
-				return false;
-			}
-			// Delegated event; lazy-add a change handler on descendant inputs
-			jQuery.event.add( this, "beforeactivate._change", function( e ) {
-				var elem = e.target;
-
-				if ( rformElems.test( elem.nodeName ) && !elem._change_attached ) {
-					jQuery.event.add( elem, "change._change", function( event ) {
-						if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
-							jQuery.event.simulate( "change", this.parentNode, event, true );
-						}
-					});
-					elem._change_attached = true;
-				}
-			});
-		},
-
-		handle: function( event ) {
-			var elem = event.target;
-
-			// Swallow native change events from checkbox/radio, we already triggered them above
-			if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
-				return event.handleObj.handler.apply( this, arguments );
-			}
-		},
-
-		teardown: function() {
-			jQuery.event.remove( this, "._change" );
-
-			return rformElems.test( this.nodeName );
-		}
-	};
-}
-
-// Create "bubbling" focus and blur events
-if ( !jQuery.support.focusinBubbles ) {
-	jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
-
-		// Attach a single capturing handler while someone wants focusin/focusout
-		var attaches = 0,
-			handler = function( event ) {
-				jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
-			};
-
-		jQuery.event.special[ fix ] = {
-			setup: function() {
-				if ( attaches++ === 0 ) {
-					document.addEventListener( orig, handler, true );
-				}
-			},
-			teardown: function() {
-				if ( --attaches === 0 ) {
-					document.removeEventListener( orig, handler, true );
-				}
-			}
-		};
-	});
-}
-
-jQuery.fn.extend({
-
-	on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
-		var origFn, type;
-
-		// Types can be a map of types/handlers
-		if ( typeof types === "object" ) {
-			// ( types-Object, selector, data )
-			if ( typeof selector !== "string" ) {
-				// ( types-Object, data )
-				data = selector;
-				selector = undefined;
-			}
-			for ( type in types ) {
-				this.on( type, selector, data, types[ type ], one );
-			}
-			return this;
-		}
-
-		if ( data == null && fn == null ) {
-			// ( types, fn )
-			fn = selector;
-			data = selector = undefined;
-		} else if ( fn == null ) {
-			if ( typeof selector === "string" ) {
-				// ( types, selector, fn )
-				fn = data;
-				data = undefined;
-			} else {
-				// ( types, data, fn )
-				fn = data;
-				data = selector;
-				selector = undefined;
-			}
-		}
-		if ( fn === false ) {
-			fn = returnFalse;
-		} else if ( !fn ) {
-			return this;
-		}
-
-		if ( one === 1 ) {
-			origFn = fn;
-			fn = function( event ) {
-				// Can use an empty set, since event contains the info
-				jQuery().off( event );
-				return origFn.apply( this, arguments );
-			};
-			// Use same guid so caller can remove using origFn
-			fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
-		}
-		return this.each( function() {
-			jQuery.event.add( this, types, fn, data, selector );
-		});
-	},
-	one: function( types, selector, data, fn ) {
-		return this.on.call( this, types, selector, data, fn, 1 );
-	},
-	off: function( types, selector, fn ) {
-		if ( types && types.preventDefault && types.handleObj ) {
-			// ( event )  dispatched jQuery.Event
-			var handleObj = types.handleObj;
-			jQuery( types.delegateTarget ).off(
-				handleObj.namespace? handleObj.type + "." + handleObj.namespace : handleObj.type,
-				handleObj.selector,
-				handleObj.handler
-			);
-			return this;
-		}
-		if ( typeof types === "object" ) {
-			// ( types-object [, selector] )
-			for ( var type in types ) {
-				this.off( type, selector, types[ type ] );
-			}
-			return this;
-		}
-		if ( selector === false || typeof selector === "function" ) {
-			// ( types [, fn] )
-			fn = selector;
-			selector = undefined;
-		}
-		if ( fn === false ) {
-			fn = returnFalse;
-		}
-		return this.each(function() {
-			jQuery.event.remove( this, types, fn, selector );
-		});
-	},
-
-	bind: function( types, data, fn ) {
-		return this.on( types, null, data, fn );
-	},
-	unbind: function( types, fn ) {
-		return this.off( types, null, fn );
-	},
-
-	live: function( types, data, fn ) {
-		jQuery( this.context ).on( types, this.selector, data, fn );
-		return this;
-	},
-	die: function( types, fn ) {
-		jQuery( this.context ).off( types, this.selector || "**", fn );
-		return this;
-	},
-
-	delegate: function( selector, types, data, fn ) {
-		return this.on( types, selector, data, fn );
-	},
-	undelegate: function( selector, types, fn ) {
-		// ( namespace ) or ( selector, types [, fn] )
-		return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector, fn );
-	},
-
-	trigger: function( type, data ) {
-		return this.each(function() {
-			jQuery.event.trigger( type, data, this );
-		});
-	},
-	triggerHandler: function( type, data ) {
-		if ( this[0] ) {
-			return jQuery.event.trigger( type, data, this[0], true );
-		}
-	},
-
-	toggle: function( fn ) {
-		// Save reference to arguments for access in closure
-		var args = arguments,
-			guid = fn.guid || jQuery.guid++,
-			i = 0,
-			toggler = function( event ) {
-				// Figure out which function to execute
-				var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
-				jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
-
-				// Make sure that clicks stop
-				event.preventDefault();
-
-				// and execute the function
-				return args[ lastToggle ].apply( this, arguments ) || false;
-			};
-
-		// link all the functions, so any of them can unbind this click handler
-		toggler.guid = guid;
-		while ( i < args.length ) {
-			args[ i++ ].guid = guid;
-		}
-
-		return this.click( toggler );
-	},
-
-	hover: function( fnOver, fnOut ) {
-		return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
-	}
-});
-
-jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
-	"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
-	"change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
-
-	// Handle event binding
-	jQuery.fn[ name ] = function( data, fn ) {
-		if ( fn == null ) {
-			fn = data;
-			data = null;
-		}
-
-		return arguments.length > 0 ?
-			this.on( name, null, data, fn ) :
-			this.trigger( name );
-	};
-
-	if ( jQuery.attrFn ) {
-		jQuery.attrFn[ name ] = true;
-	}
-
-	if ( rkeyEvent.test( name ) ) {
-		jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks;
-	}
-
-	if ( rmouseEvent.test( name ) ) {
-		jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks;
-	}
-});
-
-
-
-/*!
- * Sizzle CSS Selector Engine
- *  Copyright 2011, The Dojo Foundation
- *  Released under the MIT, BSD, and GPL Licenses.
- *  More information: http://sizzlejs.com/
- */
-(function(){
-
-var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
-	expando = "sizcache" + (Math.random() + '').replace('.', ''),
-	done = 0,
-	toString = Object.prototype.toString,
-	hasDuplicate = false,
-	baseHasDuplicate = true,
-	rBackslash = /\\/g,
-	rReturn = /\r\n/g,
-	rNonWord = /\W/;
-
-// Here we check if the JavaScript engine is using some sort of
-// optimization where it does not always call our comparision
-// function. If that is the case, discard the hasDuplicate value.
-//   Thus far that includes Google Chrome.
-[0, 0].sort(function() {
-	baseHasDuplicate = false;
-	return 0;
-});
-
-var Sizzle = function( selector, context, results, seed ) {
-	results = results || [];
-	context = context || document;
-
-	var origContext = context;
-
-	if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
-		return [];
-	}
-	
-	if ( !selector || typeof selector !== "string" ) {
-		return results;
-	}
-
-	var m, set, checkSet, extra, ret, cur, pop, i,
-		prune = true,
-		contextXML = Sizzle.isXML( context ),
-		parts = [],
-		soFar = selector;
-	
-	// Reset the position of the chunker regexp (start from head)
-	do {
-		chunker.exec( "" );
-		m = chunker.exec( soFar );
-
-		if ( m ) {
-			soFar = m[3];
-		
-			parts.push( m[1] );
-		
-			if ( m[2] ) {
-				extra = m[3];
-				break;
-			}
-		}
-	} while ( m );
-
-	if ( parts.length > 1 && origPOS.exec( selector ) ) {
-
-		if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
-			set = posProcess( parts[0] + parts[1], context, seed );
-
-		} else {
-			set = Expr.relative[ parts[0] ] ?
-				[ context ] :
-				Sizzle( parts.shift(), context );
-
-			while ( parts.length ) {
-				selector = parts.shift();
-
-				if ( Expr.relative[ selector ] ) {
-					selector += parts.shift();
-				}
-				
-				set = posProcess( selector, set, seed );
-			}
-		}
-
-	} else {
-		// Take a shortcut and set the context if the root selector is an ID
-		// (but not if it'll be faster if the inner selector is an ID)
-		if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
-				Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
-
-			ret = Sizzle.find( parts.shift(), context, contextXML );
-			context = ret.expr ?
-				Sizzle.filter( ret.expr, ret.set )[0] :
-				ret.set[0];
-		}
-
-		if ( context ) {
-			ret = seed ?
-				{ expr: parts.pop(), set: makeArray(seed) } :
-				Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
-
-			set = ret.expr ?
-				Sizzle.filter( ret.expr, ret.set ) :
-				ret.set;
-
-			if ( parts.length > 0 ) {
-				checkSet = makeArray( set );
-
-			} else {
-				prune = false;
-			}
-
-			while ( parts.length ) {
-				cur = parts.pop();
-				pop = cur;
-
-				if ( !Expr.relative[ cur ] ) {
-					cur = "";
-				} else {
-					pop = parts.pop();
-				}
-
-				if ( pop == null ) {
-					pop = context;
-				}
-
-				Expr.relative[ cur ]( checkSet, pop, contextXML );
-			}
-
-		} else {
-			checkSet = parts = [];
-		}
-	}
-
-	if ( !checkSet ) {
-		checkSet = set;
-	}
-
-	if ( !checkSet ) {
-		Sizzle.error( cur || selector );
-	}
-
-	if ( toString.call(checkSet) === "[object Array]" ) {
-		if ( !prune ) {
-			results.push.apply( results, checkSet );
-
-		} else if ( context && context.nodeType === 1 ) {
-			for ( i = 0; checkSet[i] != null; i++ ) {
-				if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) {
-					results.push( set[i] );
-				}
-			}
-
-		} else {
-			for ( i = 0; checkSet[i] != null; i++ ) {
-				if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
-					results.push( set[i] );
-				}
-			}
-		}
-
-	} else {
-		makeArray( checkSet, results );
-	}
-
-	if ( extra ) {
-		Sizzle( extra, origContext, results, seed );
-		Sizzle.uniqueSort( results );
-	}
-
-	return results;
-};
-
-Sizzle.uniqueSort = function( results ) {
-	if ( sortOrder ) {
-		hasDuplicate = baseHasDuplicate;
-		results.sort( sortOrder );
-
-		if ( hasDuplicate ) {
-			for ( var i = 1; i < results.length; i++ ) {
-				if ( results[i] === results[ i - 1 ] ) {
-					results.splice( i--, 1 );
-				}
-			}
-		}
-	}
-
-	return results;
-};
-
-Sizzle.matches = function( expr, set ) {
-	return Sizzle( expr, null, null, set );
-};
-
-Sizzle.matchesSelector = function( node, expr ) {
-	return Sizzle( expr, null, null, [node] ).length > 0;
-};
-
-Sizzle.find = function( expr, context, isXML ) {
-	var set, i, len, match, type, left;
-
-	if ( !expr ) {
-		return [];
-	}
-
-	for ( i = 0, len = Expr.order.length; i < len; i++ ) {
-		type = Expr.order[i];
-		
-		if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
-			left = match[1];
-			match.splice( 1, 1 );
-
-			if ( left.substr( left.length - 1 ) !== "\\" ) {
-				match[1] = (match[1] || "").replace( rBackslash, "" );
-				set = Expr.find[ type ]( match, context, isXML );
-
-				if ( set != null ) {
-					expr = expr.replace( Expr.match[ type ], "" );
-					break;
-				}
-			}
-		}
-	}
-
-	if ( !set ) {
-		set = typeof context.getElementsByTagName !== "undefined" ?
-			context.getElementsByTagName( "*" ) :
-			[];
-	}
-
-	return { set: set, expr: expr };
-};
-
-Sizzle.filter = function( expr, set, inplace, not ) {
-	var match, anyFound,
-		type, found, item, filter, left,
-		i, pass,
-		old = expr,
-		result = [],
-		curLoop = set,
-		isXMLFilter = set && set[0] && Sizzle.isXML( set[0] );
-
-	while ( expr && set.length ) {
-		for ( type in Expr.filter ) {
-			if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
-				filter = Expr.filter[ type ];
-				left = match[1];
-
-				anyFound = false;
-
-				match.splice(1,1);
-
-				if ( left.substr( left.length - 1 ) === "\\" ) {
-					continue;
-				}
-
-				if ( curLoop === result ) {
-					result = [];
-				}
-
-				if ( Expr.preFilter[ type ] ) {
-					match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
-
-					if ( !match ) {
-						anyFound = found = true;
-
-					} else if ( match === true ) {
-						continue;
-					}
-				}
-
-				if ( match ) {
-					for ( i = 0; (item = curLoop[i]) != null; i++ ) {
-						if ( item ) {
-							found = filter( item, match, i, curLoop );
-							pass = not ^ found;
-
-							if ( inplace && found != null ) {
-								if ( pass ) {
-									anyFound = true;
-
-								} else {
-									curLoop[i] = false;
-								}
-
-							} else if ( pass ) {
-								result.push( item );
-								anyFound = true;
-							}
-						}
-					}
-				}
-
-				if ( found !== undefined ) {
-					if ( !inplace ) {
-						curLoop = result;
-					}
-
-					expr = expr.replace( Expr.match[ type ], "" );
-
-					if ( !anyFound ) {
-						return [];
-					}
-
-					break;
-				}
-			}
-		}
-
-		// Improper expression
-		if ( expr === old ) {
-			if ( anyFound == null ) {
-				Sizzle.error( expr );
-
-			} else {
-				break;
-			}
-		}
-
-		old = expr;
-	}
-
-	return curLoop;
-};
-
-Sizzle.error = function( msg ) {
-	throw new Error( "Syntax error, unrecognized expression: " + msg );
-};
-
-/**
- * Utility function for retreiving the text value of an array of DOM nodes
- * @param {Array|Element} elem
- */
-var getText = Sizzle.getText = function( elem ) {
-    var i, node,
-		nodeType = elem.nodeType,
-		ret = "";
-
-	if ( nodeType ) {
-		if ( nodeType === 1 || nodeType === 9 ) {
-			// Use textContent || innerText for elements
-			if ( typeof elem.textContent === 'string' ) {
-				return elem.textContent;
-			} else if ( typeof elem.innerText === 'string' ) {
-				// Replace IE's carriage returns
-				return elem.innerText.replace( rReturn, '' );
-			} else {
-				// Traverse it's children
-				for ( elem = elem.firstChild; elem; elem = elem.nextSibling) {
-					ret += getText( elem );
-				}
-			}
-		} else if ( nodeType === 3 || nodeType === 4 ) {
-			return elem.nodeValue;
-		}
-	} else {
-
-		// If no nodeType, this is expected to be an array
-		for ( i = 0; (node = elem[i]); i++ ) {
-			// Do not traverse comment nodes
-			if ( node.nodeType !== 8 ) {
-				ret += getText( node );
-			}
-		}
-	}
-	return ret;
-};
-
-var Expr = Sizzle.selectors = {
-	order: [ "ID", "NAME", "TAG" ],
-
-	match: {
-		ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
-		CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
-		NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,
-		ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,
-		TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,
-		CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,
-		POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,
-		PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
-	},
-
-	leftMatch: {},
-
-	attrMap: {
-		"class": "className",
-		"for": "htmlFor"
-	},
-
-	attrHandle: {
-		href: function( elem ) {
-			return elem.getAttribute( "href" );
-		},
-		type: function( elem ) {
-			return elem.getAttribute( "type" );
-		}
-	},
-
-	relative: {
-		"+": function(checkSet, part){
-			var isPartStr = typeof part === "string",
-				isTag = isPartStr && !rNonWord.test( part ),
-				isPartStrNotTag = isPartStr && !isTag;
-
-			if ( isTag ) {
-				part = part.toLowerCase();
-			}
-
-			for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
-				if ( (elem = checkSet[i]) ) {
-					while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
-
-					checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?
-						elem || false :
-						elem === part;
-				}
-			}
-
-			if ( isPartStrNotTag ) {
-				Sizzle.filter( part, checkSet, true );
-			}
-		},
-
-		">": function( checkSet, part ) {
-			var elem,
-				isPartStr = typeof part === "string",
-				i = 0,
-				l = checkSet.length;
-
-			if ( isPartStr && !rNonWord.test( part ) ) {
-				part = part.toLowerCase();
-
-				for ( ; i < l; i++ ) {
-					elem = checkSet[i];
-
-					if ( elem ) {
-						var parent = elem.parentNode;
-						checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
-					}
-				}
-
-			} else {
-				for ( ; i < l; i++ ) {
-					elem = checkSet[i];
-
-					if ( elem ) {
-						checkSet[i] = isPartStr ?
-							elem.parentNode :
-							elem.parentNode === part;
-					}
-				}
-
-				if ( isPartStr ) {
-					Sizzle.filter( part, checkSet, true );
-				}
-			}
-		},
-
-		"": function(checkSet, part, isXML){
-			var nodeCheck,
-				doneName = done++,
-				checkFn = dirCheck;
-
-			if ( typeof part === "string" && !rNonWord.test( part ) ) {
-				part = part.toLowerCase();
-				nodeCheck = part;
-				checkFn = dirNodeCheck;
-			}
-
-			checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML );
-		},
-
-		"~": function( checkSet, part, isXML ) {
-			var nodeCheck,
-				doneName = done++,
-				checkFn = dirCheck;
-
-			if ( typeof part === "string" && !rNonWord.test( part ) ) {
-				part = part.toLowerCase();
-				nodeCheck = part;
-				checkFn = dirNodeCheck;
-			}
-
-			checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML );
-		}
-	},
-
-	find: {
-		ID: function( match, context, isXML ) {
-			if ( typeof context.getElementById !== "undefined" && !isXML ) {
-				var m = context.getElementById(match[1]);
-				// Check parentNode to catch when Blackberry 4.6 returns
-				// nodes that are no longer in the document #6963
-				return m && m.parentNode ? [m] : [];
-			}
-		},
-
-		NAME: function( match, context ) {
-			if ( typeof context.getElementsByName !== "undefined" ) {
-				var ret = [],
-					results = context.getElementsByName( match[1] );
-
-				for ( var i = 0, l = results.length; i < l; i++ ) {
-					if ( results[i].getAttribute("name") === match[1] ) {
-						ret.push( results[i] );
-					}
-				}
-
-				return ret.length === 0 ? null : ret;
-			}
-		},
-
-		TAG: function( match, context ) {
-			if ( typeof context.getElementsByTagName !== "undefined" ) {
-				return context.getElementsByTagName( match[1] );
-			}
-		}
-	},
-	preFilter: {
-		CLASS: function( match, curLoop, inplace, result, not, isXML ) {
-			match = " " + match[1].replace( rBackslash, "" ) + " ";
-
-			if ( isXML ) {
-				return match;
-			}
-
-			for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
-				if ( elem ) {
-					if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) {
-						if ( !inplace ) {
-							result.push( elem );
-						}
-
-					} else if ( inplace ) {
-						curLoop[i] = false;
-					}
-				}
-			}
-
-			return false;
-		},
-
-		ID: function( match ) {
-			return match[1].replace( rBackslash, "" );
-		},
-
-		TAG: function( match, curLoop ) {
-			return match[1].replace( rBackslash, "" ).toLowerCase();
-		},
-
-		CHILD: function( match ) {
-			if ( match[1] === "nth" ) {
-				if ( !match[2] ) {
-					Sizzle.error( match[0] );
-				}
-
-				match[2] = match[2].replace(/^\+|\s*/g, '');
-
-				// parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
-				var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec(
-					match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||
-					!/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
-
-				// calculate the numbers (first)n+(last) including if they are negative
-				match[2] = (test[1] + (test[2] || 1)) - 0;
-				match[3] = test[3] - 0;
-			}
-			else if ( match[2] ) {
-				Sizzle.error( match[0] );
-			}
-
-			// TODO: Move to normal caching system
-			match[0] = done++;
-
-			return match;
-		},
-
-		ATTR: function( match, curLoop, inplace, result, not, isXML ) {
-			var name = match[1] = match[1].replace( rBackslash, "" );
-			
-			if ( !isXML && Expr.attrMap[name] ) {
-				match[1] = Expr.attrMap[name];
-			}
-
-			// Handle if an un-quoted value was used
-			match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" );
-
-			if ( match[2] === "~=" ) {
-				match[4] = " " + match[4] + " ";
-			}
-
-			return match;
-		},
-
-		PSEUDO: function( match, curLoop, inplace, result, not ) {
-			if ( match[1] === "not" ) {
-				// If we're dealing with a complex expression, or a simple one
-				if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
-					match[3] = Sizzle(match[3], null, null, curLoop);
-
-				} else {
-					var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
-
-					if ( !inplace ) {
-						result.push.apply( result, ret );
-					}
-
-					return false;
-				}
-
-			} else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
-				return true;
-			}
-			
-			return match;
-		},
-
-		POS: function( match ) {
-			match.unshift( true );
-
-			return match;
-		}
-	},
-	
-	filters: {
-		enabled: function( elem ) {
-			return elem.disabled === false && elem.type !== "hidden";
-		},
-
-		disabled: function( elem ) {
-			return elem.disabled === true;
-		},
-
-		checked: function( elem ) {
-			return elem.checked === true;
-		},
-		
-		selected: function( elem ) {
-			// Accessing this property makes selected-by-default
-			// options in Safari work properly
-			if ( elem.parentNode ) {
-				elem.parentNode.selectedIndex;
-			}
-			
-			return elem.selected === true;
-		},
-
-		parent: function( elem ) {
-			return !!elem.firstChild;
-		},
-
-		empty: function( elem ) {
-			return !elem.firstChild;
-		},
-
-		has: function( elem, i, match ) {
-			return !!Sizzle( match[3], elem ).length;
-		},
-
-		header: function( elem ) {
-			return (/h\d/i).test( elem.nodeName );
-		},
-
-		text: function( elem ) {
-			var attr = elem.getAttribute( "type" ), type = elem.type;
-			// IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) 
-			// use getAttribute instead to test this case
-			return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null );
-		},
-
-		radio: function( elem ) {
-			return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type;
-		},
-
-		checkbox: function( elem ) {
-			return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type;
-		},
-
-		file: function( elem ) {
-			return elem.nodeName.toLowerCase() === "input" && "file" === elem.type;
-		},
-
-		password: function( elem ) {
-			return elem.nodeName.toLowerCase() === "input" && "password" === elem.type;
-		},
-
-		submit: function( elem ) {
-			var name = elem.nodeName.toLowerCase();
-			return (name === "input" || name === "button") && "submit" === elem.type;
-		},
-
-		image: function( elem ) {
-			return elem.nodeName.toLowerCase() === "input" && "image" === elem.type;
-		},
-
-		reset: function( elem ) {
-			var name = elem.nodeName.toLowerCase();
-			return (name === "input" || name === "button") && "reset" === elem.type;
-		},
-
-		button: function( elem ) {
-			var name = elem.nodeName.toLowerCase();
-			return name === "input" && "button" === elem.type || name === "button";
-		},
-
-		input: function( elem ) {
-			return (/input|select|textarea|button/i).test( elem.nodeName );
-		},
-
-		focus: function( elem ) {
-			return elem === elem.ownerDocument.activeElement;
-		}
-	},
-	setFilters: {
-		first: function( elem, i ) {
-			return i === 0;
-		},
-
-		last: function( elem, i, match, array ) {
-			return i === array.length - 1;
-		},
-
-		even: function( elem, i ) {
-			return i % 2 === 0;
-		},
-
-		odd: function( elem, i ) {
-			return i % 2 === 1;
-		},
-
-		lt: function( elem, i, match ) {
-			return i < match[3] - 0;
-		},
-
-		gt: function( elem, i, match ) {
-			return i > match[3] - 0;
-		},
-
-		nth: function( elem, i, match ) {
-			return match[3] - 0 === i;
-		},
-
-		eq: function( elem, i, match ) {
-			return match[3] - 0 === i;
-		}
-	},
-	filter: {
-		PSEUDO: function( elem, match, i, array ) {
-			var name = match[1],
-				filter = Expr.filters[ name ];
-
-			if ( filter ) {
-				return filter( elem, i, match, array );
-
-			} else if ( name === "contains" ) {
-				return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0;
-
-			} else if ( name === "not" ) {
-				var not = match[3];
-
-				for ( var j = 0, l = not.length; j < l; j++ ) {
-					if ( not[j] === elem ) {
-						return false;
-					}
-				}
-
-				return true;
-
-			} else {
-				Sizzle.error( name );
-			}
-		},
-
-		CHILD: function( elem, match ) {
-			var first, last,
-				doneName, parent, cache,
-				count, diff,
-				type = match[1],
-				node = elem;
-
-			switch ( type ) {
-				case "only":
-				case "first":
-					while ( (node = node.previousSibling) )	 {
-						if ( node.nodeType === 1 ) { 
-							return false; 
-						}
-					}
-
-					if ( type === "first" ) { 
-						return true; 
-					}
-
-					node = elem;
-
-				case "last":
-					while ( (node = node.nextSibling) )	 {
-						if ( node.nodeType === 1 ) { 
-							return false; 
-						}
-					}
-
-					return true;
-
-				case "nth":
-					first = match[2];
-					last = match[3];
-
-					if ( first === 1 && last === 0 ) {
-						return true;
-					}
-					
-					doneName = match[0];
-					parent = elem.parentNode;
-	
-					if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) {
-						count = 0;
-						
-						for ( node = parent.firstChild; node; node = node.nextSibling ) {
-							if ( node.nodeType === 1 ) {
-								node.nodeIndex = ++count;
-							}
-						} 
-
-						parent[ expando ] = doneName;
-					}
-					
-					diff = elem.nodeIndex - last;
-
-					if ( first === 0 ) {
-						return diff === 0;
-
-					} else {
-						return ( diff % first === 0 && diff / first >= 0 );
-					}
-			}
-		},
-
-		ID: function( elem, match ) {
-			return elem.nodeType === 1 && elem.getAttribute("id") === match;
-		},
-
-		TAG: function( elem, match ) {
-			return (match === "*" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match;
-		},
-		
-		CLASS: function( elem, match ) {
-			return (" " + (elem.className || elem.getAttribute("class")) + " ")
-				.indexOf( match ) > -1;
-		},
-
-		ATTR: function( elem, match ) {
-			var name = match[1],
-				result = Sizzle.attr ?
-					Sizzle.attr( elem, name ) :
-					Expr.attrHandle[ name ] ?
-					Expr.attrHandle[ name ]( elem ) :
-					elem[ name ] != null ?
-						elem[ name ] :
-						elem.getAttribute( name ),
-				value = result + "",
-				type = match[2],
-				check = match[4];
-
-			return result == null ?
-				type === "!=" :
-				!type && Sizzle.attr ?
-				result != null :
-				type === "=" ?
-				value === check :
-				type === "*=" ?
-				value.indexOf(check) >= 0 :
-				type === "~=" ?
-				(" " + value + " ").indexOf(check) >= 0 :
-				!check ?
-				value && result !== false :
-				type === "!=" ?
-				value !== check :
-				type === "^=" ?
-				value.indexOf(check) === 0 :
-				type === "$=" ?
-				value.substr(value.length - check.length) === check :
-				type === "|=" ?
-				value === check || value.substr(0, check.length + 1) === check + "-" :
-				false;
-		},
-
-		POS: function( elem, match, i, array ) {
-			var name = match[2],
-				filter = Expr.setFilters[ name ];
-
-			if ( filter ) {
-				return filter( elem, i, match, array );
-			}
-		}
-	}
-};
-
-var origPOS = Expr.match.POS,
-	fescape = function(all, num){
-		return "\\" + (num - 0 + 1);
-	};
-
-for ( var type in Expr.match ) {
-	Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) );
-	Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) );
-}
-
-var makeArray = function( array, results ) {
-	array = Array.prototype.slice.call( array, 0 );
-
-	if ( results ) {
-		results.push.apply( results, array );
-		return results;
-	}
-	
-	return array;
-};
-
-// Perform a simple check to determine if the browser is capable of
-// converting a NodeList to an array using builtin methods.
-// Also verifies that the returned array holds DOM nodes
-// (which is not the case in the Blackberry browser)
-try {
-	Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;
-
-// Provide a fallback method if it does not work
-} catch( e ) {
-	makeArray = function( array, results ) {
-		var i = 0,
-			ret = results || [];
-
-		if ( toString.call(array) === "[object Array]" ) {
-			Array.prototype.push.apply( ret, array );
-
-		} else {
-			if ( typeof array.length === "number" ) {
-				for ( var l = array.length; i < l; i++ ) {
-					ret.push( array[i] );
-				}
-
-			} else {
-				for ( ; array[i]; i++ ) {
-					ret.push( array[i] );
-				}
-			}
-		}
-
-		return ret;
-	};
-}
-
-var sortOrder, siblingCheck;
-
-if ( document.documentElement.compareDocumentPosition ) {
-	sortOrder = function( a, b ) {
-		if ( a === b ) {
-			hasDuplicate = true;
-			return 0;
-		}
-
-		if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
-			return a.compareDocumentPosition ? -1 : 1;
-		}
-
-		return a.compareDocumentPosition(b) & 4 ? -1 : 1;
-	};
-
-} else {
-	sortOrder = function( a, b ) {
-		// The nodes are identical, we can exit early
-		if ( a === b ) {
-			hasDuplicate = true;
-			return 0;
-
-		// Fallback to using sourceIndex (in IE) if it's available on both nodes
-		} else if ( a.sourceIndex && b.sourceIndex ) {
-			return a.sourceIndex - b.sourceIndex;
-		}
-
-		var al, bl,
-			ap = [],
-			bp = [],
-			aup = a.parentNode,
-			bup = b.parentNode,
-			cur = aup;
-
-		// If the nodes are siblings (or identical) we can do a quick check
-		if ( aup === bup ) {
-			return siblingCheck( a, b );
-
-		// If no parents were found then the nodes are disconnected
-		} else if ( !aup ) {
-			return -1;
-
-		} else if ( !bup ) {
-			return 1;
-		}
-
-		// Otherwise they're somewhere else in the tree so we need
-		// to build up a full list of the parentNodes for comparison
-		while ( cur ) {
-			ap.unshift( cur );
-			cur = cur.parentNode;
-		}
-
-		cur = bup;
-
-		while ( cur ) {
-			bp.unshift( cur );
-			cur = cur.parentNode;
-		}
-
-		al = ap.length;
-		bl = bp.length;
-
-		// Start walking down the tree looking for a discrepancy
-		for ( var i = 0; i < al && i < bl; i++ ) {
-			if ( ap[i] !== bp[i] ) {
-				return siblingCheck( ap[i], bp[i] );
-			}
-		}
-
-		// We ended someplace up the tree so do a sibling check
-		return i === al ?
-			siblingCheck( a, bp[i], -1 ) :
-			siblingCheck( ap[i], b, 1 );
-	};
-
-	siblingCheck = function( a, b, ret ) {
-		if ( a === b ) {
-			return ret;
-		}
-
-		var cur = a.nextSibling;
-
-		while ( cur ) {
-			if ( cur === b ) {
-				return -1;
-			}
-
-			cur = cur.nextSibling;
-		}
-
-		return 1;
-	};
-}
-
-// Check to see if the browser returns elements by name when
-// querying by getElementById (and provide a workaround)
-(function(){
-	// We're going to inject a fake input element with a specified name
-	var form = document.createElement("div"),
-		id = "script" + (new Date()).getTime(),
-		root = document.documentElement;
-
-	form.innerHTML = "<a name='" + id + "'/>";
-
-	// Inject it into the root element, check its status, and remove it quickly
-	root.insertBefore( form, root.firstChild );
-
-	// The workaround has to do additional checks after a getElementById
-	// Which slows things down for other browsers (hence the branching)
-	if ( document.getElementById( id ) ) {
-		Expr.find.ID = function( match, context, isXML ) {
-			if ( typeof context.getElementById !== "undefined" && !isXML ) {
-				var m = context.getElementById(match[1]);
-
-				return m ?
-					m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ?
-						[m] :
-						undefined :
-					[];
-			}
-		};
-
-		Expr.filter.ID = function( elem, match ) {
-			var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
-
-			return elem.nodeType === 1 && node && node.nodeValue === match;
-		};
-	}
-
-	root.removeChild( form );
-
-	// release memory in IE
-	root = form = null;
-})();
-
-(function(){
-	// Check to see if the browser returns only elements
-	// when doing getElementsByTagName("*")
-
-	// Create a fake element
-	var div = document.createElement("div");
-	div.appendChild( document.createComment("") );
-
-	// Make sure no comments are found
-	if ( div.getElementsByTagName("*").length > 0 ) {
-		Expr.find.TAG = function( match, context ) {
-			var results = context.getElementsByTagName( match[1] );
-
-			// Filter out possible comments
-			if ( match[1] === "*" ) {
-				var tmp = [];
-
-				for ( var i = 0; results[i]; i++ ) {
-					if ( results[i].nodeType === 1 ) {
-						tmp.push( results[i] );
-					}
-				}
-
-				results = tmp;
-			}
-
-			return results;
-		};
-	}
-
-	// Check to see if an attribute returns normalized href attributes
-	div.innerHTML = "<a href='#'></a>";
-
-	if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
-			div.firstChild.getAttribute("href") !== "#" ) {
-
-		Expr.attrHandle.href = function( elem ) {
-			return elem.getAttribute( "href", 2 );
-		};
-	}
-
-	// release memory in IE
-	div = null;
-})();
-
-if ( document.querySelectorAll ) {
-	(function(){
-		var oldSizzle = Sizzle,
-			div = document.createElement("div"),
-			id = "__sizzle__";
-
-		div.innerHTML = "<p class='TEST'></p>";
-
-		// Safari can't handle uppercase or unicode characters when
-		// in quirks mode.
-		if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
-			return;
-		}
-	
-		Sizzle = function( query, context, extra, seed ) {
-			context = context || document;
-
-			// Only use querySelectorAll on non-XML documents
-			// (ID selectors don't work in non-HTML documents)
-			if ( !seed && !Sizzle.isXML(context) ) {
-				// See if we find a selector to speed up
-				var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query );
-				
-				if ( match && (context.nodeType === 1 || context.nodeType === 9) ) {
-					// Speed-up: Sizzle("TAG")
-					if ( match[1] ) {
-						return makeArray( context.getElementsByTagName( query ), extra );
-					
-					// Speed-up: Sizzle(".CLASS")
-					} else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) {
-						return makeArray( context.getElementsByClassName( match[2] ), extra );
-					}
-				}
-				
-				if ( context.nodeType === 9 ) {
-					// Speed-up: Sizzle("body")
-					// The body element only exists once, optimize finding it
-					if ( query === "body" && context.body ) {
-						return makeArray( [ context.body ], extra );
-						
-					// Speed-up: Sizzle("#ID")
-					} else if ( match && match[3] ) {
-						var elem = context.getElementById( match[3] );
-
-						// Check parentNode to catch when Blackberry 4.6 returns
-						// nodes that are no longer in the document #6963
-						if ( elem && elem.parentNode ) {
-							// Handle the case where IE and Opera return items
-							// by name instead of ID
-							if ( elem.id === match[3] ) {
-								return makeArray( [ elem ], extra );
-							}
-							
-						} else {
-							return makeArray( [], extra );
-						}
-					}
-					
-					try {
-						return makeArray( context.querySelectorAll(query), extra );
-					} catch(qsaError) {}
-
-				// qSA works strangely on Element-rooted queries
-				// We can work around this by specifying an extra ID on the root
-				// and working up from there (Thanks to Andrew Dupont for the technique)
-				// IE 8 doesn't work on object elements
-				} else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
-					var oldContext = context,
-						old = context.getAttribute( "id" ),
-						nid = old || id,
-						hasParent = context.parentNode,
-						relativeHierarchySelector = /^\s*[+~]/.test( query );
-
-					if ( !old ) {
-						context.setAttribute( "id", nid );
-					} else {
-						nid = nid.replace( /'/g, "\\$&" );
-					}
-					if ( relativeHierarchySelector && hasParent ) {
-						context = context.parentNode;
-					}
-
-					try {
-						if ( !relativeHierarchySelector || hasParent ) {
-							return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra );
-						}
-
-					} catch(pseudoError) {
-					} finally {
-						if ( !old ) {
-							oldContext.removeAttribute( "id" );
-						}
-					}
-				}
-			}
-		
-			return oldSizzle(query, context, extra, seed);
-		};
-
-		for ( var prop in oldSizzle ) {
-			Sizzle[ prop ] = oldSizzle[ prop ];
-		}
-
-		// release memory in IE
-		div = null;
-	})();
-}
-
-(function(){
-	var html = document.documentElement,
-		matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector;
-
-	if ( matches ) {
-		// Check to see if it's possible to do matchesSelector
-		// on a disconnected node (IE 9 fails this)
-		var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ),
-			pseudoWorks = false;
-
-		try {
-			// This should fail with an exception
-			// Gecko does not error, returns false instead
-			matches.call( document.documentElement, "[test!='']:sizzle" );
-	
-		} catch( pseudoError ) {
-			pseudoWorks = true;
-		}
-
-		Sizzle.matchesSelector = function( node, expr ) {
-			// Make sure that attribute selectors are quoted
-			expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']");
-
-			if ( !Sizzle.isXML( node ) ) {
-				try { 
-					if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) {
-						var ret = matches.call( node, expr );
-
-						// IE 9's matchesSelector returns false on disconnected nodes
-						if ( ret || !disconnectedMatch ||
-								// As well, disconnected nodes are said to be in a document
-								// fragment in IE 9, so check for that
-								node.document && node.document.nodeType !== 11 ) {
-							return ret;
-						}
-					}
-				} catch(e) {}
-			}
-
-			return Sizzle(expr, null, null, [node]).length > 0;
-		};
-	}
-})();
-
-(function(){
-	var div = document.createElement("div");
-
-	div.innerHTML = "<div class='test e'></div><div class='test'></div>";
-
-	// Opera can't find a second classname (in 9.6)
-	// Also, make sure that getElementsByClassName actually exists
-	if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) {
-		return;
-	}
-
-	// Safari caches class attributes, doesn't catch changes (in 3.2)
-	div.lastChild.className = "e";
-
-	if ( div.getElementsByClassName("e").length === 1 ) {
-		return;
-	}
-	
-	Expr.order.splice(1, 0, "CLASS");
-	Expr.find.CLASS = function( match, context, isXML ) {
-		if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
-			return context.getElementsByClassName(match[1]);
-		}
-	};
-
-	// release memory in IE
-	div = null;
-})();
-
-function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
-	for ( var i = 0, l = checkSet.length; i < l; i++ ) {
-		var elem = checkSet[i];
-
-		if ( elem ) {
-			var match = false;
-
-			elem = elem[dir];
-
-			while ( elem ) {
-				if ( elem[ expando ] === doneName ) {
-					match = checkSet[elem.sizset];
-					break;
-				}
-
-				if ( elem.nodeType === 1 && !isXML ){
-					elem[ expando ] = doneName;
-					elem.sizset = i;
-				}
-
-				if ( elem.nodeName.toLowerCase() === cur ) {
-					match = elem;
-					break;
-				}
-
-				elem = elem[dir];
-			}
-
-			checkSet[i] = match;
-		}
-	}
-}
-
-function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
-	for ( var i = 0, l = checkSet.length; i < l; i++ ) {
-		var elem = checkSet[i];
-
-		if ( elem ) {
-			var match = false;
-			
-			elem = elem[dir];
-
-			while ( elem ) {
-				if ( elem[ expando ] === doneName ) {
-					match = checkSet[elem.sizset];
-					break;
-				}
-
-				if ( elem.nodeType === 1 ) {
-					if ( !isXML ) {
-						elem[ expando ] = doneName;
-						elem.sizset = i;
-					}
-
-					if ( typeof cur !== "string" ) {
-						if ( elem === cur ) {
-							match = true;
-							break;
-						}
-
-					} else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
-						match = elem;
-						break;
-					}
-				}
-
-				elem = elem[dir];
-			}
-
-			checkSet[i] = match;
-		}
-	}
-}
-
-if ( document.documentElement.contains ) {
-	Sizzle.contains = function( a, b ) {
-		return a !== b && (a.contains ? a.contains(b) : true);
-	};
-
-} else if ( document.documentElement.compareDocumentPosition ) {
-	Sizzle.contains = function( a, b ) {
-		return !!(a.compareDocumentPosition(b) & 16);
-	};
-
-} else {
-	Sizzle.contains = function() {
-		return false;
-	};
-}
-
-Sizzle.isXML = function( elem ) {
-	// documentElement is verified for cases where it doesn't yet exist
-	// (such as loading iframes in IE - #4833) 
-	var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;
-
-	return documentElement ? documentElement.nodeName !== "HTML" : false;
-};
-
-var posProcess = function( selector, context, seed ) {
-	var match,
-		tmpSet = [],
-		later = "",
-		root = context.nodeType ? [context] : context;
-
-	// Position selectors must be done after the filter
-	// And so must :not(positional) so we move all PSEUDOs to the end
-	while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
-		later += match[0];
-		selector = selector.replace( Expr.match.PSEUDO, "" );
-	}
-
-	selector = Expr.relative[selector] ? selector + "*" : selector;
-
-	for ( var i = 0, l = root.length; i < l; i++ ) {
-		Sizzle( selector, root[i], tmpSet, seed );
-	}
-
-	return Sizzle.filter( later, tmpSet );
-};
-
-// EXPOSE
-// Override sizzle attribute retrieval
-Sizzle.attr = jQuery.attr;
-Sizzle.selectors.attrMap = {};
-jQuery.find = Sizzle;
-jQuery.expr = Sizzle.selectors;
-jQuery.expr[":"] = jQuery.expr.filters;
-jQuery.unique = Sizzle.uniqueSort;
-jQuery.text = Sizzle.getText;
-jQuery.isXMLDoc = Sizzle.isXML;
-jQuery.contains = Sizzle.contains;
-
-
-})();
-
-
-var runtil = /Until$/,
-	rparentsprev = /^(?:parents|prevUntil|prevAll)/,
-	// Note: This RegExp should be improved, or likely pulled from Sizzle
-	rmultiselector = /,/,
-	isSimple = /^.[^:#\[\.,]*$/,
-	slice = Array.prototype.slice,
-	POS = jQuery.expr.match.POS,
-	// methods guaranteed to produce a unique set when starting from a unique set
-	guaranteedUnique = {
-		children: true,
-		contents: true,
-		next: true,
-		prev: true
-	};
-
-jQuery.fn.extend({
-	find: function( selector ) {
-		var self = this,
-			i, l;
-
-		if ( typeof selector !== "string" ) {
-			return jQuery( selector ).filter(function() {
-				for ( i = 0, l = self.length; i < l; i++ ) {
-					if ( jQuery.contains( self[ i ], this ) ) {
-						return true;
-					}
-				}
-			});
-		}
-
-		var ret = this.pushStack( "", "find", selector ),
-			length, n, r;
-
-		for ( i = 0, l = this.length; i < l; i++ ) {
-			length = ret.length;
-			jQuery.find( selector, this[i], ret );
-
-			if ( i > 0 ) {
-				// Make sure that the results are unique
-				for ( n = length; n < ret.length; n++ ) {
-					for ( r = 0; r < length; r++ ) {
-						if ( ret[r] === ret[n] ) {
-							ret.splice(n--, 1);
-							break;
-						}
-					}
-				}
-			}
-		}
-
-		return ret;
-	},
-
-	has: function( target ) {
-		var targets = jQuery( target );
-		return this.filter(function() {
-			for ( var i = 0, l = targets.length; i < l; i++ ) {
-				if ( jQuery.contains( this, targets[i] ) ) {
-					return true;
-				}
-			}
-		});
-	},
-
-	not: function( selector ) {
-		return this.pushStack( winnow(this, selector, false), "not", selector);
-	},
-
-	filter: function( selector ) {
-		return this.pushStack( winnow(this, selector, true), "filter", selector );
-	},
-
-	is: function( selector ) {
-		return !!selector && ( 
-			typeof selector === "string" ?
-				// If this is a positional selector, check membership in the returned set
-				// so $("p:first").is("p:last") won't return true for a doc with two "p".
-				POS.test( selector ) ? 
-					jQuery( selector, this.context ).index( this[0] ) >= 0 :
-					jQuery.filter( selector, this ).length > 0 :
-				this.filter( selector ).length > 0 );
-	},
-
-	closest: function( selectors, context ) {
-		var ret = [], i, l, cur = this[0];
-		
-		// Array (deprecated as of jQuery 1.7)
-		if ( jQuery.isArray( selectors ) ) {
-			var level = 1;
-
-			while ( cur && cur.ownerDocument && cur !== context ) {
-				for ( i = 0; i < selectors.length; i++ ) {
-
-					if ( jQuery( cur ).is( selectors[ i ] ) ) {
-						ret.push({ selector: selectors[ i ], elem: cur, level: level });
-					}
-				}
-
-				cur = cur.parentNode;
-				level++;
-			}
-
-			return ret;
-		}
-
-		// String
-		var pos = POS.test( selectors ) || typeof selectors !== "string" ?
-				jQuery( selectors, context || this.context ) :
-				0;
-
-		for ( i = 0, l = this.length; i < l; i++ ) {
-			cur = this[i];
-
-			while ( cur ) {
-				if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
-					ret.push( cur );
-					break;
-
-				} else {
-					cur = cur.parentNode;
-					if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) {
-						break;
-					}
-				}
-			}
-		}
-
-		ret = ret.length > 1 ? jQuery.unique( ret ) : ret;
-
-		return this.pushStack( ret, "closest", selectors );
-	},
-
-	// Determine the position of an element within
-	// the matched set of elements
-	index: function( elem ) {
-
-		// No argument, return index in parent
-		if ( !elem ) {
-			return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1;
-		}
-
-		// index in selector
-		if ( typeof elem === "string" ) {
-			return jQuery.inArray( this[0], jQuery( elem ) );
-		}
-
-		// Locate the position of the desired element
-		return jQuery.inArray(
-			// If it receives a jQuery object, the first element is used
-			elem.jquery ? elem[0] : elem, this );
-	},
-
-	add: function( selector, context ) {
-		var set = typeof selector === "string" ?
-				jQuery( selector, context ) :
-				jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
-			all = jQuery.merge( this.get(), set );
-
-		return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
-			all :
-			jQuery.unique( all ) );
-	},
-
-	andSelf: function() {
-		return this.add( this.prevObject );
-	}
-});
-
-// A painfully simple check to see if an element is disconnected
-// from a document (should be improved, where feasible).
-function isDisconnected( node ) {
-	return !node || !node.parentNode || node.parentNode.nodeType === 11;
-}
-
-jQuery.each({
-	parent: function( elem ) {
-		var parent = elem.parentNode;
-		return parent && parent.nodeType !== 11 ? parent : null;
-	},
-	parents: function( elem ) {
-		return jQuery.dir( elem, "parentNode" );
-	},
-	parentsUntil: function( elem, i, until ) {
-		return jQuery.dir( elem, "parentNode", until );
-	},
-	next: function( elem ) {
-		return jQuery.nth( elem, 2, "nextSibling" );
-	},
-	prev: function( elem ) {
-		return jQuery.nth( elem, 2, "previousSibling" );
-	},
-	nextAll: function( elem ) {
-		return jQuery.dir( elem, "nextSibling" );
-	},
-	prevAll: function( elem ) {
-		return jQuery.dir( elem, "previousSibling" );
-	},
-	nextUntil: function( elem, i, until ) {
-		return jQuery.dir( elem, "nextSibling", until );
-	},
-	prevUntil: function( elem, i, until ) {
-		return jQuery.dir( elem, "previousSibling", until );
-	},
-	siblings: function( elem ) {
-		return jQuery.sibling( elem.parentNode.firstChild, elem );
-	},
-	children: function( elem ) {
-		return jQuery.sibling( elem.firstChild );
-	},
-	contents: function( elem ) {
-		return jQuery.nodeName( elem, "iframe" ) ?
-			elem.contentDocument || elem.contentWindow.document :
-			jQuery.makeArray( elem.childNodes );
-	}
-}, function( name, fn ) {
-	jQuery.fn[ name ] = function( until, selector ) {
-		var ret = jQuery.map( this, fn, until );
-
-		if ( !runtil.test( name ) ) {
-			selector = until;
-		}
-
-		if ( selector && typeof selector === "string" ) {
-			ret = jQuery.filter( selector, ret );
-		}
-
-		ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
-
-		if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
-			ret = ret.reverse();
-		}
-
-		return this.pushStack( ret, name, slice.call( arguments ).join(",") );
-	};
-});
-
-jQuery.extend({
-	filter: function( expr, elems, not ) {
-		if ( not ) {
-			expr = ":not(" + expr + ")";
-		}
-
-		return elems.length === 1 ?
-			jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
-			jQuery.find.matches(expr, elems);
-	},
-
-	dir: function( elem, dir, until ) {
-		var matched = [],
-			cur = elem[ dir ];
-
-		while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
-			if ( cur.nodeType === 1 ) {
-				matched.push( cur );
-			}
-			cur = cur[dir];
-		}
-		return matched;
-	},
-
-	nth: function( cur, result, dir, elem ) {
-		result = result || 1;
-		var num = 0;
-
-		for ( ; cur; cur = cur[dir] ) {
-			if ( cur.nodeType === 1 && ++num === result ) {
-				break;
-			}
-		}
-
-		return cur;
-	},
-
-	sibling: function( n, elem ) {
-		var r = [];
-
-		for ( ; n; n = n.nextSibling ) {
-			if ( n.nodeType === 1 && n !== elem ) {
-				r.push( n );
-			}
-		}
-
-		return r;
-	}
-});
-
-// Implement the identical functionality for filter and not
-function winnow( elements, qualifier, keep ) {
-
-	// Can't pass null or undefined to indexOf in Firefox 4
-	// Set to 0 to skip string check
-	qualifier = qualifier || 0;
-
-	if ( jQuery.isFunction( qualifier ) ) {
-		return jQuery.grep(elements, function( elem, i ) {
-			var retVal = !!qualifier.call( elem, i, elem );
-			return retVal === keep;
-		});
-
-	} else if ( qualifier.nodeType ) {
-		return jQuery.grep(elements, function( elem, i ) {
-			return ( elem === qualifier ) === keep;
-		});
-
-	} else if ( typeof qualifier === "string" ) {
-		var filtered = jQuery.grep(elements, function( elem ) {
-			return elem.nodeType === 1;
-		});
-
-		if ( isSimple.test( qualifier ) ) {
-			return jQuery.filter(qualifier, filtered, !keep);
-		} else {
-			qualifier = jQuery.filter( qualifier, filtered );
-		}
-	}
-
-	return jQuery.grep(elements, function( elem, i ) {
-		return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep;
-	});
-}
-
-
-
-
-function createSafeFragment( document ) {
-	var list = nodeNames.split( "|" ),
-	safeFrag = document.createDocumentFragment();
-
-	if ( safeFrag.createElement ) {
-		while ( list.length ) {
-			safeFrag.createElement(
-				list.pop()
-			);
-		}
-	}
-	return safeFrag;
-}
-
-var nodeNames = "abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|" +
-		"header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
-	rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g,
-	rleadingWhitespace = /^\s+/,
-	rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,
-	rtagName = /<([\w:]+)/,
-	rtbody = /<tbody/i,
-	rhtml = /<|&#?\w+;/,
-	rnoInnerhtml = /<(?:script|style)/i,
-	rnocache = /<(?:script|object|embed|option|style)/i,
-	rnoshimcache = new RegExp("<(?:" + nodeNames + ")", "i"),
-	// checked="checked" or checked
-	rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
-	rscriptType = /\/(java|ecma)script/i,
-	rcleanScript = /^\s*<!(?:\[CDATA\[|\-\-)/,
-	wrapMap = {
-		option: [ 1, "<select multiple='multiple'>", "</select>" ],
-		legend: [ 1, "<fieldset>", "</fieldset>" ],
-		thead: [ 1, "<table>", "</table>" ],
-		tr: [ 2, "<table><tbody>", "</tbody></table>" ],
-		td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
-		col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
-		area: [ 1, "<map>", "</map>" ],
-		_default: [ 0, "", "" ]
-	},
-	safeFragment = createSafeFragment( document );
-
-wrapMap.optgroup = wrapMap.option;
-wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
-wrapMap.th = wrapMap.td;
-
-// IE can't serialize <link> and <script> tags normally
-if ( !jQuery.support.htmlSerialize ) {
-	wrapMap._default = [ 1, "div<div>", "</div>" ];
-}
-
-jQuery.fn.extend({
-	text: function( text ) {
-		if ( jQuery.isFunction(text) ) {
-			return this.each(function(i) {
-				var self = jQuery( this );
-
-				self.text( text.call(this, i, self.text()) );
-			});
-		}
-
-		if ( typeof text !== "object" && text !== undefined ) {
-			return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
-		}
-
-		return jQuery.text( this );
-	},
-
-	wrapAll: function( html ) {
-		if ( jQuery.isFunction( html ) ) {
-			return this.each(function(i) {
-				jQuery(this).wrapAll( html.call(this, i) );
-			});
-		}
-
-		if ( this[0] ) {
-			// The elements to wrap the target around
-			var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
-
-			if ( this[0].parentNode ) {
-				wrap.insertBefore( this[0] );
-			}
-
-			wrap.map(function() {
-				var elem = this;
-
-				while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
-					elem = elem.firstChild;
-				}
-
-				return elem;
-			}).append( this );
-		}
-
-		return this;
-	},
-
-	wrapInner: function( html ) {
-		if ( jQuery.isFunction( html ) ) {
-			return this.each(function(i) {
-				jQuery(this).wrapInner( html.call(this, i) );
-			});
-		}
-
-		return this.each(function() {
-			var self = jQuery( this ),
-				contents = self.contents();
-
-			if ( contents.length ) {
-				contents.wrapAll( html );
-
-			} else {
-				self.append( html );
-			}
-		});
-	},
-
-	wrap: function( html ) {
-		var isFunction = jQuery.isFunction( html );
-
-		return this.each(function(i) {
-			jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
-		});
-	},
-
-	unwrap: function() {
-		return this.parent().each(function() {
-			if ( !jQuery.nodeName( this, "body" ) ) {
-				jQuery( this ).replaceWith( this.childNodes );
-			}
-		}).end();
-	},
-
-	append: function() {
-		return this.domManip(arguments, true, function( elem ) {
-			if ( this.nodeType === 1 ) {
-				this.appendChild( elem );
-			}
-		});
-	},
-
-	prepend: function() {
-		return this.domManip(arguments, true, function( elem ) {
-			if ( this.nodeType === 1 ) {
-				this.insertBefore( elem, this.firstChild );
-			}
-		});
-	},
-
-	before: function() {
-		if ( this[0] && this[0].parentNode ) {
-			return this.domManip(arguments, false, function( elem ) {
-				this.parentNode.insertBefore( elem, this );
-			});
-		} else if ( arguments.length ) {
-			var set = jQuery.clean( arguments );
-			set.push.apply( set, this.toArray() );
-			return this.pushStack( set, "before", arguments );
-		}
-	},
-
-	after: function() {
-		if ( this[0] && this[0].parentNode ) {
-			return this.domManip(arguments, false, function( elem ) {
-				this.parentNode.insertBefore( elem, this.nextSibling );
-			});
-		} else if ( arguments.length ) {
-			var set = this.pushStack( this, "after", arguments );
-			set.push.apply( set, jQuery.clean(arguments) );
-			return set;
-		}
-	},
-
-	// keepData is for internal use only--do not document
-	remove: function( selector, keepData ) {
-		for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
-			if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
-				if ( !keepData && elem.nodeType === 1 ) {
-					jQuery.cleanData( elem.getElementsByTagName("*") );
-					jQuery.cleanData( [ elem ] );
-				}
-
-				if ( elem.parentNode ) {
-					elem.parentNode.removeChild( elem );
-				}
-			}
-		}
-
-		return this;
-	},
-
-	empty: function() {
-		for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
-			// Remove element nodes and prevent memory leaks
-			if ( elem.nodeType === 1 ) {
-				jQuery.cleanData( elem.getElementsByTagName("*") );
-			}
-
-			// Remove any remaining nodes
-			while ( elem.firstChild ) {
-				elem.removeChild( elem.firstChild );
-			}
-		}
-
-		return this;
-	},
-
-	clone: function( dataAndEvents, deepDataAndEvents ) {
-		dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
-		deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
-
-		return this.map( function () {
-			return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
-		});
-	},
-
-	html: function( value ) {
-		if ( value === undefined ) {
-			return this[0] && this[0].nodeType === 1 ?
-				this[0].innerHTML.replace(rinlinejQuery, "") :
-				null;
-
-		// See if we can take a shortcut and just use innerHTML
-		} else if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
-			(jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&
-			!wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) {
-
-			value = value.replace(rxhtmlTag, "<$1></$2>");
-
-			try {
-				for ( var i = 0, l = this.length; i < l; i++ ) {
-					// Remove element nodes and prevent memory leaks
-					if ( this[i].nodeType === 1 ) {
-						jQuery.cleanData( this[i].getElementsByTagName("*") );
-						this[i].innerHTML = value;
-					}
-				}
-
-			// If using innerHTML throws an exception, use the fallback method
-			} catch(e) {
-				this.empty().append( value );
-			}
-
-		} else if ( jQuery.isFunction( value ) ) {
-			this.each(function(i){
-				var self = jQuery( this );
-
-				self.html( value.call(this, i, self.html()) );
-			});
-
-		} else {
-			this.empty().append( value );
-		}
-
-		return this;
-	},
-
-	replaceWith: function( value ) {
-		if ( this[0] && this[0].parentNode ) {
-			// Make sure that the elements are removed from the DOM before they are inserted
-			// this can help fix replacing a parent with child elements
-			if ( jQuery.isFunction( value ) ) {
-				return this.each(function(i) {
-					var self = jQuery(this), old = self.html();
-					self.replaceWith( value.call( this, i, old ) );
-				});
-			}
-
-			if ( typeof value !== "string" ) {
-				value = jQuery( value ).detach();
-			}
-
-			return this.each(function() {
-				var next = this.nextSibling,
-					parent = this.parentNode;
-
-				jQuery( this ).remove();
-
-				if ( next ) {
-					jQuery(next).before( value );
-				} else {
-					jQuery(parent).append( value );
-				}
-			});
-		} else {
-			return this.length ?
-				this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) :
-				this;
-		}
-	},
-
-	detach: function( selector ) {
-		return this.remove( selector, true );
-	},
-
-	domManip: function( args, table, callback ) {
-		var results, first, fragment, parent,
-			value = args[0],
-			scripts = [];
-
-		// We can't cloneNode fragments that contain checked, in WebKit
-		if ( !jQuery.support.checkClone && arguments.length === 3 && typeof value === "string" && rchecked.test( value ) ) {
-			return this.each(function() {
-				jQuery(this).domManip( args, table, callback, true );
-			});
-		}
-
-		if ( jQuery.isFunction(value) ) {
-			return this.each(function(i) {
-				var self = jQuery(this);
-				args[0] = value.call(this, i, table ? self.html() : undefined);
-				self.domManip( args, table, callback );
-			});
-		}
-
-		if ( this[0] ) {
-			parent = value && value.parentNode;
-
-			// If we're in a fragment, just use that instead of building a new one
-			if ( jQuery.support.parentNode && parent && parent.nodeType === 11 && parent.childNodes.length === this.length ) {
-				results = { fragment: parent };
-
-			} else {
-				results = jQuery.buildFragment( args, this, scripts );
-			}
-
-			fragment = results.fragment;
-
-			if ( fragment.childNodes.length === 1 ) {
-				first = fragment = fragment.firstChild;
-			} else {
-				first = fragment.firstChild;
-			}
-
-			if ( first ) {
-				table = table && jQuery.nodeName( first, "tr" );
-
-				for ( var i = 0, l = this.length, lastIndex = l - 1; i < l; i++ ) {
-					callback.call(
-						table ?
-							root(this[i], first) :
-							this[i],
-						// Make sure that we do not leak memory by inadvertently discarding
-						// the original fragment (which might have attached data) instead of
-						// using it; in addition, use the original fragment object for the last
-						// item instead of first because it can end up being emptied incorrectly
-						// in certain situations (Bug #8070).
-						// Fragments from the fragment cache must always be cloned and never used
-						// in place.
-						results.cacheable || ( l > 1 && i < lastIndex ) ?
-							jQuery.clone( fragment, true, true ) :
-							fragment
-					);
-				}
-			}
-
-			if ( scripts.length ) {
-				jQuery.each( scripts, evalScript );
-			}
-		}
-
-		return this;
-	}
-});
-
-function root( elem, cur ) {
-	return jQuery.nodeName(elem, "table") ?
-		(elem.getElementsByTagName("tbody")[0] ||
-		elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
-		elem;
-}
-
-function cloneCopyEvent( src, dest ) {
-
-	if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
-		return;
-	}
-
-	var type, i, l,
-		oldData = jQuery._data( src ),
-		curData = jQuery._data( dest, oldData ),
-		events = oldData.events;
-
-	if ( events ) {
-		delete curData.handle;
-		curData.events = {};
-
-		for ( type in events ) {
-			for ( i = 0, l = events[ type ].length; i < l; i++ ) {
-				jQuery.event.add( dest, type + ( events[ type ][ i ].namespace ? "." : "" ) + events[ type ][ i ].namespace, events[ type ][ i ], events[ type ][ i ].data );
-			}
-		}
-	}
-
-	// make the cloned public data object a copy from the original
-	if ( curData.data ) {
-		curData.data = jQuery.extend( {}, curData.data );
-	}
-}
-
-function cloneFixAttributes( src, dest ) {
-	var nodeName;
-
-	// We do not need to do anything for non-Elements
-	if ( dest.nodeType !== 1 ) {
-		return;
-	}
-
-	// clearAttributes removes the attributes, which we don't want,
-	// but also removes the attachEvent events, which we *do* want
-	if ( dest.clearAttributes ) {
-		dest.clearAttributes();
-	}
-
-	// mergeAttributes, in contrast, only merges back on the
-	// original attributes, not the events
-	if ( dest.mergeAttributes ) {
-		dest.mergeAttributes( src );
-	}
-
-	nodeName = dest.nodeName.toLowerCase();
-
-	// IE6-8 fail to clone children inside object elements that use
-	// the proprietary classid attribute value (rather than the type
-	// attribute) to identify the type of content to display
-	if ( nodeName === "object" ) {
-		dest.outerHTML = src.outerHTML;
-
-	} else if ( nodeName === "input" && (src.type === "checkbox" || src.type === "radio") ) {
-		// IE6-8 fails to persist the checked state of a cloned checkbox
-		// or radio button. Worse, IE6-7 fail to give the cloned element
-		// a checked appearance if the defaultChecked value isn't also set
-		if ( src.checked ) {
-			dest.defaultChecked = dest.checked = src.checked;
-		}
-
-		// IE6-7 get confused and end up setting the value of a cloned
-		// checkbox/radio button to an empty string instead of "on"
-		if ( dest.value !== src.value ) {
-			dest.value = src.value;
-		}
-
-	// IE6-8 fails to return the selected option to the default selected
-	// state when cloning options
-	} else if ( nodeName === "option" ) {
-		dest.selected = src.defaultSelected;
-
-	// IE6-8 fails to set the defaultValue to the correct value when
-	// cloning other types of input fields
-	} else if ( nodeName === "input" || nodeName === "textarea" ) {
-		dest.defaultValue = src.defaultValue;
-	}
-
-	// Event data gets referenced instead of copied if the expando
-	// gets copied too
-	dest.removeAttribute( jQuery.expando );
-}
-
-jQuery.buildFragment = function( args, nodes, scripts ) {
-	var fragment, cacheable, cacheresults, doc,
-	first = args[ 0 ];
-
-	// nodes may contain either an explicit document object,
-	// a jQuery collection or context object.
-	// If nodes[0] contains a valid object to assign to doc
-	if ( nodes && nodes[0] ) {
-		doc = nodes[0].ownerDocument || nodes[0];
-	}
-
-	// Ensure that an attr object doesn't incorrectly stand in as a document object
-	// Chrome and Firefox seem to allow this to occur and will throw exception
-	// Fixes #8950
-	if ( !doc.createDocumentFragment ) {
-		doc = document;
-	}
-
-	// Only cache "small" (1/2 KB) HTML strings that are associated with the main document
-	// Cloning options loses the selected state, so don't cache them
-	// IE 6 doesn't like it when you put <object> or <embed> elements in a fragment
-	// Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache
-	// Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501
-	if ( args.length === 1 && typeof first === "string" && first.length < 512 && doc === document &&
-		first.charAt(0) === "<" && !rnocache.test( first ) &&
-		(jQuery.support.checkClone || !rchecked.test( first )) &&
-		(jQuery.support.html5Clone || !rnoshimcache.test( first )) ) {
-
-		cacheable = true;
-
-		cacheresults = jQuery.fragments[ first ];
-		if ( cacheresults && cacheresults !== 1 ) {
-			fragment = cacheresults;
-		}
-	}
-
-	if ( !fragment ) {
-		fragment = doc.createDocumentFragment();
-		jQuery.clean( args, doc, fragment, scripts );
-	}
-
-	if ( cacheable ) {
-		jQuery.fragments[ first ] = cacheresults ? fragment : 1;
-	}
-
-	return { fragment: fragment, cacheable: cacheable };
-};
-
-jQuery.fragments = {};
-
-jQuery.each({
-	appendTo: "append",
-	prependTo: "prepend",
-	insertBefore: "before",
-	insertAfter: "after",
-	replaceAll: "replaceWith"
-}, function( name, original ) {
-	jQuery.fn[ name ] = function( selector ) {
-		var ret = [],
-			insert = jQuery( selector ),
-			parent = this.length === 1 && this[0].parentNode;
-
-		if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) {
-			insert[ original ]( this[0] );
-			return this;
-
-		} else {
-			for ( var i = 0, l = insert.length; i < l; i++ ) {
-				var elems = ( i > 0 ? this.clone(true) : this ).get();
-				jQuery( insert[i] )[ original ]( elems );
-				ret = ret.concat( elems );
-			}
-
-			return this.pushStack( ret, name, insert.selector );
-		}
-	};
-});
-
-function getAll( elem ) {
-	if ( typeof elem.getElementsByTagName !== "undefined" ) {
-		return elem.getElementsByTagName( "*" );
-
-	} else if ( typeof elem.querySelectorAll !== "undefined" ) {
-		return elem.querySelectorAll( "*" );
-
-	} else {
-		return [];
-	}
-}
-
-// Used in clean, fixes the defaultChecked property
-function fixDefaultChecked( elem ) {
-	if ( elem.type === "checkbox" || elem.type === "radio" ) {
-		elem.defaultChecked = elem.checked;
-	}
-}
-// Finds all inputs and passes them to fixDefaultChecked
-function findInputs( elem ) {
-	var nodeName = ( elem.nodeName || "" ).toLowerCase();
-	if ( nodeName === "input" ) {
-		fixDefaultChecked( elem );
-	// Skip scripts, get other children
-	} else if ( nodeName !== "script" && typeof elem.getElementsByTagName !== "undefined" ) {
-		jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked );
-	}
-}
-
-// Derived From: http://www.iecss.com/shimprove/javascript/shimprove.1-0-1.js
-function shimCloneNode( elem ) {
-	var div = document.createElement( "div" );
-	safeFragment.appendChild( div );
-
-	div.innerHTML = elem.outerHTML;
-	return div.firstChild;
-}
-
-jQuery.extend({
-	clone: function( elem, dataAndEvents, deepDataAndEvents ) {
-		var srcElements,
-			destElements,
-			i,
-			// IE<=8 does not properly clone detached, unknown element nodes
-			clone = jQuery.support.html5Clone || !rnoshimcache.test( "<" + elem.nodeName ) ?
-				elem.cloneNode( true ) :
-				shimCloneNode( elem );
-
-		if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
-				(elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
-			// IE copies events bound via attachEvent when using cloneNode.
-			// Calling detachEvent on the clone will also remove the events
-			// from the original. In order to get around this, we use some
-			// proprietary methods to clear the events. Thanks to MooTools
-			// guys for this hotness.
-
-			cloneFixAttributes( elem, clone );
-
-			// Using Sizzle here is crazy slow, so we use getElementsByTagName instead
-			srcElements = getAll( elem );
-			destElements = getAll( clone );
-
-			// Weird iteration because IE will replace the length property
-			// with an element if you are cloning the body and one of the
-			// elements on the page has a name or id of "length"
-			for ( i = 0; srcElements[i]; ++i ) {
-				// Ensure that the destination node is not null; Fixes #9587
-				if ( destElements[i] ) {
-					cloneFixAttributes( srcElements[i], destElements[i] );
-				}
-			}
-		}
-
-		// Copy the events from the original to the clone
-		if ( dataAndEvents ) {
-			cloneCopyEvent( elem, clone );
-
-			if ( deepDataAndEvents ) {
-				srcElements = getAll( elem );
-				destElements = getAll( clone );
-
-				for ( i = 0; srcElements[i]; ++i ) {
-					cloneCopyEvent( srcElements[i], destElements[i] );
-				}
-			}
-		}
-
-		srcElements = destElements = null;
-
-		// Return the cloned set
-		return clone;
-	},
-
-	clean: function( elems, context, fragment, scripts ) {
-		var checkScriptType;
-
-		context = context || document;
-
-		// !context.createElement fails in IE with an error but returns typeof 'object'
-		if ( typeof context.createElement === "undefined" ) {
-			context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
-		}
-
-		var ret = [], j;
-
-		for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
-			if ( typeof elem === "number" ) {
-				elem += "";
-			}
-
-			if ( !elem ) {
-				continue;
-			}
-
-			// Convert html string into DOM nodes
-			if ( typeof elem === "string" ) {
-				if ( !rhtml.test( elem ) ) {
-					elem = context.createTextNode( elem );
-				} else {
-					// Fix "XHTML"-style tags in all browsers
-					elem = elem.replace(rxhtmlTag, "<$1></$2>");
-
-					// Trim whitespace, otherwise indexOf won't work as expected
-					var tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(),
-						wrap = wrapMap[ tag ] || wrapMap._default,
-						depth = wrap[0],
-						div = context.createElement("div");
-
-					// Append wrapper element to unknown element safe doc fragment
-					if ( context === document ) {
-						// Use the fragment we've already created for this document
-						safeFragment.appendChild( div );
-					} else {
-						// Use a fragment created with the owner document
-						createSafeFragment( context ).appendChild( div );
-					}
-
-					// Go to html and back, then peel off extra wrappers
-					div.innerHTML = wrap[1] + elem + wrap[2];
-
-					// Move to the right depth
-					while ( depth-- ) {
-						div = div.lastChild;
-					}
-
-					// Remove IE's autoinserted <tbody> from table fragments
-					if ( !jQuery.support.tbody ) {
-
-						// String was a <table>, *may* have spurious <tbody>
-						var hasBody = rtbody.test(elem),
-							tbody = tag === "table" && !hasBody ?
-								div.firstChild && div.firstChild.childNodes :
-
-								// String was a bare <thead> or <tfoot>
-								wrap[1] === "<table>" && !hasBody ?
-									div.childNodes :
-									[];
-
-						for ( j = tbody.length - 1; j >= 0 ; --j ) {
-							if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) {
-								tbody[ j ].parentNode.removeChild( tbody[ j ] );
-							}
-						}
-					}
-
-					// IE completely kills leading whitespace when innerHTML is used
-					if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
-						div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );
-					}
-
-					elem = div.childNodes;
-				}
-			}
-
-			// Resets defaultChecked for any radios and checkboxes
-			// about to be appended to the DOM in IE 6/7 (#8060)
-			var len;
-			if ( !jQuery.support.appendChecked ) {
-				if ( elem[0] && typeof (len = elem.length) === "number" ) {
-					for ( j = 0; j < len; j++ ) {
-						findInputs( elem[j] );
-					}
-				} else {
-					findInputs( elem );
-				}
-			}
-
-			if ( elem.nodeType ) {
-				ret.push( elem );
-			} else {
-				ret = jQuery.merge( ret, elem );
-			}
-		}
-
-		if ( fragment ) {
-			checkScriptType = function( elem ) {
-				return !elem.type || rscriptType.test( elem.type );
-			};
-			for ( i = 0; ret[i]; i++ ) {
-				if ( scripts && jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) {
-					scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] );
-
-				} else {
-					if ( ret[i].nodeType === 1 ) {
-						var jsTags = jQuery.grep( ret[i].getElementsByTagName( "script" ), checkScriptType );
-
-						ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
-					}
-					fragment.appendChild( ret[i] );
-				}
-			}
-		}
-
-		return ret;
-	},
-
-	cleanData: function( elems ) {
-		var data, id,
-			cache = jQuery.cache,
-			special = jQuery.event.special,
-			deleteExpando = jQuery.support.deleteExpando;
-
-		for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
-			if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
-				continue;
-			}
-
-			id = elem[ jQuery.expando ];
-
-			if ( id ) {
-				data = cache[ id ];
-
-				if ( data && data.events ) {
-					for ( var type in data.events ) {
-						if ( special[ type ] ) {
-							jQuery.event.remove( elem, type );
-
-						// This is a shortcut to avoid jQuery.event.remove's overhead
-						} else {
-							jQuery.removeEvent( elem, type, data.handle );
-						}
-					}
-
-					// Null the DOM reference to avoid IE6/7/8 leak (#7054)
-					if ( data.handle ) {
-						data.handle.elem = null;
-					}
-				}
-
-				if ( deleteExpando ) {
-					delete elem[ jQuery.expando ];
-
-				} else if ( elem.removeAttribute ) {
-					elem.removeAttribute( jQuery.expando );
-				}
-
-				delete cache[ id ];
-			}
-		}
-	}
-});
-
-function evalScript( i, elem ) {
-	if ( elem.src ) {
-		jQuery.ajax({
-			url: elem.src,
-			async: false,
-			dataType: "script"
-		});
-	} else {
-		jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "/*$0*/" ) );
-	}
-
-	if ( elem.parentNode ) {
-		elem.parentNode.removeChild( elem );
-	}
-}
-
-
-
-
-var ralpha = /alpha\([^)]*\)/i,
-	ropacity = /opacity=([^)]*)/,
-	// fixed for IE9, see #8346
-	rupper = /([A-Z]|^ms)/g,
-	rnumpx = /^-?\d+(?:px)?$/i,
-	rnum = /^-?\d/,
-	rrelNum = /^([\-+])=([\-+.\de]+)/,
-
-	cssShow = { position: "absolute", visibility: "hidden", display: "block" },
-	cssWidth = [ "Left", "Right" ],
-	cssHeight = [ "Top", "Bottom" ],
-	curCSS,
-
-	getComputedStyle,
-	currentStyle;
-
-jQuery.fn.css = function( name, value ) {
-	// Setting 'undefined' is a no-op
-	if ( arguments.length === 2 && value === undefined ) {
-		return this;
-	}
-
-	return jQuery.access( this, name, value, true, function( elem, name, value ) {
-		return value !== undefined ?
-			jQuery.style( elem, name, value ) :
-			jQuery.css( elem, name );
-	});
-};
-
-jQuery.extend({
-	// Add in style property hooks for overriding the default
-	// behavior of getting and setting a style property
-	cssHooks: {
-		opacity: {
-			get: function( elem, computed ) {
-				if ( computed ) {
-					// We should always get a number back from opacity
-					var ret = curCSS( elem, "opacity", "opacity" );
-					return ret === "" ? "1" : ret;
-
-				} else {
-					return elem.style.opacity;
-				}
-			}
-		}
-	},
-
-	// Exclude the following css properties to add px
-	cssNumber: {
-		"fillOpacity": true,
-		"fontWeight": true,
-		"lineHeight": true,
-		"opacity": true,
-		"orphans": true,
-		"widows": true,
-		"zIndex": true,
-		"zoom": true
-	},
-
-	// Add in properties whose names you wish to fix before
-	// setting or getting the value
-	cssProps: {
-		// normalize float css property
-		"float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
-	},
-
-	// Get and set the style property on a DOM Node
-	style: function( elem, name, value, extra ) {
-		// Don't set styles on text and comment nodes
-		if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
-			return;
-		}
-
-		// Make sure that we're working with the right name
-		var ret, type, origName = jQuery.camelCase( name ),
-			style = elem.style, hooks = jQuery.cssHooks[ origName ];
-
-		name = jQuery.cssProps[ origName ] || origName;
-
-		// Check if we're setting a value
-		if ( value !== undefined ) {
-			type = typeof value;
-
-			// convert relative number strings (+= or -=) to relative numbers. #7345
-			if ( type === "string" && (ret = rrelNum.exec( value )) ) {
-				value = ( +( ret[1] + 1) * +ret[2] ) + parseFloat( jQuery.css( elem, name ) );
-				// Fixes bug #9237
-				type = "number";
-			}
-
-			// Make sure that NaN and null values aren't set. See: #7116
-			if ( value == null || type === "number" && isNaN( value ) ) {
-				return;
-			}
-
-			// If a number was passed in, add 'px' to the (except for certain CSS properties)
-			if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
-				value += "px";
-			}
-
-			// If a hook was provided, use that value, otherwise just set the specified value
-			if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value )) !== undefined ) {
-				// Wrapped to prevent IE from throwing errors when 'invalid' values are provided
-				// Fixes bug #5509
-				try {
-					style[ name ] = value;
-				} catch(e) {}
-			}
-
-		} else {
-			// If a hook was provided get the non-computed value from there
-			if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
-				return ret;
-			}
-
-			// Otherwise just get the value from the style object
-			return style[ name ];
-		}
-	},
-
-	css: function( elem, name, extra ) {
-		var ret, hooks;
-
-		// Make sure that we're working with the right name
-		name = jQuery.camelCase( name );
-		hooks = jQuery.cssHooks[ name ];
-		name = jQuery.cssProps[ name ] || name;
-
-		// cssFloat needs a special treatment
-		if ( name === "cssFloat" ) {
-			name = "float";
-		}
-
-		// If a hook was provided get the computed value from there
-		if ( hooks && "get" in hooks && (ret = hooks.get( elem, true, extra )) !== undefined ) {
-			return ret;
-
-		// Otherwise, if a way to get the computed value exists, use that
-		} else if ( curCSS ) {
-			return curCSS( elem, name );
-		}
-	},
-
-	// A method for quickly swapping in/out CSS properties to get correct calculations
-	swap: function( elem, options, callback ) {
-		var old = {};
-
-		// Remember the old values, and insert the new ones
-		for ( var name in options ) {
-			old[ name ] = elem.style[ name ];
-			elem.style[ name ] = options[ name ];
-		}
-
-		callback.call( elem );
-
-		// Revert the old values
-		for ( name in options ) {
-			elem.style[ name ] = old[ name ];
-		}
-	}
-});
-
-// DEPRECATED, Use jQuery.css() instead
-jQuery.curCSS = jQuery.css;
-
-jQuery.each(["height", "width"], function( i, name ) {
-	jQuery.cssHooks[ name ] = {
-		get: function( elem, computed, extra ) {
-			var val;
-
-			if ( computed ) {
-				if ( elem.offsetWidth !== 0 ) {
-					return getWH( elem, name, extra );
-				} else {
-					jQuery.swap( elem, cssShow, function() {
-						val = getWH( elem, name, extra );
-					});
-				}
-
-				return val;
-			}
-		},
-
-		set: function( elem, value ) {
-			if ( rnumpx.test( value ) ) {
-				// ignore negative width and height values #1599
-				value = parseFloat( value );
-
-				if ( value >= 0 ) {
-					return value + "px";
-				}
-
-			} else {
-				return value;
-			}
-		}
-	};
-});
-
-if ( !jQuery.support.opacity ) {
-	jQuery.cssHooks.opacity = {
-		get: function( elem, computed ) {
-			// IE uses filters for opacity
-			return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
-				( parseFloat( RegExp.$1 ) / 100 ) + "" :
-				computed ? "1" : "";
-		},
-
-		set: function( elem, value ) {
-			var style = elem.style,
-				currentStyle = elem.currentStyle,
-				opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
-				filter = currentStyle && currentStyle.filter || style.filter || "";
-
-			// IE has trouble with opacity if it does not have layout
-			// Force it by setting the zoom level
-			style.zoom = 1;
-
-			// if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
-			if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" ) {
-
-				// Setting style.filter to null, "" & " " still leave "filter:" in the cssText
-				// if "filter:" is present at all, clearType is disabled, we want to avoid this
-				// style.removeAttribute is IE Only, but so apparently is this code path...
-				style.removeAttribute( "filter" );
-
-				// if there there is no filter style applied in a css rule, we are done
-				if ( currentStyle && !currentStyle.filter ) {
-					return;
-				}
-			}
-
-			// otherwise, set new filter values
-			style.filter = ralpha.test( filter ) ?
-				filter.replace( ralpha, opacity ) :
-				filter + " " + opacity;
-		}
-	};
-}
-
-jQuery(function() {
-	// This hook cannot be added until DOM ready because the support test
-	// for it is not run until after DOM ready
-	if ( !jQuery.support.reliableMarginRight ) {
-		jQuery.cssHooks.marginRight = {
-			get: function( elem, computed ) {
-				// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
-				// Work around by temporarily setting element display to inline-block
-				var ret;
-				jQuery.swap( elem, { "display": "inline-block" }, function() {
-					if ( computed ) {
-						ret = curCSS( elem, "margin-right", "marginRight" );
-					} else {
-						ret = elem.style.marginRight;
-					}
-				});
-				return ret;
-			}
-		};
-	}
-});
-
-if ( document.defaultView && document.defaultView.getComputedStyle ) {
-	getComputedStyle = function( elem, name ) {
-		var ret, defaultView, computedStyle;
-
-		name = name.replace( rupper, "-$1" ).toLowerCase();
-
-		if ( (defaultView = elem.ownerDocument.defaultView) &&
-				(computedStyle = defaultView.getComputedStyle( elem, null )) ) {
-			ret = computedStyle.getPropertyValue( name );
-			if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {
-				ret = jQuery.style( elem, name );
-			}
-		}
-
-		return ret;
-	};
-}
-
-if ( document.documentElement.currentStyle ) {
-	currentStyle = function( elem, name ) {
-		var left, rsLeft, uncomputed,
-			ret = elem.currentStyle && elem.currentStyle[ name ],
-			style = elem.style;
-
-		// Avoid setting ret to empty string here
-		// so we don't default to auto
-		if ( ret === null && style && (uncomputed = style[ name ]) ) {
-			ret = uncomputed;
-		}
-
-		// From the awesome hack by Dean Edwards
-		// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
-
-		// If we're not dealing with a regular pixel number
-		// but a number that has a weird ending, we need to convert it to pixels
-		if ( !rnumpx.test( ret ) && rnum.test( ret ) ) {
-
-			// Remember the original values
-			left = style.left;
-			rsLeft = elem.runtimeStyle && elem.runtimeStyle.left;
-
-			// Put in the new values to get a computed value out
-			if ( rsLeft ) {
-				elem.runtimeStyle.left = elem.currentStyle.left;
-			}
-			style.left = name === "fontSize" ? "1em" : ( ret || 0 );
-			ret = style.pixelLeft + "px";
-
-			// Revert the changed values
-			style.left = left;
-			if ( rsLeft ) {
-				elem.runtimeStyle.left = rsLeft;
-			}
-		}
-
-		return ret === "" ? "auto" : ret;
-	};
-}
-
-curCSS = getComputedStyle || currentStyle;
-
-function getWH( elem, name, extra ) {
-
-	// Start with offset property
-	var val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
-		which = name === "width" ? cssWidth : cssHeight,
-		i = 0,
-		len = which.length;
-
-	if ( val > 0 ) {
-		if ( extra !== "border" ) {
-			for ( ; i < len; i++ ) {
-				if ( !extra ) {
-					val -= parseFloat( jQuery.css( elem, "padding" + which[ i ] ) ) || 0;
-				}
-				if ( extra === "margin" ) {
-					val += parseFloat( jQuery.css( elem, extra + which[ i ] ) ) || 0;
-				} else {
-					val -= parseFloat( jQuery.css( elem, "border" + which[ i ] + "Width" ) ) || 0;
-				}
-			}
-		}
-
-		return val + "px";
-	}
-
-	// Fall back to computed then uncomputed css if necessary
-	val = curCSS( elem, name, name );
-	if ( val < 0 || val == null ) {
-		val = elem.style[ name ] || 0;
-	}
-	// Normalize "", auto, and prepare for extra
-	val = parseFloat( val ) || 0;
-
-	// Add padding, border, margin
-	if ( extra ) {
-		for ( ; i < len; i++ ) {
-			val += parseFloat( jQuery.css( elem, "padding" + which[ i ] ) ) || 0;
-			if ( extra !== "padding" ) {
-				val += parseFloat( jQuery.css( elem, "border" + which[ i ] + "Width" ) ) || 0;
-			}
-			if ( extra === "margin" ) {
-				val += parseFloat( jQuery.css( elem, extra + which[ i ] ) ) || 0;
-			}
-		}
-	}
-
-	return val + "px";
-}
-
-if ( jQuery.expr && jQuery.expr.filters ) {
-	jQuery.expr.filters.hidden = function( elem ) {
-		var width = elem.offsetWidth,
-			height = elem.offsetHeight;
-
-		return ( width === 0 && height === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
-	};
-
-	jQuery.expr.filters.visible = function( elem ) {
-		return !jQuery.expr.filters.hidden( elem );
-	};
-}
-
-
-
-
-var r20 = /%20/g,
-	rbracket = /\[\]$/,
-	rCRLF = /\r?\n/g,
-	rhash = /#.*$/,
-	rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
-	rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
-	// #7653, #8125, #8152: local protocol detection
-	rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,
-	rnoContent = /^(?:GET|HEAD)$/,
-	rprotocol = /^\/\//,
-	rquery = /\?/,
-	rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
-	rselectTextarea = /^(?:select|textarea)/i,
-	rspacesAjax = /\s+/,
-	rts = /([?&])_=[^&]*/,
-	rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,
-
-	// Keep a copy of the old load method
-	_load = jQuery.fn.load,
-
-	/* Prefilters
-	 * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
-	 * 2) These are called:
-	 *    - BEFORE asking for a transport
-	 *    - AFTER param serialization (s.data is a string if s.processData is true)
-	 * 3) key is the dataType
-	 * 4) the catchall symbol "*" can be used
-	 * 5) execution will start with transport dataType and THEN continue down to "*" if needed
-	 */
-	prefilters = {},
-
-	/* Transports bindings
-	 * 1) key is the dataType
-	 * 2) the catchall symbol "*" can be used
-	 * 3) selection will start with transport dataType and THEN go to "*" if needed
-	 */
-	transports = {},
-
-	// Document location
-	ajaxLocation,
-
-	// Document location segments
-	ajaxLocParts,
-
-	// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
-	allTypes = ["*/"] + ["*"];
-
-// #8138, IE may throw an exception when accessing
-// a field from window.location if document.domain has been set
-try {
-	ajaxLocation = location.href;
-} catch( e ) {
-	// Use the href attribute of an A element
-	// since IE will modify it given document.location
-	ajaxLocation = document.createElement( "a" );
-	ajaxLocation.href = "";
-	ajaxLocation = ajaxLocation.href;
-}
-
-// Segment location into parts
-ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
-
-// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
-function addToPrefiltersOrTransports( structure ) {
-
-	// dataTypeExpression is optional and defaults to "*"
-	return function( dataTypeExpression, func ) {
-
-		if ( typeof dataTypeExpression !== "string" ) {
-			func = dataTypeExpression;
-			dataTypeExpression = "*";
-		}
-
-		if ( jQuery.isFunction( func ) ) {
-			var dataTypes = dataTypeExpression.toLowerCase().split( rspacesAjax ),
-				i = 0,
-				length = dataTypes.length,
-				dataType,
-				list,
-				placeBefore;
-
-			// For each dataType in the dataTypeExpression
-			for ( ; i < length; i++ ) {
-				dataType = dataTypes[ i ];
-				// We control if we're asked to add before
-				// any existing element
-				placeBefore = /^\+/.test( dataType );
-				if ( placeBefore ) {
-					dataType = dataType.substr( 1 ) || "*";
-				}
-				list = structure[ dataType ] = structure[ dataType ] || [];
-				// then we add to the structure accordingly
-				list[ placeBefore ? "unshift" : "push" ]( func );
-			}
-		}
-	};
-}
-
-// Base inspection function for prefilters and transports
-function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR,
-		dataType /* internal */, inspected /* internal */ ) {
-
-	dataType = dataType || options.dataTypes[ 0 ];
-	inspected = inspected || {};
-
-	inspected[ dataType ] = true;
-
-	var list = structure[ dataType ],
-		i = 0,
-		length = list ? list.length : 0,
-		executeOnly = ( structure === prefilters ),
-		selection;
-
-	for ( ; i < length && ( executeOnly || !selection ); i++ ) {
-		selection = list[ i ]( options, originalOptions, jqXHR );
-		// If we got redirected to another dataType
-		// we try there if executing only and not done already
-		if ( typeof selection === "string" ) {
-			if ( !executeOnly || inspected[ selection ] ) {
-				selection = undefined;
-			} else {
-				options.dataTypes.unshift( selection );
-				selection = inspectPrefiltersOrTransports(
-						structure, options, originalOptions, jqXHR, selection, inspected );
-			}
-		}
-	}
-	// If we're only executing or nothing was selected
-	// we try the catchall dataType if not done already
-	if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) {
-		selection = inspectPrefiltersOrTransports(
-				structure, options, originalOptions, jqXHR, "*", inspected );
-	}
-	// unnecessary when only executing (prefilters)
-	// but it'll be ignored by the caller in that case
-	return selection;
-}
-
-// A special extend for ajax options
-// that takes "flat" options (not to be deep extended)
-// Fixes #9887
-function ajaxExtend( target, src ) {
-	var key, deep,
-		flatOptions = jQuery.ajaxSettings.flatOptions || {};
-	for ( key in src ) {
-		if ( src[ key ] !== undefined ) {
-			( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
-		}
-	}
-	if ( deep ) {
-		jQuery.extend( true, target, deep );
-	}
-}
-
-jQuery.fn.extend({
-	load: function( url, params, callback ) {
-		if ( typeof url !== "string" && _load ) {
-			return _load.apply( this, arguments );
-
-		// Don't do a request if no elements are being requested
-		} else if ( !this.length ) {
-			return this;
-		}
-
-		var off = url.indexOf( " " );
-		if ( off >= 0 ) {
-			var selector = url.slice( off, url.length );
-			url = url.slice( 0, off );
-		}
-
-		// Default to a GET request
-		var type = "GET";
-
-		// If the second parameter was provided
-		if ( params ) {
-			// If it's a function
-			if ( jQuery.isFunction( params ) ) {
-				// We assume that it's the callback
-				callback = params;
-				params = undefined;
-
-			// Otherwise, build a param string
-			} else if ( typeof params === "object" ) {
-				params = jQuery.param( params, jQuery.ajaxSettings.traditional );
-				type = "POST";
-			}
-		}
-
-		var self = this;
-
-		// Request the remote document
-		jQuery.ajax({
-			url: url,
-			type: type,
-			dataType: "html",
-			data: params,
-			// Complete callback (responseText is used internally)
-			complete: function( jqXHR, status, responseText ) {
-				// Store the response as specified by the jqXHR object
-				responseText = jqXHR.responseText;
-				// If successful, inject the HTML into all the matched elements
-				if ( jqXHR.isResolved() ) {
-					// #4825: Get the actual response in case
-					// a dataFilter is present in ajaxSettings
-					jqXHR.done(function( r ) {
-						responseText = r;
-					});
-					// See if a selector was specified
-					self.html( selector ?
-						// Create a dummy div to hold the results
-						jQuery("<div>")
-							// inject the contents of the document in, removing the scripts
-							// to avoid any 'Permission Denied' errors in IE
-							.append(responseText.replace(rscript, ""))
-
-							// Locate the specified elements
-							.find(selector) :
-
-						// If not, just inject the full result
-						responseText );
-				}
-
-				if ( callback ) {
-					self.each( callback, [ responseText, status, jqXHR ] );
-				}
-			}
-		});
-
-		return this;
-	},
-
-	serialize: function() {
-		return jQuery.param( this.serializeArray() );
-	},
-
-	serializeArray: function() {
-		return this.map(function(){
-			return this.elements ? jQuery.makeArray( this.elements ) : this;
-		})
-		.filter(function(){
-			return this.name && !this.disabled &&
-				( this.checked || rselectTextarea.test( this.nodeName ) ||
-					rinput.test( this.type ) );
-		})
-		.map(function( i, elem ){
-			var val = jQuery( this ).val();
-
-			return val == null ?
-				null :
-				jQuery.isArray( val ) ?
-					jQuery.map( val, function( val, i ){
-						return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
-					}) :
-					{ name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
-		}).get();
-	}
-});
-
-// Attach a bunch of functions for handling common AJAX events
-jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){
-	jQuery.fn[ o ] = function( f ){
-		return this.on( o, f );
-	};
-});
-
-jQuery.each( [ "get", "post" ], function( i, method ) {
-	jQuery[ method ] = function( url, data, callback, type ) {
-		// shift arguments if data argument was omitted
-		if ( jQuery.isFunction( data ) ) {
-			type = type || callback;
-			callback = data;
-			data = undefined;
-		}
-
-		return jQuery.ajax({
-			type: method,
-			url: url,
-			data: data,
-			success: callback,
-			dataType: type
-		});
-	};
-});
-
-jQuery.extend({
-
-	getScript: function( url, callback ) {
-		return jQuery.get( url, undefined, callback, "script" );
-	},
-
-	getJSON: function( url, data, callback ) {
-		return jQuery.get( url, data, callback, "json" );
-	},
-
-	// Creates a full fledged settings object into target
-	// with both ajaxSettings and settings fields.
-	// If target is omitted, writes into ajaxSettings.
-	ajaxSetup: function( target, settings ) {
-		if ( settings ) {
-			// Building a settings object
-			ajaxExtend( target, jQuery.ajaxSettings );
-		} else {
-			// Extending ajaxSettings
-			settings = target;
-			target = jQuery.ajaxSettings;
-		}
-		ajaxExtend( target, settings );
-		return target;
-	},
-
-	ajaxSettings: {
-		url: ajaxLocation,
-		isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
-		global: true,
-		type: "GET",
-		contentType: "application/x-www-form-urlencoded",
-		processData: true,
-		async: true,
-		/*
-		timeout: 0,
-		data: null,
-		dataType: null,
-		username: null,
-		password: null,
-		cache: null,
-		traditional: false,
-		headers: {},
-		*/
-
-		accepts: {
-			xml: "application/xml, text/xml",
-			html: "text/html",
-			text: "text/plain",
-			json: "application/json, text/javascript",
-			"*": allTypes
-		},
-
-		contents: {
-			xml: /xml/,
-			html: /html/,
-			json: /json/
-		},
-
-		responseFields: {
-			xml: "responseXML",
-			text: "responseText"
-		},
-
-		// List of data converters
-		// 1) key format is "source_type destination_type" (a single space in-between)
-		// 2) the catchall symbol "*" can be used for source_type
-		converters: {
-
-			// Convert anything to text
-			"* text": window.String,
-
-			// Text to html (true = no transformation)
-			"text html": true,
-
-			// Evaluate text as a json expression
-			"text json": jQuery.parseJSON,
-
-			// Parse text as xml
-			"text xml": jQuery.parseXML
-		},
-
-		// For options that shouldn't be deep extended:
-		// you can add your own custom options here if
-		// and when you create one that shouldn't be
-		// deep extended (see ajaxExtend)
-		flatOptions: {
-			context: true,
-			url: true
-		}
-	},
-
-	ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
-	ajaxTransport: addToPrefiltersOrTransports( transports ),
-
-	// Main method
-	ajax: function( url, options ) {
-
-		// If url is an object, simulate pre-1.5 signature
-		if ( typeof url === "object" ) {
-			options = url;
-			url = undefined;
-		}
-
-		// Force options to be an object
-		options = options || {};
-
-		var // Create the final options object
-			s = jQuery.ajaxSetup( {}, options ),
-			// Callbacks context
-			callbackContext = s.context || s,
-			// Context for global events
-			// It's the callbackContext if one was provided in the options
-			// and if it's a DOM node or a jQuery collection
-			globalEventContext = callbackContext !== s &&
-				( callbackContext.nodeType || callbackContext instanceof jQuery ) ?
-						jQuery( callbackContext ) : jQuery.event,
-			// Deferreds
-			deferred = jQuery.Deferred(),
-			completeDeferred = jQuery.Callbacks( "once memory" ),
-			// Status-dependent callbacks
-			statusCode = s.statusCode || {},
-			// ifModified key
-			ifModifiedKey,
-			// Headers (they are sent all at once)
-			requestHeaders = {},
-			requestHeadersNames = {},
-			// Response headers
-			responseHeadersString,
-			responseHeaders,
-			// transport
-			transport,
-			// timeout handle
-			timeoutTimer,
-			// Cross-domain detection vars
-			parts,
-			// The jqXHR state
-			state = 0,
-			// To know if global events are to be dispatched
-			fireGlobals,
-			// Loop variable
-			i,
-			// Fake xhr
-			jqXHR = {
-
-				readyState: 0,
-
-				// Caches the header
-				setRequestHeader: function( name, value ) {
-					if ( !state ) {
-						var lname = name.toLowerCase();
-						name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
-						requestHeaders[ name ] = value;
-					}
-					return this;
-				},
-
-				// Raw string
-				getAllResponseHeaders: function() {
-					return state === 2 ? responseHeadersString : null;
-				},
-
-				// Builds headers hashtable if needed
-				getResponseHeader: function( key ) {
-					var match;
-					if ( state === 2 ) {
-						if ( !responseHeaders ) {
-							responseHeaders = {};
-							while( ( match = rheaders.exec( responseHeadersString ) ) ) {
-								responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
-							}
-						}
-						match = responseHeaders[ key.toLowerCase() ];
-					}
-					return match === undefined ? null : match;
-				},
-
-				// Overrides response content-type header
-				overrideMimeType: function( type ) {
-					if ( !state ) {
-						s.mimeType = type;
-					}
-					return this;
-				},
-
-				// Cancel the request
-				abort: function( statusText ) {
-					statusText = statusText || "abort";
-					if ( transport ) {
-						transport.abort( statusText );
-					}
-					done( 0, statusText );
-					return this;
-				}
-			};
-
-		// Callback for when everything is done
-		// It is defined here because jslint complains if it is declared
-		// at the end of the function (which would be more logical and readable)
-		function done( status, nativeStatusText, responses, headers ) {
-
-			// Called once
-			if ( state === 2 ) {
-				return;
-			}
-
-			// State is "done" now
-			state = 2;
-
-			// Clear timeout if it exists
-			if ( timeoutTimer ) {
-				clearTimeout( timeoutTimer );
-			}
-
-			// Dereference transport for early garbage collection
-			// (no matter how long the jqXHR object will be used)
-			transport = undefined;
-
-			// Cache response headers
-			responseHeadersString = headers || "";
-
-			// Set readyState
-			jqXHR.readyState = status > 0 ? 4 : 0;
-
-			var isSuccess,
-				success,
-				error,
-				statusText = nativeStatusText,
-				response = responses ? ajaxHandleResponses( s, jqXHR, responses ) : undefined,
-				lastModified,
-				etag;
-
-			// If successful, handle type chaining
-			if ( status >= 200 && status < 300 || status === 304 ) {
-
-				// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
-				if ( s.ifModified ) {
-
-					if ( ( lastModified = jqXHR.getResponseHeader( "Last-Modified" ) ) ) {
-						jQuery.lastModified[ ifModifiedKey ] = lastModified;
-					}
-					if ( ( etag = jqXHR.getResponseHeader( "Etag" ) ) ) {
-						jQuery.etag[ ifModifiedKey ] = etag;
-					}
-				}
-
-				// If not modified
-				if ( status === 304 ) {
-
-					statusText = "notmodified";
-					isSuccess = true;
-
-				// If we have data
-				} else {
-
-					try {
-						success = ajaxConvert( s, response );
-						statusText = "success";
-						isSuccess = true;
-					} catch(e) {
-						// We have a parsererror
-						statusText = "parsererror";
-						error = e;
-					}
-				}
-			} else {
-				// We extract error from statusText
-				// then normalize statusText and status for non-aborts
-				error = statusText;
-				if ( !statusText || status ) {
-					statusText = "error";
-					if ( status < 0 ) {
-						status = 0;
-					}
-				}
-			}
-
-			// Set data for the fake xhr object
-			jqXHR.status = status;
-			jqXHR.statusText = "" + ( nativeStatusText || statusText );
-
-			// Success/Error
-			if ( isSuccess ) {
-				deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
-			} else {
-				deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
-			}
-
-			// Status-dependent callbacks
-			jqXHR.statusCode( statusCode );
-			statusCode = undefined;
-
-			if ( fireGlobals ) {
-				globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ),
-						[ jqXHR, s, isSuccess ? success : error ] );
-			}
-
-			// Complete
-			completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
-
-			if ( fireGlobals ) {
-				globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
-				// Handle the global AJAX counter
-				if ( !( --jQuery.active ) ) {
-					jQuery.event.trigger( "ajaxStop" );
-				}
-			}
-		}
-
-		// Attach deferreds
-		deferred.promise( jqXHR );
-		jqXHR.success = jqXHR.done;
-		jqXHR.error = jqXHR.fail;
-		jqXHR.complete = completeDeferred.add;
-
-		// Status-dependent callbacks
-		jqXHR.statusCode = function( map ) {
-			if ( map ) {
-				var tmp;
-				if ( state < 2 ) {
-					for ( tmp in map ) {
-						statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ];
-					}
-				} else {
-					tmp = map[ jqXHR.status ];
-					jqXHR.then( tmp, tmp );
-				}
-			}
-			return this;
-		};
-
-		// Remove hash character (#7531: and string promotion)
-		// Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
-		// We also use the url parameter if available
-		s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
-
-		// Extract dataTypes list
-		s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( rspacesAjax );
-
-		// Determine if a cross-domain request is in order
-		if ( s.crossDomain == null ) {
-			parts = rurl.exec( s.url.toLowerCase() );
-			s.crossDomain = !!( parts &&
-				( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] ||
-					( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
-						( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) )
-			);
-		}
-
-		// Convert data if not already a string
-		if ( s.data && s.processData && typeof s.data !== "string" ) {
-			s.data = jQuery.param( s.data, s.traditional );
-		}
-
-		// Apply prefilters
-		inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
-
-		// If request was aborted inside a prefiler, stop there
-		if ( state === 2 ) {
-			return false;
-		}
-
-		// We can fire global events as of now if asked to
-		fireGlobals = s.global;
-
-		// Uppercase the type
-		s.type = s.type.toUpperCase();
-
-		// Determine if request has content
-		s.hasContent = !rnoContent.test( s.type );
-
-		// Watch for a new set of requests
-		if ( fireGlobals && jQuery.active++ === 0 ) {
-			jQuery.event.trigger( "ajaxStart" );
-		}
-
-		// More options handling for requests with no content
-		if ( !s.hasContent ) {
-
-			// If data is available, append data to url
-			if ( s.data ) {
-				s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data;
-				// #9682: remove data so that it's not used in an eventual retry
-				delete s.data;
-			}
-
-			// Get ifModifiedKey before adding the anti-cache parameter
-			ifModifiedKey = s.url;
-
-			// Add anti-cache in url if needed
-			if ( s.cache === false ) {
-
-				var ts = jQuery.now(),
-					// try replacing _= if it is there
-					ret = s.url.replace( rts, "$1_=" + ts );
-
-				// if nothing was replaced, add timestamp to the end
-				s.url = ret + ( ( ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" );
-			}
-		}
-
-		// Set the correct header, if data is being sent
-		if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
-			jqXHR.setRequestHeader( "Content-Type", s.contentType );
-		}
-
-		// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
-		if ( s.ifModified ) {
-			ifModifiedKey = ifModifiedKey || s.url;
-			if ( jQuery.lastModified[ ifModifiedKey ] ) {
-				jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] );
-			}
-			if ( jQuery.etag[ ifModifiedKey ] ) {
-				jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] );
-			}
-		}
-
-		// Set the Accepts header for the server, depending on the dataType
-		jqXHR.setRequestHeader(
-			"Accept",
-			s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
-				s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
-				s.accepts[ "*" ]
-		);
-
-		// Check for headers option
-		for ( i in s.headers ) {
-			jqXHR.setRequestHeader( i, s.headers[ i ] );
-		}
-
-		// Allow custom headers/mimetypes and early abort
-		if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
-				// Abort if not done already
-				jqXHR.abort();
-				return false;
-
-		}
-
-		// Install callbacks on deferreds
-		for ( i in { success: 1, error: 1, complete: 1 } ) {
-			jqXHR[ i ]( s[ i ] );
-		}
-
-		// Get transport
-		transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
-
-		// If no transport, we auto-abort
-		if ( !transport ) {
-			done( -1, "No Transport" );
-		} else {
-			jqXHR.readyState = 1;
-			// Send global event
-			if ( fireGlobals ) {
-				globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
-			}
-			// Timeout
-			if ( s.async && s.timeout > 0 ) {
-				timeoutTimer = setTimeout( function(){
-					jqXHR.abort( "timeout" );
-				}, s.timeout );
-			}
-
-			try {
-				state = 1;
-				transport.send( requestHeaders, done );
-			} catch (e) {
-				// Propagate exception as error if not done
-				if ( state < 2 ) {
-					done( -1, e );
-				// Simply rethrow otherwise
-				} else {
-					throw e;
-				}
-			}
-		}
-
-		return jqXHR;
-	},
-
-	// Serialize an array of form elements or a set of
-	// key/values into a query string
-	param: function( a, traditional ) {
-		var s = [],
-			add = function( key, value ) {
-				// If value is a function, invoke it and return its value
-				value = jQuery.isFunction( value ) ? value() : value;
-				s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
-			};
-
-		// Set traditional to true for jQuery <= 1.3.2 behavior.
-		if ( traditional === undefined ) {
-			traditional = jQuery.ajaxSettings.traditional;
-		}
-
-		// If an array was passed in, assume that it is an array of form elements.
-		if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
-			// Serialize the form elements
-			jQuery.each( a, function() {
-				add( this.name, this.value );
-			});
-
-		} else {
-			// If traditional, encode the "old" way (the way 1.3.2 or older
-			// did it), otherwise encode params recursively.
-			for ( var prefix in a ) {
-				buildParams( prefix, a[ prefix ], traditional, add );
-			}
-		}
-
-		// Return the resulting serialization
-		return s.join( "&" ).replace( r20, "+" );
-	}
-});
-
-function buildParams( prefix, obj, traditional, add ) {
-	if ( jQuery.isArray( obj ) ) {
-		// Serialize array item.
-		jQuery.each( obj, function( i, v ) {
-			if ( traditional || rbracket.test( prefix ) ) {
-				// Treat each array item as a scalar.
-				add( prefix, v );
-
-			} else {
-				// If array item is non-scalar (array or object), encode its
-				// numeric index to resolve deserialization ambiguity issues.
-				// Note that rack (as of 1.0.0) can't currently deserialize
-				// nested arrays properly, and attempting to do so may cause
-				// a server error. Possible fixes are to modify rack's
-				// deserialization algorithm or to provide an option or flag
-				// to force array serialization to be shallow.
-				buildParams( prefix + "[" + ( typeof v === "object" || jQuery.isArray(v) ? i : "" ) + "]", v, traditional, add );
-			}
-		});
-
-	} else if ( !traditional && obj != null && typeof obj === "object" ) {
-		// Serialize object item.
-		for ( var name in obj ) {
-			buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
-		}
-
-	} else {
-		// Serialize scalar item.
-		add( prefix, obj );
-	}
-}
-
-// This is still on the jQuery object... for now
-// Want to move this to jQuery.ajax some day
-jQuery.extend({
-
-	// Counter for holding the number of active queries
-	active: 0,
-
-	// Last-Modified header cache for next request
-	lastModified: {},
-	etag: {}
-
-});
-
-/* Handles responses to an ajax request:
- * - sets all responseXXX fields accordingly
- * - finds the right dataType (mediates between content-type and expected dataType)
- * - returns the corresponding response
- */
-function ajaxHandleResponses( s, jqXHR, responses ) {
-
-	var contents = s.contents,
-		dataTypes = s.dataTypes,
-		responseFields = s.responseFields,
-		ct,
-		type,
-		finalDataType,
-		firstDataType;
-
-	// Fill responseXXX fields
-	for ( type in responseFields ) {
-		if ( type in responses ) {
-			jqXHR[ responseFields[type] ] = responses[ type ];
-		}
-	}
-
-	// Remove auto dataType and get content-type in the process
-	while( dataTypes[ 0 ] === "*" ) {
-		dataTypes.shift();
-		if ( ct === undefined ) {
-			ct = s.mimeType || jqXHR.getResponseHeader( "content-type" );
-		}
-	}
-
-	// Check if we're dealing with a known content-type
-	if ( ct ) {
-		for ( type in contents ) {
-			if ( contents[ type ] && contents[ type ].test( ct ) ) {
-				dataTypes.unshift( type );
-				break;
-			}
-		}
-	}
-
-	// Check to see if we have a response for the expected dataType
-	if ( dataTypes[ 0 ] in responses ) {
-		finalDataType = dataTypes[ 0 ];
-	} else {
-		// Try convertible dataTypes
-		for ( type in responses ) {
-			if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
-				finalDataType = type;
-				break;
-			}
-			if ( !firstDataType ) {
-				firstDataType = type;
-			}
-		}
-		// Or just use first one
-		finalDataType = finalDataType || firstDataType;
-	}
-
-	// If we found a dataType
-	// We add the dataType to the list if needed
-	// and return the corresponding response
-	if ( finalDataType ) {
-		if ( finalDataType !== dataTypes[ 0 ] ) {
-			dataTypes.unshift( finalDataType );
-		}
-		return responses[ finalDataType ];
-	}
-}
-
-// Chain conversions given the request and the original response
-function ajaxConvert( s, response ) {
-
-	// Apply the dataFilter if provided
-	if ( s.dataFilter ) {
-		response = s.dataFilter( response, s.dataType );
-	}
-
-	var dataTypes = s.dataTypes,
-		converters = {},
-		i,
-		key,
-		length = dataTypes.length,
-		tmp,
-		// Current and previous dataTypes
-		current = dataTypes[ 0 ],
-		prev,
-		// Conversion expression
-		conversion,
-		// Conversion function
-		conv,
-		// Conversion functions (transitive conversion)
-		conv1,
-		conv2;
-
-	// For each dataType in the chain
-	for ( i = 1; i < length; i++ ) {
-
-		// Create converters map
-		// with lowercased keys
-		if ( i === 1 ) {
-			for ( key in s.converters ) {
-				if ( typeof key === "string" ) {
-					converters[ key.toLowerCase() ] = s.converters[ key ];
-				}
-			}
-		}
-
-		// Get the dataTypes
-		prev = current;
-		current = dataTypes[ i ];
-
-		// If current is auto dataType, update it to prev
-		if ( current === "*" ) {
-			current = prev;
-		// If no auto and dataTypes are actually different
-		} else if ( prev !== "*" && prev !== current ) {
-
-			// Get the converter
-			conversion = prev + " " + current;
-			conv = converters[ conversion ] || converters[ "* " + current ];
-
-			// If there is no direct converter, search transitively
-			if ( !conv ) {
-				conv2 = undefined;
-				for ( conv1 in converters ) {
-					tmp = conv1.split( " " );
-					if ( tmp[ 0 ] === prev || tmp[ 0 ] === "*" ) {
-						conv2 = converters[ tmp[1] + " " + current ];
-						if ( conv2 ) {
-							conv1 = converters[ conv1 ];
-							if ( conv1 === true ) {
-								conv = conv2;
-							} else if ( conv2 === true ) {
-								conv = conv1;
-							}
-							break;
-						}
-					}
-				}
-			}
-			// If we found no converter, dispatch an error
-			if ( !( conv || conv2 ) ) {
-				jQuery.error( "No conversion from " + conversion.replace(" "," to ") );
-			}
-			// If found converter is not an equivalence
-			if ( conv !== true ) {
-				// Convert with 1 or 2 converters accordingly
-				response = conv ? conv( response ) : conv2( conv1(response) );
-			}
-		}
-	}
-	return response;
-}
-
-
-
-
-var jsc = jQuery.now(),
-	jsre = /(\=)\?(&|$)|\?\?/i;
-
-// Default jsonp settings
-jQuery.ajaxSetup({
-	jsonp: "callback",
-	jsonpCallback: function() {
-		return jQuery.expando + "_" + ( jsc++ );
-	}
-});
-
-// Detect, normalize options and install callbacks for jsonp requests
-jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
-
-	var inspectData = s.contentType === "application/x-www-form-urlencoded" &&
-		( typeof s.data === "string" );
-
-	if ( s.dataTypes[ 0 ] === "jsonp" ||
-		s.jsonp !== false && ( jsre.test( s.url ) ||
-				inspectData && jsre.test( s.data ) ) ) {
-
-		var responseContainer,
-			jsonpCallback = s.jsonpCallback =
-				jQuery.isFunction( s.jsonpCallback ) ? s.jsonpCallback() : s.jsonpCallback,
-			previous = window[ jsonpCallback ],
-			url = s.url,
-			data = s.data,
-			replace = "$1" + jsonpCallback + "$2";
-
-		if ( s.jsonp !== false ) {
-			url = url.replace( jsre, replace );
-			if ( s.url === url ) {
-				if ( inspectData ) {
-					data = data.replace( jsre, replace );
-				}
-				if ( s.data === data ) {
-					// Add callback manually
-					url += (/\?/.test( url ) ? "&" : "?") + s.jsonp + "=" + jsonpCallback;
-				}
-			}
-		}
-
-		s.url = url;
-		s.data = data;
-
-		// Install callback
-		window[ jsonpCallback ] = function( response ) {
-			responseContainer = [ response ];
-		};
-
-		// Clean-up function
-		jqXHR.always(function() {
-			// Set callback back to previous value
-			window[ jsonpCallback ] = previous;
-			// Call if it was a function and we have a response
-			if ( responseContainer && jQuery.isFunction( previous ) ) {
-				window[ jsonpCallback ]( responseContainer[ 0 ] );
-			}
-		});
-
-		// Use data converter to retrieve json after script execution
-		s.converters["script json"] = function() {
-			if ( !responseContainer ) {
-				jQuery.error( jsonpCallback + " was not called" );
-			}
-			return responseContainer[ 0 ];
-		};
-
-		// force json dataType
-		s.dataTypes[ 0 ] = "json";
-
-		// Delegate to script
-		return "script";
-	}
-});
-
-
-
-
-// Install script dataType
-jQuery.ajaxSetup({
-	accepts: {
-		script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
-	},
-	contents: {
-		script: /javascript|ecmascript/
-	},
-	converters: {
-		"text script": function( text ) {
-			jQuery.globalEval( text );
-			return text;
-		}
-	}
-});
-
-// Handle cache's special case and global
-jQuery.ajaxPrefilter( "script", function( s ) {
-	if ( s.cache === undefined ) {
-		s.cache = false;
-	}
-	if ( s.crossDomain ) {
-		s.type = "GET";
-		s.global = false;
-	}
-});
-
-// Bind script tag hack transport
-jQuery.ajaxTransport( "script", function(s) {
-
-	// This transport only deals with cross domain requests
-	if ( s.crossDomain ) {
-
-		var script,
-			head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement;
-
-		return {
-
-			send: function( _, callback ) {
-
-				script = document.createElement( "script" );
-
-				script.async = "async";
-
-				if ( s.scriptCharset ) {
-					script.charset = s.scriptCharset;
-				}
-
-				script.src = s.url;
-
-				// Attach handlers for all browsers
-				script.onload = script.onreadystatechange = function( _, isAbort ) {
-
-					if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
-
-						// Handle memory leak in IE
-						script.onload = script.onreadystatechange = null;
-
-						// Remove the script
-						if ( head && script.parentNode ) {
-							head.removeChild( script );
-						}
-
-						// Dereference the script
-						script = undefined;
-
-						// Callback if not abort
-						if ( !isAbort ) {
-							callback( 200, "success" );
-						}
-					}
-				};
-				// Use insertBefore instead of appendChild  to circumvent an IE6 bug.
-				// This arises when a base node is used (#2709 and #4378).
-				head.insertBefore( script, head.firstChild );
-			},
-
-			abort: function() {
-				if ( script ) {
-					script.onload( 0, 1 );
-				}
-			}
-		};
-	}
-});
-
-
-
-
-var // #5280: Internet Explorer will keep connections alive if we don't abort on unload
-	xhrOnUnloadAbort = window.ActiveXObject ? function() {
-		// Abort all pending requests
-		for ( var key in xhrCallbacks ) {
-			xhrCallbacks[ key ]( 0, 1 );
-		}
-	} : false,
-	xhrId = 0,
-	xhrCallbacks;
-
-// Functions to create xhrs
-function createStandardXHR() {
-	try {
-		return new window.XMLHttpRequest();
-	} catch( e ) {}
-}
-
-function createActiveXHR() {
-	try {
-		return new window.ActiveXObject( "Microsoft.XMLHTTP" );
-	} catch( e ) {}
-}
-
-// Create the request object
-// (This is still attached to ajaxSettings for backward compatibility)
-jQuery.ajaxSettings.xhr = window.ActiveXObject ?
-	/* Microsoft failed to properly
-	 * implement the XMLHttpRequest in IE7 (can't request local files),
-	 * so we use the ActiveXObject when it is available
-	 * Additionally XMLHttpRequest can be disabled in IE7/IE8 so
-	 * we need a fallback.
-	 */
-	function() {
-		return !this.isLocal && createStandardXHR() || createActiveXHR();
-	} :
-	// For all other browsers, use the standard XMLHttpRequest object
-	createStandardXHR;
-
-// Determine support properties
-(function( xhr ) {
-	jQuery.extend( jQuery.support, {
-		ajax: !!xhr,
-		cors: !!xhr && ( "withCredentials" in xhr )
-	});
-})( jQuery.ajaxSettings.xhr() );
-
-// Create transport if the browser can provide an xhr
-if ( jQuery.support.ajax ) {
-
-	jQuery.ajaxTransport(function( s ) {
-		// Cross domain only allowed if supported through XMLHttpRequest
-		if ( !s.crossDomain || jQuery.support.cors ) {
-
-			var callback;
-
-			return {
-				send: function( headers, complete ) {
-
-					// Get a new xhr
-					var xhr = s.xhr(),
-						handle,
-						i;
-
-					// Open the socket
-					// Passing null username, generates a login popup on Opera (#2865)
-					if ( s.username ) {
-						xhr.open( s.type, s.url, s.async, s.username, s.password );
-					} else {
-						xhr.open( s.type, s.url, s.async );
-					}
-
-					// Apply custom fields if provided
-					if ( s.xhrFields ) {
-						for ( i in s.xhrFields ) {
-							xhr[ i ] = s.xhrFields[ i ];
-						}
-					}
-
-					// Override mime type if needed
-					if ( s.mimeType && xhr.overrideMimeType ) {
-						xhr.overrideMimeType( s.mimeType );
-					}
-
-					// X-Requested-With header
-					// For cross-domain requests, seeing as conditions for a preflight are
-					// akin to a jigsaw puzzle, we simply never set it to be sure.
-					// (it can always be set on a per-request basis or even using ajaxSetup)
-					// For same-domain requests, won't change header if already provided.
-					if ( !s.crossDomain && !headers["X-Requested-With"] ) {
-						headers[ "X-Requested-With" ] = "XMLHttpRequest";
-					}
-
-					// Need an extra try/catch for cross domain requests in Firefox 3
-					try {
-						for ( i in headers ) {
-							xhr.setRequestHeader( i, headers[ i ] );
-						}
-					} catch( _ ) {}
-
-					// Do send the request
-					// This may raise an exception which is actually
-					// handled in jQuery.ajax (so no try/catch here)
-					xhr.send( ( s.hasContent && s.data ) || null );
-
-					// Listener
-					callback = function( _, isAbort ) {
-
-						var status,
-							statusText,
-							responseHeaders,
-							responses,
-							xml;
-
-						// Firefox throws exceptions when accessing properties
-						// of an xhr when a network error occured
-						// http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
-						try {
-
-							// Was never called and is aborted or complete
-							if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
-
-								// Only called once
-								callback = undefined;
-
-								// Do not keep as active anymore
-								if ( handle ) {
-									xhr.onreadystatechange = jQuery.noop;
-									if ( xhrOnUnloadAbort ) {
-										delete xhrCallbacks[ handle ];
-									}
-								}
-
-								// If it's an abort
-								if ( isAbort ) {
-									// Abort it manually if needed
-									if ( xhr.readyState !== 4 ) {
-										xhr.abort();
-									}
-								} else {
-									status = xhr.status;
-									responseHeaders = xhr.getAllResponseHeaders();
-									responses = {};
-									xml = xhr.responseXML;
-
-									// Construct response list
-									if ( xml && xml.documentElement /* #4958 */ ) {
-										responses.xml = xml;
-									}
-									responses.text = xhr.responseText;
-
-									// Firefox throws an exception when accessing
-									// statusText for faulty cross-domain requests
-									try {
-										statusText = xhr.statusText;
-									} catch( e ) {
-										// We normalize with Webkit giving an empty statusText
-										statusText = "";
-									}
-
-									// Filter status for non standard behaviors
-
-									// If the request is local and we have data: assume a success
-									// (success with no data won't get notified, that's the best we
-									// can do given current implementations)
-									if ( !status && s.isLocal && !s.crossDomain ) {
-										status = responses.text ? 200 : 404;
-									// IE - #1450: sometimes returns 1223 when it should be 204
-									} else if ( status === 1223 ) {
-										status = 204;
-									}
-								}
-							}
-						} catch( firefoxAccessException ) {
-							if ( !isAbort ) {
-								complete( -1, firefoxAccessException );
-							}
-						}
-
-						// Call complete if needed
-						if ( responses ) {
-							complete( status, statusText, responses, responseHeaders );
-						}
-					};
-
-					// if we're in sync mode or it's in cache
-					// and has been retrieved directly (IE6 & IE7)
-					// we need to manually fire the callback
-					if ( !s.async || xhr.readyState === 4 ) {
-						callback();
-					} else {
-						handle = ++xhrId;
-						if ( xhrOnUnloadAbort ) {
-							// Create the active xhrs callbacks list if needed
-							// and attach the unload handler
-							if ( !xhrCallbacks ) {
-								xhrCallbacks = {};
-								jQuery( window ).unload( xhrOnUnloadAbort );
-							}
-							// Add to list of active xhrs callbacks
-							xhrCallbacks[ handle ] = callback;
-						}
-						xhr.onreadystatechange = callback;
-					}
-				},
-
-				abort: function() {
-					if ( callback ) {
-						callback(0,1);
-					}
-				}
-			};
-		}
-	});
-}
-
-
-
-
-var elemdisplay = {},
-	iframe, iframeDoc,
-	rfxtypes = /^(?:toggle|show|hide)$/,
-	rfxnum = /^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,
-	timerId,
-	fxAttrs = [
-		// height animations
-		[ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ],
-		// width animations
-		[ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ],
-		// opacity animations
-		[ "opacity" ]
-	],
-	fxNow;
-
-jQuery.fn.extend({
-	show: function( speed, easing, callback ) {
-		var elem, display;
-
-		if ( speed || speed === 0 ) {
-			return this.animate( genFx("show", 3), speed, easing, callback );
-
-		} else {
-			for ( var i = 0, j = this.length; i < j; i++ ) {
-				elem = this[ i ];
-
-				if ( elem.style ) {
-					display = elem.style.display;
-
-					// Reset the inline display of this element to learn if it is
-					// being hidden by cascaded rules or not
-					if ( !jQuery._data(elem, "olddisplay") && display === "none" ) {
-						display = elem.style.display = "";
-					}
-
-					// Set elements which have been overridden with display: none
-					// in a stylesheet to whatever the default browser style is
-					// for such an element
-					if ( display === "" && jQuery.css(elem, "display") === "none" ) {
-						jQuery._data( elem, "olddisplay", defaultDisplay(elem.nodeName) );
-					}
-				}
-			}
-
-			// Set the display of most of the elements in a second loop
-			// to avoid the constant reflow
-			for ( i = 0; i < j; i++ ) {
-				elem = this[ i ];
-
-				if ( elem.style ) {
-					display = elem.style.display;
-
-					if ( display === "" || display === "none" ) {
-						elem.style.display = jQuery._data( elem, "olddisplay" ) || "";
-					}
-				}
-			}
-
-			return this;
-		}
-	},
-
-	hide: function( speed, easing, callback ) {
-		if ( speed || speed === 0 ) {
-			return this.animate( genFx("hide", 3), speed, easing, callback);
-
-		} else {
-			var elem, display,
-				i = 0,
-				j = this.length;
-
-			for ( ; i < j; i++ ) {
-				elem = this[i];
-				if ( elem.style ) {
-					display = jQuery.css( elem, "display" );
-
-					if ( display !== "none" && !jQuery._data( elem, "olddisplay" ) ) {
-						jQuery._data( elem, "olddisplay", display );
-					}
-				}
-			}
-
-			// Set the display of the elements in a second loop
-			// to avoid the constant reflow
-			for ( i = 0; i < j; i++ ) {
-				if ( this[i].style ) {
-					this[i].style.display = "none";
-				}
-			}
-
-			return this;
-		}
-	},
-
-	// Save the old toggle function
-	_toggle: jQuery.fn.toggle,
-
-	toggle: function( fn, fn2, callback ) {
-		var bool = typeof fn === "boolean";
-
-		if ( jQuery.isFunction(fn) && jQuery.isFunction(fn2) ) {
-			this._toggle.apply( this, arguments );
-
-		} else if ( fn == null || bool ) {
-			this.each(function() {
-				var state = bool ? fn : jQuery(this).is(":hidden");
-				jQuery(this)[ state ? "show" : "hide" ]();
-			});
-
-		} else {
-			this.animate(genFx("toggle", 3), fn, fn2, callback);
-		}
-
-		return this;
-	},
-
-	fadeTo: function( speed, to, easing, callback ) {
-		return this.filter(":hidden").css("opacity", 0).show().end()
-					.animate({opacity: to}, speed, easing, callback);
-	},
-
-	animate: function( prop, speed, easing, callback ) {
-		var optall = jQuery.speed( speed, easing, callback );
-
-		if ( jQuery.isEmptyObject( prop ) ) {
-			return this.each( optall.complete, [ false ] );
-		}
-
-		// Do not change referenced properties as per-property easing will be lost
-		prop = jQuery.extend( {}, prop );
-
-		function doAnimation() {
-			// XXX 'this' does not always have a nodeName when running the
-			// test suite
-
-			if ( optall.queue === false ) {
-				jQuery._mark( this );
-			}
-
-			var opt = jQuery.extend( {}, optall ),
-				isElement = this.nodeType === 1,
-				hidden = isElement && jQuery(this).is(":hidden"),
-				name, val, p, e,
-				parts, start, end, unit,
-				method;
-
-			// will store per property easing and be used to determine when an animation is complete
-			opt.animatedProperties = {};
-
-			for ( p in prop ) {
-
-				// property name normalization
-				name = jQuery.camelCase( p );
-				if ( p !== name ) {
-					prop[ name ] = prop[ p ];
-					delete prop[ p ];
-				}
-
-				val = prop[ name ];
-
-				// easing resolution: per property > opt.specialEasing > opt.easing > 'swing' (default)
-				if ( jQuery.isArray( val ) ) {
-					opt.animatedProperties[ name ] = val[ 1 ];
-					val = prop[ name ] = val[ 0 ];
-				} else {
-					opt.animatedProperties[ name ] = opt.specialEasing && opt.specialEasing[ name ] || opt.easing || 'swing';
-				}
-
-				if ( val === "hide" && hidden || val === "show" && !hidden ) {
-					return opt.complete.call( this );
-				}
-
-				if ( isElement && ( name === "height" || name === "width" ) ) {
-					// Make sure that nothing sneaks out
-					// Record all 3 overflow attributes because IE does not
-					// change the overflow attribute when overflowX and
-					// overflowY are set to the same value
-					opt.overflow = [ this.style.overflow, this.style.overflowX, this.style.overflowY ];
-
-					// Set display property to inline-block for height/width
-					// animations on inline elements that are having width/height animated
-					if ( jQuery.css( this, "display" ) === "inline" &&
-							jQuery.css( this, "float" ) === "none" ) {
-
-						// inline-level elements accept inline-block;
-						// block-level elements need to be inline with layout
-						if ( !jQuery.support.inlineBlockNeedsLayout || defaultDisplay( this.nodeName ) === "inline" ) {
-							this.style.display = "inline-block";
-
-						} else {
-							this.style.zoom = 1;
-						}
-					}
-				}
-			}
-
-			if ( opt.overflow != null ) {
-				this.style.overflow = "hidden";
-			}
-
-			for ( p in prop ) {
-				e = new jQuery.fx( this, opt, p );
-				val = prop[ p ];
-
-				if ( rfxtypes.test( val ) ) {
-
-					// Tracks whether to show or hide based on private
-					// data attached to the element
-					method = jQuery._data( this, "toggle" + p ) || ( val === "toggle" ? hidden ? "show" : "hide" : 0 );
-					if ( method ) {
-						jQuery._data( this, "toggle" + p, method === "show" ? "hide" : "show" );
-						e[ method ]();
-					} else {
-						e[ val ]();
-					}
-
-				} else {
-					parts = rfxnum.exec( val );
-					start = e.cur();
-
-					if ( parts ) {
-						end = parseFloat( parts[2] );
-						unit = parts[3] || ( jQuery.cssNumber[ p ] ? "" : "px" );
-
-						// We need to compute starting value
-						if ( unit !== "px" ) {
-							jQuery.style( this, p, (end || 1) + unit);
-							start = ( (end || 1) / e.cur() ) * start;
-							jQuery.style( this, p, start + unit);
-						}
-
-						// If a +=/-= token was provided, we're doing a relative animation
-						if ( parts[1] ) {
-							end = ( (parts[ 1 ] === "-=" ? -1 : 1) * end ) + start;
-						}
-
-						e.custom( start, end, unit );
-
-					} else {
-						e.custom( start, val, "" );
-					}
-				}
-			}
-
-			// For JS strict compliance
-			return true;
-		}
-
-		return optall.queue === false ?
-			this.each( doAnimation ) :
-			this.queue( optall.queue, doAnimation );
-	},
-
-	stop: function( type, clearQueue, gotoEnd ) {
-		if ( typeof type !== "string" ) {
-			gotoEnd = clearQueue;
-			clearQueue = type;
-			type = undefined;
-		}
-		if ( clearQueue && type !== false ) {
-			this.queue( type || "fx", [] );
-		}
-
-		return this.each(function() {
-			var index,
-				hadTimers = false,
-				timers = jQuery.timers,
-				data = jQuery._data( this );
-
-			// clear marker counters if we know they won't be
-			if ( !gotoEnd ) {
-				jQuery._unmark( true, this );
-			}
-
-			function stopQueue( elem, data, index ) {
-				var hooks = data[ index ];
-				jQuery.removeData( elem, index, true );
-				hooks.stop( gotoEnd );
-			}
-
-			if ( type == null ) {
-				for ( index in data ) {
-					if ( data[ index ] && data[ index ].stop && index.indexOf(".run") === index.length - 4 ) {
-						stopQueue( this, data, index );
-					}
-				}
-			} else if ( data[ index = type + ".run" ] && data[ index ].stop ){
-				stopQueue( this, data, index );
-			}
-
-			for ( index = timers.length; index--; ) {
-				if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
-					if ( gotoEnd ) {
-
-						// force the next step to be the last
-						timers[ index ]( true );
-					} else {
-						timers[ index ].saveState();
-					}
-					hadTimers = true;
-					timers.splice( index, 1 );
-				}
-			}
-
-			// start the next in the queue if the last step wasn't forced
-			// timers currently will call their complete callbacks, which will dequeue
-			// but only if they were gotoEnd
-			if ( !( gotoEnd && hadTimers ) ) {
-				jQuery.dequeue( this, type );
-			}
-		});
-	}
-
-});
-
-// Animations created synchronously will run synchronously
-function createFxNow() {
-	setTimeout( clearFxNow, 0 );
-	return ( fxNow = jQuery.now() );
-}
-
-function clearFxNow() {
-	fxNow = undefined;
-}
-
-// Generate parameters to create a standard animation
-function genFx( type, num ) {
-	var obj = {};
-
-	jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice( 0, num )), function() {
-		obj[ this ] = type;
-	});
-
-	return obj;
-}
-
-// Generate shortcuts for custom animations
-jQuery.each({
-	slideDown: genFx( "show", 1 ),
-	slideUp: genFx( "hide", 1 ),
-	slideToggle: genFx( "toggle", 1 ),
-	fadeIn: { opacity: "show" },
-	fadeOut: { opacity: "hide" },
-	fadeToggle: { opacity: "toggle" }
-}, function( name, props ) {
-	jQuery.fn[ name ] = function( speed, easing, callback ) {
-		return this.animate( props, speed, easing, callback );
-	};
-});
-
-jQuery.extend({
-	speed: function( speed, easing, fn ) {
-		var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
-			complete: fn || !fn && easing ||
-				jQuery.isFunction( speed ) && speed,
-			duration: speed,
-			easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
-		};
-
-		opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
-			opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
-
-		// normalize opt.queue - true/undefined/null -> "fx"
-		if ( opt.queue == null || opt.queue === true ) {
-			opt.queue = "fx";
-		}
-
-		// Queueing
-		opt.old = opt.complete;
-
-		opt.complete = function( noUnmark ) {
-			if ( jQuery.isFunction( opt.old ) ) {
-				opt.old.call( this );
-			}
-
-			if ( opt.queue ) {
-				jQuery.dequeue( this, opt.queue );
-			} else if ( noUnmark !== false ) {
-				jQuery._unmark( this );
-			}
-		};
-
-		return opt;
-	},
-
-	easing: {
-		linear: function( p, n, firstNum, diff ) {
-			return firstNum + diff * p;
-		},
-		swing: function( p, n, firstNum, diff ) {
-			return ( ( -Math.cos( p*Math.PI ) / 2 ) + 0.5 ) * diff + firstNum;
-		}
-	},
-
-	timers: [],
-
-	fx: function( elem, options, prop ) {
-		this.options = options;
-		this.elem = elem;
-		this.prop = prop;
-
-		options.orig = options.orig || {};
-	}
-
-});
-
-jQuery.fx.prototype = {
-	// Simple function for setting a style value
-	update: function() {
-		if ( this.options.step ) {
-			this.options.step.call( this.elem, this.now, this );
-		}
-
-		( jQuery.fx.step[ this.prop ] || jQuery.fx.step._default )( this );
-	},
-
-	// Get the current size
-	cur: function() {
-		if ( this.elem[ this.prop ] != null && (!this.elem.style || this.elem.style[ this.prop ] == null) ) {
-			return this.elem[ this.prop ];
-		}
-
-		var parsed,
-			r = jQuery.css( this.elem, this.prop );
-		// Empty strings, null, undefined and "auto" are converted to 0,
-		// complex values such as "rotate(1rad)" are returned as is,
-		// simple values such as "10px" are parsed to Float.
-		return isNaN( parsed = parseFloat( r ) ) ? !r || r === "auto" ? 0 : r : parsed;
-	},
-
-	// Start an animation from one number to another
-	custom: function( from, to, unit ) {
-		var self = this,
-			fx = jQuery.fx;
-
-		this.startTime = fxNow || createFxNow();
-		this.end = to;
-		this.now = this.start = from;
-		this.pos = this.state = 0;
-		this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" );
-
-		function t( gotoEnd ) {
-			return self.step( gotoEnd );
-		}
-
-		t.queue = this.options.queue;
-		t.elem = this.elem;
-		t.saveState = function() {
-			if ( self.options.hide && jQuery._data( self.elem, "fxshow" + self.prop ) === undefined ) {
-				jQuery._data( self.elem, "fxshow" + self.prop, self.start );
-			}
-		};
-
-		if ( t() && jQuery.timers.push(t) && !timerId ) {
-			timerId = setInterval( fx.tick, fx.interval );
-		}
-	},
-
-	// Simple 'show' function
-	show: function() {
-		var dataShow = jQuery._data( this.elem, "fxshow" + this.prop );
-
-		// Remember where we started, so that we can go back to it later
-		this.options.orig[ this.prop ] = dataShow || jQuery.style( this.elem, this.prop );
-		this.options.show = true;
-
-		// Begin the animation
-		// Make sure that we start at a small width/height to avoid any flash of content
-		if ( dataShow !== undefined ) {
-			// This show is picking up where a previous hide or show left off
-			this.custom( this.cur(), dataShow );
-		} else {
-			this.custom( this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur() );
-		}
-
-		// Start by showing the element
-		jQuery( this.elem ).show();
-	},
-
-	// Simple 'hide' function
-	hide: function() {
-		// Remember where we started, so that we can go back to it later
-		this.options.orig[ this.prop ] = jQuery._data( this.elem, "fxshow" + this.prop ) || jQuery.style( this.elem, this.prop );
-		this.options.hide = true;
-
-		// Begin the animation
-		this.custom( this.cur(), 0 );
-	},
-
-	// Each step of an animation
-	step: function( gotoEnd ) {
-		var p, n, complete,
-			t = fxNow || createFxNow(),
-			done = true,
-			elem = this.elem,
-			options = this.options;
-
-		if ( gotoEnd || t >= options.duration + this.startTime ) {
-			this.now = this.end;
-			this.pos = this.state = 1;
-			this.update();
-
-			options.animatedProperties[ this.prop ] = true;
-
-			for ( p in options.animatedProperties ) {
-				if ( options.animatedProperties[ p ] !== true ) {
-					done = false;
-				}
-			}
-
-			if ( done ) {
-				// Reset the overflow
-				if ( options.overflow != null && !jQuery.support.shrinkWrapBlocks ) {
-
-					jQuery.each( [ "", "X", "Y" ], function( index, value ) {
-						elem.style[ "overflow" + value ] = options.overflow[ index ];
-					});
-				}
-
-				// Hide the element if the "hide" operation was done
-				if ( options.hide ) {
-					jQuery( elem ).hide();
-				}
-
-				// Reset the properties, if the item has been hidden or shown
-				if ( options.hide || options.show ) {
-					for ( p in options.animatedProperties ) {
-						jQuery.style( elem, p, options.orig[ p ] );
-						jQuery.removeData( elem, "fxshow" + p, true );
-						// Toggle data is no longer needed
-						jQuery.removeData( elem, "toggle" + p, true );
-					}
-				}
-
-				// Execute the complete function
-				// in the event that the complete function throws an exception
-				// we must ensure it won't be called twice. #5684
-
-				complete = options.complete;
-				if ( complete ) {
-
-					options.complete = false;
-					complete.call( elem );
-				}
-			}
-
-			return false;
-
-		} else {
-			// classical easing cannot be used with an Infinity duration
-			if ( options.duration == Infinity ) {
-				this.now = t;
-			} else {
-				n = t - this.startTime;
-				this.state = n / options.duration;
-
-				// Perform the easing function, defaults to swing
-				this.pos = jQuery.easing[ options.animatedProperties[this.prop] ]( this.state, n, 0, 1, options.duration );
-				this.now = this.start + ( (this.end - this.start) * this.pos );
-			}
-			// Perform the next step of the animation
-			this.update();
-		}
-
-		return true;
-	}
-};
-
-jQuery.extend( jQuery.fx, {
-	tick: function() {
-		var timer,
-			timers = jQuery.timers,
-			i = 0;
-
-		for ( ; i < timers.length; i++ ) {
-			timer = timers[ i ];
-			// Checks the timer has not already been removed
-			if ( !timer() && timers[ i ] === timer ) {
-				timers.splice( i--, 1 );
-			}
-		}
-
-		if ( !timers.length ) {
-			jQuery.fx.stop();
-		}
-	},
-
-	interval: 13,
-
-	stop: function() {
-		clearInterval( timerId );
-		timerId = null;
-	},
-
-	speeds: {
-		slow: 600,
-		fast: 200,
-		// Default speed
-		_default: 400
-	},
-
-	step: {
-		opacity: function( fx ) {
-			jQuery.style( fx.elem, "opacity", fx.now );
-		},
-
-		_default: function( fx ) {
-			if ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) {
-				fx.elem.style[ fx.prop ] = fx.now + fx.unit;
-			} else {
-				fx.elem[ fx.prop ] = fx.now;
-			}
-		}
-	}
-});
-
-// Adds width/height step functions
-// Do not set anything below 0
-jQuery.each([ "width", "height" ], function( i, prop ) {
-	jQuery.fx.step[ prop ] = function( fx ) {
-		jQuery.style( fx.elem, prop, Math.max(0, fx.now) + fx.unit );
-	};
-});
-
-if ( jQuery.expr && jQuery.expr.filters ) {
-	jQuery.expr.filters.animated = function( elem ) {
-		return jQuery.grep(jQuery.timers, function( fn ) {
-			return elem === fn.elem;
-		}).length;
-	};
-}
-
-// Try to restore the default display value of an element
-function defaultDisplay( nodeName ) {
-
-	if ( !elemdisplay[ nodeName ] ) {
-
-		var body = document.body,
-			elem = jQuery( "<" + nodeName + ">" ).appendTo( body ),
-			display = elem.css( "display" );
-		elem.remove();
-
-		// If the simple way fails,
-		// get element's real default display by attaching it to a temp iframe
-		if ( display === "none" || display === "" ) {
-			// No iframe to use yet, so create it
-			if ( !iframe ) {
-				iframe = document.createElement( "iframe" );
-				iframe.frameBorder = iframe.width = iframe.height = 0;
-			}
-
-			body.appendChild( iframe );
-
-			// Create a cacheable copy of the iframe document on first call.
-			// IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML
-			// document to it; WebKit & Firefox won't allow reusing the iframe document.
-			if ( !iframeDoc || !iframe.createElement ) {
-				iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document;
-				iframeDoc.write( ( document.compatMode === "CSS1Compat" ? "<!doctype html>" : "" ) + "<html><body>" );
-				iframeDoc.close();
-			}
-
-			elem = iframeDoc.createElement( nodeName );
-
-			iframeDoc.body.appendChild( elem );
-
-			display = jQuery.css( elem, "display" );
-			body.removeChild( iframe );
-		}
-
-		// Store the correct default display
-		elemdisplay[ nodeName ] = display;
-	}
-
-	return elemdisplay[ nodeName ];
-}
-
-
-
-
-var rtable = /^t(?:able|d|h)$/i,
-	rroot = /^(?:body|html)$/i;
-
-if ( "getBoundingClientRect" in document.documentElement ) {
-	jQuery.fn.offset = function( options ) {
-		var elem = this[0], box;
-
-		if ( options ) {
-			return this.each(function( i ) {
-				jQuery.offset.setOffset( this, options, i );
-			});
-		}
-
-		if ( !elem || !elem.ownerDocument ) {
-			return null;
-		}
-
-		if ( elem === elem.ownerDocument.body ) {
-			return jQuery.offset.bodyOffset( elem );
-		}
-
-		try {
-			box = elem.getBoundingClientRect();
-		} catch(e) {}
-
-		var doc = elem.ownerDocument,
-			docElem = doc.documentElement;
-
-		// Make sure we're not dealing with a disconnected DOM node
-		if ( !box || !jQuery.contains( docElem, elem ) ) {
-			return box ? { top: box.top, left: box.left } : { top: 0, left: 0 };
-		}
-
-		var body = doc.body,
-			win = getWindow(doc),
-			clientTop  = docElem.clientTop  || body.clientTop  || 0,
-			clientLeft = docElem.clientLeft || body.clientLeft || 0,
-			scrollTop  = win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop  || body.scrollTop,
-			scrollLeft = win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft,
-			top  = box.top  + scrollTop  - clientTop,
-			left = box.left + scrollLeft - clientLeft;
-
-		return { top: top, left: left };
-	};
-
-} else {
-	jQuery.fn.offset = function( options ) {
-		var elem = this[0];
-
-		if ( options ) {
-			return this.each(function( i ) {
-				jQuery.offset.setOffset( this, options, i );
-			});
-		}
-
-		if ( !elem || !elem.ownerDocument ) {
-			return null;
-		}
-
-		if ( elem === elem.ownerDocument.body ) {
-			return jQuery.offset.bodyOffset( elem );
-		}
-
-		var computedStyle,
-			offsetParent = elem.offsetParent,
-			prevOffsetParent = elem,
-			doc = elem.ownerDocument,
-			docElem = doc.documentElement,
-			body = doc.body,
-			defaultView = doc.defaultView,
-			prevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,
-			top = elem.offsetTop,
-			left = elem.offsetLeft;
-
-		while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
-			if ( jQuery.support.fixedPosition && prevComputedStyle.position === "fixed" ) {
-				break;
-			}
-
-			computedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle;
-			top  -= elem.scrollTop;
-			left -= elem.scrollLeft;
-
-			if ( elem === offsetParent ) {
-				top  += elem.offsetTop;
-				left += elem.offsetLeft;
-
-				if ( jQuery.support.doesNotAddBorder && !(jQuery.support.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) {
-					top  += parseFloat( computedStyle.borderTopWidth  ) || 0;
-					left += parseFloat( computedStyle.borderLeftWidth ) || 0;
-				}
-
-				prevOffsetParent = offsetParent;
-				offsetParent = elem.offsetParent;
-			}
-
-			if ( jQuery.support.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) {
-				top  += parseFloat( computedStyle.borderTopWidth  ) || 0;
-				left += parseFloat( computedStyle.borderLeftWidth ) || 0;
-			}
-
-			prevComputedStyle = computedStyle;
-		}
-
-		if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" ) {
-			top  += body.offsetTop;
-			left += body.offsetLeft;
-		}
-
-		if ( jQuery.support.fixedPosition && prevComputedStyle.position === "fixed" ) {
-			top  += Math.max( docElem.scrollTop, body.scrollTop );
-			left += Math.max( docElem.scrollLeft, body.scrollLeft );
-		}
-
-		return { top: top, left: left };
-	};
-}
-
-jQuery.offset = {
-
-	bodyOffset: function( body ) {
-		var top = body.offsetTop,
-			left = body.offsetLeft;
-
-		if ( jQuery.support.doesNotIncludeMarginInBodyOffset ) {
-			top  += parseFloat( jQuery.css(body, "marginTop") ) || 0;
-			left += parseFloat( jQuery.css(body, "marginLeft") ) || 0;
-		}
-
-		return { top: top, left: left };
-	},
-
-	setOffset: function( elem, options, i ) {
-		var position = jQuery.css( elem, "position" );
-
-		// set position first, in-case top/left are set even on static elem
-		if ( position === "static" ) {
-			elem.style.position = "relative";
-		}
-
-		var curElem = jQuery( elem ),
-			curOffset = curElem.offset(),
-			curCSSTop = jQuery.css( elem, "top" ),
-			curCSSLeft = jQuery.css( elem, "left" ),
-			calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
-			props = {}, curPosition = {}, curTop, curLeft;
-
-		// need to be able to calculate position if either top or left is auto and position is either absolute or fixed
-		if ( calculatePosition ) {
-			curPosition = curElem.position();
-			curTop = curPosition.top;
-			curLeft = curPosition.left;
-		} else {
-			curTop = parseFloat( curCSSTop ) || 0;
-			curLeft = parseFloat( curCSSLeft ) || 0;
-		}
-
-		if ( jQuery.isFunction( options ) ) {
-			options = options.call( elem, i, curOffset );
-		}
-
-		if ( options.top != null ) {
-			props.top = ( options.top - curOffset.top ) + curTop;
-		}
-		if ( options.left != null ) {
-			props.left = ( options.left - curOffset.left ) + curLeft;
-		}
-
-		if ( "using" in options ) {
-			options.using.call( elem, props );
-		} else {
-			curElem.css( props );
-		}
-	}
-};
-
-
-jQuery.fn.extend({
-
-	position: function() {
-		if ( !this[0] ) {
-			return null;
-		}
-
-		var elem = this[0],
-
-		// Get *real* offsetParent
-		offsetParent = this.offsetParent(),
-
-		// Get correct offsets
-		offset       = this.offset(),
-		parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();
-
-		// Subtract element margins
-		// note: when an element has margin: auto the offsetLeft and marginLeft
-		// are the same in Safari causing offset.left to incorrectly be 0
-		offset.top  -= parseFloat( jQuery.css(elem, "marginTop") ) || 0;
-		offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0;
-
-		// Add offsetParent borders
-		parentOffset.top  += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0;
-		parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0;
-
-		// Subtract the two offsets
-		return {
-			top:  offset.top  - parentOffset.top,
-			left: offset.left - parentOffset.left
-		};
-	},
-
-	offsetParent: function() {
-		return this.map(function() {
-			var offsetParent = this.offsetParent || document.body;
-			while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) {
-				offsetParent = offsetParent.offsetParent;
-			}
-			return offsetParent;
-		});
-	}
-});
-
-
-// Create scrollLeft and scrollTop methods
-jQuery.each( ["Left", "Top"], function( i, name ) {
-	var method = "scroll" + name;
-
-	jQuery.fn[ method ] = function( val ) {
-		var elem, win;
-
-		if ( val === undefined ) {
-			elem = this[ 0 ];
-
-			if ( !elem ) {
-				return null;
-			}
-
-			win = getWindow( elem );
-
-			// Return the scroll offset
-			return win ? ("pageXOffset" in win) ? win[ i ? "pageYOffset" : "pageXOffset" ] :
-				jQuery.support.boxModel && win.document.documentElement[ method ] ||
-					win.document.body[ method ] :
-				elem[ method ];
-		}
-
-		// Set the scroll offset
-		return this.each(function() {
-			win = getWindow( this );
-
-			if ( win ) {
-				win.scrollTo(
-					!i ? val : jQuery( win ).scrollLeft(),
-					 i ? val : jQuery( win ).scrollTop()
-				);
-
-			} else {
-				this[ method ] = val;
-			}
-		});
-	};
-});
-
-function getWindow( elem ) {
-	return jQuery.isWindow( elem ) ?
-		elem :
-		elem.nodeType === 9 ?
-			elem.defaultView || elem.parentWindow :
-			false;
-}
-
-
-
-
-// Create width, height, innerHeight, innerWidth, outerHeight and outerWidth methods
-jQuery.each([ "Height", "Width" ], function( i, name ) {
-
-	var type = name.toLowerCase();
-
-	// innerHeight and innerWidth
-	jQuery.fn[ "inner" + name ] = function() {
-		var elem = this[0];
-		return elem ?
-			elem.style ?
-			parseFloat( jQuery.css( elem, type, "padding" ) ) :
-			this[ type ]() :
-			null;
-	};
-
-	// outerHeight and outerWidth
-	jQuery.fn[ "outer" + name ] = function( margin ) {
-		var elem = this[0];
-		return elem ?
-			elem.style ?
-			parseFloat( jQuery.css( elem, type, margin ? "margin" : "border" ) ) :
-			this[ type ]() :
-			null;
-	};
-
-	jQuery.fn[ type ] = function( size ) {
-		// Get window width or height
-		var elem = this[0];
-		if ( !elem ) {
-			return size == null ? null : this;
-		}
-
-		if ( jQuery.isFunction( size ) ) {
-			return this.each(function( i ) {
-				var self = jQuery( this );
-				self[ type ]( size.call( this, i, self[ type ]() ) );
-			});
-		}
-
-		if ( jQuery.isWindow( elem ) ) {
-			// Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
-			// 3rd condition allows Nokia support, as it supports the docElem prop but not CSS1Compat
-			var docElemProp = elem.document.documentElement[ "client" + name ],
-				body = elem.document.body;
-			return elem.document.compatMode === "CSS1Compat" && docElemProp ||
-				body && body[ "client" + name ] || docElemProp;
-
-		// Get document width or height
-		} else if ( elem.nodeType === 9 ) {
-			// Either scroll[Width/Height] or offset[Width/Height], whichever is greater
-			return Math.max(
-				elem.documentElement["client" + name],
-				elem.body["scroll" + name], elem.documentElement["scroll" + name],
-				elem.body["offset" + name], elem.documentElement["offset" + name]
-			);
-
-		// Get or set width or height on the element
-		} else if ( size === undefined ) {
-			var orig = jQuery.css( elem, type ),
-				ret = parseFloat( orig );
-
-			return jQuery.isNumeric( ret ) ? ret : orig;
-
-		// Set the width or height on the element (default to pixels if value is unitless)
-		} else {
-			return this.css( type, typeof size === "string" ? size : size + "px" );
-		}
-	};
-
-});
-
-
-
-
-// Expose jQuery to the global object
-window.jQuery = window.$ = jQuery;
-
-// Expose jQuery as an AMD module, but only for AMD loaders that
-// understand the issues with loading multiple versions of jQuery
-// in a page that all might call define(). The loader will indicate
-// they have special allowances for multiple jQuery versions by
-// specifying define.amd.jQuery = true. Register as a named module,
-// since jQuery can be concatenated with other files that may use define,
-// but not use a proper concatenation script that understands anonymous
-// AMD modules. A named AMD is safest and most robust way to register.
-// Lowercase jquery is used because AMD module names are derived from
-// file names, and jQuery is normally delivered in a lowercase file name.
-// Do this after creating the global so that if an AMD module wants to call
-// noConflict to hide this version of jQuery, it will work.
-if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
-	define( "jquery", [], function () { return jQuery; } );
-}
-
-
-
-})( window );
diff --git a/src/site/resources/js/jquery.min.js b/src/site/resources/js/jquery.min.js
deleted file mode 100644
index 198b3ff..0000000
--- a/src/site/resources/js/jquery.min.js
+++ /dev/null
@@ -1,4 +0,0 @@
-/*! jQuery v1.7.1 jquery.com | jquery.org/license */
-(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!ck[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){cl||(cl=c.createElement("iframe"),cl.frameBorder=cl.width=cl.height=0),b.appendChild(cl);if(!cm||!cl.createElement)cm=(cl.contentWindow||cl.contentDocument).document,cm.write((c.compatMode==="CSS1Compat"?"<!doctype html>":"")+"<html><body>"),cm.close();d=cm.createElement(a),cm.body.appendChild(d),e=f.css(d,"display"),b.removeChild(cl)}ck[a]=e}return ck[a]}function cu(a,b){var c={};f.each(cq.concat.apply([],cq.slice(0,b)),function(){c[this]=a});return c}function ct(){cr=b}function cs(){setTimeout(ct,0);return cr=f.now()}function cj(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ci(){try{return new a.XMLHttpRequest}catch(b){}}function cc(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g<i;g++){if(g===1)for(h in a.converters)typeof h=="string"&&(e[h.toLowerCase()]=a.converters[h]);l=k,k=d[g];if(k==="*")k=l;else if(l!=="*"&&l!==k){m=l+" "+k,n=e[m]||e["* "+k];if(!n){p=b;for(o in e){j=o.split(" ");if(j[0]===l||j[0]==="*"){p=e[j[1]+" "+k];if(p){o=e[o],o===!0?n=p:p===!0&&(n=o);break}}}}!n&&!p&&f.error("No conversion from "+m.replace(" "," to ")),n!==!0&&(c=n?n(c):p(o(c)))}}return c}function cb(a,c,d){var e=a.contents,f=a.dataTypes,g=a.responseFields,h,i,j,k;for(i in g)i in d&&(c[g[i]]=d[i]);while(f[0]==="*")f.shift(),h===b&&(h=a.mimeType||c.getResponseHeader("content-type"));if(h)for(i in e)if(e[i]&&e[i].test(h)){f.unshift(i);break}if(f[0]in d)j=f[0];else{for(i in d){if(!f[0]||a.converters[i+" "+f[0]]){j=i;break}k||(k=i)}j=j||k}if(j){j!==f[0]&&f.unshift(j);return d[j]}}function ca(a,b,c,d){if(f.isArray(b))f.each(b,function(b,e){c||bE.test(a)?d(a,e):ca(a+"["+(typeof e=="object"||f.isArray(e)?b:"")+"]",e,c,d)});else if(!c&&b!=null&&typeof b=="object")for(var e in b)ca(a+"["+e+"]",b[e],c,d);else d(a,b)}function b_(a,c){var d,e,g=f.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((g[d]?a:e||(e={}))[d]=c[d]);e&&f.extend(!0,a,e)}function b$(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h=a[f],i=0,j=h?h.length:0,k=a===bT,l;for(;i<j&&(k||!l);i++)l=h[i](c,d,e),typeof l=="string"&&(!k||g[l]?l=b:(c.dataTypes.unshift(l),l=b$(a,c,d,e,l,g)));(k||!l)&&!g["*"]&&(l=b$(a,c,d,e,"*",g));return l}function bZ(a){return function(b,c){typeof b!="string"&&(c=b,b="*");if(f.isFunction(c)){var d=b.toLowerCase().split(bP),e=0,g=d.length,h,i,j;for(;e<g;e++)h=d[e],j=/^\+/.test(h),j&&(h=h.substr(1)||"*"),i=a[h]=a[h]||[],i[j?"unshift":"push"](c)}}}function bC(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=b==="width"?bx:by,g=0,h=e.length;if(d>0){if(c!=="border")for(;g<h;g++)c||(d-=parseFloat(f.css(a,"padding"+e[g]))||0),c==="margin"?d+=parseFloat(f.css(a,c+e[g]))||0:d-=parseFloat(f.css(a,"border"+e[g]+"Width"))||0;return d+"px"}d=bz(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0;if(c)for(;g<h;g++)d+=parseFloat(f.css(a,"padding"+e[g]))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+e[g]+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+e[g]))||0);return d+"px"}function bp(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(bf,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bo(a){var b=c.createElement("div");bh.appendChild(b),b.innerHTML=a.outerHTML;return b.firstChild}function bn(a){var b=(a.nodeName||"").toLowerCase();b==="input"?bm(a):b!=="script"&&typeof a.getElementsByTagName!="undefined"&&f.grep(a.getElementsByTagName("input"),bm)}function bm(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bl(a){return typeof a.getElementsByTagName!="undefined"?a.getElementsByTagName("*"):typeof a.querySelectorAll!="undefined"?a.querySelectorAll("*"):[]}function bk(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bj(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c,d,e,g=f._data(a),h=f._data(b,g),i=g.events;if(i){delete h.handle,h.events={};for(c in i)for(d=0,e=i[c].length;d<e;d++)f.event.add(b,c+(i[c][d].namespace?".":"")+i[c][d].namespace,i[c][d],i[c][d].data)}h.data&&(h.data=f.extend({},h.data))}}function bi(a,b){return f.nodeName(a,"table")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function U(a){var b=V.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function T(a,b,c){b=b||0;if(f.isFunction(b))return f.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return f.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=f.grep(a,function(a){return a.nodeType===1});if(O.test(b))return f.filter(b,d,!c);b=f.filter(b,d)}return f.grep(a,function(a,d){return f.inArray(a,b)>=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?parseFloat(d):j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c<d;c++)b[a[c]]=!0;return b}var c=a.document,d=a.navigator,e=a.location,f=function(){function J(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(J,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.1",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j<k;j++)if((a=arguments[j])!=null)for(c in a){d=i[c],f=a[c];if(i===f)continue;l&&f&&(e.isPlainObject(f)||(g=e.isArray(f)))?(g?(g=!1,h=d&&e.isArray(d)?d:[]):h=d&&e.isPlainObject(d)?d:{},i[c]=e.extend(l,h,f)):f!==b&&(i[c]=f)}return i},e.extend({noConflict:function(b){a.$===e&&(a.$=g),b&&a.jQuery===e&&(a.jQuery=f);return e},isReady:!1,readyWait:1,holdReady:function(a){a?e.readyWait++:e.ready(!0)},ready:function(a){if(a===!0&&!--e.readyWait||a!==!0&&!e.isReady){if(!c.body)return setTimeout(e.ready,1);e.isReady=!0;if(a!==!0&&--e.readyWait>0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g<h;)if(c.apply(a[g++],d)===!1)break}else if(i){for(f in a)if(c.call(a[f],f,a[f])===!1)break}else for(;g<h;)if(c.call(a[g],g,a[g++])===!1)break;return a},trim:G?function(a){return a==null?"":G.call(a)}:function(a){return a==null?"":(a+"").replace(k,"").replace(l,"")},makeArray:function(a,b){var c=b||[];if(a!=null){var d=e.type(a);a.length==null||d==="string"||d==="function"||d==="regexp"||e.isWindow(a)?E.call(c,a):e.merge(c,a)}return c},inArray:function(a,b,c){var d;if(b){if(H)return H.call(b,a,c);d=b.length,c=c?c<0?Math.max(0,d+c):c:0;for(;c<d;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,c){var d=a.length,e=0;if(typeof c.length=="number")for(var f=c.length;e<f;e++)a[d++]=c[e];else while(c[e]!==b)a[d++]=c[e++];a.length=d;return a},grep:function(a,b,c){var d=[],e;c=!!c;for(var f=0,g=a.length;f<g;f++)e=!!b(a[f],f),c!==e&&d.push(a[f]);return d},map:function(a,c,d){var f,g,h=[],i=0,j=a.length,k=a instanceof e||j!==b&&typeof j=="number"&&(j>0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i<j;i++)f=c(a[i],i,d),f!=null&&(h[h.length]=f);else for(g in a)f=c(a[g],g,d),f!=null&&(h[h.length]=f);return h.concat.apply([],h)},guid:1,proxy:function(a,c){if(typeof c=="string"){var d=a[c];c=a,a=d}if(!e.isFunction(a))return b;var f=F.call(arguments,2),g=function(){return a.apply(c,f.concat(F.call(arguments)))};g.guid=a.guid=a.guid||g.guid||e.guid++;return g},access:function(a,c,d,f,g,h){var i=a.length;if(typeof c=="object"){for(var j in c)e.access(a,j,c[j],f,g,d);return a}if(d!==b){f=!h&&f&&e.isFunction(d);for(var k=0;k<i;k++)g(a[k],c,f?d.call(a[k],k,g(a[k],c)):d,h);return a}return i?g(a[0],c):b},now:function(){return(new Date).getTime()},uaMatch:function(a){a=a.toLowerCase();var b=r.exec(a)||s.exec(a)||t.exec(a)||a.indexOf("compatible")<0&&u.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}e.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function(d,f){f&&f instanceof e&&!(f instanceof a)&&(f=a(f));return e.fn.init.call(this,d,f,b)},a.fn.init.prototype=a.fn;var b=a(c);return a},browser:{}}),e.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){I["[object "+b+"]"]=b.toLowerCase()}),z=e.uaMatch(y),z.browser&&(e.browser[z.browser]=!0,e.browser.version=z.version),e.browser.webkit&&(e.browser.safari=!0),j.test(" ")&&(k=/^[\s\xA0]+/,l=/[\s\xA0]+$/),h=e(c),c.addEventListener?B=function(){c.removeEventListener("DOMContentLoaded",B,!1),e.ready()}:c.attachEvent&&(B=function(){c.readyState==="complete"&&(c.detachEvent("onreadystatechange",B),e.ready())});return e}(),g={};f.Callbacks=function(a){a=a?g[a]||h(a):{};var c=[],d=[],e,i,j,k,l,m=function(b){var d,e,g,h,i;for(d=0,e=b.length;d<e;d++)g=b[d],h=f.type(g),h==="array"?m(g):h==="function"&&(!a.unique||!o.has(g))&&c.push(g)},n=function(b,f){f=f||[],e=!a.memory||[b,f],i=!0,l=j||0,j=0,k=c.length;for(;c&&l<k;l++)if(c[l].apply(b,f)===!1&&a.stopOnFalse){e=!0;break}i=!1,c&&(a.once?e===!0?o.disable():c=[]:d&&d.length&&(e=d.shift(),o.fireWith(e[0],e[1])))},o={add:function(){if(c){var a=c.length;m(arguments),i?k=c.length:e&&e!==!0&&(j=a,n(e[0],e[1]))}return this},remove:function(){if(c){var b=arguments,d=0,e=b.length;for(;d<e;d++)for(var f=0;f<c.length;f++)if(b[d]===c[f]){i&&f<=k&&(k--,f<=l&&l--),c.splice(f--,1);if(a.unique)break}}return this},has:function(a){if(c){var b=0,d=c.length;for(;b<d;b++)if(a===c[b])return!0}return!1},empty:function(){c=[];return this},disable:function(){c=d=e=b;return this},disabled:function(){return!c},lock:function(){d=b,(!e||e===!0)&&o.disable();return this},locked:function(){return!d},fireWith:function(b,c){d&&(i?a.once||d.push([b,c]):(!a.once||!e)&&n(b,c));return this},fire:function(){o.fireWith(this,arguments);return this},fired:function(){return!!e}};return o};var i=[].slice;f.extend({Deferred:function(a){var b=f.Callbacks("once memory"),c=f.Callbacks("once memory"),d=f.Callbacks("memory"),e="pending",g={resolve:b,reject:c,notify:d},h={done:b.add,fail:c.add,progress:d.add,state:function(){return e},isResolved:b.fired,isRejected:c.fired,then:function(a,b,c){i.done(a).fail(b).progress(c);return this},always:function(){i.done.apply(i,arguments).fail.apply(i,arguments);return this},pipe:function(a,b,c){return f.Deferred(function(d){f.each({done:[a,"resolve"],fail:[b,"reject"],progress:[c,"notify"]},function(a,b){var c=b[0],e=b[1],g;f.isFunction(c)?i[a](function(){g=c.apply(this,arguments),g&&f.isFunction(g.promise)?g.promise().then(d.resolve,d.reject,d.notify):d[e+"With"](this===i?d:this,[g])}):i[a](d[e])})}).promise()},promise:function(a){if(a==null)a=h;else for(var b in h)a[b]=h[b];return a}},i=h.promise({}),j;for(j in g)i[j]=g[j].fire,i[j+"With"]=g[j].fireWith;i.done(function(){e="resolved"},c.disable,d.lock).fail(function(){e="rejected"},b.disable,d.lock),a&&a.call(i,i);return i},when:function(a){function m(a){return function(b){e[a]=arguments.length>1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c<d;c++)b[c]&&b[c].promise&&f.isFunction(b[c].promise)?b[c].promise().then(l(c),j.reject,m(c)):--g;g||j.resolveWith(j,b)}else j!==a&&j.resolveWith(j,d?[a]:[]);return k}}),f.support=function(){var b,d,e,g,h,i,j,k,l,m,n,o,p,q=c.createElement("div"),r=c.documentElement;q.setAttribute("className","t"),q.innerHTML="   <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>",d=q.getElementsByTagName("*"),e=q.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=q.getElementsByTagName("input")[0],b={leadingWhitespace:q.firstChild.nodeType===3,tbody:!q.getElementsByTagName("tbody").length,htmlSerialize:!!q.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:q.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete q.test}catch(s){b.deleteExpando=!1}!q.addEventListener&&q.attachEvent&&q.fireEvent&&(q.attachEvent("onclick",function(){b.noCloneEvent=!1}),q.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),q.appendChild(i),k=c.createDocumentFragment(),k.appendChild(q.lastChild),b.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,k.removeChild(i),k.appendChild(q),q.innerHTML="",a.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",q.style.width="2px",q.appendChild(j),b.reliableMarginRight=(parseInt((a.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0);if(q.attachEvent)for(o in{submit:1,change:1,focusin:1})n="on"+o,p=n in q,p||(q.setAttribute(n,"return;"),p=typeof q[n]=="function"),b[o+"Bubbles"]=p;k.removeChild(q),k=g=h=j=q=i=null,f(function(){var a,d,e,g,h,i,j,k,m,n,o,r=c.getElementsByTagName("body")[0];!r||(j=1,k="position:absolute;top:0;left:0;width:1px;height:1px;margin:0;",m="visibility:hidden;border:0;",n="style='"+k+"border:5px solid #000;padding:0;'",o="<div "+n+"><div></div></div>"+"<table "+n+" cellpadding='0' cellspacing='0'>"+"<tr><td></td></tr></table>",a=c.createElement("div"),a.style.cssText=m+"width:0;height:0;position:static;top:0;margin-top:"+j+"px",r.insertBefore(a,r.firstChild),q=c.createElement("div"),a.appendChild(q),q.innerHTML="<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>",l=q.getElementsByTagName("td"),p=l[0].offsetHeight===0,l[0].style.display="",l[1].style.display="none",b.reliableHiddenOffsets=p&&l[0].offsetHeight===0,q.innerHTML="",q.style.width=q.style.paddingLeft="1px",f.boxModel=b.boxModel=q.offsetWidth===2,typeof q.style.zoom!="undefined"&&(q.style.display="inline",q.style.zoom=1,b.inlineBlockNeedsLayout=q.offsetWidth===2,q.style.display="",q.innerHTML="<div style='width:4px;'></div>",b.shrinkWrapBlocks=q.offsetWidth!==2),q.style.cssText=k+m,q.innerHTML=o,d=q.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,i={doesNotAddBorder:e.offsetTop!==5,doesAddBorderForTableAndCells:h.offsetTop===5},e.style.position="fixed",e.style.top="20px",i.fixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",i.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,i.doesNotIncludeMarginInBodyOffset=r.offsetTop!==j,r.removeChild(a),q=a=null,f.extend(b,i))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e<g;e++)delete d[b[e]];if(!(c?m:f.isEmptyObject)(d))return}}if(!c){delete j[k].data;if(!m(j[k]))return}f.support.deleteExpando||!j.setInterval?delete j[k]:j[k]=null,i&&(f.support.deleteExpando?delete a[h]:a.removeAttribute?a.removeAttribute(h):a[h]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d,e,g,h=null;if(typeof a=="undefined"){if(this.length){h=f.data(this[0]);if(this[0].nodeType===1&&!f._data(this[0],"parsedAttrs")){e=this[0].attributes;for(var i=0,j=e.length;i<j;i++)g=e[i].name,g.indexOf("data-")===0&&(g=f.camelCase(g.substring(5)),l(this[0],g,h[g]));f._data(this[0],"parsedAttrs",!0)}}return h}if(typeof a=="object")return this.each(function(){f.data(this,a)});d=a.split("."),d[1]=d[1]?"."+d[1]:"";if(c===b){h=this.triggerHandler("getData"+d[1]+"!",[d[0]]),h===b&&this.length&&(h=f.data(this[0],a),h=l(this[0],a,h));return h===b&&d[1]?this.data(d[0]):h}return this.each(function(){var b=f(this),e=[d[0],c];b.triggerHandler("setData"+d[1]+"!",e),f.data(this,a,c),b.triggerHandler("changeData"+d[1]+"!",e)})},removeData:function(a){return this.each(function(){f.removeData(this,a)})}}),f.extend({_mark:function(a,b){a&&(b=(b||"fx")+"mark",f._data(a,b,(f._data(a,b)||0)+1))},_unmark:function(a,b,c){a!==!0&&(c=b,b=a,a=!1);if(b){c=c||"fx";var d=c+"mark",e=a?0:(f._data(b,d)||1)-1;e?f._data(b,d,e):(f.removeData(b,d,!0),n(b,c,"mark"))}},queue:function(a,b,c){var d;if(a){b=(b||"fx")+"queue",d=f._data(a,b),c&&(!d||f.isArray(c)?d=f._data(a,b,f.makeArray(c)):d.push(c));return d||[]}},dequeue:function(a,b){b=b||"fx";var c=f.queue(a,b),d=c.shift(),e={};d==="inprogress"&&(d=c.shift()),d&&(b==="fx"&&c.unshift("inprogress"),f._data(a,b+".run",e),d.call(a,function(){f.dequeue(a,b)},e)),c.length||(f.removeData(a,b+"queue "+b+".run",!0),n(a,b,"queue"))}}),f.fn.extend({queue:function(a,c){typeof a!="string"&&(c=a,a="fx");if(c===b)return f.queue(this[0],a);return this.each(function(){var b=f.queue(this,a,c);a==="fx"&&b[0]!=="inprogress"&&f.dequeue(this,a)})},dequeue:function(a){return this.each(function(){f.dequeue(this,a)})},delay:function(a,b){a=f.fx?f.fx.speeds[a]||a:a,b=b||"fx";return this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){function m(){--h||d.resolveWith(e,[e])}typeof a!="string"&&(c=a,a=b),a=a||"fx";var d=f.Deferred(),e=this,g=e.length,h=1,i=a+"defer",j=a+"queue",k=a+"mark",l;while(g--)if(l=f.data(e[g],i,b,!0)||(f.data(e[g],j,b,!0)||f.data(e[g],k,b,!0))&&f.data(e[g],i,f.Callbacks("once memory"),!0))h++,l.add(m);m();return d.promise()}});var o=/[\n\t\r]/g,p=/\s+/,q=/\r/g,r=/^(?:button|input)$/i,s=/^(?:button|input|object|select|textarea)$/i,t=/^a(?:rea)?$/i,u=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,v=f.support.getSetAttribute,w,x,y;f.fn.extend({attr:function(a,b){return f.access(this,a,b,!0,f.attr)},removeAttr:function(a){return this.each(function(){f.removeAttr(this,a)})},prop:function(a,b){return f.access(this,a,b,!0,f.prop)},removeProp:function(a){a=f.propFix[a]||a;return this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,g,h,i;if(f.isFunction(a))return this.each(function(b){f(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(p);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{g=" "+e.className+" ";for(h=0,i=b.length;h<i;h++)~g.indexOf(" "+b[h]+" ")||(g+=b[h]+" ");e.className=f.trim(g)}}}return this},removeClass:function(a){var c,d,e,g,h,i,j;if(f.isFunction(a))return this.each(function(b){f(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a=="string"||a===b){c=(a||"").split(p);for(d=0,e=this.length;d<e;d++){g=this[d];if(g.nodeType===1&&g.className)if(a){h=(" "+g.className+" ").replace(o," ");for(i=0,j=c.length;i<j;i++)h=h.replace(" "+c[i]+" "," ");g.className=f.trim(h)}else g.className=""}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";if(f.isFunction(a))return this.each(function(c){f(this).toggleClass(a.call(this,c,this.className,b),b)});return this.each(function(){if(c==="string"){var e,g=0,h=f(this),i=b,j=a.split(p);while(e=j[g++])i=d?i:!h.hasClass(e),h[i?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&f._data(this,"__className__",this.className),this.className=this.className||a===!1?"":f._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ",c=0,d=this.length;for(;c<d;c++)if(this[c].nodeType===1&&(" "+this[c].className+" ").replace(o," ").indexOf(b)>-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.nodeName.toLowerCase()]||f.valHooks[g.type];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c<d;c++){e=i[c];if(e.selected&&(f.support.optDisabled?!e.disabled:e.getAttribute("disabled")===null)&&(!e.parentNode.disabled||!f.nodeName(e.parentNode,"optgroup"))){b=f(e).val();if(j)return b;h.push(b)}}if(j&&!h.length&&i.length)return f(i[g]).val();return h},set:function(a,b){var c=f.makeArray(b);f(a).find("option").each(function(){this.selected=f.inArray(f(this).val(),c)>=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;h<g;h++)e=d[h],e&&(c=f.propFix[e]||e,f.attr(a,e,""),a.removeAttribute(v?e:c),u.test(e)&&c in a&&(a[c]=!1))}},attrHooks:{type:{set:function(a,b){if(r.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},value:{get:function(a,b){if(w&&f.nodeName(a,"button"))return w.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(w&&f.nodeName(a,"button"))return w.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e,g,h,i=a.nodeType;if(!!a&&i!==3&&i!==8&&i!==2){h=i!==1||!f.isXMLDoc(a),h&&(c=f.propFix[c]||c,g=f.propHooks[c]);return d!==b?g&&"set"in g&&(e=g.set(a,d,c))!==b?e:a[c]=d:g&&"get"in g&&(e=g.get(a,c))!==null?e:a[c]}},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):s.test(a.nodeName)||t.test(a.nodeName)&&a.href?0:b}}}}),f.attrHooks.tabindex=f.propHooks.tabIndex,x={get:function(a,c){var d,e=f.prop(a,c);return e===!0||typeof e!="boolean"&&(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},v||(y={name:!0,id:!0},w=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&(y[c]?d.nodeValue!=="":d.specified)?d.nodeValue:b},set:function(a,b,d){var e=a.getAttributeNode(d);e||(e=c.createAttribute(d),a.setAttributeNode(e));return e.nodeValue=b+""}},f.attrHooks.tabindex.set=w.set,f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})}),f.attrHooks.contenteditable={get:w.get,set:function(a,b,c){b===""&&(b="false"),w.set(a,b,c)}}),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex);return null}})),f.support.enctype||(f.propFix.enctype="encoding"),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/\bhover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function(a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")};
-f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k<c.length;k++){l=A.exec(c[k])||[],m=l[1],n=(l[2]||"").split(".").sort(),s=f.event.special[m]||{},m=(g?s.delegateType:s.bindType)||m,s=f.event.special[m]||{},o=f.extend({type:m,origType:l[1],data:e,handler:d,guid:d.guid,selector:g,quick:G(g),namespace:n.join(".")},p),r=j[m];if(!r){r=j[m]=[],r.delegateCount=0;if(!s.setup||s.setup.call(a,e,n,i)===!1)a.addEventListener?a.addEventListener(m,i,!1):a.attachEvent&&a.attachEvent("on"+m,i)}s.add&&(s.add.call(a,o),o.handler.guid||(o.handler.guid=d.guid)),g?r.splice(r.delegateCount++,0,o):r.push(o),f.event.global[m]=!0}a=null}},global:{},remove:function(a,b,c,d,e){var g=f.hasData(a)&&f._data(a),h,i,j,k,l,m,n,o,p,q,r,s;if(!!g&&!!(o=g.events)){b=f.trim(I(b||"")).split(" ");for(h=0;h<b.length;h++){i=A.exec(b[h])||[],j=k=i[1],l=i[2];if(!j){for(j in o)f.event.remove(a,j+b[h],c,d,!0);continue}p=f.event.special[j]||{},j=(d?p.delegateType:p.bindType)||j,r=o[j]||[],m=r.length,l=l?new RegExp("(^|\\.)"+l.split(".").sort().join("\\.(?:.*\\.)?")+"(\\.|$)"):null;for(n=0;n<r.length;n++)s=r[n],(e||k===s.origType)&&(!c||c.guid===s.guid)&&(!l||l.test(s.namespace))&&(!d||d===s.selector||d==="**"&&s.selector)&&(r.splice(n--,1),s.selector&&r.delegateCount--,p.remove&&p.remove.call(a,s));r.length===0&&m!==r.length&&((!p.teardown||p.teardown.call(a,l)===!1)&&f.removeEvent(a,j,g.handle),delete o[j])}f.isEmptyObject(o)&&(q=g.handle,q&&(q.elem=null),f.removeData(a,["events","handle"],!0))}},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,e,g){if(!e||e.nodeType!==3&&e.nodeType!==8){var h=c.type||c,i=[],j,k,l,m,n,o,p,q,r,s;if(E.test(h+f.event.triggered))return;h.indexOf("!")>=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;l<r.length&&!c.isPropagationStopped();l++)m=r[l][0],c.type=r[l][1],q=(f._data(m,"events")||{})[c.type]&&f._data(m,"handle"),q&&q.apply(m,d),q=o&&m[o],q&&f.acceptData(m)&&q.apply(m,d)===!1&&c.preventDefault();c.type=h,!g&&!c.isDefaultPrevented()&&(!p._default||p._default.apply(e.ownerDocument,d)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)&&o&&e[h]&&(h!=="focus"&&h!=="blur"||c.target.offsetWidth!==0)&&!f.isWindow(e)&&(n=e[o],n&&(e[o]=null),f.event.triggered=h,e[h](),f.event.triggered=b,n&&(e[o]=n));return c.result}},dispatch:function(c){c=f.event.fix(c||a.event);var d=(f._data(this,"events")||{})[c.type]||[],e=d.delegateCount,g=[].slice.call(arguments,0),h=!c.exclusive&&!c.namespace,i=[],j,k,l,m,n,o,p,q,r,s,t;g[0]=c,c.delegateTarget=this;if(e&&!c.target.disabled&&(!c.button||c.type!=="click")){m=f(this),m.context=this.ownerDocument||this;for(l=c.target;l!=this;l=l.parentNode||this){o={},q=[],m[0]=l;for(j=0;j<e;j++)r=d[j],s=r.selector,o[s]===b&&(o[s]=r.quick?H(l,r.quick):m.is(s)),o[s]&&q.push(r);q.length&&i.push({elem:l,matches:q})}}d.length>e&&i.push({elem:this,matches:d.slice(e)});for(j=0;j<i.length&&!c.isPropagationStopped();j++){p=i[j],c.currentTarget=p.elem;for(k=0;k<p.matches.length&&!c.isImmediatePropagationStopped();k++){r=p.matches[k];if(h||!c.namespace&&!r.namespace||c.namespace_re&&c.namespace_re.test(r.namespace))c.data=r.data,c.handleObj=r,n=((f.event.special[r.origType]||{}).handle||r.handler).apply(p.elem,g),n!==b&&(c.result=n,n===!1&&(c.preventDefault(),c.stopPropagation()))}}return c.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){a.which==null&&(a.which=b.charCode!=null?b.charCode:b.keyCode);return a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,d){var e,f,g,h=d.button,i=d.fromElement;a.pageX==null&&d.clientX!=null&&(e=a.target.ownerDocument||c,f=e.documentElement,g=e.body,a.pageX=d.clientX+(f&&f.scrollLeft||g&&g.scrollLeft||0)-(f&&f.clientLeft||g&&g.clientLeft||0),a.pageY=d.clientY+(f&&f.scrollTop||g&&g.scrollTop||0)-(f&&f.clientTop||g&&g.clientTop||0)),!a.relatedTarget&&i&&(a.relatedTarget=i===a.target?d.toElement:i),!a.which&&h!==b&&(a.which=h&1?1:h&2?3:h&4?2:0);return a}},fix:function(a){if(a[f.expando])return a;var d,e,g=a,h=f.event.fixHooks[a.type]||{},i=h.props?this.props.concat(h.props):this.props;a=f.Event(g);for(d=i.length;d;)e=i[--d],a[e]=g[e];a.target||(a.target=g.srcElement||c),a.target.nodeType===3&&(a.target=a.target.parentNode),a.metaKey===b&&(a.metaKey=a.ctrlKey);return h.filter?h.filter(a,g):a},special:{ready:{setup:f.bindReady},load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(a,b,c){f.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}},simulate:function(a,b,c,d){var e=f.extend(new f.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?f.event.trigger(e,null,b):f.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},f.event.handle=f.event.dispatch,f.removeEvent=c.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){a.detachEvent&&a.detachEvent("on"+b,c)},f.Event=function(a,b){if(!(this instanceof f.Event))return new f.Event(a,b);a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?K:J):this.type=a,b&&f.extend(this,b),this.timeStamp=a&&a.timeStamp||f.now(),this[f.expando]=!0},f.Event.prototype={preventDefault:function(){this.isDefaultPrevented=K;var a=this.originalEvent;!a||(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){this.isPropagationStopped=K;var a=this.originalEvent;!a||(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=K,this.stopPropagation()},isDefaultPrevented:J,isPropagationStopped:J,isImmediatePropagationStopped:J},f.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){f.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c=this,d=a.relatedTarget,e=a.handleObj,g=e.selector,h;if(!d||d!==c&&!f.contains(c,d))a.type=e.origType,h=e.handler.apply(this,arguments),a.type=b;return h}}}),f.support.submitBubbles||(f.event.special.submit={setup:function(){if(f.nodeName(this,"form"))return!1;f.event.add(this,"click._submit keypress._submit",function(a){var c=a.target,d=f.nodeName(c,"input")||f.nodeName(c,"button")?c.form:b;d&&!d._submit_attached&&(f.event.add(d,"submit._submit",function(a){this.parentNode&&!a.isTrigger&&f.event.simulate("submit",this.parentNode,a,!0)}),d._submit_attached=!0)})},teardown:function(){if(f.nodeName(this,"form"))return!1;f.event.remove(this,"._submit")}}),f.support.changeBubbles||(f.event.special.change={setup:function(){if(z.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")f.event.add(this,"propertychange._change",function(a){a.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),f.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1,f.event.simulate("change",this,a,!0))});return!1}f.event.add(this,"beforeactivate._change",function(a){var b=a.target;z.test(b.nodeName)&&!b._change_attached&&(f.event.add(b,"change._change",function(a){this.parentNode&&!a.isSimulated&&!a.isTrigger&&f.event.simulate("change",this.parentNode,a,!0)}),b._change_attached=!0)})},handle:function(a){var b=a.target;if(this!==b||a.isSimulated||a.isTrigger||b.type!=="radio"&&b.type!=="checkbox")return a.handleObj.handler.apply(this,arguments)},teardown:function(){f.event.remove(this,"._change");return z.test(this.nodeName)}}),f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){var d=0,e=function(a){f.event.simulate(b,a.target,f.event.fix(a),!0)};f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.fn.extend({on:function(a,c,d,e,g){var h,i;if(typeof a=="object"){typeof c!="string"&&(d=c,c=b);for(i in a)this.on(i,c,d,a[i],g);return this}d==null&&e==null?(e=c,d=c=b):e==null&&(typeof c=="string"?(e=d,d=b):(e=d,d=c,c=b));if(e===!1)e=J;else if(!e)return this;g===1&&(h=e,e=function(a){f().off(a);return h.apply(this,arguments)},e.guid=h.guid||(h.guid=f.guid++));return this.each(function(){f.event.add(this,a,e,d,c)})},one:function(a,b,c,d){return this.on.call(this,a,b,c,d,1)},off:function(a,c,d){if(a&&a.preventDefault&&a.handleObj){var e=a.handleObj;f(a.delegateTarget).off(e.namespace?e.type+"."+e.namespace:e.type,e.selector,e.handler);return this}if(typeof a=="object"){for(var g in a)this.off(g,c,a[g]);return this}if(c===!1||typeof c=="function")d=c,c=b;d===!1&&(d=J);return this.each(function(){f.event.remove(this,a,d,c)})},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},live:function(a,b,c){f(this.context).on(a,this.selector,b,c);return this},die:function(a,b){f(this.context).off(a,this.selector||"**",b);return this},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return arguments.length==1?this.off(a,"**"):this.off(b,a,c)},trigger:function(a,b){return this.each(function(){f.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return f.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||f.guid++,d=0,e=function(c){var e=(f._data(this,"lastToggle"+a.guid)||0)%d;f._data(this,"lastToggle"+a.guid,e+1),c.preventDefault();return b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),f.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){f.fn[b]=function(a,c){c==null&&(c=a,a=null);return arguments.length>0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}if(j.nodeType===1){g||(j[d]=c,j.sizset=h);if(typeof b!="string"){if(j===b){k=!0;break}}else if(m.filter(b,[j]).length>0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}j.nodeType===1&&!g&&(j[d]=c,j.sizset=h);if(j.nodeName.toLowerCase()===b){k=j;break}j=j[a]}e[h]=k}}}var a=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b<a.length;b++)a[b]===a[b-1]&&a.splice(b--,1)}return a},m.matches=function(a,b){return m(a,null,null,b)},m.matchesSelector=function(a,b){return m(b,null,null,[a]).length>0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e<f;e++){h=o.order[e];if(g=o.leftMatch[h].exec(a)){i=g[1],g.splice(1,1);if(i.substr(i.length-1)!=="\\"){g[1]=(g[1]||"").replace(j,""),d=o.find[h](g,b,c);if(d!=null){a=a.replace(o.match[h],"");break}}}}d||(d=typeof b.getElementsByTagName!="undefined"?b.getElementsByTagName("*"):[]);return{set:d,expr:a}},m.filter=function(a,c,d,e){var f,g,h,i,j,k,l,n,p,q=a,r=[],s=c,t=c&&c[0]&&m.isXML(c[0]);while(a&&c.length){for(h in o.filter)if((f=o.leftMatch[h].exec(a))!=null&&f[2]){k=o.filter[h],l=f[1],g=!1,f.splice(1,1);if(l.substr(l.length-1)==="\\")continue;s===r&&(r=[]);if(o.preFilter[h]){f=o.preFilter[h](f,s,d,r,e,t);if(!f)g=i=!0;else if(f===!0)continue}if(f)for(n=0;(j=s[n])!=null;n++)j&&(i=k(j,f,n,s),p=e^i,d&&i!=null?p?g=!0:s[n]=!1:p&&(r.push(j),g=!0));if(i!==b){d||(s=r),a=a.replace(o.match[h],"");if(!g)return[];break}}if(a===q)if(g==null)m.error(a);else break;q=a}return s},m.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)};var n=m.getText=function(a){var b,c,d=a.nodeType,e="";if(d){if(d===1||d===9){if(typeof a.textContent=="string")return a.textContent;if(typeof a.innerText=="string")return a.innerText.replace(k,"");for(a=a.firstChild;a;a=a.nextSibling)e+=n(a)}else if(d===3||d===4)return a.nodeValue}else for(b=0;c=a[b];b++)c.nodeType!==8&&(e+=n(c));return e},o=m.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(a){return a.getAttribute("href")},type:function(a){return a.getAttribute("type")}},relative:{"+":function(a,b){var c=typeof b=="string",d=c&&!l.test(b),e=c&&!d;d&&(b=b.toLowerCase());for(var f=0,g=a.length,h;f<g;f++)if(h=a[f]){while((h=h.previousSibling)&&h.nodeType!==1);a[f]=e||h&&h.nodeName.toLowerCase()===b?h||!1:h===b}e&&m.filter(b,a,!0)},">":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e<f;e++){c=a[e];if(c){var g=c.parentNode;a[e]=g.nodeName.toLowerCase()===b?g:!1}}}else{for(;e<f;e++)c=a[e],c&&(a[e]=d?c.parentNode:c.parentNode===b);d&&m.filter(b,a,!0)}},"":function(a,b,c){var d,f=e++,g=x;typeof b=="string"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g("parentNode",b,f,a,d,c)},"~":function(a,b,c){var d,f=e++,g=x;typeof b=="string"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g("previousSibling",b,f,a,d,c)}},find:{ID:function(a,b,c){if(typeof b.getElementById!="undefined"&&!c){var d=b.getElementById(a[1]);return d&&d.parentNode?[d]:[]}},NAME:function(a,b){if(typeof b.getElementsByName!="undefined"){var c=[],d=b.getElementsByName(a[1]);for(var e=0,f=d.length;e<f;e++)d[e].getAttribute("name")===a[1]&&c.push(d[e]);return c.length===0?null:c}},TAG:function(a,b){if(typeof b.getElementsByTagName!="undefined")return b.getElementsByTagName(a[1])}},preFilter:{CLASS:function(a,b,c,d,e,f){a=" "+a[1].replace(j,"")+" ";if(f)return a;for(var g=0,h;(h=b[g])!=null;g++)h&&(e^(h.className&&(" "+h.className+" ").replace(/[\t\n\r]/g," ").indexOf(a)>=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return b<c[3]-0},gt:function(a,b,c){return b>c[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h<i;h++)if(g[h]===a)return!1;return!0}m.error(e)},CHILD:function(a,b){var c,e,f,g,h,i,j,k=b[1],l=a;switch(k){case"only":case"first":while(l=l.previousSibling)if(l.nodeType===1)return!1;if(k==="first")return!0;l=a;case"last":while(l=l.nextSibling)if(l.nodeType===1)return!1;return!0;case"nth":c=b[2],e=b[3];if(c===1&&e===0)return!0;f=b[0],g=a.parentNode;if(g&&(g[d]!==f||!a.nodeIndex)){i=0;for(l=g.firstChild;l;l=l.nextSibling)l.nodeType===1&&(l.nodeIndex=++i);g[d]=f}j=a.nodeIndex-e;return c===0?j===0:j%c===0&&j/c>=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c<e;c++)d.push(a[c]);else for(;a[c];c++)d.push(a[c]);return d}}var u,v;c.documentElement.compareDocumentPosition?u=function(a,b){if(a===b){h=!0;return 0}if(!a.compareDocumentPosition||!b.compareDocumentPosition)return a.compareDocumentPosition?-1:1;return a.compareDocumentPosition(b)&4?-1:1}:(u=function(a,b){if(a===b){h=!0;return 0}if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],g=a.parentNode,i=b.parentNode,j=g;if(g===i)return v(a,b);if(!g)return-1;if(!i)return 1;while(j)e.unshift(j),j=j.parentNode;j=i;while(j)f.unshift(j),j=j.parentNode;c=e.length,d=f.length;for(var k=0;k<c&&k<d;k++)if(e[k]!==f[k])return v(e[k],f[k]);return k===c?v(a,f[k],-1):v(e[k],b,1)},v=function(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}),function(){var a=c.createElement("div"),d="script"+(new Date).getTime(),e=c.documentElement;a.innerHTML="<a name='"+d+"'/>",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="<p class='TEST'></p>";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="<div class='test e'></div><div class='test'></div>";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h<i;h++)m(a,g[h],e,c);return m.filter(f,e)};m.attr=f.attr,m.selectors.attrMap={},f.find=m,f.expr=m.selectors,f.expr[":"]=f.expr.filters,f.unique=m.uniqueSort,f.text=m.getText,f.isXMLDoc=m.isXML,f.contains=m.contains}();var L=/Until$/,M=/^(?:parents|prevUntil|prevAll)/,N=/,/,O=/^.[^:#\[\.,]*$/,P=Array.prototype.slice,Q=f.expr.match.POS,R={children:!0,contents:!0,next:!0,prev:!0};f.fn.extend({find:function(a){var b=this,c,d;if(typeof a!="string")return f(a).filter(function(){for(c=0,d=b.length;c<d;c++)if(f.contains(b[c],this))return!0});var e=this.pushStack("","find",a),g,h,i;for(c=0,d=this.length;c<d;c++){g=e.length,f.find(a,this[c],e);if(c>0)for(h=g;h<e.length;h++)for(i=0;i<g;i++)if(e[i]===e[h]){e.splice(h--,1);break}}return e},has:function(a){var b=f(a);return this.filter(function(){for(var a=0,c=b.length;a<c;a++)if(f.contains(this,b[a]))return!0})},not:function(a){return this.pushStack(T(this,a,!1),"not",a)},filter:function(a){return this.pushStack(T(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?Q.test(a)?f(a,this.context).index(this[0])>=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d<a.length;d++)f(g).is(a[d])&&c.push({selector:a[d],elem:g,level:h});g=g.parentNode,h++}return c}var i=Q.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d<e;d++){g=this[d];while(g){if(i?i.index(g)>-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/<tbody/i,_=/<|&#?\w+;/,ba=/<(?:script|style)/i,bb=/<(?:script|object|embed|option|style)/i,bc=new RegExp("<(?:"+V+")","i"),bd=/checked\s*(?:[^=]|=\s*.checked.)/i,be=/\/(java|ecma)script/i,bf=/^\s*<!(?:\[CDATA\[|\-\-)/,bg={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div<div>","</div>"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function()
-{for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1></$2>");try{for(var c=0,d=this.length;c<d;c++)this[c].nodeType===1&&(f.cleanData(this[c].getElementsByTagName("*")),this[c].innerHTML=a)}catch(e){this.empty().append(a)}}else f.isFunction(a)?this.each(function(b){var c=f(this);c.html(a.call(this,b,c.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(f.isFunction(a))return this.each(function(b){var c=f(this),d=c.html();c.replaceWith(a.call(this,b,d))});typeof a!="string"&&(a=f(a).detach());return this.each(function(){var b=this.nextSibling,c=this.parentNode;f(this).remove(),b?f(b).before(a):f(c).append(a)})}return this.length?this.pushStack(f(f.isFunction(a)?a():a),"replaceWith",a):this},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){var e,g,h,i,j=a[0],k=[];if(!f.support.checkClone&&arguments.length===3&&typeof j=="string"&&bd.test(j))return this.each(function(){f(this).domManip(a,c,d,!0)});if(f.isFunction(j))return this.each(function(e){var g=f(this);a[0]=j.call(this,e,c?g.html():b),g.domManip(a,c,d)});if(this[0]){i=j&&j.parentNode,f.support.parentNode&&i&&i.nodeType===11&&i.childNodes.length===this.length?e={fragment:i}:e=f.buildFragment(a,this,k),h=e.fragment,h.childNodes.length===1?g=h=h.firstChild:g=h.firstChild;if(g){c=c&&f.nodeName(g,"tr");for(var l=0,m=this.length,n=m-1;l<m;l++)d.call(c?bi(this[l],g):this[l],e.cacheable||m>1&&l<n?f.clone(h,!0,!0):h)}k.length&&f.each(k,bp)}return this}}),f.buildFragment=function(a,b,d){var e,g,h,i,j=a[0];b&&b[0]&&(i=b[0].ownerDocument||b[0]),i.createDocumentFragment||(i=c),a.length===1&&typeof j=="string"&&j.length<512&&i===c&&j.charAt(0)==="<"&&!bb.test(j)&&(f.support.checkClone||!bd.test(j))&&(f.support.html5Clone||!bc.test(j))&&(g=!0,h=f.fragments[j],h&&h!==1&&(e=h)),e||(e=i.createDocumentFragment(),f.clean(a,i,e,d)),g&&(f.fragments[j]=h?e:1);return{fragment:e,cacheable:g}},f.fragments={},f.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){f.fn[a]=function(c){var d=[],e=f(c),g=this.length===1&&this[0].parentNode;if(g&&g.nodeType===11&&g.childNodes.length===1&&e.length===1){e[b](this[0]);return this}for(var h=0,i=e.length;h<i;h++){var j=(h>0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||!bc.test("<"+a.nodeName)?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1></$2>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");b===c?bh.appendChild(o):U(b).appendChild(o),o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]==="<table>"&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i<r;i++)bn(k[i]);else bn(k);k.nodeType?h.push(k):h=f.merge(h,k)}if(d){g=function(a){return!a.type||be.test(a.type)};for(j=0;h[j];j++)if(e&&f.nodeName(h[j],"script")&&(!h[j].type||h[j].type.toLowerCase()==="text/javascript"))e.push(h[j].parentNode?h[j].parentNode.removeChild(h[j]):h[j]);else{if(h[j].nodeType===1){var s=f.grep(h[j].getElementsByTagName("script"),g);h.splice.apply(h,[j+1,0].concat(s))}d.appendChild(h[j])}}return h},cleanData:function(a){var b,c,d=f.cache,e=f.event.special,g=f.support.deleteExpando;for(var h=0,i;(i=a[h])!=null;h++){if(i.nodeName&&f.noData[i.nodeName.toLowerCase()])continue;c=i[f.expando];if(c){b=d[c];if(b&&b.events){for(var j in b.events)e[j]?f.event.remove(i,j):f.removeEvent(i,j,b.handle);b.handle&&(b.handle.elem=null)}g?delete i[f.expando]:i.removeAttribute&&i.removeAttribute(f.expando),delete d[c]}}}});var bq=/alpha\([^)]*\)/i,br=/opacity=([^)]*)/,bs=/([A-Z]|^ms)/g,bt=/^-?\d+(?:px)?$/i,bu=/^-?\d/,bv=/^([\-+])=([\-+.\de]+)/,bw={position:"absolute",visibility:"hidden",display:"block"},bx=["Left","Right"],by=["Top","Bottom"],bz,bA,bB;f.fn.css=function(a,c){if(arguments.length===2&&c===b)return this;return f.access(this,a,c,!0,function(a,c,d){return d!==b?f.style(a,c,d):f.css(a,c)})},f.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bz(a,"opacity","opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":f.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!!a&&a.nodeType!==3&&a.nodeType!==8&&!!a.style){var g,h,i=f.camelCase(c),j=a.style,k=f.cssHooks[i];c=f.cssProps[i]||i;if(d===b){if(k&&"get"in k&&(g=k.get(a,!1,e))!==b)return g;return j[c]}h=typeof d,h==="string"&&(g=bv.exec(d))&&(d=+(g[1]+1)*+g[2]+parseFloat(f.css(a,c)),h="number");if(d==null||h==="number"&&isNaN(d))return;h==="number"&&!f.cssNumber[i]&&(d+="px");if(!k||!("set"in k)||(d=k.set(a,d))!==b)try{j[c]=d}catch(l){}}},css:function(a,c,d){var e,g;c=f.camelCase(c),g=f.cssHooks[c],c=f.cssProps[c]||c,c==="cssFloat"&&(c="float");if(g&&"get"in g&&(e=g.get(a,!0,d))!==b)return e;if(bz)return bz(a,c)},swap:function(a,b,c){var d={};for(var e in b)d[e]=a.style[e],a.style[e]=b[e];c.call(a);for(e in b)a.style[e]=d[e]}}),f.curCSS=f.css,f.each(["height","width"],function(a,b){f.cssHooks[b]={get:function(a,c,d){var e;if(c){if(a.offsetWidth!==0)return bC(a,b,d);f.swap(a,bw,function(){e=bC(a,b,d)});return e}},set:function(a,b){if(!bt.test(b))return b;b=parseFloat(b);if(b>=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return br.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bq,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bq.test(g)?g.replace(bq,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bz(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,b){var c,d,e;b=b.replace(bs,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b)));return c}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f===null&&g&&(e=g[b])&&(f=e),!bt.test(f)&&bu.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f||0,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bD=/%20/g,bE=/\[\]$/,bF=/\r?\n/g,bG=/#.*$/,bH=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bI=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bJ=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bK=/^(?:GET|HEAD)$/,bL=/^\/\//,bM=/\?/,bN=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bO=/^(?:select|textarea)/i,bP=/\s+/,bQ=/([?&])_=[^&]*/,bR=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bS=f.fn.load,bT={},bU={},bV,bW,bX=["*/"]+["*"];try{bV=e.href}catch(bY){bV=c.createElement("a"),bV.href="",bV=bV.href}bW=bR.exec(bV.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bS)return bS.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("<div>").append(c.replace(bN,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bO.test(this.nodeName)||bI.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bF,"\r\n")}}):{name:b.name,value:c.replace(bF,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b_(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b_(a,b);return a},ajaxSettings:{url:bV,isLocal:bJ.test(bW[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bX},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bZ(bT),ajaxTransport:bZ(bU),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?cb(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cc(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bH.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bG,"").replace(bL,bW[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bP),d.crossDomain==null&&(r=bR.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bW[1]&&r[2]==bW[2]&&(r[3]||(r[1]==="http:"?80:443))==(bW[3]||(bW[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),b$(bT,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bK.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bM.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bQ,"$1_="+x);d.url=y+(y===d.url?(bM.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bX+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bU,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)ca(g,a[g],c,e);return d.join("&").replace(bD,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cd=f.now(),ce=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cd++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ce.test(b.url)||e&&ce.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ce,l),b.url===j&&(e&&(k=k.replace(ce,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cf=a.ActiveXObject?function(){for(var a in ch)ch[a](0,1)}:!1,cg=0,ch;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ci()||cj()}:ci,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cf&&delete ch[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cg,cf&&(ch||(ch={},f(a).unload(cf)),ch[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var ck={},cl,cm,cn=/^(?:toggle|show|hide)$/,co=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cp,cq=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cr;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu("show",3),a,b,c);for(var g=0,h=this.length;g<h;g++)d=this[g],d.style&&(e=d.style.display,!f._data(d,"olddisplay")&&e==="none"&&(e=d.style.display=""),e===""&&f.css(d,"display")==="none"&&f._data(d,"olddisplay",cv(d.nodeName)));for(g=0;g<h;g++){d=this[g];if(d.style){e=d.style.display;if(e===""||e==="none")d.style.display=f._data(d,"olddisplay")||""}}return this},hide:function(a,b,c){if(a||a===0)return this.animate(cu("hide",3),a,b,c);var d,e,g=0,h=this.length;for(;g<h;g++)d=this[g],d.style&&(e=f.css(d,"display"),e!=="none"&&!f._data(d,"olddisplay")&&f._data(d,"olddisplay",e));for(g=0;g<h;g++)this[g].style&&(this[g].style.display="none");return this},_toggle:f.fn.toggle,toggle:function(a,b,c){var d=typeof a=="boolean";f.isFunction(a)&&f.isFunction(b)?this._toggle.apply(this,arguments):a==null||d?this.each(function(){var b=d?a:f(this).is(":hidden");f(this)[b?"show":"hide"]()}):this.animate(cu("toggle",3),a,b,c);return this},fadeTo:function(a,b,c,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){function g(){e.queue===!1&&f._mark(this);var b=f.extend({},e),c=this.nodeType===1,d=c&&f(this).is(":hidden"),g,h,i,j,k,l,m,n,o;b.animatedProperties={};for(i in a){g=f.camelCase(i),i!==g&&(a[g]=a[i],delete a[i]),h=a[g],f.isArray(h)?(b.animatedProperties[g]=h[1],h=a[g]=h[0]):b.animatedProperties[g]=b.specialEasing&&b.specialEasing[g]||b.easing||"swing";if(h==="hide"&&d||h==="show"&&!d)return b.complete.call(this);c&&(g==="height"||g==="width")&&(b.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY],f.css(this,"display")==="inline"&&f.css(this,"float")==="none"&&(!f.support.inlineBlockNeedsLayout||cv(this.nodeName)==="inline"?this.style.display="inline-block":this.style.zoom=1))}b.overflow!=null&&(this.style.overflow="hidden");for(i in a)j=new f.fx(this,b,i),h=a[i],cn.test(h)?(o=f._data(this,"toggle"+i)||(h==="toggle"?d?"show":"hide":0),o?(f._data(this,"toggle"+i,o==="show"?"hide":"show"),j[o]()):j[h]()):(k=co.exec(h),l=j.cur(),k?(m=parseFloat(k[2]),n=k[3]||(f.cssNumber[i]?"":"px"),n!=="px"&&(f.style(this,i,(m||1)+n),l=(m||1)/j.cur()*l,f.style(this,i,l+n)),k[1]&&(m=(k[1]==="-="?-1:1)*m+l),j.custom(l,m,n)):j.custom(l,h,""));return!0}var e=f.speed(b,c,d);if(f.isEmptyObject(a))return this.each(e.complete,[!1]);a=f.extend({},a);return e.queue===!1?this.each(g):this.queue(e.queue,g)},stop:function(a,c,d){typeof a!="string"&&(d=c,c=a,a=b),c&&a!==!1&&this.queue(a||"fx",[]);return this.each(function(){function h(a,b,c){var e=b[c];f.removeData(a,c,!0),e.stop(d)}var b,c=!1,e=f.timers,g=f._data(this);d||f._unmark(!0,this);if(a==null)for(b in g)g[b]&&g[b].stop&&b.indexOf(".run")===b.length-4&&h(this,g,b);else g[b=a+".run"]&&g[b].stop&&h(this,g,b);for(b=e.length;b--;)e[b].elem===this&&(a==null||e[b].queue===a)&&(d?e[b](!0):e[b].saveState(),c=!0,e.splice(b,1));(!d||!c)&&f.dequeue(this,a)})}}),f.each({slideDown:cu("show",1),slideUp:cu("hide",1),slideToggle:cu("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){f.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),f.extend({speed:function(a,b,c){var d=a&&typeof a=="object"?f.extend({},a):{complete:c||!c&&b||f.isFunction(a)&&a,duration:a,easing:c&&b||b&&!f.isFunction(b)&&b};d.duration=f.fx.off?0:typeof d.duration=="number"?d.duration:d.duration in f.fx.speeds?f.fx.speeds[d.duration]:f.fx.speeds._default;if(d.queue==null||d.queue===!0)d.queue="fx";d.old=d.complete,d.complete=function(a){f.isFunction(d.old)&&d.old.call(this),d.queue?f.dequeue(this,d.queue):a!==!1&&f._unmark(this)};return d},easing:{linear:function(a,b,c,d){return c+d*a},swing:function(a,b,c,d){return(-Math.cos(a*Math.PI)/2+.5)*d+c}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig=b.orig||{}}}),f.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(f.fx.step[this.prop]||f.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a,b=f.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b==="auto"?0:b:a},custom:function(a,c,d){function h(a){return e.step(a)}var e=this,g=f.fx;this.startTime=cr||cs(),this.end=c,this.now=this.start=a,this.pos=this.state=0,this.unit=d||this.unit||(f.cssNumber[this.prop]?"":"px"),h.queue=this.options.queue,h.elem=this.elem,h.saveState=function(){e.options.hide&&f._data(e.elem,"fxshow"+e.prop)===b&&f._data(e.elem,"fxshow"+e.prop,e.start)},h()&&f.timers.push(h)&&!cp&&(cp=setInterval(g.tick,g.interval))},show:function(){var a=f._data(this.elem,"fxshow"+this.prop);this.options.orig[this.prop]=a||f.style(this.elem,this.prop),this.options.show=!0,a!==b?this.custom(this.cur(),a):this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur()),f(this.elem).show()},hide:function(){this.options.orig[this.prop]=f._data(this.elem,"fxshow"+this.prop)||f.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b,c,d,e=cr||cs(),g=!0,h=this.elem,i=this.options;if(a||e>=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c<b.length;c++)a=b[c],!a()&&b[c]===a&&b.splice(c--,1);b.length||f.fx.stop()},interval:13,stop:function(){clearInterval(cp),cp=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){f.style(a.elem,"opacity",a.now)},_default:function(a){a.elem.style&&a.elem.style[a.prop]!=null?a.elem.style[a.prop]=a.now+a.unit:a.elem[a.prop]=a.now}}}),f.each(["width","height"],function(a,b){f.fx.step[b]=function(a){f.style(a.elem,b,Math.max(0,a.now)+a.unit)}}),f.expr&&f.expr.filters&&(f.expr.filters.animated=function(a){return f.grep(f.timers,function(b){return a===b.elem}).length});var cw=/^t(?:able|d|h)$/i,cx=/^(?:body|html)$/i;"getBoundingClientRect"in c.documentElement?f.fn.offset=function(a){var b=this[0],c;if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);try{c=b.getBoundingClientRect()}catch(d){}var e=b.ownerDocument,g=e.documentElement;if(!c||!f.contains(g,b))return c?{top:c.top,left:c.left}:{top:0,left:0};var h=e.body,i=cy(e),j=g.clientTop||h.clientTop||0,k=g.clientLeft||h.clientLeft||0,l=i.pageYOffset||f.support.boxModel&&g.scrollTop||h.scrollTop,m=i.pageXOffset||f.support.boxModel&&g.scrollLeft||h.scrollLeft,n=c.top+l-j,o=c.left+m-k;return{top:n,left:o}}:f.fn.offset=function(a){var b=this[0];if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);var c,d=b.offsetParent,e=b,g=b.ownerDocument,h=g.documentElement,i=g.body,j=g.defaultView,k=j?j.getComputedStyle(b,null):b.currentStyle,l=b.offsetTop,m=b.offsetLeft;while((b=b.parentNode)&&b!==i&&b!==h){if(f.support.fixedPosition&&k.position==="fixed")break;c=j?j.getComputedStyle(b,null):b.currentStyle,l-=b.scrollTop,m-=b.scrollLeft,b===d&&(l+=b.offsetTop,m+=b.offsetLeft,f.support.doesNotAddBorder&&(!f.support.doesAddBorderForTableAndCells||!cw.test(b.nodeName))&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),e=d,d=b.offsetParent),f.support.subtractsBorderForOverflowNotVisible&&c.overflow!=="visible"&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),k=c}if(k.position==="relative"||k.position==="static")l+=i.offsetTop,m+=i.offsetLeft;f.support.fixedPosition&&k.position==="fixed"&&(l+=Math.max(h.scrollTop,i.scrollTop),m+=Math.max(h.scrollLeft,i.scrollLeft));return{top:l,left:m}},f.offset={bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.support.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,d,"padding")):this[d]():null},f.fn["outer"+c]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,d,a?"margin":"border")):this[d]():null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNumeric(j)?j:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window);
\ No newline at end of file
diff --git a/src/site/resources/js/site.js b/src/site/resources/js/site.js
deleted file mode 100644
index 7e37161..0000000
--- a/src/site/resources/js/site.js
+++ /dev/null
@@ -1,75 +0,0 @@
-/*

-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.

-*/

-

-/* Executed on page load. */

-$(document).ready(function() {

-

-	// Hack to add default visuals to tables

-	$('table').each(function() {

-		if ($(this).hasClass('bodyTable') || $(this).hasClass('tableblock')) {

-			

-			// Remove border="1" which is added by maven

-			this.border = 0;

-			

-			// Add bootstrap table styling

-			$(this).addClass('table table-striped table-bordered');

-		}

-	});

-	

-	// Render tabs

-	$('.auto-tabs').each(function(groupid) {

-

-		// Find tab bar

-		$(this).find('ul').each(function() {

-

-			// Add styling

-			$(this).addClass('nav nav-tabs');

-

-			// Go tab bar items

-			$(this).find('li').each(function(itemid) {

-			

-				// Set first tab as active

-				if (itemid == 0) {

-					$(this).addClass('active');

-				}

-				

-				// Replace text with a link to tab contents

-				var name = $(this).html();

-				var link = $('<a>')

-					.attr('href', '#' + 'tab-' + groupid + '-' + itemid)

-					.attr('data-toggle', 'tab')

-					.html(name);

-				$(this).html(link);

-			});

-		});

-		

-		// Find tab contents

-		$(this).find('.tab-content .tab-pane').each(function(itemid) {

-			

-			// Set first tab as active

-			if (itemid == 0) {

-				$(this).addClass('active');

-			}

-			

-			// Set the tab id

-			$(this).attr('id', 'tab-' + groupid + '-' + itemid);

-		});

-	});

-	

-	// Make external links open in new tab

-	$('a.external').attr('target', '_blank');

-});

diff --git a/src/site/site.vm b/src/site/site.vm
deleted file mode 100644
index 981d0a3..0000000
--- a/src/site/site.vm
+++ /dev/null
@@ -1,521 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<!--
-   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.
--->
-<!-- Generated by Apache Maven Doxia at $dateFormat.format( $currentDate ) -->
-#macro ( link $href $name $target $img $position $alt $border $width $height )
-	#set ( $linkTitle = ' title="' + $name + '"' )
-	#if( $target )
-		#set ( $linkTarget = ' target="' + $target + '"' )
-	#else
-		#set ( $linkTarget = "" )
-	#end
-	#if ( $href.toLowerCase().startsWith("http:/") || $href.toLowerCase().startsWith("https:/") ||
-		$href.toLowerCase().startsWith("ftp:/") || $href.toLowerCase().startsWith("mailto:/") ||
-		$href.toLowerCase().startsWith("file:/") || ($href.toLowerCase().indexOf("://") != -1) )
-		#set ( $linkClass = ' class="external" target="_blank"' )
-
-		#if ( $linkTarget )
-		#else
-			#set ( $linkTarget = "_blank" )
-		#end
-
-	#else
-		#set ( $linkClass = "" )
-	#end
-	#if ( $img )
-		#if ( $position == "left" )
-			<a href="$href"$linkClass$linkTarget$linkTitle>#image($img $alt $border $width $height)$name</a>
-		#else
-			<a href="$href"$linkClass$linkTarget$linkTitle>$name #image($img $alt $border $width $height)</a>
-		#end
-	#else
-		<a href="$href"$linkClass$linkTarget$linkTitle>$name</a>
-	#end
-#end
-##
-#macro ( image $img $alt $border $width $height )
-	#if( $img )
-		#if ( ! ( $img.toLowerCase().startsWith("http:/") || $img.toLowerCase().startsWith("https:/") ||
-						$img.toLowerCase().startsWith("ftp:/") || $img.toLowerCase().startsWith("mailto:/") ||
-						$img.toLowerCase().startsWith("file:/") || ($img.toLowerCase().indexOf("://") != -1) ) )
-			#set ( $imgSrc = $PathTool.calculateLink( $img, $relativePath ) )
-			#set ( $imgSrc = $imgSrc.replaceAll( '\\', '/' ) )
-			#set ( $imgSrc = ' src="' + $imgSrc + '"' )
-		#else
-			#set ( $imgSrc = ' src="' + $img + '"' )
-		#end
-		#if( $alt )
-			#set ( $imgAlt = ' alt="' + $alt + '"' )
-		#else
-			#set ( $imgAlt = ' alt=""' )
-		#end
-		#if( $border )
-			#set ( $imgBorder = ' border="' + $border + '"' )
-		#else
-			#set ( $imgBorder = "" )
-		#end
-		#if( $width )
-			#set ( $imgWidth = ' width="' + $width + '"' )
-		#else
-			#set ( $imgWidth = "" )
-		#end
-		#if( $height )
-			#set ( $imgHeight = ' height="' + $height + '"' )
-		#else
-			#set ( $imgHeight = "" )
-		#end
-		<img class="imageLink"$imgSrc$imgAlt$imgBorder$imgWidth$imgHeight/>
-	#end
-#end
-#macro ( banner $banner $id )
-	#if ( $banner )
-		#if( $banner.href )
-			#set ( $hrf = $banner.href )
-			#if ( ! ( $hrf.toLowerCase().startsWith("http:/") || $hrf.toLowerCase().startsWith("https:/") ||
-				$hrf.toLowerCase().startsWith("ftp:/") || $hrf.toLowerCase().startsWith("mailto:/") ||
-				$hrf.toLowerCase().startsWith("file:/") || ($hrf.toLowerCase().indexOf("://") != -1) ) )
-				#set ( $hrf = $PathTool.calculateLink( $hrf, $relativePath ) )
-				#set ( $hrf = $hrf.replaceAll( '\\', '/' ) )
-				#if ( ( $hrf == '' ) )
-					#set ( $hrf = './' )
-				#end
-			#end
-			<a href="$hrf" id="$id"#if( $banner.alt ) title="$banner.alt"#end>
-		#else
-				<div id="$id">
-		#end
-##
-		#if( $banner.src )
-				#set ( $src = $banner.src )
-				#if ( ! ( $src.toLowerCase().startsWith("http:/") || $src.toLowerCase().startsWith("https:/") ||
-								$src.toLowerCase().startsWith("ftp:/") || $src.toLowerCase().startsWith("mailto:/") ||
-								$src.toLowerCase().startsWith("file:/") || ($src.toLowerCase().indexOf("://") != -1) ) )
-						#set ( $src = $PathTool.calculateLink( $src, $relativePath ) )
-						#set ( $src = $src.replaceAll( '\\', '/' ) )
-				#end
-				#if ( $banner.alt )
-						#set ( $alt = $banner.alt )
-				#else
-						#set ( $alt = $banner.name )
-				#end
-				<img src="$src" alt="$alt" />
-		#else
-				$banner.name
-		#end
-##
-		#if( $banner.href )
-				</a>
-		#else
-				</div>
-		#end
-	#end
-#end
-##
-#macro ( links $links )
-	<ul class="nav">
-	#set ( $counter = 0 )
-	#foreach( $item in $links )
-		#set ( $counter = $counter + 1 )
-		#set ( $currentItemHref = $PathTool.calculateLink( $item.href, $relativePath ) )
-		#set ( $currentItemHref = $currentItemHref.replaceAll( '\\', '/' ) )
-		#set ( $activeClass = "" )
-		#if ( $alignedFileName == $currentItemHref)
-			#set ( $activeClass = ' class="active"' )
-		#end
-		<li$activeClass>
-		#link( $currentItemHref $item.name $item.target $item.img $item.position $item.alt $item.border $item.width $item.height )
-		</li>
-	#end
-	</ul>
-#end
-##
-#macro ( breadcrumbs $breadcrumbs )
-	#foreach( $item in $breadcrumbs )
-		#set ( $currentItemHref = $PathTool.calculateLink( $item.href, $relativePath ) )
-		#set ( $currentItemHref = $currentItemHref.replaceAll( '\\', '/' ) )
-		#if ( ( $currentItemHref == '' ) )
-			#set ( $currentItemHref = './' )
-		#end
-##
-			#link( $currentItemHref $item.name $item.target $item.img $item.position $item.alt $item.border $item.width $item.height )
-			<span class="divider">&gt;</span>
-	#end
-	$title
-#end
-##
-#macro ( displayTree $display $item )
-	#if ( $item && $item.items && $item.items.size() > 0 )
-		#foreach( $subitem in $item.items )
-			#set ( $subitemHref = $PathTool.calculateLink( $subitem.href, $relativePath ) )
-			#set ( $subitemHref = $subitemHref.replaceAll( '\\', '/' ) )
-##
-			#if ( $alignedFileName == $subitemHref )
-				#set ( $display = true )
-			#end
-##
-			#displayTree( $display $subitem )
-		#end
-	#end
-#end
-##
-#macro ( menuItem $item $isComponentDocumentation )
-	#set ( $collapse = "none" )
-	#set ( $currentItemHref = $PathTool.calculateLink( $item.href, $relativePath ) )
-	#set ( $currentItemHref = $currentItemHref.replaceAll( '\\', '/' ) )
-##
-	#if ( $item && $item.items && $item.items.size() > 0 )
-		#if ( $item.collapse == false )
-			#set ( $collapse = "expanded" )
-		#else
-			## By default collapsed
-			#set ( $collapse = "collapsed" )
-		#end
-##
-		#set ( $display = false )
-		#displayTree( $display $item )
-##
-		#if ( $alignedFileName == $currentItemHref || $display )
-			#set ( $collapse = "expanded" )
-		#end
-	#end
-	#set ( $active = "" )
-	#if ( $alignedFileName == $currentItemHref )
-	#set ($active = " active")
-	#end
-	#set ( $thisProjectDir = "../${project.artifactId}" )
-	#if ($thisProjectDir == $PathTool.getDirectoryComponent( $item.href ))
-	#set ($active = " active")
-	#end
-	#if (${project.artifactId} != "log4j" && $isComponentDocumentation &&
-				($item.href == "team-list.html" || $item.href == "mail-lists.html"
-				|| $item.href == "issue-tracking.html" || $item.href == "license.html"
-				|| $item.href == "source-repository.html"))
-	<!-- Removing overall project item $item.name from component-specific menu -->
-	#else
-		#set ($thisItemName = $item.name)
-		#if (${project.artifactId} != "log4j" && $isComponentDocumentation )
-		#set ($thisItemName = $item.name.replace("Project Information", "Component Project"))
-		#set ($thisItemName = $item.name.replace("Project", "Component"))
-		#end
-		<li class="$collapse$active">
-		#link($currentItemHref $thisItemName $item.target $item.img $item.position $item.alt $item.border $item.width $item.height )
-		#if ( $item && $item.items && $item.items.size() > 0 )
-			#if ( $collapse == "expanded" )
-				<ul>
-					#foreach( $subitem in $item.items )
-						#menuItem( $subitem $isComponentDocumentation )
-					#end
-				</ul>
-			#end
-		#end
-		</li>
- 	#end
-#end
-##
-#macro ( mainMenu $menus )
-	#foreach( $menu in $menus )
-		<ul class="nav nav-list">
-		#set ($isComponentDocumentation = false)
- 		#if ( $menu.name )
-			#set ( $menuName = $menu.name )
-			#if ( $menuName == "Project Documentation" )
-			#set ( $menuName = "Component Documentation" )
-			#set ($isComponentDocumentation = true)
-			#end
-			#if ( $menu.img )
-			 <li class="nav-header"><i class="$menu.img"></i>$menuName</li>
-			#else
-			 <li class="nav-header">$menuName</li>
-			#end
-		#end
-		#if ( $menu.items && $menu.items.size() > 0 )
-			#foreach( $item in $menu.items )
-				#menuItem( $item $isComponentDocumentation )
-			#end
-		#end
-		</ul>
-	#end
-#end
-##
-#macro ( copyright )
-	#if ( $project )
-		#if ( ${project.organization} && ${project.organization.name} )
-			#set ( $period = "" )
-		#else
-			#set ( $period = "." )
-	 #end
-##
-	 #set ( $currentYear = ${currentDate.year} + 1900 )
-##
-		#if ( ${project.inceptionYear} && ( ${project.inceptionYear} != ${currentYear.toString()} ) )
-			${project.inceptionYear}-${currentYear}${period}
-		#else
-			${currentYear}${period}
-		#end
-##
-		#if ( ${project.organization} )
-			#if ( ${project.organization.name} && ${project.organization.url} )
-					<a href="$project.organization.url">${project.organization.name}</a>.
-			#elseif ( ${project.organization.name} )
-				${project.organization.name}.
-			#end
-		#end
-	#end
-#end
-##
-#macro ( publishDate $position $publishDate $version )
-	#if ( $publishDate && $publishDate.format )
-		#set ( $format = $publishDate.format )
-	#else
-		#set ( $format = "yyyy-MM-dd" )
-	#end
-##
-	$dateFormat.applyPattern( $format )
-##
-	#set ( $dateToday = $dateFormat.format( $currentDate ) )
-##
-	#if ( $publishDate && $publishDate.position )
-		#set ( $datePosition = $publishDate.position )
-	#else
-		#set ( $datePosition = "left" )
-	#end
-##
-	#if ( $version )
-		#if ( $version.position )
-			#set ( $versionPosition = $version.position )
-		#else
-			#set ( $versionPosition = "left" )
-		#end
-	#else
-		#set ( $version = "" )
-		#set ( $versionPosition = "left" )
-	#end
-##
-	#set ( $breadcrumbs = $decoration.body.breadcrumbs )
-	#set ( $links = $decoration.body.links )
-
-	#if ( $datePosition.equalsIgnoreCase( $position ) )
-		#if ( ( $datePosition.equalsIgnoreCase( "right" ) ) || ( $datePosition.equalsIgnoreCase( "bottom" ) ) )
-			<span id="publishDate">$i18n.getString( "site-renderer", $locale, "template.lastpublished" ): $dateToday</span>
-			#if ( $versionPosition.equalsIgnoreCase( $position ) )
-				<span class="divider">|</span> <span id="projectVersion">$i18n.getString( "site-renderer", $locale, "template.version" ): ${project.version}</span>
-			#end
-		#elseif ( ( $datePosition.equalsIgnoreCase( "navigation-bottom" ) ) || ( $datePosition.equalsIgnoreCase( "navigation-top" ) ) )
-			<div id="lastPublished">
-				<span id="publishDate">$i18n.getString( "site-renderer", $locale, "template.lastpublished" ): $dateToday</span>
-				#if ( $versionPosition.equalsIgnoreCase( $position ) )
-					<span class="divider">|</span> <span id="projectVersion">$i18n.getString( "site-renderer", $locale, "template.version" ): ${project.version}</span>
-				#end
-			</div>
-		#elseif ( $datePosition.equalsIgnoreCase("left") )
-			<div class="pull-left">
-				<span id="publishDate">$i18n.getString( "site-renderer", $locale, "template.lastpublished" ): $dateToday</span>
-				#if ( $versionPosition.equalsIgnoreCase( $position ) )
-					<span class="divider">|</span> <span id="projectVersion">$i18n.getString( "site-renderer", $locale, "template.version" ): ${project.version}</span>
-				#end
-				#if ( $breadcrumbs && $breadcrumbs.size() > 0 )
-					<span class="divider">|</span> #breadcrumbs( $breadcrumbs )
-				#end
-			</div>
-		#end
-	#elseif ( $versionPosition.equalsIgnoreCase( $position ) )
-		#if ( ( $versionPosition.equalsIgnoreCase( "right" ) ) || ( $versionPosition.equalsIgnoreCase( "bottom" ) ) )
-			$prefix <span id="projectVersion">$i18n.getString( "site-renderer", $locale, "template.version" ): ${project.version}</span>
-		#elseif ( ( $versionPosition.equalsIgnoreCase( "navigation-bottom" ) ) || ( $versionPosition.equalsIgnoreCase( "navigation-top" ) ) )
-			<div id="lastPublished">
-				<span id="projectVersion">$i18n.getString( "site-renderer", $locale, "template.version" ): ${project.version}</span>
-			</div>
-		#elseif ( $versionPosition.equalsIgnoreCase("left") )
-			<div class="pull-left">
-				<span id="projectVersion">$i18n.getString( "site-renderer", $locale, "template.version" ): ${project.version}</span>
-				#if ( $breadcrumbs && $breadcrumbs.size() > 0 )
-					<span class="divider">|</span> #breadcrumbs( $breadcrumbs )
-				#end
-			</div>
-		#end
-	#elseif ( $position.equalsIgnoreCase( "left" ) )
-		#if ( $breadcrumbs && $breadcrumbs.size() > 0 )
-			<div class="pull-left">
-				#breadcrumbs( $breadcrumbs )
-			</div>
-		#end
-	#end
-#end
-##
-#macro ( poweredByLogo $poweredBy )
-	#if( $poweredBy )
-		#foreach ($item in $poweredBy)
-			#if( $item.href )
-				#set ( $href = $PathTool.calculateLink( $item.href, $relativePath ) )
-				#set ( $href = $href.replaceAll( '\\', '/' ) )
-			#else
-				#set ( $href="http://maven.apache.org/" )
-			#end
-##
-			#if( $item.name )
-				#set ( $name = $item.name )
-			#else
-				#set ( $name = $i18n.getString( "site-renderer", $locale, "template.builtby" )	)
-				#set ( $name = "${name} Maven"	)
-			#end
-##
-			#if( $item.img )
-				#set ( $img = $item.img )
-			#else
-				#set ( $img = "images/maven-feather.png" )
-			#end
-##
-			#if ( ! ( $img.toLowerCase().startsWith("http:/") || $img.toLowerCase().startsWith("https:/") ||
-						$img.toLowerCase().startsWith("ftp:/") || $img.toLowerCase().startsWith("mailto:/") ||
-						$img.toLowerCase().startsWith("file:/") || ($img.toLowerCase().indexOf("://") != -1) ) )
-				#set ( $img = $PathTool.calculateLink( $img, $relativePath ) )
-				#set ( $img = $img.replaceAll( '\\', '/' ) )
-			#end
-##
-			#if( $item.alt )
-				#set ( $alt = ' alt="' + $item.alt + '"' )
-			#else
-				#set ( $alt = ' alt="' + $name + '"' )
-			#end
-##
-			#if( $item.border )
-				#set ( $border = ' border="' + $item.border + '"' )
-			#else
-				#set ( $border = "" )
-			#end
-##
-			#if( $item.width )
-				#set ( $width = ' width="' + $item.width + '"' )
-			#else
-				#set ( $width = "" )
-			#end
-			#if( $item.height )
-				#set ( $height = ' height="' + $item.height + '"' )
-			#else
-				#set ( $height = "" )
-			#end
-##
-			<a href="$href" title="$name" class="poweredBy">
-				<img class="poweredBy" $alt src="$img" $border $width $height />
-			</a>
-		#end
-		#if( $poweredBy.isEmpty() )
-			<a href="http://maven.apache.org/" title="$i18n.getString( "site-renderer", $locale, "template.builtby" ) Maven" class="poweredBy">
-				<img class="poweredBy" alt="$i18n.getString( "site-renderer", $locale, "template.builtby" ) Maven" src="$relativePath/images/maven-feather.png" />
-			</a>
-		#end
-	#else
-		<a href="http://maven.apache.org/" title="$i18n.getString( "site-renderer", $locale, "template.builtby" ) Maven" class="poweredBy">
-			<img class="poweredBy" alt="$i18n.getString( "site-renderer", $locale, "template.builtby" ) Maven" src="$relativePath/images/maven-feather.png" />
-		</a>
-	#end
-#end
-##
-#macro ( googleAnalytics $accountId )
-	#if( $accountId && $accountId != "" )
-		<!-- Google Analytics -->
-		<script type="text/javascript">
-
-			var _gaq = _gaq || [];
-			_gaq.push(['_setAccount', '$accountId']);
-			_gaq.push (['_gat._anonymizeIp']);
-			_gaq.push(['_trackPageview']);
-
-			(function() {
-				var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
-				ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
-				var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
-			})();
-
-		</script>
-	#end
-#end
-##
-<html xmlns="http://www.w3.org/1999/xhtml"#if ( $locale ) xml:lang="$locale.language" lang="$locale.language"#end>
-	<head>
-		<meta http-equiv="Content-Type" content="text/html; charset=${outputEncoding}" />
-		<title>$title - $project.name</title>
-		<link rel="stylesheet" href="$relativePath/css/bootstrap.min.css" type="text/css" />
-		<link rel="stylesheet" href="$relativePath/css/github.css" type="text/css" />
-		<link rel="stylesheet" href="$relativePath/css/site.css" type="text/css" />
-		<script type="text/javascript" src="$relativePath/js/jquery.min.js"></script>
-		<script type="text/javascript" src="$relativePath/js/bootstrap.min.js"></script>
-		<script type="text/javascript" src="$relativePath/js/highlight.pack.js"></script>
-		<script type="text/javascript">hljs.initHighlightingOnLoad();</script>
-		<script type="text/javascript" src="$relativePath/js/site.js"></script>
-#foreach( $author in $authors )
-			<meta name="author" content="$author" />
-#end
-#if ( $dateCreation )
-		<meta name="Date-Creation-yyyymmdd" content="$dateCreation" />
-#end
-#if ( $dateRevision )
-		<meta name="Date-Revision-yyyymmdd" content="$dateRevision" />
-#end
-#if ( $locale )
-		<meta http-equiv="Content-Language" content="$locale.language" />
-#end
-		$headContent
-		#googleAnalytics( $decoration.googleAnalyticsAccountId )
-	</head>
-	<body class="composite">
-        <a  href="http://www.apache.org/events/current-event.html">
-          <img class=logo-left src="http://www.apache.org/events/current-event-234x60.png"/>
-        </a>
-        <img class="logo-right" src="$relativePath/images/logo.png" alt="Apache log4j logo" />
-        <a href="https://logging.apache.org/">
-          <img class="logo-center" src="$relativePath/images/ls-logo.jpg" alt="Apache logging services logo" />
-        </a>
-
-		<div class="clear"></div>
-
-		<div class="navbar">
-			<div class="navbar-inner">
-				<div class="container-fluid">
-					<a class="brand" href="$project.url">$project.name &trade;</a>
-					#links( $decoration.body.links )
-				</div>
-			</div>
-		</div>
-
-		<div class="container-fluid">
-			<table class="layout-table">
-				<tr>
-					<td class="sidebar">
-						<div class="well sidebar-nav">
-							#mainMenu( $decoration.body.menus )
-						</div>
-						<div id="poweredBy">
-							#poweredByLogo( $decoration.poweredBy )
-						</div>
-					</td>
-					<td class="content">
-						$bodyContent
-					</td>
-				</tr>
-			</table>
-		</div>
-
-		<div class="footer">
-			#set ( $currentYear = ${currentDate.year} + 1900 )
-				<p>Copyright &copy; ${project.inceptionYear}-${currentYear} <a class="external" href="$project.organization.url">${project.organization.name}</a>. All Rights Reserved.</p>
-				<p>Apache Logging, Apache Log4j, Log4j, Apache, the Apache feather logo, and the Apache Logging project logo are trademarks of The Apache Software Foundation.</p>
-				<p>Site powered by <a class="external" href="http://getbootstrap.com/">Twitter Bootstrap</a>. Icons from <a class="external" href="http://glyphicons.com/">Glyphicons Free</a>.</p>
-			</div>
-		</div>
-	</body>
-</html>
diff --git a/src/site/site.xml b/src/site/site.xml
index 48ae309..bd86e7f 100644
--- a/src/site/site.xml
+++ b/src/site/site.xml
@@ -19,6 +19,19 @@
          xmlns="http://maven.apache.org/DECORATION/1.4.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/DECORATION/1.4.0 http://maven.apache.org/xsd/decoration-1.4.0.xsd">
+  <bannerLeft>
+    <src>images/ls-logo.jpg</src>
+    <href>http://logging.apache.org</href>
+  </bannerLeft>
+  <bannerRight>
+    <src>images/logo.png</src>
+    <href>http://logging.apache.org/log4j/2.x</href>
+  </bannerRight>
+  <skin>
+    <groupId>org.apache.maven.skins</groupId>
+    <artifactId>maven-fluido-skin</artifactId>
+    <version>1.8</version>
+  </skin>
   <body>
     <links>
       <item name="Logging Wiki" href="https://cwiki.apache.org/confluence/display/LOGGING/Log4j"/>
@@ -28,7 +41,7 @@
       <item name="GitHub" href="https://github.com/apache/logging-log4j2"/>
     </links>
 
-    <menu name="Apache Log4j™ 2" inherit="top" img="icon-home">
+    <menu name="Apache Log4j™ 2" inherit="top" img="img/glyphicons/home.png">
       <item name="About" href="/index.html"/>
       <item name="Download" href="/download.html"/>
       <item name="Javadoc" href="/javadoc.html" collapse="true">
@@ -64,15 +77,16 @@
       <item name="Thanks" href="/thanks.html"/>
     </menu>
 
-    <menu name="For Contributors" inherit="top" img="icon-pencil">
+    <menu name="For Contributors" inherit="top" img="img/glyphicons/pencil.png">
       <item name="Building Log4j from Source" href="/build.html"/>
       <item name="Guidelines" href="/guidelines.html"/>
       <item name="Style Guide" href="/javastyle.html"/>
     </menu>
 
-    <menu name="Manual" inherit="top" img="icon-book">
+    <menu name="Manual" inherit="top" img="img/glyphicons/book.png">
       <item name="Introduction" href="/manual/index.html"/>
       <item name="Architecture" href="/manual/architecture.html"/>
+      <item name="Log4j 1.x Compatibility" href="manual/compatibility.html"/>
       <item name="Log4j 1.x Migration" href="manual/migration.html"/>
 
       <item name="Java API" href="/manual/api.html" collapse="true">
@@ -132,9 +146,11 @@
         <item name="Java" href="/manual/lookups.html#JavaLookup"/>
         <item name="JNDI" href="/manual/lookups.html#JndiLookup"/>
         <item name="JVM Arguments" href="/manual/lookups.html#JmxRuntimeInputArgumentsLookup"/>
+        <item name="Kubernetes" href="/manual/lookups.html#KubernetesLookup"/>
         <item name="Log4j Config" href="/manual/lookups.html#Log4jConfigLookup"/>
         <item name="Main Arguments" href="/manual/lookups.html#AppMainArgsLookup"/>
         <item name="Map" href="/manual/lookups.html#MapLookup"/>
+        <item name="Spring" href="/manual/lookups.html#SpringLookup"/>
         <item name="Structured Data" href="/manual/lookups.html#StructuredDataLookup"/>
         <item name="System Properties" href="/manual/lookups.html#SystemPropertiesLookup"/>
         <item name="Web" href="/manual/lookups.html#WebLookup"/>
@@ -270,17 +286,17 @@
 
     </menu>
 
-    <menu name="Related Projects" inherit="top" img="icon-tags">
+    <menu name="Related Projects" inherit="top" img="img/glyphicons/tag.png">
       <item name="Log4j-Scala" href="http://logging.apache.org/log4j/scala/index.html"/>
     </menu>
 
-    <menu name="Legacy" inherit="top" img="icon-tags">
+    <menu name="Legacy" inherit="top" img="img/glyphicons/link.png">
       <item name="Log4j 1.2 - End of Life" href="http://logging.apache.org/log4j/1.2/"/>
       <item name="Log4j 2.3 - Java 6" href="http://logging.apache.org/log4j/log4j-2.3/"/>
       <item name="Log4j 2.12.1 - Java 7" href="http://logging.apache.org/log4j/log4j-2.12.1/"/>
     </menu>
 
-    <menu name="Components" inherit="top" img="icon-cog">
+    <menu name="Components" inherit="top" img="img/glyphicons/cog.png">
       <item name="API" href="log4j-api/index.html"/>
       <item name="Implementation" href="log4j-core/index.html"/>
       <item name="Commons Logging Bridge" href="log4j-jcl/index.html"/>
@@ -300,10 +316,11 @@
       <item name="Log4j IO Streams" href="log4j-iostreams/index.html"/>
       <item name="Log4j Liquibase Binding" href="log4j-liquibase/index.html"/>
       <item name="Log4j Docker Support" href="log4j-docker/index.html"/>
+      <item name="Lob4j Kubernetes Support" href="log4j-kubernetes/index.html"/>
       <item name="Log4j Spring Cloud Config Client" href="log4j-spring-cloud-config/log4j-spring-cloud-config-client/index.html"/>
     </menu>
 
-    <menu name="Project Information" img="icon-info-sign">
+    <menu name="Project Information" img="img/glyphicons/info.png">
       <item name="Dependency Convergence" href="/dependency-convergence.html" />
       <item name="Dependency Management" href="/dependency-management.html" />
       <item name="Project Team" href="/team-list.html" />
@@ -314,10 +331,13 @@
       <item name="Project Summary" href="/project-summary.html" />
     </menu>
 
-    <menu name="Project Reports" img="icon-cog">
+    <menu name="Project Reports" img="img/glyphicons/layers.png">
       <item name="Changes Report" href="/changes-report.html" />
       <item name="JIRA Report" href="/jira-report.html" />
       <item name="RAT Report" href="/rat-report.html" />
     </menu>
+    <footer><![CDATA[<p align="center">Copyright &copy; ${project.inceptionYear}-${currentYear} <a class="external" href="http://www.apache.org">The Apache Software Foundation</a>. All Rights Reserved.<br>
+      Apache Logging, Apache Log4j, Log4j, Apache, the Apache feather logo, and the Apache Logging project logo are trademarks of The Apache Software Foundation.</p>]]>
+    </footer>
   </body>
 </project>