Merge
authorlana
Thu, 09 Jul 2015 16:37:55 -0700
changeset 31541 8fc82d01db26
parent 31528 7ee165176843 (current diff)
parent 31540 6efd719b3330 (diff)
child 31542 8d8f66194222
Merge
jdk/make/non-build-utils/sharing/README.txt
jdk/make/non-build-utils/sharing/tests/GHello.java
jdk/make/non-build-utils/sharing/tests/Hello.java
jdk/make/non-build-utils/sharing/tests/JHello.java
jdk/make/non-build-utils/src/build/tools/makeclasslist/MakeClasslist.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/lib/Lib-jdk.internal.le.gmk	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,60 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+include LibCommon.gmk
+
+################################################################################
+
+ifeq ($(OPENJDK_TARGET_OS), windows)
+
+  LIBLE_SRC := $(JDK_TOPDIR)/src/jdk.internal.le/$(OPENJDK_TARGET_OS_TYPE)/native/lible \
+      #
+  LIBLE_CPPFLAGS := \
+      $(addprefix -I, $(LIBLE_SRC)) \
+      -I$(SUPPORT_OUTPUTDIR)/headers/jdk.internal.le \
+      #
+
+  $(eval $(call SetupNativeCompilation,BUILD_LIBLE, \
+      LIBRARY := le, \
+      OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
+      SRC := $(LIBLE_SRC), \
+      OPTIMIZATION := LOW, \
+      CFLAGS := $(CFLAGS_JDKLIB) $(LIBJAVA_HEADER_FLAGS)\
+          $(LIBLE_CPPFLAGS), \
+      LDFLAGS := $(LDFLAGS_JDKLIB), \
+      LDFLAGS_SUFFIX := $(LDFLAGS_JDKLIB_SUFFIX) user32.lib, \
+      VERSIONINFO_RESOURCE := $(GLOBAL_VERSION_INFO_RESOURCE), \
+      RC_FLAGS := $(RC_FLAGS) \
+          -D "JDK_FNAME=le.dll" \
+          -D "JDK_INTERNAL_NAME=le" \
+          -D "JDK_FTYPE=0x2L", \
+      OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/lible, \
+      DEBUG_SYMBOLS := $(DEBUG_ALL_BINARIES)))
+
+  TARGETS += $(BUILD_LIBLE)
+
+endif # OPENJDK_TARGET_OS
+
+################################################################################
--- a/jdk/make/non-build-utils/sharing/README.txt	Thu Jul 09 13:49:36 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-This directory contains tools and tests associated with creating the
-class list for class data sharing.
-
-The class list is produced by running the refWorkload startup3 benchmark with
-the -XX:+TraceClassLoadingPreorder option.  The -Xshare:off option must also be
-used so that bootclasspath classes are loaded from rt.jar.  The MakeClasslist
-program should be built into the jar file makeclasslist.jar and is run
-on one of the logs from each of the benchmarks in the following fashion:
-
-cd .../<resultsdir>/results.startup3
-$JAVA_HOME/bin/java -jar makeclasslist.jar results.Noop/results_1/log results.Framer/results_1/log results.XFramer/results_1/log results.JEdit/results_1/log results.LimeWire/results_1/log results.NetBeans50/results_1/log
-
-Presently, $JAVA_HOME must be the same path used to run the startup3 benchmark.
-
-The logs are deliberately concatenated in roughly smallest to largest order
-based on application size.  The resulting output is redirected into a file
-and results in one of classlist.solaris, classlist.linux, classlist.macosx,
-or classlist.windows.  These files are checked in to the workspace.  A
-necessary checksum (AddJsum.java) is added to the final classlist
-(installed in lib/ or jre/lib/) during the build process by the
-makefiles in make/java/redist.
-
-In a forthcoming JDK build we plan to manually add the dependent
-classes for the calendar manager Glow, which pulls in the Preferences
-classes and, on Unix platforms, the XML parsing classes.
-
-The properties file supplied to the refworkload is approximately the
-following:
-
-javahome=/usr/java/j2sdk1.8.0
-resultsdir=classlist-run
-iterations=1
-benchmarks=startup3
-globalvmoptions=-client -Xshare:off -XX:+TraceClassLoadingPreorder
--- a/jdk/make/non-build-utils/sharing/tests/GHello.java	Thu Jul 09 13:49:36 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-import java.awt.Font;
-import java.awt.Frame;
-import java.awt.Label;
-
-public class GHello extends Frame {
-
-    public static void main(String[] args) {
-        System.out.println("Hello");
-
-        new GHello().show();
-        if (args.length == 1 && args[0].equals("quit")) {
-            try {
-                Thread.currentThread().sleep(200);
-            } catch (InterruptedException e) {
-            }
-            System.exit(0);
-        }
-    }
-
-
-    GHello() {
-        Label label = new Label("Hello");
-        label.setFont(new Font("Monospaced", Font.PLAIN, 144));
-        add(label);
-        pack();
-    }
-}
--- a/jdk/make/non-build-utils/sharing/tests/Hello.java	Thu Jul 09 13:49:36 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-/*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-
-public class Hello {
-    public static void main(String[] args) {
-        System.out.println("Hello, World!");
-    }
-}
--- a/jdk/make/non-build-utils/sharing/tests/JHello.java	Thu Jul 09 13:49:36 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-import java.awt.Font;
-import javax.swing.JFrame;
-import javax.swing.JLabel;
-
-public class JHello extends JFrame {
-
-    public static void main(String[] args) {
-        System.out.println("Hello");
-
-        new JHello().show();
-        if (args.length == 1 && args[0].equals("quit")) {
-            try {
-                Thread.currentThread().sleep(1000);
-            } catch (InterruptedException e) {
-            }
-            System.exit(0);
-        }
-    }
-
-
-    JHello() {
-        JLabel jlabel = new JLabel("Hello");
-        jlabel.setFont(new Font("Monospaced", Font.PLAIN, 144));
-        getContentPane().add(jlabel);
-        pack();
-    }
-}
--- a/jdk/make/non-build-utils/src/build/tools/makeclasslist/MakeClasslist.java	Thu Jul 09 13:49:36 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,130 +0,0 @@
-/*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package build.tools.makeclasslist;
-
-import java.io.*;
-import java.util.*;
-import java.util.jar.*;
-
-/** Reads a set of files containing the output of java
-    -XX:+TraceClassLoadingPreorder runs. Finds all classes that were
-    loaded from the bootstrap class path by comparing the prefix of
-    the load path to the current JRE's java.home system property.
-    Prints the names of these classes to stdout.
-*/
-
-public class MakeClasslist {
-  public static void main(String[] args) throws IOException {
-    List<String> classes = new ArrayList<>();
-    String origJavaHome = System.getProperty("java.home");
-    String javaHome     = origJavaHome.toLowerCase();
-    if (javaHome.endsWith("jre")) {
-      origJavaHome = origJavaHome.substring(0, origJavaHome.length() - 4);
-      javaHome     = javaHome.substring(0, javaHome.length() - 4);
-    }
-    for (int i = 0; i < args.length; i++) {
-      try {
-        File file = new File(args[i]);
-        BufferedReader reader = new BufferedReader(new FileReader(file));
-        String line = null;
-        while ((line = reader.readLine()) != null) {
-          StringTokenizer tok = new StringTokenizer(line, "[ \t\n\r\f");
-          if (tok.hasMoreTokens()) {
-            String t = tok.nextToken();
-            // Understand only "Loading" from -XX:+TraceClassLoadingPreorder.
-            // This ignores old "Loaded" from -verbose:class to force correct
-            // classlist generation on Mustang.
-            if (t.equals("Loading")) {
-              t = tok.nextToken();
-              t = t.replace('.', '/');
-
-              // Check to make sure it came from the boot class path
-              if (tok.hasMoreTokens()) {
-                String tmp = tok.nextToken();
-                if (tmp.equals("from")) {
-                  if (tok.hasMoreTokens()) {
-                    tmp = tok.nextToken().toLowerCase();
-                    // System.err.println("Loaded " + t + " from " + tmp);
-                    if (tmp.startsWith(javaHome)) {
-                      // OK, remember this class for later
-                      classes.add(t);
-                    }
-                  }
-                }
-              }
-            }
-          }
-        }
-      } catch (IOException e) {
-        System.err.println("Error reading file " + args[i]);
-        throw(e);
-      }
-    }
-
-    Set<String> seenClasses = new HashSet<>();
-
-    for (String str : classes) {
-      if (seenClasses.add(str)) {
-        System.out.println(str);
-      }
-    }
-
-    // Try to complete certain packages
-    // Note: not using this new code yet; need to consider whether the
-    // footprint increase is worth any startup gains
-    // Note also that the packages considered below for completion are
-    // (obviously) platform-specific
-    // JarFile rtJar = new JarFile(origJavaHome + File.separator +
-    //                             "jre" + File.separator +
-    //                             "lib" + File.separator +
-    //                             "rt.jar");
-    // completePackage(seenClasses, rtJar, "java/awt");
-    // completePackage(seenClasses, rtJar, "sun/awt");
-    // completePackage(seenClasses, rtJar, "sun/awt/X11");
-    // completePackage(seenClasses, rtJar, "java/awt/im/spi");
-    // completePackage(seenClasses, rtJar, "java/lang");
-  }
-
-  private static void completePackage(Set<String> seenClasses,
-                                      JarFile jar,
-                                      String packageName) {
-    int len = packageName.length();
-    Enumeration<JarEntry> entries = jar.entries();
-    while (entries.hasMoreElements()) {
-      JarEntry entry = entries.nextElement();
-      String name = entry.getName();
-      if (name.startsWith(packageName) &&
-          name.endsWith(".class") &&
-          name.lastIndexOf('/') == len) {
-        // Trim ".class" from end
-        name = name.substring(0, name.length() - 6);
-        if (seenClasses.add(name)) {
-          System.out.println(name);
-        }
-      }
-    }
-  }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/non-build-utils/src/build/tools/makeclasslist/makeClasslist.js	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * This tool is used to help create the class list for class data sharing.
+ *
+ * The classlist is produced internally by first running a select number of
+ * startup benchmarks with the -XX:DumpLoadedClassList=<file> option, then
+ * running this tool in the following fashion to produce a complete classlist:
+ *
+ * jjs -scripting makeClasslist.js -- list1 list2 list3 > classlist.platform
+ *
+ * The lists should be listed in roughly smallest to largest order based on
+ * application size.
+ *
+ * After generating the classlist it's necessary to add a checksum (using
+ * AddJsum.java) before checking it into the workspace as the corresponding
+ * platform-specific classlist, such as make/data/classlist/classlist.linux 
+ */
+"use strict";
+var classlist = [];
+var seenClasses = {};
+
+for (var a in $ARG) {
+  var arg = $ARG[a];
+
+  var classes = readFully(arg).replace(/[\r\n]+/g, "\n").split("\n");
+
+  for (var c in classes) {
+    var clazz = classes[c];
+    if (clazz !== "" && seenClasses[clazz] === undefined) {
+      seenClasses[clazz] = clazz;
+      classlist.push(clazz);
+    }
+  }
+}
+
+for (c in classlist) {
+  print(classlist[c]);
+}
--- a/jdk/src/java.base/share/classes/java/net/SocksSocketImpl.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/net/SocksSocketImpl.java	Thu Jul 09 16:37:55 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,6 +31,7 @@
 import java.security.PrivilegedAction;
 import java.security.PrivilegedExceptionAction;
 import sun.net.SocksProxy;
+import sun.net.spi.DefaultProxySelector;
 import sun.net.www.ParseUtil;
 /* import org.ietf.jgss.*; */
 
@@ -69,12 +70,21 @@
             server = ad.getHostString();
             serverPort = ad.getPort();
         }
+        useV4 = useV4(proxy);
     }
 
     void setV4() {
         useV4 = true;
     }
 
+    private static boolean useV4(Proxy proxy) {
+        if (proxy instanceof SocksProxy
+            && ((SocksProxy)proxy).protocolVersion() == 4) {
+            return true;
+        }
+        return DefaultProxySelector.socksProxyVersion() == 4;
+    }
+
     private synchronized void privilegedConnect(final String host,
                                               final int port,
                                               final int timeout)
@@ -398,11 +408,7 @@
                 // Use getHostString() to avoid reverse lookups
                 server = ((InetSocketAddress) p.address()).getHostString();
                 serverPort = ((InetSocketAddress) p.address()).getPort();
-                if (p instanceof SocksProxy) {
-                    if (((SocksProxy)p).protocolVersion() == 4) {
-                        useV4 = true;
-                    }
-                }
+                useV4 = useV4(p);
 
                 // Connects to the SOCKS server
                 try {
@@ -715,11 +721,7 @@
                 // Use getHostString() to avoid reverse lookups
                 server = ((InetSocketAddress) p.address()).getHostString();
                 serverPort = ((InetSocketAddress) p.address()).getPort();
-                if (p instanceof SocksProxy) {
-                    if (((SocksProxy)p).protocolVersion() == 4) {
-                        useV4 = true;
-                    }
-                }
+                useV4 = useV4(p);
 
                 // Connects to the SOCKS server
                 try {
--- a/jdk/src/java.base/share/classes/java/security/AccessControlContext.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/security/AccessControlContext.java	Thu Jul 09 16:37:55 2015 -0700
@@ -76,7 +76,7 @@
 
 public final class AccessControlContext {
 
-    private ProtectionDomain context[];
+    private ProtectionDomain[] context;
     // isPrivileged and isAuthorized are referenced by the VM - do not remove
     // or change their names
     private boolean isPrivileged;
@@ -89,13 +89,13 @@
     private DomainCombiner combiner = null;
 
     // limited privilege scope
-    private Permission permissions[];
+    private Permission[] permissions;
     private AccessControlContext parent;
     private boolean isWrapped;
 
     // is constrained by limited privilege scope?
     private boolean isLimited;
-    private ProtectionDomain limitedContext[];
+    private ProtectionDomain[] limitedContext;
 
     private static boolean debugInit = false;
     private static Debug debug = null;
@@ -123,7 +123,7 @@
      * changes to the array will not affect this AccessControlContext.
      * @throws NullPointerException if {@code context} is {@code null}
      */
-    public AccessControlContext(ProtectionDomain context[])
+    public AccessControlContext(ProtectionDomain[] context)
     {
         if (context.length == 0) {
             this.context = null;
@@ -282,7 +282,7 @@
      * package private constructor for AccessController.getContext()
      */
 
-    AccessControlContext(ProtectionDomain context[],
+    AccessControlContext(ProtectionDomain[] context,
                          boolean isPrivileged)
     {
         this.context = context;
@@ -643,7 +643,7 @@
     /*
      * Combine the current (stack) and assigned domains.
      */
-    private static ProtectionDomain[] combine(ProtectionDomain[]current,
+    private static ProtectionDomain[] combine(ProtectionDomain[] current,
         ProtectionDomain[] assigned) {
 
         // current could be null if only system code is on the stack;
@@ -666,7 +666,7 @@
         int n = (skipAssigned) ? 0 : assigned.length;
 
         // now we combine both of them, and create a new context
-        ProtectionDomain pd[] = new ProtectionDomain[slen + n];
+        ProtectionDomain[] pd = new ProtectionDomain[slen + n];
 
         // first copy in the assigned context domains, no need to compress
         if (!skipAssigned) {
@@ -695,7 +695,7 @@
             } else if (skipAssigned && n == slen) {
                 return current;
             }
-            ProtectionDomain tmp[] = new ProtectionDomain[n];
+            ProtectionDomain[] tmp = new ProtectionDomain[n];
             System.arraycopy(pd, 0, tmp, 0, n);
             pd = tmp;
         }
--- a/jdk/src/java.base/share/classes/java/security/CodeSource.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/security/CodeSource.java	Thu Jul 09 16:37:55 2015 -0700
@@ -65,7 +65,7 @@
     /*
      * The code signers. Certificate chains are concatenated.
      */
-    private transient java.security.cert.Certificate certs[] = null;
+    private transient java.security.cert.Certificate[] certs = null;
 
     // cached SocketPermission used for matchLocation
     private transient SocketPermission sp;
@@ -91,7 +91,7 @@
      * @param certs the certificate(s). It may be null. The contents of the
      * array are copied to protect against subsequent modification.
      */
-    public CodeSource(URL url, java.security.cert.Certificate certs[]) {
+    public CodeSource(URL url, java.security.cert.Certificate[] certs) {
         this.location = url;
         if (url != null) {
             this.locationNoFragString = URLUtil.urlNoFragString(url);
--- a/jdk/src/java.base/share/classes/java/security/Permissions.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/security/Permissions.java	Thu Jul 09 16:37:55 2015 -0700
@@ -289,9 +289,9 @@
         if (unresolvedPerms == null)
             return null;
 
-        java.security.cert.Certificate certs[] = null;
+        java.security.cert.Certificate[] certs = null;
 
-        Object signers[] = p.getClass().getSigners();
+        Object[] signers = p.getClass().getSigners();
 
         int n = 0;
         if (signers != null) {
--- a/jdk/src/java.base/share/classes/java/security/SecureRandom.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/security/SecureRandom.java	Thu Jul 09 16:37:55 2015 -0700
@@ -69,7 +69,7 @@
  *
  * <pre>
  *      SecureRandom random = new SecureRandom();
- *      byte bytes[] = new byte[20];
+ *      byte[] bytes = new byte[20];
  *      random.nextBytes(bytes);
  * </pre>
  *
@@ -77,7 +77,7 @@
  * to generate a given number of seed bytes (to seed other random number
  * generators, for example):
  * <pre>
- *      byte seed[] = random.generateSeed(20);
+ *      byte[] seed = random.generateSeed(20);
  * </pre>
  *
  * Note: Depending on the implementation, the {@code generateSeed} and
@@ -186,7 +186,7 @@
      *
      * @param seed the seed.
      */
-    public SecureRandom(byte seed[]) {
+    public SecureRandom(byte[] seed) {
         super(0);
         getDefaultPRNG(true, seed);
     }
@@ -486,7 +486,7 @@
     @Override
     final protected int next(int numBits) {
         int numBytes = (numBits+7)/8;
-        byte b[] = new byte[numBytes];
+        byte[] b = new byte[numBytes];
         int next = 0;
 
         nextBytes(b);
--- a/jdk/src/java.base/share/classes/java/security/UnresolvedPermission.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/security/UnresolvedPermission.java	Thu Jul 09 16:37:55 2015 -0700
@@ -130,7 +130,7 @@
      */
     private String actions;
 
-    private transient java.security.cert.Certificate certs[];
+    private transient java.security.cert.Certificate[] certs;
 
     /**
      * Creates a new UnresolvedPermission containing the permission
@@ -152,7 +152,7 @@
     public UnresolvedPermission(String type,
                                 String name,
                                 String actions,
-                                java.security.cert.Certificate certs[])
+                                java.security.cert.Certificate[] certs)
     {
         super(type);
 
@@ -224,7 +224,7 @@
      * try and resolve this permission using the class loader of the permission
      * that was passed in.
      */
-    Permission resolve(Permission p, java.security.cert.Certificate certs[]) {
+    Permission resolve(Permission p, java.security.cert.Certificate[] certs) {
         if (this.certs != null) {
             // if p wasn't signed, we don't have a match
             if (certs == null) {
--- a/jdk/src/java.base/share/classes/java/security/spec/RSAMultiPrimePrivateCrtKeySpec.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/security/spec/RSAMultiPrimePrivateCrtKeySpec.java	Thu Jul 09 16:37:55 2015 -0700
@@ -54,7 +54,7 @@
     private final BigInteger primeExponentP;
     private final BigInteger primeExponentQ;
     private final BigInteger crtCoefficient;
-    private final RSAOtherPrimeInfo otherPrimeInfo[];
+    private final RSAOtherPrimeInfo[] otherPrimeInfo;
 
    /**
     * Creates a new {@code RSAMultiPrimePrivateCrtKeySpec}
--- a/jdk/src/java.base/share/classes/java/util/ArrayList.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/ArrayList.java	Thu Jul 09 16:37:55 2015 -0700
@@ -178,7 +178,8 @@
     public ArrayList(Collection<? extends E> c) {
         elementData = c.toArray();
         if ((size = elementData.length) != 0) {
-            // c.toArray might (incorrectly) not return Object[] (see 6260652)
+            // defend against c.toArray (incorrectly) not returning Object[]
+            // (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)
             if (elementData.getClass() != Object[].class)
                 elementData = Arrays.copyOf(elementData, size, Object[].class);
         } else {
--- a/jdk/src/java.base/share/classes/java/util/Arrays.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/Arrays.java	Thu Jul 09 16:37:55 2015 -0700
@@ -3820,7 +3820,7 @@
 
         @Override
         public Object[] toArray() {
-            return a.clone();
+            return Arrays.copyOf(a, a.length, Object[].class);
         }
 
         @Override
--- a/jdk/src/java.base/share/classes/java/util/Vector.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/Vector.java	Thu Jul 09 16:37:55 2015 -0700
@@ -174,7 +174,8 @@
     public Vector(Collection<? extends E> c) {
         elementData = c.toArray();
         elementCount = elementData.length;
-        // c.toArray might (incorrectly) not return Object[] (see 6260652)
+        // defend against c.toArray (incorrectly) not returning Object[]
+        // (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)
         if (elementData.getClass() != Object[].class)
             elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
     }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java	Thu Jul 09 16:37:55 2015 -0700
@@ -134,7 +134,8 @@
             elements = ((CopyOnWriteArrayList<?>)c).getArray();
         else {
             elements = c.toArray();
-            // c.toArray might (incorrectly) not return Object[] (see 6260652)
+            // defend against c.toArray (incorrectly) not returning Object[]
+            // (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)
             if (elements.getClass() != Object[].class)
                 elements = Arrays.copyOf(elements, elements.length, Object[].class);
         }
--- a/jdk/src/java.base/share/classes/sun/net/spi/DefaultProxySelector.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/net/spi/DefaultProxySelector.java	Thu Jul 09 16:37:55 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -106,6 +106,15 @@
         }
     }
 
+    public static int socksProxyVersion() {
+        return AccessController.doPrivileged(
+                new PrivilegedAction<Integer>() {
+                    @Override public Integer run() {
+                        return NetProperties.getInteger(SOCKS_PROXY_VERSION, 5);
+                    }
+                });
+    }
+
     /**
      * How to deal with "non proxy hosts":
      * since we do have to generate a pattern we don't want to do that if
@@ -302,8 +311,7 @@
                             saddr = InetSocketAddress.createUnresolved(phost, pport);
                             // Socks is *always* the last on the list.
                             if (j == (props[i].length - 1)) {
-                                int version = NetProperties.getInteger(SOCKS_PROXY_VERSION, 5).intValue();
-                                return SocksProxy.create(saddr, version);
+                                return SocksProxy.create(saddr, socksProxyVersion());
                             } else {
                                 return new Proxy(Proxy.Type.HTTP, saddr);
                             }
--- a/jdk/src/java.base/share/classes/sun/security/pkcs/PKCS7.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/pkcs/PKCS7.java	Thu Jul 09 16:37:55 2015 -0700
@@ -507,7 +507,7 @@
         // certificates (optional)
         if (certificates != null && certificates.length != 0) {
             // cast to X509CertImpl[] since X509CertImpl implements DerEncoder
-            X509CertImpl implCerts[] = new X509CertImpl[certificates.length];
+            X509CertImpl[] implCerts = new X509CertImpl[certificates.length];
             for (int i = 0; i < certificates.length; i++) {
                 if (certificates[i] instanceof X509CertImpl)
                     implCerts[i] = (X509CertImpl) certificates[i];
--- a/jdk/src/java.base/share/classes/sun/security/pkcs/PKCS8Key.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/pkcs/PKCS8Key.java	Thu Jul 09 16:37:55 2015 -0700
@@ -78,7 +78,7 @@
      * data is stored and transmitted losslessly, but no knowledge
      * about this particular algorithm is available.
      */
-    private PKCS8Key (AlgorithmId algid, byte key [])
+    private PKCS8Key (AlgorithmId algid, byte[] key)
     throws InvalidKeyException {
         this.algid = algid;
         this.key = key;
--- a/jdk/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java	Thu Jul 09 16:37:55 2015 -0700
@@ -154,28 +154,28 @@
 
     private static final Debug debug = Debug.getInstance("pkcs12");
 
-    private static final int keyBag[]  = {1, 2, 840, 113549, 1, 12, 10, 1, 2};
-    private static final int certBag[] = {1, 2, 840, 113549, 1, 12, 10, 1, 3};
-    private static final int secretBag[] = {1, 2, 840, 113549, 1, 12, 10, 1, 5};
+    private static final int[] keyBag  = {1, 2, 840, 113549, 1, 12, 10, 1, 2};
+    private static final int[] certBag = {1, 2, 840, 113549, 1, 12, 10, 1, 3};
+    private static final int[] secretBag = {1, 2, 840, 113549, 1, 12, 10, 1, 5};
 
-    private static final int pkcs9Name[]  = {1, 2, 840, 113549, 1, 9, 20};
-    private static final int pkcs9KeyId[] = {1, 2, 840, 113549, 1, 9, 21};
+    private static final int[] pkcs9Name  = {1, 2, 840, 113549, 1, 9, 20};
+    private static final int[] pkcs9KeyId = {1, 2, 840, 113549, 1, 9, 21};
 
-    private static final int pkcs9certType[] = {1, 2, 840, 113549, 1, 9, 22, 1};
+    private static final int[] pkcs9certType = {1, 2, 840, 113549, 1, 9, 22, 1};
 
-    private static final int pbeWithSHAAnd40BitRC2CBC[] =
+    private static final int[] pbeWithSHAAnd40BitRC2CBC =
                                         {1, 2, 840, 113549, 1, 12, 1, 6};
-    private static final int pbeWithSHAAnd3KeyTripleDESCBC[] =
+    private static final int[] pbeWithSHAAnd3KeyTripleDESCBC =
                                         {1, 2, 840, 113549, 1, 12, 1, 3};
-    private static final int pbes2[] = {1, 2, 840, 113549, 1, 5, 13};
+    private static final int[] pbes2 = {1, 2, 840, 113549, 1, 5, 13};
     // TODO: temporary Oracle OID
     /*
      * { joint-iso-itu-t(2) country(16) us(840) organization(1) oracle(113894)
      *   jdk(746875) crypto(1) id-at-trustedKeyUsage(1) }
      */
-    private static final int TrustedKeyUsage[] =
+    private static final int[] TrustedKeyUsage =
                                         {2, 16, 840, 1, 113894, 746875, 1, 1};
-    private static final int AnyExtendedKeyUsage[] = {2, 5, 29, 37, 0};
+    private static final int[] AnyExtendedKeyUsage = {2, 5, 29, 37, 0};
 
     private static ObjectIdentifier PKCS8ShroudedKeyBag_OID;
     private static ObjectIdentifier CertBag_OID;
@@ -243,7 +243,7 @@
     // A private key entry and its supporting certificate chain
     private static class PrivateKeyEntry extends KeyEntry {
         byte[] protectedPrivKey;
-        Certificate chain[];
+        Certificate[] chain;
     };
 
     // A secret key
--- a/jdk/src/java.base/share/classes/sun/security/provider/AuthPolicyFile.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/provider/AuthPolicyFile.java	Thu Jul 09 16:37:55 2015 -0700
@@ -403,7 +403,7 @@
                         debug.println("  "+perm);
                     }
                 } catch (ClassNotFoundException cnfe) {
-                    Certificate certs[];
+                    Certificate[] certs;
                     if (pe.signedBy != null) {
                         certs = getCertificates(keyStore, pe.signedBy);
                     } else {
@@ -623,7 +623,7 @@
             init();
         }
 
-        final CodeSource codesource[] = {null};
+        final CodeSource[] codesource = {null};
 
         codesource[0] = canonicalizeCodebase(cs, true);
 
@@ -666,7 +666,7 @@
         // now see if any of the keys are trusted ids.
 
         if (!ignoreIdentityScope) {
-            Certificate certs[] = codesource[0].getCertificates();
+            Certificate[] certs = codesource[0].getCertificates();
             if (certs != null) {
                 for (int k=0; k < certs.length; k++) {
                     if (aliasMapping.get(certs[k]) == null &&
--- a/jdk/src/java.base/share/classes/sun/security/provider/DSAParameterGenerator.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/provider/DSAParameterGenerator.java	Thu Jul 09 16:37:55 2015 -0700
@@ -237,7 +237,7 @@
             BigInteger offset = ONE;
             /* Step 11 */
             for (counter = 0; counter < 4*valueL; counter++) {
-                BigInteger V[] = new BigInteger[n + 1];
+                BigInteger[] V = new BigInteger[n + 1];
                 /* Step 11.1 */
                 for (int j = 0; j <= n; j++) {
                     BigInteger J = BigInteger.valueOf(j);
--- a/jdk/src/java.base/share/classes/sun/security/provider/JavaKeyStore.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/provider/JavaKeyStore.java	Thu Jul 09 16:37:55 2015 -0700
@@ -82,7 +82,7 @@
     private static class KeyEntry {
         Date date; // the creation date of this entry
         byte[] protectedPrivKey;
-        Certificate chain[];
+        Certificate[] chain;
     };
 
     // Trusted certificates
@@ -604,7 +604,7 @@
              * the keystore (such as deleting or modifying key or
              * certificate entries).
              */
-            byte digest[] = md.digest();
+            byte[] digest = md.digest();
 
             dos.write(digest);
             dos.flush();
@@ -770,9 +770,8 @@
              * with
              */
             if (password != null) {
-                byte computed[], actual[];
-                computed = md.digest();
-                actual = new byte[computed.length];
+                byte[] computed = md.digest();
+                byte[] actual = new byte[computed.length];
                 dis.readFully(actual);
                 for (int i = 0; i < computed.length; i++) {
                     if (computed[i] != actual[i]) {
--- a/jdk/src/java.base/share/classes/sun/security/provider/PolicyFile.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/provider/PolicyFile.java	Thu Jul 09 16:37:55 2015 -0700
@@ -795,7 +795,7 @@
                         // an unresolved permission which will be resolved
                         // when implies is called
                         // Add it to entry
-                        Certificate certs[];
+                        Certificate[] certs;
                         if (pe.signedBy != null) {
                             certs = getCertificates(keyStore,
                                                     pe.signedBy,
@@ -817,7 +817,7 @@
                         debug.println("  "+perm);
                     }
                 } catch (ClassNotFoundException cnfe) {
-                    Certificate certs[];
+                    Certificate[] certs;
                     if (pe.signedBy != null) {
                         certs = getCertificates(keyStore,
                                                 pe.signedBy,
@@ -2032,7 +2032,7 @@
          *
          * @serial
          */
-        private Certificate certs[];
+        private Certificate[] certs;
 
         /**
          * Creates a new SelfPermission containing the permission
@@ -2048,7 +2048,7 @@
          * certificate first and the (root) certificate authority last).
          */
         public SelfPermission(String type, String name, String actions,
-                              Certificate certs[])
+                              Certificate[] certs)
         {
             super(type);
             if (type == null) {
--- a/jdk/src/java.base/share/classes/sun/security/provider/PolicyParser.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/provider/PolicyParser.java	Thu Jul 09 16:37:55 2015 -0700
@@ -1353,7 +1353,7 @@
         }
     }
 
-    public static void main(String arg[]) throws Exception {
+    public static void main(String[] arg) throws Exception {
         try (FileReader fr = new FileReader(arg[0]);
              FileWriter fw = new FileWriter(arg[1])) {
             PolicyParser pp = new PolicyParser(true);
--- a/jdk/src/java.base/share/classes/sun/security/provider/SecureRandom.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/provider/SecureRandom.java	Thu Jul 09 16:37:55 2015 -0700
@@ -85,7 +85,7 @@
      *
      * @param seed the seed.
      */
-    private SecureRandom(byte seed[]) {
+    private SecureRandom(byte[] seed) {
         init(seed);
     }
 
--- a/jdk/src/java.base/share/classes/sun/security/ssl/ByteBufferInputStream.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ByteBufferInputStream.java	Thu Jul 09 16:37:55 2015 -0700
@@ -70,7 +70,7 @@
      * Increments position().
      */
     @Override
-    public int read(byte b[]) throws IOException {
+    public int read(byte[] b) throws IOException {
 
         if (bb == null) {
             throw new IOException("read on a closed InputStream");
@@ -85,7 +85,7 @@
      * Increments position().
      */
     @Override
-    public int read(byte b[], int off, int len) throws IOException {
+    public int read(byte[] b, int off, int len) throws IOException {
 
         if (bb == null) {
             throw new IOException("read on a closed InputStream");
--- a/jdk/src/java.base/share/classes/sun/security/ssl/ClientHandshaker.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ClientHandshaker.java	Thu Jul 09 16:37:55 2015 -0700
@@ -810,7 +810,7 @@
             String alias = null;
             int keytypesTmpSize = keytypesTmp.size();
             if (keytypesTmpSize != 0) {
-                String keytypes[] =
+                String[] keytypes =
                         keytypesTmp.toArray(new String[keytypesTmpSize]);
 
                 if (conn != null) {
--- a/jdk/src/java.base/share/classes/sun/security/ssl/DHClientKeyExchange.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/DHClientKeyExchange.java	Thu Jul 09 16:37:55 2015 -0700
@@ -48,7 +48,7 @@
      * This value may be empty if it was included in the
      * client's certificate ...
      */
-    private byte dh_Yc[];               // 1 to 2^16 -1 bytes
+    private byte[] dh_Yc;               // 1 to 2^16 -1 bytes
 
     BigInteger getClientPublicKey() {
         return dh_Yc == null ? null : new BigInteger(1, dh_Yc);
--- a/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeInStream.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeInStream.java	Thu Jul 09 16:37:55 2015 -0700
@@ -146,7 +146,7 @@
     byte[] getBytes8() throws IOException {
         int len = getInt8();
         verifyLength(len);
-        byte b[] = new byte[len];
+        byte[] b = new byte[len];
 
         read(b);
         return b;
@@ -155,7 +155,7 @@
     public byte[] getBytes16() throws IOException {
         int len = getInt16();
         verifyLength(len);
-        byte b[] = new byte[len];
+        byte[] b = new byte[len];
 
         read(b);
         return b;
@@ -164,7 +164,7 @@
     byte[] getBytes24() throws IOException {
         int len = getInt24();
         verifyLength(len);
-        byte b[] = new byte[len];
+        byte[] b = new byte[len];
 
         read(b);
         return b;
--- a/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeMessage.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeMessage.java	Thu Jul 09 16:37:55 2015 -0700
@@ -689,8 +689,8 @@
 static final
 class RSA_ServerKeyExchange extends ServerKeyExchange
 {
-    private byte rsa_modulus[];     // 1 to 2^16 - 1 bytes
-    private byte rsa_exponent[];    // 1 to 2^16 - 1 bytes
+    private byte[] rsa_modulus;     // 1 to 2^16 - 1 bytes
+    private byte[] rsa_exponent;    // 1 to 2^16 - 1 bytes
 
     private Signature signature;
     private byte[] signatureBytes;
@@ -698,7 +698,7 @@
     /*
      * Hash the nonces and the ephemeral RSA public key.
      */
-    private void updateSignature(byte clntNonce[], byte svrNonce[])
+    private void updateSignature(byte[] clntNonce, byte[] svrNonce)
             throws SignatureException {
         int tmp;
 
@@ -827,11 +827,11 @@
     private final static boolean dhKeyExchangeFix =
         Debug.getBooleanProperty("com.sun.net.ssl.dhKeyExchangeFix", true);
 
-    private byte                dh_p [];        // 1 to 2^16 - 1 bytes
-    private byte                dh_g [];        // 1 to 2^16 - 1 bytes
-    private byte                dh_Ys [];       // 1 to 2^16 - 1 bytes
+    private byte[]                dh_p;        // 1 to 2^16 - 1 bytes
+    private byte[]                dh_g;        // 1 to 2^16 - 1 bytes
+    private byte[]                dh_Ys;       // 1 to 2^16 - 1 bytes
 
-    private byte                signature [];
+    private byte[]                signature;
 
     // protocol version being established using this ServerKeyExchange message
     ProtocolVersion protocolVersion;
@@ -857,8 +857,8 @@
      * with the cert chain which was sent ... for DHE_DSS and DHE_RSA
      * key exchange.  (Constructor called by server.)
      */
-    DH_ServerKeyExchange(DHCrypt obj, PrivateKey key, byte clntNonce[],
-            byte svrNonce[], SecureRandom sr,
+    DH_ServerKeyExchange(DHCrypt obj, PrivateKey key, byte[] clntNonce,
+            byte[] svrNonce, SecureRandom sr,
             SignatureAndHashAlgorithm signAlgorithm,
             ProtocolVersion protocolVersion) throws GeneralSecurityException {
 
@@ -913,7 +913,7 @@
      * DHE_DSS or DHE_RSA key exchange.  (Called by client.)
      */
     DH_ServerKeyExchange(HandshakeInStream input, PublicKey publicKey,
-            byte clntNonce[], byte svrNonce[], int messageSize,
+            byte[] clntNonce, byte[] svrNonce, int messageSize,
             Collection<SignatureAndHashAlgorithm> localSupportedSignAlgs,
             ProtocolVersion protocolVersion)
             throws IOException, GeneralSecurityException {
@@ -948,7 +948,7 @@
         }
 
         // read the signature
-        byte signature[];
+        byte[] signature;
         if (dhKeyExchangeFix) {
             signature = input.getBytes16();
         } else {
@@ -1004,8 +1004,8 @@
     /*
      * Update sig with nonces and Diffie-Hellman public key.
      */
-    private void updateSignature(Signature sig, byte clntNonce[],
-            byte svrNonce[]) throws SignatureException {
+    private void updateSignature(Signature sig, byte[] clntNonce,
+            byte[] svrNonce) throws SignatureException {
         int tmp;
 
         sig.update(clntNonce);
@@ -1268,8 +1268,8 @@
             }
     }
 
-    private void updateSignature(Signature sig, byte clntNonce[],
-            byte svrNonce[]) throws SignatureException {
+    private void updateSignature(Signature sig, byte[] clntNonce,
+            byte[] svrNonce) throws SignatureException {
         sig.update(clntNonce);
         sig.update(svrNonce);
 
@@ -1334,7 +1334,7 @@
      * DER encoded distinguished name.
      * TLS requires that its not longer than 65535 bytes.
      */
-    byte name[];
+    byte[] name;
 
     DistinguishedName(HandshakeInStream input) throws IOException {
         name = input.getBytes16();
@@ -1411,8 +1411,8 @@
     private final static byte[] TYPES_ECC =
         { cct_rsa_sign, cct_dss_sign, cct_ecdsa_sign };
 
-    byte                types [];               // 1 to 255 types
-    DistinguishedName   authorities [];         // 3 to 2^16 - 1
+    byte[]                types;               // 1 to 255 types
+    DistinguishedName[]   authorities;         // 3 to 2^16 - 1
         // ... "3" because that's the smallest DER-encoded X500 DN
 
     // protocol version being established using this CertificateRequest message
@@ -1424,7 +1424,7 @@
     // length of supported_signature_algorithms
     private int algorithmsLen;
 
-    CertificateRequest(X509Certificate ca[], KeyExchange keyExchange,
+    CertificateRequest(X509Certificate[] ca, KeyExchange keyExchange,
             Collection<SignatureAndHashAlgorithm> signAlgs,
             ProtocolVersion protocolVersion) throws IOException {
 
@@ -2063,7 +2063,7 @@
         if (protocolVersion.useTLS10PlusSpec()) {
             // TLS 1.0+
             try {
-                byte [] seed;
+                byte[] seed;
                 String prfAlg;
                 PRF prf;
 
--- a/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeOutStream.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeOutStream.java	Thu Jul 09 16:37:55 2015 -0700
@@ -119,7 +119,7 @@
         }
     }
 
-    public void putBytes16(byte b[]) throws IOException {
+    public void putBytes16(byte[] b) throws IOException {
         if (b == null) {
             putInt16(0);
         } else {
@@ -128,7 +128,7 @@
         }
     }
 
-    void putBytes24(byte b[]) throws IOException {
+    void putBytes24(byte[] b) throws IOException {
         if (b == null) {
             putInt24(0);
         } else {
--- a/jdk/src/java.base/share/classes/sun/security/ssl/MAC.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/MAC.java	Thu Jul 09 16:37:55 2015 -0700
@@ -52,7 +52,7 @@
     final static MAC TLS_NULL = new MAC(false);
 
     // Value of the null MAC is fixed
-    private static final byte nullMAC[] = new byte[0];
+    private static final byte[] nullMAC = new byte[0];
 
     // internal identifier for the MAC algorithm
     private final MacAlg macAlg;
--- a/jdk/src/java.base/share/classes/sun/security/ssl/RandomCookie.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/RandomCookie.java	Thu Jul 09 16:37:55 2015 -0700
@@ -38,7 +38,7 @@
  */
 final class RandomCookie {
 
-    byte random_bytes[];  // exactly 32 bytes
+    byte[] random_bytes;  // exactly 32 bytes
 
     RandomCookie(SecureRandom generator) {
         long temp = System.currentTimeMillis() / 1000;
--- a/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java	Thu Jul 09 16:37:55 2015 -0700
@@ -986,7 +986,7 @@
                 ClientKeyExchangeService.find(keyExchange.name) == null) {
 
             CertificateRequest m4;
-            X509Certificate caCerts[];
+            X509Certificate[] caCerts;
 
             Collection<SignatureAndHashAlgorithm> localSignAlgs = null;
             if (protocolVersion.useTLS12PlusSpec()) {
--- a/jdk/src/java.base/share/classes/sun/security/ssl/SessionId.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SessionId.java	Thu Jul 09 16:37:55 2015 -0700
@@ -43,7 +43,7 @@
 class SessionId
 {
     static int MAX_LENGTH = 32;
-    private byte sessionId [];          // max 32 bytes
+    private byte[] sessionId;          // max 32 bytes
 
     /** Constructs a new session ID ... perhaps for a rejoinable session */
     SessionId (boolean isRejoinable, SecureRandom generator)
@@ -56,7 +56,7 @@
     }
 
     /** Constructs a session ID from a byte array (max size 32 bytes) */
-    SessionId (byte sessionId [])
+    SessionId (byte[] sessionId)
         { this.sessionId = sessionId; }
 
     /** Returns the length of the ID, in bytes */
@@ -64,7 +64,7 @@
         { return sessionId.length; }
 
     /** Returns the bytes in the ID.  May be an empty array.  */
-    byte [] getId ()
+    byte[] getId ()
     {
         return sessionId.clone ();
     }
@@ -106,7 +106,7 @@
             return false;
 
         SessionId s = (SessionId) obj;
-        byte b [] = s.getId ();
+        byte[] b = s.getId ();
 
         if (b.length != sessionId.length)
             return false;
--- a/jdk/src/java.base/share/classes/sun/security/ssl/X509TrustManagerImpl.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/X509TrustManagerImpl.java	Thu Jul 09 16:37:55 2015 -0700
@@ -94,13 +94,13 @@
     }
 
     @Override
-    public void checkClientTrusted(X509Certificate chain[], String authType)
+    public void checkClientTrusted(X509Certificate[] chain, String authType)
             throws CertificateException {
         checkTrusted(chain, authType, (Socket)null, true);
     }
 
     @Override
-    public void checkServerTrusted(X509Certificate chain[], String authType)
+    public void checkServerTrusted(X509Certificate[] chain, String authType)
             throws CertificateException {
         checkTrusted(chain, authType, (Socket)null, false);
     }
--- a/jdk/src/java.base/share/classes/sun/security/util/ManifestDigester.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/util/ManifestDigester.java	Thu Jul 09 16:37:55 2015 -0700
@@ -37,7 +37,7 @@
     public static final String MF_MAIN_ATTRS = "Manifest-Main-Attributes";
 
     /** the raw bytes of the manifest */
-    private byte rawBytes[];
+    private byte[] rawBytes;
 
     /** the offset/length pair for a section */
     private HashMap<String, Entry> entries; // key is a UTF-8 string
@@ -107,7 +107,7 @@
         return false;
     }
 
-    public ManifestDigester(byte bytes[])
+    public ManifestDigester(byte[] bytes)
     {
         rawBytes = bytes;
         entries = new HashMap<>();
@@ -181,7 +181,7 @@
         }
     }
 
-    private boolean isNameAttr(byte bytes[], int start)
+    private boolean isNameAttr(byte[] bytes, int start)
     {
         return ((bytes[start] == 'N') || (bytes[start] == 'n')) &&
                ((bytes[start+1] == 'a') || (bytes[start+1] == 'A')) &&
@@ -261,11 +261,10 @@
         return e;
     }
 
-    public byte[] manifestDigest(MessageDigest md)
-        {
-            md.reset();
-            md.update(rawBytes, 0, rawBytes.length);
-            return md.digest();
-        }
+    public byte[] manifestDigest(MessageDigest md) {
+        md.reset();
+        md.update(rawBytes, 0, rawBytes.length);
+        return md.digest();
+    }
 
 }
--- a/jdk/src/java.base/share/classes/sun/security/util/ManifestEntryVerifier.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/util/ManifestEntryVerifier.java	Thu Jul 09 16:37:55 2015 -0700
@@ -165,7 +165,7 @@
     /**
      * update the digests for the digests we are interested in
      */
-    public void update(byte buffer[], int off, int len) {
+    public void update(byte[] buffer, int off, int len) {
         if (skip) return;
 
         for (int i=0; i < digests.size(); i++) {
--- a/jdk/src/java.base/share/classes/sun/security/util/ObjectIdentifier.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/util/ObjectIdentifier.java	Thu Jul 09 16:37:55 2015 -0700
@@ -212,7 +212,7 @@
      * Constructor, from an array of integers.
      * Validity check included.
      */
-    public ObjectIdentifier (int values []) throws IOException
+    public ObjectIdentifier(int[] values) throws IOException
     {
         checkCount(values.length);
         checkFirstComponent(values[0]);
--- a/jdk/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java	Thu Jul 09 16:37:55 2015 -0700
@@ -55,7 +55,7 @@
     private PKCS7 block;
 
     /** the raw bytes of the .SF file */
-    private byte sfBytes[];
+    private byte[] sfBytes;
 
     /** the name of the signature block file, uppercased and without
      *  the extension (.DSA/.RSA/.EC)
@@ -84,7 +84,7 @@
     public SignatureFileVerifier(ArrayList<CodeSigner[]> signerCache,
                                  ManifestDigester md,
                                  String name,
-                                 byte rawBytes[])
+                                 byte[] rawBytes)
         throws IOException, CertificateException
     {
         // new PKCS7() calls CertificateFactory.getInstance()
@@ -129,7 +129,7 @@
      * used to set the raw bytes of the .SF file when it
      * is external to the signature block file.
      */
-    public void setSignatureFile(byte sfBytes[])
+    public void setSignatureFile(byte[] sfBytes)
     {
         this.sfBytes = sfBytes;
     }
@@ -511,7 +511,7 @@
      * CodeSigner objects. We do this only *once* for a given
      * signature block file.
      */
-    private CodeSigner[] getSigners(SignerInfo infos[], PKCS7 block)
+    private CodeSigner[] getSigners(SignerInfo[] infos, PKCS7 block)
         throws IOException, NoSuchAlgorithmException, SignatureException,
             CertificateException {
 
--- a/jdk/src/java.base/share/classes/sun/security/x509/AVA.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/x509/AVA.java	Thu Jul 09 16:37:55 2015 -0700
@@ -967,7 +967,7 @@
 
                     previousWhite = false;
 
-                    byte valueBytes[] = null;
+                    byte[] valueBytes = null;
                     try {
                         valueBytes = Character.toString(c).getBytes("UTF8");
                     } catch (IOException ie) {
@@ -1051,7 +1051,7 @@
                 // using the hex format below.  This will be used only
                 // when the value is not a string type
 
-                byte    data [] = value.toByteArray();
+                byte[] data = value.toByteArray();
 
                 retval.append('#');
                 for (int i = 0; i < data.length; i++) {
--- a/jdk/src/java.base/share/classes/sun/security/x509/AlgIdDSA.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/x509/AlgIdDSA.java	Thu Jul 09 16:37:55 2015 -0700
@@ -117,7 +117,7 @@
      * @param q the DSS/DSA parameter "Q"
      * @param g the DSS/DSA parameter "G"
      */
-    public AlgIdDSA (byte p [], byte q [], byte g [])
+    public AlgIdDSA (byte[] p, byte[] q, byte[] g)
     throws IOException
     {
         this (new BigInteger (1, p),
--- a/jdk/src/java.base/share/classes/sun/security/x509/AlgorithmId.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/x509/AlgorithmId.java	Thu Jul 09 16:37:55 2015 -0700
@@ -648,12 +648,12 @@
     /*
      * COMMON PUBLIC KEY TYPES
      */
-    private static final int DH_data[] = { 1, 2, 840, 113549, 1, 3, 1 };
-    private static final int DH_PKIX_data[] = { 1, 2, 840, 10046, 2, 1 };
-    private static final int DSA_OIW_data[] = { 1, 3, 14, 3, 2, 12 };
-    private static final int DSA_PKIX_data[] = { 1, 2, 840, 10040, 4, 1 };
-    private static final int RSA_data[] = { 2, 5, 8, 1, 1 };
-    private static final int RSAEncryption_data[] =
+    private static final int[] DH_data = { 1, 2, 840, 113549, 1, 3, 1 };
+    private static final int[] DH_PKIX_data = { 1, 2, 840, 10046, 2, 1 };
+    private static final int[] DSA_OIW_data = { 1, 3, 14, 3, 2, 12 };
+    private static final int[] DSA_PKIX_data = { 1, 2, 840, 10040, 4, 1 };
+    private static final int[] RSA_data = { 2, 5, 8, 1, 1 };
+    private static final int[] RSAEncryption_data =
                                  { 1, 2, 840, 113549, 1, 1, 1 };
 
     public static final ObjectIdentifier DH_oid;
@@ -674,27 +674,27 @@
     /*
      * COMMON SIGNATURE ALGORITHMS
      */
-    private static final int md2WithRSAEncryption_data[] =
+    private static final int[] md2WithRSAEncryption_data =
                                        { 1, 2, 840, 113549, 1, 1, 2 };
-    private static final int md5WithRSAEncryption_data[] =
+    private static final int[] md5WithRSAEncryption_data =
                                        { 1, 2, 840, 113549, 1, 1, 4 };
-    private static final int sha1WithRSAEncryption_data[] =
+    private static final int[] sha1WithRSAEncryption_data =
                                        { 1, 2, 840, 113549, 1, 1, 5 };
-    private static final int sha1WithRSAEncryption_OIW_data[] =
+    private static final int[] sha1WithRSAEncryption_OIW_data =
                                        { 1, 3, 14, 3, 2, 29 };
-    private static final int sha224WithRSAEncryption_data[] =
+    private static final int[] sha224WithRSAEncryption_data =
                                        { 1, 2, 840, 113549, 1, 1, 14 };
-    private static final int sha256WithRSAEncryption_data[] =
+    private static final int[] sha256WithRSAEncryption_data =
                                        { 1, 2, 840, 113549, 1, 1, 11 };
-    private static final int sha384WithRSAEncryption_data[] =
+    private static final int[] sha384WithRSAEncryption_data =
                                        { 1, 2, 840, 113549, 1, 1, 12 };
-    private static final int sha512WithRSAEncryption_data[] =
+    private static final int[] sha512WithRSAEncryption_data =
                                        { 1, 2, 840, 113549, 1, 1, 13 };
-    private static final int shaWithDSA_OIW_data[] =
+    private static final int[] shaWithDSA_OIW_data =
                                        { 1, 3, 14, 3, 2, 13 };
-    private static final int sha1WithDSA_OIW_data[] =
+    private static final int[] sha1WithDSA_OIW_data =
                                        { 1, 3, 14, 3, 2, 27 };
-    private static final int dsaWithSHA1_PKIX_data[] =
+    private static final int[] dsaWithSHA1_PKIX_data =
                                        { 1, 2, 840, 10040, 4, 3 };
 
     public static final ObjectIdentifier md2WithRSAEncryption_oid;
--- a/jdk/src/java.base/share/classes/sun/security/x509/NetscapeCertTypeExtension.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/x509/NetscapeCertTypeExtension.java	Thu Jul 09 16:37:55 2015 -0700
@@ -69,7 +69,7 @@
     public static final String S_MIME_CA = "s_mime_ca";
     public static final String OBJECT_SIGNING_CA = "object_signing_ca";
 
-    private static final int CertType_data[] = { 2, 16, 840, 1, 113730, 1, 1 };
+    private static final int[] CertType_data = { 2, 16, 840, 1, 113730, 1, 1 };
 
     /**
      * Object identifier for the Netscape-Cert-Type extension.
--- a/jdk/src/java.base/share/classes/sun/security/x509/OIDMap.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/x509/OIDMap.java	Thu Jul 09 16:37:55 2015 -0700
@@ -102,7 +102,7 @@
     private static final String OCSPNOCHECK = ROOT + "." +
                                         OCSPNoCheckExtension.NAME;
 
-    private static final int NetscapeCertType_data[] =
+    private static final int[] NetscapeCertType_data =
         { 2, 16, 840, 1, 113730, 1, 1 };
 
     /** Map ObjectIdentifier(oid) -> OIDInfo(info) */
--- a/jdk/src/java.base/share/classes/sun/security/x509/PKIXExtensions.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/x509/PKIXExtensions.java	Thu Jul 09 16:37:55 2015 -0700
@@ -49,32 +49,32 @@
  */
 public class PKIXExtensions {
     // The object identifiers
-    private static final int AuthorityKey_data [] = { 2, 5, 29, 35 };
-    private static final int SubjectKey_data [] = { 2, 5, 29, 14 };
-    private static final int KeyUsage_data [] = { 2, 5, 29, 15 };
-    private static final int PrivateKeyUsage_data [] = { 2, 5, 29, 16 };
-    private static final int CertificatePolicies_data [] = { 2, 5, 29, 32 };
-    private static final int PolicyMappings_data [] = { 2, 5, 29, 33 };
-    private static final int SubjectAlternativeName_data [] = { 2, 5, 29, 17 };
-    private static final int IssuerAlternativeName_data [] = { 2, 5, 29, 18 };
-    private static final int SubjectDirectoryAttributes_data [] = { 2, 5, 29, 9 };
-    private static final int BasicConstraints_data [] = { 2, 5, 29, 19 };
-    private static final int NameConstraints_data [] = { 2, 5, 29, 30 };
-    private static final int PolicyConstraints_data [] = { 2, 5, 29, 36 };
-    private static final int CRLDistributionPoints_data [] = { 2, 5, 29, 31 };
-    private static final int CRLNumber_data [] = { 2, 5, 29, 20 };
-    private static final int IssuingDistributionPoint_data [] = { 2, 5, 29, 28 };
-    private static final int DeltaCRLIndicator_data [] = { 2, 5, 29, 27 };
-    private static final int ReasonCode_data [] = { 2, 5, 29, 21 };
-    private static final int HoldInstructionCode_data [] = { 2, 5, 29, 23 };
-    private static final int InvalidityDate_data [] = { 2, 5, 29, 24 };
-    private static final int ExtendedKeyUsage_data [] = { 2, 5, 29, 37 };
-    private static final int InhibitAnyPolicy_data [] = { 2, 5, 29, 54 };
-    private static final int CertificateIssuer_data [] = { 2, 5, 29, 29 };
-    private static final int AuthInfoAccess_data [] = { 1, 3, 6, 1, 5, 5, 7, 1, 1};
-    private static final int SubjectInfoAccess_data [] = { 1, 3, 6, 1, 5, 5, 7, 1, 11};
-    private static final int FreshestCRL_data [] = { 2, 5, 29, 46 };
-    private static final int OCSPNoCheck_data [] = { 1, 3, 6, 1, 5, 5, 7,
+    private static final int[] AuthorityKey_data = { 2, 5, 29, 35 };
+    private static final int[] SubjectKey_data = { 2, 5, 29, 14 };
+    private static final int[] KeyUsage_data = { 2, 5, 29, 15 };
+    private static final int[] PrivateKeyUsage_data = { 2, 5, 29, 16 };
+    private static final int[] CertificatePolicies_data = { 2, 5, 29, 32 };
+    private static final int[] PolicyMappings_data = { 2, 5, 29, 33 };
+    private static final int[] SubjectAlternativeName_data = { 2, 5, 29, 17 };
+    private static final int[] IssuerAlternativeName_data = { 2, 5, 29, 18 };
+    private static final int[] SubjectDirectoryAttributes_data = { 2, 5, 29, 9 };
+    private static final int[] BasicConstraints_data = { 2, 5, 29, 19 };
+    private static final int[] NameConstraints_data = { 2, 5, 29, 30 };
+    private static final int[] PolicyConstraints_data = { 2, 5, 29, 36 };
+    private static final int[] CRLDistributionPoints_data = { 2, 5, 29, 31 };
+    private static final int[] CRLNumber_data = { 2, 5, 29, 20 };
+    private static final int[] IssuingDistributionPoint_data = { 2, 5, 29, 28 };
+    private static final int[] DeltaCRLIndicator_data = { 2, 5, 29, 27 };
+    private static final int[] ReasonCode_data = { 2, 5, 29, 21 };
+    private static final int[] HoldInstructionCode_data = { 2, 5, 29, 23 };
+    private static final int[] InvalidityDate_data = { 2, 5, 29, 24 };
+    private static final int[] ExtendedKeyUsage_data = { 2, 5, 29, 37 };
+    private static final int[] InhibitAnyPolicy_data = { 2, 5, 29, 54 };
+    private static final int[] CertificateIssuer_data = { 2, 5, 29, 29 };
+    private static final int[] AuthInfoAccess_data = { 1, 3, 6, 1, 5, 5, 7, 1, 1};
+    private static final int[] SubjectInfoAccess_data = { 1, 3, 6, 1, 5, 5, 7, 1, 11};
+    private static final int[] FreshestCRL_data = { 2, 5, 29, 46 };
+    private static final int[] OCSPNoCheck_data = { 1, 3, 6, 1, 5, 5, 7,
                                                     48, 1, 5};
 
     /**
--- a/jdk/src/java.base/share/classes/sun/security/x509/X500Name.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/x509/X500Name.java	Thu Jul 09 16:37:55 2015 -0700
@@ -1119,25 +1119,25 @@
      * Includes all those specified in RFC 5280 as MUST or SHOULD
      * be recognized
      */
-    private static final int commonName_data[] = { 2, 5, 4, 3 };
-    private static final int SURNAME_DATA[] = { 2, 5, 4, 4 };
-    private static final int SERIALNUMBER_DATA[] = { 2, 5, 4, 5 };
-    private static final int countryName_data[] = { 2, 5, 4, 6 };
-    private static final int localityName_data[] = { 2, 5, 4, 7 };
-    private static final int stateName_data[] = { 2, 5, 4, 8 };
-    private static final int streetAddress_data[] = { 2, 5, 4, 9 };
-    private static final int orgName_data[] = { 2, 5, 4, 10 };
-    private static final int orgUnitName_data[] = { 2, 5, 4, 11 };
-    private static final int title_data[] = { 2, 5, 4, 12 };
-    private static final int GIVENNAME_DATA[] = { 2, 5, 4, 42 };
-    private static final int INITIALS_DATA[] = { 2, 5, 4, 43 };
-    private static final int GENERATIONQUALIFIER_DATA[] = { 2, 5, 4, 44 };
-    private static final int DNQUALIFIER_DATA[] = { 2, 5, 4, 46 };
+    private static final int[] commonName_data = { 2, 5, 4, 3 };
+    private static final int[] SURNAME_DATA = { 2, 5, 4, 4 };
+    private static final int[] SERIALNUMBER_DATA = { 2, 5, 4, 5 };
+    private static final int[] countryName_data = { 2, 5, 4, 6 };
+    private static final int[] localityName_data = { 2, 5, 4, 7 };
+    private static final int[] stateName_data = { 2, 5, 4, 8 };
+    private static final int[] streetAddress_data = { 2, 5, 4, 9 };
+    private static final int[] orgName_data = { 2, 5, 4, 10 };
+    private static final int[] orgUnitName_data = { 2, 5, 4, 11 };
+    private static final int[] title_data = { 2, 5, 4, 12 };
+    private static final int[] GIVENNAME_DATA = { 2, 5, 4, 42 };
+    private static final int[] INITIALS_DATA = { 2, 5, 4, 43 };
+    private static final int[] GENERATIONQUALIFIER_DATA = { 2, 5, 4, 44 };
+    private static final int[] DNQUALIFIER_DATA = { 2, 5, 4, 46 };
 
-    private static final int ipAddress_data[] = { 1, 3, 6, 1, 4, 1, 42, 2, 11, 2, 1 };
-    private static final int DOMAIN_COMPONENT_DATA[] =
+    private static final int[] ipAddress_data = { 1, 3, 6, 1, 4, 1, 42, 2, 11, 2, 1 };
+    private static final int[] DOMAIN_COMPONENT_DATA =
         { 0, 9, 2342, 19200300, 100, 1, 25 };
-    private static final int userid_data[] =
+    private static final int[] userid_data =
         { 0, 9, 2342, 19200300, 100, 1, 1 };
 
 
--- a/jdk/src/java.base/share/classes/sun/security/x509/X509CRLImpl.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/x509/X509CRLImpl.java	Thu Jul 09 16:37:55 2015 -0700
@@ -1086,7 +1086,7 @@
             throw new CRLException("Invalid DER-encoded CRL data");
 
         signedCRL = val.toByteArray();
-        DerValue seq[] = new DerValue[3];
+        DerValue[] seq = new DerValue[3];
 
         seq[0] = val.data.getDerValue();
         seq[1] = val.data.getDerValue();
--- a/jdk/src/java.desktop/share/classes/sun/awt/util/IdentityArrayList.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/awt/util/IdentityArrayList.java	Thu Jul 09 16:37:55 2015 -0700
@@ -142,7 +142,8 @@
     public IdentityArrayList(Collection<? extends E> c) {
         elementData = c.toArray();
         size = elementData.length;
-        // c.toArray might (incorrectly) not return Object[] (see 6260652)
+        // defend against c.toArray (incorrectly) not returning Object[]
+        // (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)
         if (elementData.getClass() != Object[].class)
             elementData = Arrays.copyOf(elementData, size, Object[].class);
     }
--- a/jdk/src/java.security.jgss/share/classes/javax/security/auth/kerberos/ServicePermission.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/javax/security/auth/kerberos/ServicePermission.java	Thu Jul 09 16:37:55 2015 -0700
@@ -427,7 +427,7 @@
 
 
     /*
-      public static void main(String args[]) throws Exception {
+      public static void main(String[] args) throws Exception {
       ServicePermission this_ =
       new ServicePermission(args[0], "accept");
       ServicePermission that_ =
--- a/jdk/src/java.security.jgss/share/classes/sun/security/jgss/GSSCredentialImpl.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/GSSCredentialImpl.java	Thu Jul 09 16:37:55 2015 -0700
@@ -75,7 +75,7 @@
     }
 
     GSSCredentialImpl(GSSManagerImpl gssManager, GSSName name,
-                      int lifetime, Oid mechs[], int usage)
+                      int lifetime, Oid[] mechs, int usage)
         throws GSSException {
         init(gssManager);
         boolean defaultList = false;
--- a/jdk/src/java.security.jgss/share/classes/sun/security/jgss/GSSManagerImpl.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/GSSManagerImpl.java	Thu Jul 09 16:37:55 2015 -0700
@@ -128,7 +128,7 @@
         return new GSSNameImpl(this, nameStr, nameType);
     }
 
-    public GSSName createName(byte name[], Oid nameType)
+    public GSSName createName(byte[] name, Oid nameType)
         throws GSSException {
         return new GSSNameImpl(this, name, nameType);
     }
@@ -138,7 +138,7 @@
         return new GSSNameImpl(this, nameStr, nameType, mech);
     }
 
-    public GSSName createName(byte name[], Oid nameType, Oid mech)
+    public GSSName createName(byte[] name, Oid nameType, Oid mech)
         throws GSSException {
         return new GSSNameImpl(this, name, nameType, mech);
     }
@@ -155,7 +155,7 @@
     }
 
     public GSSCredential createCredential(GSSName aName,
-                                          int lifetime, Oid mechs[], int usage)
+                                          int lifetime, Oid[] mechs, int usage)
         throws GSSException {
         return wrap(new GSSCredentialImpl(this, aName, lifetime, mechs, usage));
     }
--- a/jdk/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java	Thu Jul 09 16:37:55 2015 -0700
@@ -159,7 +159,7 @@
     /**
      * Constructor for Krb5Context to import a previously exported context.
      */
-    public Krb5Context(GSSCaller caller, byte [] interProcessToken)
+    public Krb5Context(GSSCaller caller, byte[] interProcessToken)
         throws GSSException {
         throw new GSSException(GSSException.UNAVAILABLE,
                                -1, "GSS Import Context not available");
@@ -905,7 +905,7 @@
      * and verifyMIC care about the remote sequence number (peerSeqNumber).
      */
 
-    public final byte[] wrap(byte inBuf[], int offset, int len,
+    public final byte[] wrap(byte[] inBuf, int offset, int len,
                              MessageProp msgProp) throws GSSException {
         if (DEBUG) {
             System.out.println("Krb5Context.wrap: data=["
@@ -943,7 +943,7 @@
         }
     }
 
-    public final int wrap(byte inBuf[], int inOffset, int len,
+    public final int wrap(byte[] inBuf, int inOffset, int len,
                           byte[] outBuf, int outOffset,
                           MessageProp msgProp) throws GSSException {
 
@@ -977,7 +977,7 @@
         }
     }
 
-    public final void wrap(byte inBuf[], int offset, int len,
+    public final void wrap(byte[] inBuf, int offset, int len,
                            OutputStream os, MessageProp msgProp)
         throws GSSException {
 
@@ -1032,7 +1032,7 @@
         wrap(data, 0, data.length, os, msgProp);
     }
 
-    public final byte[] unwrap(byte inBuf[], int offset, int len,
+    public final byte[] unwrap(byte[] inBuf, int offset, int len,
                                MessageProp msgProp)
         throws GSSException {
 
@@ -1069,7 +1069,7 @@
             return data;
         }
 
-    public final int unwrap(byte inBuf[], int inOffset, int len,
+    public final int unwrap(byte[] inBuf, int inOffset, int len,
                              byte[] outBuf, int outOffset,
                              MessageProp msgProp) throws GSSException {
 
@@ -1141,7 +1141,7 @@
         }
     }
 
-    public final byte[] getMIC(byte []inMsg, int offset, int len,
+    public final byte[] getMIC(byte[] inMsg, int offset, int len,
                                MessageProp msgProp)
         throws GSSException {
 
@@ -1166,7 +1166,7 @@
             }
         }
 
-    private int getMIC(byte []inMsg, int offset, int len,
+    private int getMIC(byte[] inMsg, int offset, int len,
                        byte[] outBuf, int outOffset,
                        MessageProp msgProp)
         throws GSSException {
@@ -1236,7 +1236,7 @@
         getMIC(data, 0, data.length, os, msgProp);
     }
 
-    public final void verifyMIC(byte []inTok, int tokOffset, int tokLen,
+    public final void verifyMIC(byte[] inTok, int tokOffset, int tokLen,
                                 byte[] inMsg, int msgOffset, int msgLen,
                                 MessageProp msgProp)
         throws GSSException {
@@ -1293,7 +1293,7 @@
      * @param os the output token will be written to this stream
      * @exception GSSException
      */
-    public final byte [] export() throws GSSException {
+    public final byte[] export() throws GSSException {
         throw new GSSException(GSSException.UNAVAILABLE, -1,
                                "GSS Export Context not available");
     }
--- a/jdk/src/java.security.jgss/share/classes/sun/security/jgss/spi/GSSContextSpi.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/spi/GSSContextSpi.java	Thu Jul 09 16:37:55 2015 -0700
@@ -265,7 +265,7 @@
     /**
      * For apps that want simplicity and don't care about buffer copies.
      */
-    public byte[] wrap(byte inBuf[], int offset, int len,
+    public byte[] wrap(byte[] inBuf, int offset, int len,
                        MessageProp msgProp) throws GSSException;
 
     /**
@@ -275,7 +275,7 @@
      *
      * NOTE: This method is not defined in public class org.ietf.jgss.GSSContext
      *
-    public int wrap(byte inBuf[], int inOffset, int len,
+    public int wrap(byte[] inBuf, int inOffset, int len,
                     byte[] outBuf, int outOffset,
                     MessageProp msgProp) throws GSSException;
 
@@ -292,7 +292,7 @@
      *
      * NOTE: This method is not defined in public class org.ietf.jgss.GSSContext
      *
-    public void wrap(byte inBuf[], int offset, int len,
+    public void wrap(byte[] inBuf, int offset, int len,
                      OutputStream os, MessageProp msgProp)
         throws GSSException;
     */
@@ -314,7 +314,7 @@
     /**
      * For apps that want simplicity and don't care about buffer copies.
      */
-    public byte[] unwrap(byte inBuf[], int offset, int len,
+    public byte[] unwrap(byte[] inBuf, int offset, int len,
                          MessageProp msgProp) throws GSSException;
 
     /**
@@ -324,7 +324,7 @@
      *
      * NOTE: This method is not defined in public class org.ietf.jgss.GSSContext
      *
-    public int unwrap(byte inBuf[], int inOffset, int len,
+    public int unwrap(byte[] inBuf, int inOffset, int len,
                       byte[] outBuf, int outOffset,
                       MessageProp msgProp) throws GSSException;
 
@@ -356,7 +356,7 @@
                         MessageProp msgProp)
                 throws GSSException;
 
-    public byte[] getMIC(byte []inMsg, int offset, int len,
+    public byte[] getMIC(byte[] inMsg, int offset, int len,
                          MessageProp msgProp) throws GSSException;
 
     /**
@@ -372,7 +372,7 @@
     public void verifyMIC(InputStream is, InputStream msgStr,
                            MessageProp mProp) throws GSSException;
 
-    public void verifyMIC(byte []inTok, int tokOffset, int tokLen,
+    public void verifyMIC(byte[] inTok, int tokOffset, int tokLen,
                           byte[] inMsg, int msgOffset, int msgLen,
                           MessageProp msgProp) throws GSSException;
 
--- a/jdk/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/NativeGSSContext.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/NativeGSSContext.java	Thu Jul 09 16:37:55 2015 -0700
@@ -372,7 +372,7 @@
         }
         return cStub.wrap(pContext, data, msgProp);
     }
-    public void wrap(byte inBuf[], int offset, int len,
+    public void wrap(byte[] inBuf, int offset, int len,
                      OutputStream os, MessageProp msgProp)
         throws GSSException {
         try {
--- a/jdk/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java	Thu Jul 09 16:37:55 2015 -0700
@@ -78,7 +78,7 @@
                             if (DEBUG) err.printStackTrace();
                             return null;
                         }
-                        String gssLibs[] = new String[0];
+                        String[] gssLibs = new String[0];
                         String defaultLib = System.getProperty(LIB_PROP);
                         if (defaultLib == null || defaultLib.trim().equals("")) {
                             String osname = System.getProperty("os.name");
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/PrincipalName.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/PrincipalName.java	Thu Jul 09 16:37:55 2015 -0700
@@ -568,7 +568,7 @@
         temp.putInteger(bint);
         bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x00), temp);
         temp = new DerOutputStream();
-        DerValue der[] = new DerValue[nameStrings.length];
+        DerValue[] der = new DerValue[nameStrings.length];
         for (int i = 0; i < nameStrings.length; i++) {
             der[i] = new KerberosString(nameStrings[i]).toDerValue();
         }
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/Authenticator.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/Authenticator.java	Thu Jul 09 16:37:55 2015 -0700
@@ -198,7 +198,7 @@
         if (authorizationData != null) {
             v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x08), authorizationData.asn1Encode()));
         }
-        DerValue der[] = new DerValue[v.size()];
+        DerValue[] der = new DerValue[v.size()];
         v.copyInto(der);
         temp = new DerOutputStream();
         temp.putSequence(der);
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/AuthorizationData.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/AuthorizationData.java	Thu Jul 09 16:37:55 2015 -0700
@@ -120,7 +120,7 @@
      */
     public byte[] asn1Encode() throws Asn1Exception, IOException {
         DerOutputStream bytes = new DerOutputStream();
-        DerValue der[] = new DerValue[entry.length];
+        DerValue[] der = new DerValue[entry.length];
         for (int i = 0; i < entry.length; i++) {
             der[i] = new DerValue(entry[i].asn1Encode());
         }
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/EncAPRepPart.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/EncAPRepPart.java	Thu Jul 09 16:37:55 2015 -0700
@@ -151,7 +151,7 @@
             v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT,
                     true, (byte) 0x03), temp.toByteArray()));
         }
-        DerValue der[] = new DerValue[v.size()];
+        DerValue[] der = new DerValue[v.size()];
         v.copyInto(der);
         temp = new DerOutputStream();
         temp.putSequence(der);
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/EncKrbCredPart.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/EncKrbCredPart.java	Thu Jul 09 16:37:55 2015 -0700
@@ -129,7 +129,7 @@
 
         subDer = der.getData().getDerValue();
         if ((subDer.getTag() & (byte) 0x1F) == (byte) 0x00) {
-            DerValue derValues[] = subDer.getData().getSequence(1);
+            DerValue[] derValues = subDer.getData().getSequence(1);
             ticketInfo = new KrbCredInfo[derValues.length];
             for (int i = 0; i < derValues.length; i++) {
                 ticketInfo[i] = new KrbCredInfo(derValues[i]);
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/HostAddresses.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/HostAddresses.java	Thu Jul 09 16:37:55 2015 -0700
@@ -98,8 +98,8 @@
             throw new KrbException(Krb5.KRB_ERR_GENERIC, "Bad name");
 
         String host = components[1];
-        InetAddress addr[] = InetAddress.getAllByName(host);
-        HostAddress hAddrs[] = new HostAddress[addr.length];
+        InetAddress[] addr = InetAddress.getAllByName(host);
+        HostAddress[] hAddrs = new HostAddress[addr.length];
 
         for (int i = 0; i < addr.length; i++) {
             hAddrs[i] = new HostAddress(addr[i]);
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/KDCReqBody.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/KDCReqBody.java	Thu Jul 09 16:37:55 2015 -0700
@@ -269,7 +269,7 @@
             ticketsTemp.write(DerValue.tag_SequenceOf, temp);
             v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x0B), ticketsTemp.toByteArray()));
         }
-        DerValue der[] = new DerValue[v.size()];
+        DerValue[] der = new DerValue[v.size()];
         v.copyInto(der);
         temp = new DerOutputStream();
         temp.putSequence(der);
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/KrbCredInfo.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/KrbCredInfo.java	Thu Jul 09 16:37:55 2015 -0700
@@ -172,7 +172,7 @@
         }
         if (caddr != null)
             v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x0A), caddr.asn1Encode()));
-        DerValue der[] = new DerValue[v.size()];
+        DerValue[] der = new DerValue[v.size()];
         v.copyInto(der);
         DerOutputStream out = new DerOutputStream();
         out.putSequence(der);
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/NetClient.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/NetClient.java	Thu Jul 09 16:37:55 2015 -0700
@@ -200,7 +200,7 @@
 
     @Override
     public byte[] receive() throws IOException {
-        byte ibuf[] = new byte[bufSize];
+        byte[] ibuf = new byte[bufSize];
         dgPacketIn = new DatagramPacket(ibuf, ibuf.length);
         try {
             dgSocket.receive(dgPacketIn);
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/Ticket.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/Ticket.java	Thu Jul 09 16:37:55 2015 -0700
@@ -135,7 +135,7 @@
     public byte[] asn1Encode() throws Asn1Exception, IOException {
         DerOutputStream bytes = new DerOutputStream();
         DerOutputStream temp = new DerOutputStream();
-        DerValue der[] = new DerValue[4];
+        DerValue[] der = new DerValue[4];
         temp.putInteger(BigInteger.valueOf(tkt_vno));
         bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x00), temp);
         bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x01), sname.getRealm().asn1Encode());
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/CCacheInputStream.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/CCacheInputStream.java	Thu Jul 09 16:37:55 2015 -0700
@@ -357,7 +357,7 @@
         if (DEBUG) {
             System.out.println(">>>DEBUG <CCacheInputStream> key type: " + key.getEType());
         }
-        long times[] = readTimes();
+        long[] times = readTimes();
         KerberosTime authtime = new KerberosTime(times[0]);
         KerberosTime starttime =
                 (times[1]==0) ? null : new KerberosTime(times[1]);
@@ -374,9 +374,9 @@
                     ((renewTill==null)?"null":renewTill.toDate().toString()));
         }
         boolean skey = readskey();
-        boolean flags[] = readFlags();
+        boolean[] flags = readFlags();
         TicketFlags tFlags = new TicketFlags(flags);
-        HostAddress addr[] = readAddr();
+        HostAddress[] addr = readAddr();
         HostAddresses addrs = null;
         if (addr != null) {
             addrs = new HostAddresses(addr);
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/crc32.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/crc32.java	Thu Jul 09 16:37:55 2015 -0700
@@ -112,7 +112,7 @@
      * This version is more efficient than the byte-at-a-time version;
      * it avoids data copies and reduces per-byte call overhead.
      */
-    protected synchronized void engineUpdate(byte input[], int offset,
+    protected synchronized void engineUpdate(byte[] input, int offset,
                                              int len) {
         processData(input, offset, len);
     }
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/ssl/KerberosPreMasterSecret.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/ssl/KerberosPreMasterSecret.java	Thu Jul 09 16:37:55 2015 -0700
@@ -53,8 +53,8 @@
 final class KerberosPreMasterSecret {
 
     private ProtocolVersion protocolVersion; // preMaster [0,1]
-    private byte preMaster[];           // 48 bytes
-    private byte encrypted[];
+    private byte[] preMaster;           // 48 bytes
+    private byte[] encrypted;
 
     /**
      * Constructor used by client to generate premaster secret.
--- a/jdk/src/java.security.sasl/share/classes/com/sun/security/sasl/ClientFactoryImpl.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.security.sasl/share/classes/com/sun/security/sasl/ClientFactoryImpl.java	Thu Jul 09 16:37:55 2015 -0700
@@ -47,13 +47,13 @@
   * @author Rosanna Lee
   */
 final public class ClientFactoryImpl implements SaslClientFactory {
-    private static final String myMechs[] = {
+    private static final String[] myMechs = {
         "EXTERNAL",
         "CRAM-MD5",
         "PLAIN",
     };
 
-    private static final int mechPolicies[] = {
+    private static final int[] mechPolicies = {
         // %%% RL: Policies should actually depend on the external channel
         PolicyUtils.NOPLAINTEXT|PolicyUtils.NOACTIVE|PolicyUtils.NODICTIONARY,
         PolicyUtils.NOPLAINTEXT|PolicyUtils.NOANONYMOUS,    // CRAM-MD5
--- a/jdk/src/java.security.sasl/share/classes/com/sun/security/sasl/CramMD5Server.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.security.sasl/share/classes/com/sun/security/sasl/CramMD5Server.java	Thu Jul 09 16:37:55 2015 -0700
@@ -165,7 +165,7 @@
                 PasswordCallback pcb =
                     new PasswordCallback("CRAM-MD5 password: ", false);
                 cbh.handle(new Callback[]{ncb,pcb});
-                char pwChars[] = pcb.getPassword();
+                char[] pwChars = pcb.getPassword();
                 if (pwChars == null || pwChars.length == 0) {
                     // user has no password; OK to disclose to server
                     aborted = true;
@@ -190,7 +190,7 @@
                 clearPassword();
 
                 // Check whether digest is as expected
-                byte [] expectedDigest = digest.getBytes("UTF8");
+                byte[] expectedDigest = digest.getBytes("UTF8");
                 int digestLen = responseData.length - ulen - 1;
                 if (expectedDigest.length != digestLen) {
                     aborted = true;
--- a/jdk/src/java.security.sasl/share/classes/com/sun/security/sasl/ServerFactoryImpl.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.security.sasl/share/classes/com/sun/security/sasl/ServerFactoryImpl.java	Thu Jul 09 16:37:55 2015 -0700
@@ -41,11 +41,11 @@
   * @author Rosanna Lee
   */
 final public class ServerFactoryImpl implements SaslServerFactory {
-    private static final String myMechs[] = {
+    private static final String[] myMechs = {
         "CRAM-MD5", //
     };
 
-    private static final int mechPolicies[] = {
+    private static final int[] mechPolicies = {
         PolicyUtils.NOPLAINTEXT|PolicyUtils.NOANONYMOUS,      // CRAM-MD5
     };
 
--- a/jdk/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Base.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Base.java	Thu Jul 09 16:37:55 2015 -0700
@@ -272,7 +272,7 @@
      */
 
     /** This array maps the characters to their 6 bit values */
-    private final static char pem_array[] = {
+    private final static char[] pem_array = {
         //       0   1   2   3   4   5   6   7
                 'A','B','C','D','E','F','G','H', // 0
                 'I','J','K','L','M','N','O','P', // 1
@@ -1068,7 +1068,7 @@
                 byte[] hMAC_MD5 = m.doFinal();
 
                 /* First 10 bytes of HMAC_MD5 digest */
-                byte macBuffer[] = new byte[10];
+                byte[] macBuffer = new byte[10];
                 System.arraycopy(hMAC_MD5, 0, macBuffer, 0, 10);
 
                 return macBuffer;
--- a/jdk/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/FactoryImpl.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/FactoryImpl.java	Thu Jul 09 16:37:55 2015 -0700
@@ -44,9 +44,9 @@
 public final class FactoryImpl implements SaslClientFactory,
 SaslServerFactory{
 
-    private static final String myMechs[] = { "DIGEST-MD5" };
+    private static final String[] myMechs = { "DIGEST-MD5" };
     private static final int DIGEST_MD5 = 0;
-    private static final int mechPolicies[] = {
+    private static final int[] mechPolicies = {
         PolicyUtils.NOPLAINTEXT|PolicyUtils.NOANONYMOUS};
 
     /**
--- a/jdk/src/java.security.sasl/share/classes/com/sun/security/sasl/ntlm/FactoryImpl.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/java.security.sasl/share/classes/com/sun/security/sasl/ntlm/FactoryImpl.java	Thu Jul 09 16:37:55 2015 -0700
@@ -43,8 +43,8 @@
 public final class FactoryImpl implements SaslClientFactory,
 SaslServerFactory{
 
-    private static final String myMechs[] = { "NTLM" };
-    private static final int mechPolicies[] = {
+    private static final String[] myMechs = { "NTLM" };
+    private static final int[] mechPolicies = {
             PolicyUtils.NOPLAINTEXT|PolicyUtils.NOANONYMOUS
     };
 
--- a/jdk/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/KeyStore.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/KeyStore.java	Thu Jul 09 16:37:55 2015 -0700
@@ -66,7 +66,7 @@
     class KeyEntry
     {
         private Key privateKey;
-        private X509Certificate certChain[];
+        private X509Certificate[] certChain;
         private String alias;
 
         KeyEntry(Key key, X509Certificate[] chain) {
--- a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11Cipher.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11Cipher.java	Thu Jul 09 16:37:55 2015 -0700
@@ -175,7 +175,7 @@
         this.algorithm = algorithm;
         this.mechanism = mechanism;
 
-        String algoParts[] = algorithm.split("/");
+        String[] algoParts = algorithm.split("/");
 
         if (algoParts[0].startsWith("AES")) {
             blockSize = 16;
--- a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11KeyStore.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11KeyStore.java	Thu Jul 09 16:37:55 2015 -0700
@@ -164,7 +164,7 @@
         private X509Certificate cert = null;
 
         // chain
-        private X509Certificate chain[] = null;
+        private X509Certificate[] chain = null;
 
         // true if CKA_ID for private key and cert match up
         private boolean matched = false;
--- a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_AES_CTR_PARAMS.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_AES_CTR_PARAMS.java	Thu Jul 09 16:37:55 2015 -0700
@@ -42,7 +42,7 @@
 public class CK_AES_CTR_PARAMS {
 
     private final long ulCounterBits;
-    private final byte cb[];
+    private final byte[] cb;
 
     public CK_AES_CTR_PARAMS(byte[] cb) {
         ulCounterBits = 128;
--- a/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/UcryptoException.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/UcryptoException.java	Thu Jul 09 16:37:55 2015 -0700
@@ -40,7 +40,7 @@
     private static final long serialVersionUID = -933864511110035746L;
 
     // NOTE: check /usr/include/sys/crypto/common.h for updates
-    private static final String ERROR_MSG[] = {
+    private static final String[] ERROR_MSG = {
         "CRYPTO_SUCCESS",
         "CRYPTO_CANCEL",
         "CRYPTO_HOST_MEMORY",
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/NoInterruptUnixTerminal.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline;
+
+// Based on Apache Karaf impl
+
+/**
+ * Non-interruptible (via CTRL-C) {@link UnixTerminal}.
+ *
+ * @since 2.0
+ */
+public class NoInterruptUnixTerminal
+    extends UnixTerminal
+{
+    public NoInterruptUnixTerminal() throws Exception {
+        super();
+    }
+
+    @Override
+    public void init() throws Exception {
+        super.init();
+        getSettings().set("intr undef");
+    }
+
+    @Override
+    public void restore() throws Exception {
+        getSettings().set("intr ^C");
+        super.restore();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/Terminal.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Representation of the input terminal for a platform.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.0
+ */
+public interface Terminal
+{
+    void init() throws Exception;
+
+    void restore() throws Exception;
+
+    void reset() throws Exception;
+
+    boolean isSupported();
+
+    int getWidth();
+
+    int getHeight();
+
+    boolean isAnsiSupported();
+
+    /**
+     * When ANSI is not natively handled, the output will have to be wrapped.
+     */
+    OutputStream wrapOutIfNeeded(OutputStream out);
+
+    /**
+     * When using native support, return the InputStream to use for reading characters
+     * else return the input stream passed as a parameter.
+     *
+     * @since 2.6
+     */
+    InputStream wrapInIfNeeded(InputStream in) throws IOException;
+
+    /**
+     * For terminals that don't wrap when character is written in last column,
+     * only when the next character is written.
+     * These are the ones that have 'am' and 'xn' termcap attributes (xterm and
+     * rxvt flavors falls under that category)
+     */
+    boolean hasWeirdWrap();
+
+    boolean isEchoEnabled();
+
+    void setEchoEnabled(boolean enabled);
+
+    String getOutputEncoding();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/TerminalFactory.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline;
+
+import java.text.MessageFormat;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Callable;
+
+import jdk.internal.jline.internal.Configuration;
+import jdk.internal.jline.internal.Log;
+import jdk.internal.jline.internal.Preconditions;
+import static jdk.internal.jline.internal.Preconditions.checkNotNull;
+
+/**
+ * Creates terminal instances.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.0
+ */
+public class TerminalFactory
+{
+    public static final String JLINE_TERMINAL = "jline.terminal";
+
+    public static final String AUTO = "auto";
+
+    public static final String UNIX = "unix";
+
+    public static final String WIN = "win";
+
+    public static final String WINDOWS = "windows";
+
+    public static final String NONE = "none";
+
+    public static final String OFF = "off";
+
+    public static final String FALSE = "false";
+
+    private static Terminal term = null;
+
+    public static synchronized Terminal create() {
+        if (Log.TRACE) {
+            //noinspection ThrowableInstanceNeverThrown
+            Log.trace(new Throwable("CREATE MARKER"));
+        }
+
+        String type = Configuration.getString(JLINE_TERMINAL, AUTO);
+        if ("dumb".equals(System.getenv("TERM"))) {
+            type = "none";
+            Log.debug("$TERM=dumb; setting type=", type);
+        }
+
+        Log.debug("Creating terminal; type=", type);
+
+        Terminal t;
+        try {
+            String tmp = type.toLowerCase();
+
+            if (tmp.equals(UNIX)) {
+                t = getFlavor(Flavor.UNIX);
+            }
+            else if (tmp.equals(WIN) | tmp.equals(WINDOWS)) {
+                t = getFlavor(Flavor.WINDOWS);
+            }
+            else if (tmp.equals(NONE) || tmp.equals(OFF) || tmp.equals(FALSE)) {
+                t = new UnsupportedTerminal();
+            }
+            else {
+                if (tmp.equals(AUTO)) {
+                    String os = Configuration.getOsName();
+                    Flavor flavor = Flavor.UNIX;
+                    if (os.contains(WINDOWS)) {
+                        flavor = Flavor.WINDOWS;
+                    }
+                    t = getFlavor(flavor);
+                }
+                else {
+                    try {
+                        t = (Terminal) Thread.currentThread().getContextClassLoader().loadClass(type).newInstance();
+                    }
+                    catch (Exception e) {
+                        throw new IllegalArgumentException(MessageFormat.format("Invalid terminal type: {0}", type), e);
+                    }
+                }
+            }
+        }
+        catch (Exception e) {
+            Log.error("Failed to construct terminal; falling back to unsupported", e);
+            t = new UnsupportedTerminal();
+        }
+
+        Log.debug("Created Terminal: ", t);
+
+        try {
+            t.init();
+        }
+        catch (Throwable e) {
+            Log.error("Terminal initialization failed; falling back to unsupported", e);
+            return new UnsupportedTerminal();
+        }
+
+        return t;
+    }
+
+    public static synchronized void reset() {
+        term = null;
+    }
+
+    public static synchronized void resetIf(final Terminal t) {
+        if(t == term) {
+            reset();
+        }
+    }
+
+    public static enum Type
+    {
+        AUTO,
+        WINDOWS,
+        UNIX,
+        NONE
+    }
+
+    public static synchronized void configure(final String type) {
+        checkNotNull(type);
+        System.setProperty(JLINE_TERMINAL, type);
+    }
+
+    public static synchronized void configure(final Type type) {
+        checkNotNull(type);
+        configure(type.name().toLowerCase());
+    }
+
+    //
+    // Flavor Support
+    //
+
+    public static enum Flavor
+    {
+        WINDOWS,
+        UNIX
+    }
+
+    private static final Map<Flavor, Callable<? extends Terminal>> FLAVORS = new HashMap<>();
+
+    static {
+//        registerFlavor(Flavor.WINDOWS, AnsiWindowsTerminal.class);
+//        registerFlavor(Flavor.UNIX, UnixTerminal.class);
+        registerFlavor(Flavor.WINDOWS, WindowsTerminal :: new);
+        registerFlavor(Flavor.UNIX, UnixTerminal :: new);
+    }
+
+    public static synchronized Terminal get() {
+        if (term == null) {
+            term = create();
+        }
+        return term;
+    }
+
+    public static Terminal getFlavor(final Flavor flavor) throws Exception {
+        return FLAVORS.getOrDefault(flavor, () -> {throw new InternalError();}).call();
+    }
+
+    public static void registerFlavor(final Flavor flavor, final Callable<? extends Terminal> sup) {
+        FLAVORS.put(flavor, sup);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/TerminalSupport.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import jdk.internal.jline.internal.Log;
+import jdk.internal.jline.internal.ShutdownHooks;
+import jdk.internal.jline.internal.ShutdownHooks.Task;
+
+/**
+ * Provides support for {@link Terminal} instances.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.0
+ */
+public abstract class TerminalSupport
+    implements Terminal
+{
+    public static final int DEFAULT_WIDTH = 80;
+
+    public static final int DEFAULT_HEIGHT = 24;
+
+    private Task shutdownTask;
+
+    private boolean supported;
+
+    private boolean echoEnabled;
+
+    private boolean ansiSupported;
+
+    protected TerminalSupport(final boolean supported) {
+        this.supported = supported;
+    }
+
+    public void init() throws Exception {
+        if (shutdownTask != null) {
+            ShutdownHooks.remove(shutdownTask);
+        }
+        // Register a task to restore the terminal on shutdown
+        this.shutdownTask = ShutdownHooks.add(new Task()
+        {
+            public void run() throws Exception {
+                restore();
+            }
+        });
+    }
+
+    public void restore() throws Exception {
+        TerminalFactory.resetIf(this);
+        if (shutdownTask != null) {
+          ShutdownHooks.remove(shutdownTask);
+          shutdownTask = null;
+        }
+    }
+
+    public void reset() throws Exception {
+        restore();
+        init();
+    }
+
+    public final boolean isSupported() {
+        return supported;
+    }
+
+    public synchronized boolean isAnsiSupported() {
+        return ansiSupported;
+    }
+
+    protected synchronized void setAnsiSupported(final boolean supported) {
+        this.ansiSupported = supported;
+        Log.debug("Ansi supported: ", supported);
+    }
+
+    /**
+     * Subclass to change behavior if needed.
+     * @return the passed out
+     */
+    public OutputStream wrapOutIfNeeded(OutputStream out) {
+        return out;
+    }
+
+    /**
+     * Defaults to true which was the behaviour before this method was added.
+     */
+    public boolean hasWeirdWrap() {
+        return true;
+    }
+
+    public int getWidth() {
+        return DEFAULT_WIDTH;
+    }
+
+    public int getHeight() {
+        return DEFAULT_HEIGHT;
+    }
+
+    public synchronized boolean isEchoEnabled() {
+        return echoEnabled;
+    }
+
+    public synchronized void setEchoEnabled(final boolean enabled) {
+        this.echoEnabled = enabled;
+        Log.debug("Echo enabled: ", enabled);
+    }
+
+    public InputStream wrapInIfNeeded(InputStream in) throws IOException {
+        return in;
+    }
+
+    public String getOutputEncoding() {
+        // null for unknown
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/UnixTerminal.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline;
+
+import jdk.internal.jline.internal.Log;
+import jdk.internal.jline.internal.TerminalLineSettings;
+
+/**
+ * Terminal that is used for unix platforms. Terminal initialization
+ * is handled by issuing the <em>stty</em> command against the
+ * <em>/dev/tty</em> file to disable character echoing and enable
+ * character input. All known unix systems (including
+ * Linux and Macintosh OS X) support the <em>stty</em>), so this
+ * implementation should work for an reasonable POSIX system.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:dwkemp@gmail.com">Dale Kemp</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @author <a href="mailto:jbonofre@apache.org">Jean-Baptiste Onofr\u00E9</a>
+ * @since 2.0
+ */
+public class UnixTerminal
+    extends TerminalSupport
+{
+    private final TerminalLineSettings settings = new TerminalLineSettings();
+
+    public UnixTerminal() throws Exception {
+        super(true);
+    }
+
+    protected TerminalLineSettings getSettings() {
+        return settings;
+    }
+
+    /**
+     * Remove line-buffered input by invoking "stty -icanon min 1"
+     * against the current terminal.
+     */
+    @Override
+    public void init() throws Exception {
+        super.init();
+
+        setAnsiSupported(true);
+
+        // Set the console to be character-buffered instead of line-buffered.
+        // Make sure we're distinguishing carriage return from newline.
+        // Allow ctrl-s keypress to be used (as forward search)
+        settings.set("-icanon min 1 -icrnl -inlcr -ixon");
+        settings.set("dsusp undef");
+
+        setEchoEnabled(false);
+    }
+
+    /**
+     * Restore the original terminal configuration, which can be used when
+     * shutting down the console reader. The ConsoleReader cannot be
+     * used after calling this method.
+     */
+    @Override
+    public void restore() throws Exception {
+        settings.restore();
+        super.restore();
+    }
+
+    /**
+     * Returns the value of <tt>stty columns</tt> param.
+     */
+    @Override
+    public int getWidth() {
+        int w = settings.getProperty("columns");
+        return w < 1 ? DEFAULT_WIDTH : w;
+    }
+
+    /**
+     * Returns the value of <tt>stty rows>/tt> param.
+     */
+    @Override
+    public int getHeight() {
+        int h = settings.getProperty("rows");
+        return h < 1 ? DEFAULT_HEIGHT : h;
+    }
+
+    @Override
+    public synchronized void setEchoEnabled(final boolean enabled) {
+        try {
+            if (enabled) {
+                settings.set("echo");
+            }
+            else {
+                settings.set("-echo");
+            }
+            super.setEchoEnabled(enabled);
+        }
+        catch (Exception e) {
+            if (e instanceof InterruptedException) {
+                Thread.currentThread().interrupt();
+            }
+            Log.error("Failed to ", (enabled ? "enable" : "disable"), " echo", e);
+        }
+    }
+
+    public void disableInterruptCharacter()
+    {
+        try {
+            settings.set("intr undef");
+        }
+        catch (Exception e) {
+            if (e instanceof InterruptedException) {
+                Thread.currentThread().interrupt();
+            }
+            Log.error("Failed to disable interrupt character", e);
+        }
+    }
+
+    public void enableInterruptCharacter()
+    {
+        try {
+            settings.set("intr ^C");
+        }
+        catch (Exception e) {
+            if (e instanceof InterruptedException) {
+                Thread.currentThread().interrupt();
+            }
+            Log.error("Failed to enable interrupt character", e);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/UnsupportedTerminal.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline;
+
+/**
+ * An unsupported terminal.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.0
+ */
+public class UnsupportedTerminal
+    extends TerminalSupport
+{
+    public UnsupportedTerminal() {
+        super(false);
+        setAnsiSupported(false);
+        setEchoEnabled(true);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/WindowsTerminal.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,546 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline;
+
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import jdk.internal.jline.internal.Configuration;
+import jdk.internal.jline.internal.Log;
+//import org.fusesource.jansi.internal.WindowsSupport;
+//import org.fusesource.jansi.internal.Kernel32;
+//import static org.fusesource.jansi.internal.Kernel32.*;
+
+import static jdk.internal.jline.WindowsTerminal.ConsoleMode.ENABLE_ECHO_INPUT;
+import static jdk.internal.jline.WindowsTerminal.ConsoleMode.ENABLE_LINE_INPUT;
+import static jdk.internal.jline.WindowsTerminal.ConsoleMode.ENABLE_PROCESSED_INPUT;
+import static jdk.internal.jline.WindowsTerminal.ConsoleMode.ENABLE_WINDOW_INPUT;
+
+/**
+ * Terminal implementation for Microsoft Windows. Terminal initialization in
+ * {@link #init} is accomplished by extracting the
+ * <em>jline_<i>version</i>.dll</em>, saving it to the system temporary
+ * directoy (determined by the setting of the <em>java.io.tmpdir</em> System
+ * property), loading the library, and then calling the Win32 APIs <a
+ * href="http://msdn.microsoft.com/library/default.asp?
+ * url=/library/en-us/dllproc/base/setconsolemode.asp">SetConsoleMode</a> and
+ * <a href="http://msdn.microsoft.com/library/default.asp?
+ * url=/library/en-us/dllproc/base/getconsolemode.asp">GetConsoleMode</a> to
+ * disable character echoing.
+ * <p/>
+ * <p>
+ * By default, the {@link #wrapInIfNeeded(java.io.InputStream)} method will attempt
+ * to test to see if the specified {@link InputStream} is {@link System#in} or a wrapper
+ * around {@link FileDescriptor#in}, and if so, will bypass the character reading to
+ * directly invoke the readc() method in the JNI library. This is so the class
+ * can read special keys (like arrow keys) which are otherwise inaccessible via
+ * the {@link System#in} stream. Using JNI reading can be bypassed by setting
+ * the <code>jline.WindowsTerminal.directConsole</code> system property
+ * to <code>false</code>.
+ * </p>
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.0
+ */
+public class WindowsTerminal
+    extends TerminalSupport
+{
+    public static final String DIRECT_CONSOLE = WindowsTerminal.class.getName() + ".directConsole";
+
+    public static final String ANSI = WindowsTerminal.class.getName() + ".ansi";
+
+    private boolean directConsole;
+
+    private int originalMode;
+
+    public WindowsTerminal() throws Exception {
+        super(true);
+    }
+
+    @Override
+    public void init() throws Exception {
+        super.init();
+
+//        setAnsiSupported(Configuration.getBoolean(ANSI, true));
+        setAnsiSupported(false);
+
+        //
+        // FIXME: Need a way to disable direct console and sysin detection muck
+        //
+
+        setDirectConsole(Configuration.getBoolean(DIRECT_CONSOLE, true));
+
+        this.originalMode = getConsoleMode();
+        setConsoleMode(originalMode & ~ENABLE_ECHO_INPUT.code);
+        setEchoEnabled(false);
+    }
+
+    /**
+     * Restore the original terminal configuration, which can be used when
+     * shutting down the console reader. The ConsoleReader cannot be
+     * used after calling this method.
+     */
+    @Override
+    public void restore() throws Exception {
+        // restore the old console mode
+        setConsoleMode(originalMode);
+        super.restore();
+    }
+
+    @Override
+    public int getWidth() {
+        int w = getWindowsTerminalWidth();
+        return w < 1 ? DEFAULT_WIDTH : w;
+    }
+
+    @Override
+    public int getHeight() {
+        int h = getWindowsTerminalHeight();
+        return h < 1 ? DEFAULT_HEIGHT : h;
+    }
+
+    @Override
+    public void setEchoEnabled(final boolean enabled) {
+        // Must set these four modes at the same time to make it work fine.
+        if (enabled) {
+            setConsoleMode(getConsoleMode() |
+                ENABLE_ECHO_INPUT.code |
+                ENABLE_LINE_INPUT.code |
+                ENABLE_PROCESSED_INPUT.code |
+                ENABLE_WINDOW_INPUT.code);
+        }
+        else {
+            setConsoleMode(getConsoleMode() &
+                ~(ENABLE_LINE_INPUT.code |
+                    ENABLE_ECHO_INPUT.code |
+                    ENABLE_PROCESSED_INPUT.code |
+                    ENABLE_WINDOW_INPUT.code));
+        }
+        super.setEchoEnabled(enabled);
+    }
+
+    /**
+     * Whether or not to allow the use of the JNI console interaction.
+     */
+    public void setDirectConsole(final boolean flag) {
+        this.directConsole = flag;
+        Log.debug("Direct console: ", flag);
+    }
+
+    /**
+     * Whether or not to allow the use of the JNI console interaction.
+     */
+    public Boolean getDirectConsole() {
+        return directConsole;
+    }
+
+
+    @Override
+    public InputStream wrapInIfNeeded(InputStream in) throws IOException {
+        if (directConsole && isSystemIn(in)) {
+            return new InputStream() {
+                private byte[] buf = null;
+                int bufIdx = 0;
+
+                @Override
+                public int read() throws IOException {
+                    while (buf == null || bufIdx == buf.length) {
+                        buf = readConsoleInput();
+                        bufIdx = 0;
+                    }
+                    int c = buf[bufIdx] & 0xFF;
+                    bufIdx++;
+                    return c;
+                }
+            };
+        } else {
+            return super.wrapInIfNeeded(in);
+        }
+    }
+
+    protected boolean isSystemIn(final InputStream in) throws IOException {
+        if (in == null) {
+            return false;
+        }
+        else if (in == System.in) {
+            return true;
+        }
+        else if (in instanceof FileInputStream && ((FileInputStream) in).getFD() == FileDescriptor.in) {
+            return true;
+        }
+
+        return false;
+    }
+
+    @Override
+    public String getOutputEncoding() {
+        int codepage = getConsoleOutputCodepage();
+        //http://docs.oracle.com/javase/6/docs/technotes/guides/intl/encoding.doc.html
+        String charsetMS = "ms" + codepage;
+        if (java.nio.charset.Charset.isSupported(charsetMS)) {
+            return charsetMS;
+        }
+        String charsetCP = "cp" + codepage;
+        if (java.nio.charset.Charset.isSupported(charsetCP)) {
+            return charsetCP;
+        }
+        Log.debug("can't figure out the Java Charset of this code page (" + codepage + ")...");
+        return super.getOutputEncoding();
+    }
+
+    //
+    // Original code:
+    //
+//    private int getConsoleMode() {
+//        return WindowsSupport.getConsoleMode();
+//    }
+//
+//    private void setConsoleMode(int mode) {
+//        WindowsSupport.setConsoleMode(mode);
+//    }
+//
+//    private byte[] readConsoleInput() {
+//        // XXX does how many events to read in one call matter?
+//        INPUT_RECORD[] events = null;
+//        try {
+//            events = WindowsSupport.readConsoleInput(1);
+//        } catch (IOException e) {
+//            Log.debug("read Windows console input error: ", e);
+//        }
+//        if (events == null) {
+//            return new byte[0];
+//        }
+//        StringBuilder sb = new StringBuilder();
+//        for (int i = 0; i < events.length; i++ ) {
+//            KEY_EVENT_RECORD keyEvent = events[i].keyEvent;
+//            //Log.trace(keyEvent.keyDown? "KEY_DOWN" : "KEY_UP", "key code:", keyEvent.keyCode, "char:", (long)keyEvent.uchar);
+//            if (keyEvent.keyDown) {
+//                if (keyEvent.uchar > 0) {
+//                    // support some C1 control sequences: ALT + [@-_] (and [a-z]?) => ESC <ascii>
+//                    // http://en.wikipedia.org/wiki/C0_and_C1_control_codes#C1_set
+//                    final int altState = KEY_EVENT_RECORD.LEFT_ALT_PRESSED | KEY_EVENT_RECORD.RIGHT_ALT_PRESSED;
+//                    // Pressing "Alt Gr" is translated to Alt-Ctrl, hence it has to be checked that Ctrl is _not_ pressed,
+//                    // otherwise inserting of "Alt Gr" codes on non-US keyboards would yield errors
+//                    final int ctrlState = KEY_EVENT_RECORD.LEFT_CTRL_PRESSED | KEY_EVENT_RECORD.RIGHT_CTRL_PRESSED;
+//                    if (((keyEvent.uchar >= '@' && keyEvent.uchar <= '_') || (keyEvent.uchar >= 'a' && keyEvent.uchar <= 'z'))
+//                        && ((keyEvent.controlKeyState & altState) != 0) && ((keyEvent.controlKeyState & ctrlState) == 0)) {
+//                        sb.append('\u001B'); // ESC
+//                    }
+//
+//                    sb.append(keyEvent.uchar);
+//                    continue;
+//                }
+//                // virtual keycodes: http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
+//                // just add support for basic editing keys (no control state, no numpad keys)
+//                String escapeSequence = null;
+//                switch (keyEvent.keyCode) {
+//                case 0x21: // VK_PRIOR PageUp
+//                    escapeSequence = "\u001B[5~";
+//                    break;
+//                case 0x22: // VK_NEXT PageDown
+//                    escapeSequence = "\u001B[6~";
+//                    break;
+//                case 0x23: // VK_END
+//                    escapeSequence = "\u001B[4~";
+//                    break;
+//                case 0x24: // VK_HOME
+//                    escapeSequence = "\u001B[1~";
+//                    break;
+//                case 0x25: // VK_LEFT
+//                    escapeSequence = "\u001B[D";
+//                    break;
+//                case 0x26: // VK_UP
+//                    escapeSequence = "\u001B[A";
+//                    break;
+//                case 0x27: // VK_RIGHT
+//                    escapeSequence = "\u001B[C";
+//                    break;
+//                case 0x28: // VK_DOWN
+//                    escapeSequence = "\u001B[B";
+//                    break;
+//                case 0x2D: // VK_INSERT
+//                    escapeSequence = "\u001B[2~";
+//                    break;
+//                case 0x2E: // VK_DELETE
+//                    escapeSequence = "\u001B[3~";
+//                    break;
+//                default:
+//                    break;
+//                }
+//                if (escapeSequence != null) {
+//                    for (int k = 0; k < keyEvent.repeatCount; k++) {
+//                        sb.append(escapeSequence);
+//                    }
+//                }
+//            } else {
+//                // key up event
+//                // support ALT+NumPad input method
+//                if (keyEvent.keyCode == 0x12/*VK_MENU ALT key*/ && keyEvent.uchar > 0) {
+//                    sb.append(keyEvent.uchar);
+//                }
+//            }
+//        }
+//        return sb.toString().getBytes();
+//    }
+//
+//    private int getConsoleOutputCodepage() {
+//        return Kernel32.GetConsoleOutputCP();
+//    }
+//
+//    private int getWindowsTerminalWidth() {
+//        return WindowsSupport.getWindowsTerminalWidth();
+//    }
+//
+//    private int getWindowsTerminalHeight() {
+//        return WindowsSupport.getWindowsTerminalHeight();
+//    }
+
+    //
+    // Native Bits
+    //
+    static {
+        System.loadLibrary("le");
+        initIDs();
+    }
+
+    private static native void initIDs();
+
+    private native int getConsoleMode();
+
+    private native void setConsoleMode(int mode);
+
+    private byte[] readConsoleInput() {
+        KEY_EVENT_RECORD keyEvent = readKeyEvent();
+
+        return convertKeys(keyEvent).getBytes();
+    }
+
+    public static String convertKeys(KEY_EVENT_RECORD keyEvent) {
+        if (keyEvent == null) {
+            return "";
+        }
+
+        StringBuilder sb = new StringBuilder();
+
+        if (keyEvent.keyDown) {
+            if (keyEvent.uchar > 0) {
+                // support some C1 control sequences: ALT + [@-_] (and [a-z]?) => ESC <ascii>
+                // http://en.wikipedia.org/wiki/C0_and_C1_control_codes#C1_set
+                final int altState = KEY_EVENT_RECORD.ALT_PRESSED;
+                // Pressing "Alt Gr" is translated to Alt-Ctrl, hence it has to be checked that Ctrl is _not_ pressed,
+                // otherwise inserting of "Alt Gr" codes on non-US keyboards would yield errors
+                final int ctrlState = KEY_EVENT_RECORD.CTRL_PRESSED;
+
+                boolean handled = false;
+
+                if ((keyEvent.controlKeyState & ctrlState) != 0) {
+                    switch (keyEvent.keyCode) {
+                        case 0x43: //Ctrl-C
+                            sb.append("\003");
+                            handled = true;
+                            break;
+                    }
+                }
+
+                if ((keyEvent.controlKeyState & KEY_EVENT_RECORD.SHIFT_PRESSED) != 0) {
+                    switch (keyEvent.keyCode) {
+                        case 0x09: //Shift-Tab
+                            sb.append("\033\133\132");
+                            handled = true;
+                            break;
+                    }
+                }
+
+                if (!handled) {
+                    if (((keyEvent.uchar >= '@' && keyEvent.uchar <= '_') || (keyEvent.uchar >= 'a' && keyEvent.uchar <= 'z'))
+                        && ((keyEvent.controlKeyState & altState) != 0) && ((keyEvent.controlKeyState & ctrlState) == 0)) {
+                        sb.append('\u001B'); // ESC
+                    }
+
+                    sb.append(keyEvent.uchar);
+                }
+            } else {
+                // virtual keycodes: http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
+                // just add support for basic editing keys (no control state, no numpad keys)
+                String escapeSequence = null;
+                switch (keyEvent.keyCode) {
+                case 0x21: // VK_PRIOR PageUp
+                    escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[5~", "\u001B[5;%d~");
+                    break;
+                case 0x22: // VK_NEXT PageDown
+                    escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[6~", "\u001B[6;%d~");
+                    break;
+                case 0x23: // VK_END
+                    escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[4~", "\u001B[4;%d~");
+                    break;
+                case 0x24: // VK_HOME
+                    escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[1~", "\u001B[1;%d~");
+                    break;
+                case 0x25: // VK_LEFT
+                    escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[D", "\u001B[1;%dD");
+                    break;
+                case 0x26: // VK_UP
+                    escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[A", "\u001B[1;%dA");
+                    break;
+                case 0x27: // VK_RIGHT
+                    escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[C", "\u001B[1;%dC");
+                    break;
+                case 0x28: // VK_DOWN
+                    escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[B", "\u001B[1;%dB");
+                    break;
+                case 0x2D: // VK_INSERT
+                    escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[2~", "\u001B[2;%d~");
+                    break;
+                case 0x2E: // VK_DELETE
+                    escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[3~", "\u001B[3;%d~");
+                    break;
+                default:
+                    break;
+                }
+                if (escapeSequence != null) {
+                    for (int k = 0; k < keyEvent.repeatCount; k++) {
+                        sb.append(escapeSequence);
+                    }
+                }
+            }
+        } else {
+            // key up event
+            // support ALT+NumPad input method
+            if (keyEvent.keyCode == 0x12/*VK_MENU ALT key*/ && keyEvent.uchar > 0) {
+                sb.append(keyEvent.uchar);
+            }
+        }
+        return sb.toString();
+    }
+
+    private static String escapeSequence(int controlKeyState, String noControlSequence, String withControlSequence) {
+        int controlNum = 1;
+
+        if ((controlKeyState & KEY_EVENT_RECORD.SHIFT_PRESSED) != 0) {
+            controlNum += 1;
+        }
+
+        if ((controlKeyState & KEY_EVENT_RECORD.ALT_PRESSED) != 0) {
+            controlNum += 2;
+        }
+
+        if ((controlKeyState & KEY_EVENT_RECORD.CTRL_PRESSED) != 0) {
+            controlNum += 4;
+        }
+
+        if (controlNum > 1) {
+            return String.format(withControlSequence, controlNum);
+        } else {
+            return noControlSequence;
+        }
+    }
+
+    private native KEY_EVENT_RECORD readKeyEvent();
+
+    public static class KEY_EVENT_RECORD {
+        public final static int ALT_PRESSED = 0x3;
+        public final static int CTRL_PRESSED = 0xC;
+        public final static int SHIFT_PRESSED = 0x10;
+        public final boolean keyDown;
+        public final char uchar;
+        public final int controlKeyState;
+        public final int keyCode;
+        public final int repeatCount;
+
+        public KEY_EVENT_RECORD(boolean keyDown, char uchar, int controlKeyState, int keyCode, int repeatCount) {
+            this.keyDown = keyDown;
+            this.uchar = uchar;
+            this.controlKeyState = controlKeyState;
+            this.keyCode = keyCode;
+            this.repeatCount = repeatCount;
+        }
+
+    }
+
+    private native int getConsoleOutputCodepage();
+
+    private native int getWindowsTerminalWidth();
+
+    private native int getWindowsTerminalHeight();
+
+    /**
+     * Console mode
+     * <p/>
+     * Constants copied <tt>wincon.h</tt>.
+     */
+    public static enum ConsoleMode
+    {
+        /**
+         * The ReadFile or ReadConsole function returns only when a carriage return
+         * character is read. If this mode is disable, the functions return when one
+         * or more characters are available.
+         */
+        ENABLE_LINE_INPUT(2),
+
+        /**
+         * Characters read by the ReadFile or ReadConsole function are written to
+         * the active screen buffer as they are read. This mode can be used only if
+         * the ENABLE_LINE_INPUT mode is also enabled.
+         */
+        ENABLE_ECHO_INPUT(4),
+
+        /**
+         * CTRL+C is processed by the system and is not placed in the input buffer.
+         * If the input buffer is being read by ReadFile or ReadConsole, other
+         * control keys are processed by the system and are not returned in the
+         * ReadFile or ReadConsole buffer. If the ENABLE_LINE_INPUT mode is also
+         * enabled, backspace, carriage return, and linefeed characters are handled
+         * by the system.
+         */
+        ENABLE_PROCESSED_INPUT(1),
+
+        /**
+         * User interactions that change the size of the console screen buffer are
+         * reported in the console's input buffee. Information about these events
+         * can be read from the input buffer by applications using
+         * theReadConsoleInput function, but not by those using ReadFile
+         * orReadConsole.
+         */
+        ENABLE_WINDOW_INPUT(8),
+
+        /**
+         * If the mouse pointer is within the borders of the console window and the
+         * window has the keyboard focus, mouse events generated by mouse movement
+         * and button presses are placed in the input buffer. These events are
+         * discarded by ReadFile or ReadConsole, even when this mode is enabled.
+         */
+        ENABLE_MOUSE_INPUT(16),
+
+        /**
+         * When enabled, text entered in a console window will be inserted at the
+         * current cursor location and all text following that location will not be
+         * overwritten. When disabled, all following text will be overwritten. An OR
+         * operation must be performed with this flag and the ENABLE_EXTENDED_FLAGS
+         * flag to enable this functionality.
+         */
+        ENABLE_PROCESSED_OUTPUT(1),
+
+        /**
+         * This flag enables the user to use the mouse to select and edit text. To
+         * enable this option, use the OR to combine this flag with
+         * ENABLE_EXTENDED_FLAGS.
+         */
+        ENABLE_WRAP_AT_EOL_OUTPUT(2),;
+
+        public final int code;
+
+        ConsoleMode(final int code) {
+            this.code = code;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/ConsoleKeys.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,399 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import jdk.internal.jline.internal.Log;
+
+/**
+ * @author St\u00E5le W. Pedersen <stale.pedersen@jboss.org>
+ */
+public class ConsoleKeys {
+
+    private KeyMap keys;
+
+    private Map<String, KeyMap> keyMaps;
+    private Map<String, String> variables = new HashMap<String,String>();
+
+    public ConsoleKeys(String appName, URL inputrcUrl) {
+        keyMaps = KeyMap.keyMaps();
+        loadKeys(appName, inputrcUrl);
+    }
+
+    protected boolean isViEditMode() {
+        return keys.isViKeyMap();
+    }
+
+    protected boolean setKeyMap (String name) {
+        KeyMap map = keyMaps.get(name);
+        if (map == null) {
+            return false;
+        }
+        this.keys = map;
+        return true;
+    }
+
+    protected Map<String, KeyMap> getKeyMaps() {
+        return keyMaps;
+    }
+
+    protected KeyMap getKeys() {
+        return keys;
+    }
+
+    protected void setKeys(KeyMap keys) {
+        this.keys = keys;
+    }
+
+    protected boolean getViEditMode() {
+        return keys.isViKeyMap ();
+    }
+
+    protected void loadKeys(String appName, URL inputrcUrl) {
+        keys = keyMaps.get(KeyMap.EMACS);
+
+        try {
+            InputStream input = inputrcUrl.openStream();
+            try {
+                loadKeys(input, appName);
+                Log.debug("Loaded user configuration: ", inputrcUrl);
+            }
+            finally {
+                try {
+                    input.close();
+                } catch (IOException e) {
+                    // Ignore
+                }
+            }
+        }
+        catch (IOException e) {
+            if (inputrcUrl.getProtocol().equals("file")) {
+                File file = new File(inputrcUrl.getPath());
+                if (file.exists()) {
+                    Log.warn("Unable to read user configuration: ", inputrcUrl, e);
+                }
+            } else {
+                Log.warn("Unable to read user configuration: ", inputrcUrl, e);
+            }
+        }
+    }
+
+    private void loadKeys(InputStream input, String appName) throws IOException {
+        BufferedReader reader = new BufferedReader( new java.io.InputStreamReader( input ) );
+        String line;
+        boolean parsing = true;
+        List<Boolean> ifsStack = new ArrayList<Boolean>();
+        while ( (line = reader.readLine()) != null ) {
+            try {
+                line = line.trim();
+                if (line.length() == 0) {
+                    continue;
+                }
+                if (line.charAt(0) == '#') {
+                    continue;
+                }
+                int i = 0;
+                if (line.charAt(i) == '$') {
+                    String cmd;
+                    String args;
+                    for (++i; i < line.length() && (line.charAt(i) == ' ' || line.charAt(i) == '\t'); i++);
+                    int s = i;
+                    for (; i < line.length() && (line.charAt(i) != ' ' && line.charAt(i) != '\t'); i++);
+                    cmd = line.substring(s, i);
+                    for (; i < line.length() && (line.charAt(i) == ' ' || line.charAt(i) == '\t'); i++);
+                    s = i;
+                    for (; i < line.length() && (line.charAt(i) != ' ' && line.charAt(i) != '\t'); i++);
+                    args = line.substring(s, i);
+                    if ("if".equalsIgnoreCase(cmd)) {
+                        ifsStack.add( parsing );
+                        if (!parsing) {
+                            continue;
+                        }
+                        if (args.startsWith("term=")) {
+                            // TODO
+                        } else if (args.startsWith("mode=")) {
+                            if (args.equalsIgnoreCase("mode=vi")) {
+                                parsing = isViEditMode();
+                            } else if (args.equals("mode=emacs")) {
+                                parsing = !isViEditMode();
+                            } else {
+                                parsing = false;
+                            }
+                        } else {
+                            parsing = args.equalsIgnoreCase(appName);
+                        }
+                    } else if ("else".equalsIgnoreCase(cmd)) {
+                        if (ifsStack.isEmpty()) {
+                            throw new IllegalArgumentException("$else found without matching $if");
+                        }
+                        boolean invert = true;
+                        for (boolean b : ifsStack) {
+                            if (!b) {
+                                invert = false;
+                                break;
+                            }
+                        }
+                        if (invert) {
+                            parsing = !parsing;
+                        }
+                    } else if ("endif".equalsIgnoreCase(cmd)) {
+                        if (ifsStack.isEmpty()) {
+                            throw new IllegalArgumentException("endif found without matching $if");
+                        }
+                        parsing = ifsStack.remove( ifsStack.size() - 1 );
+                    } else if ("include".equalsIgnoreCase(cmd)) {
+                        // TODO
+                    }
+                    continue;
+                }
+                if (!parsing) {
+                    continue;
+                }
+                boolean equivalency;
+                String keySeq = "";
+                if (line.charAt(i++) == '"') {
+                    boolean esc = false;
+                    for (;; i++) {
+                        if (i >= line.length()) {
+                            throw new IllegalArgumentException("Missing closing quote on line '" + line + "'");
+                        }
+                        if (esc) {
+                            esc = false;
+                        } else if (line.charAt(i) == '\\') {
+                            esc = true;
+                        } else if (line.charAt(i) == '"') {
+                            break;
+                        }
+                    }
+                }
+                for (; i < line.length() && line.charAt(i) != ':'
+                        && line.charAt(i) != ' ' && line.charAt(i) != '\t'
+                        ; i++);
+                keySeq = line.substring(0, i);
+                equivalency = (i + 1 < line.length() && line.charAt(i) == ':' && line.charAt(i + 1) == '=');
+                i++;
+                if (equivalency) {
+                    i++;
+                }
+                if (keySeq.equalsIgnoreCase("set")) {
+                    String key;
+                    String val;
+                    for (; i < line.length() && (line.charAt(i) == ' ' || line.charAt(i) == '\t'); i++);
+                    int s = i;
+                    for (; i < line.length() && (line.charAt(i) != ' ' && line.charAt(i) != '\t'); i++);
+                    key = line.substring( s, i );
+                    for (; i < line.length() && (line.charAt(i) == ' ' || line.charAt(i) == '\t'); i++);
+                    s = i;
+                    for (; i < line.length() && (line.charAt(i) != ' ' && line.charAt(i) != '\t'); i++);
+                    val = line.substring( s, i );
+                    setVar( key, val );
+                } else {
+                    for (; i < line.length() && (line.charAt(i) == ' ' || line.charAt(i) == '\t'); i++);
+                    int start = i;
+                    if (i < line.length() && (line.charAt(i) == '\'' || line.charAt(i) == '\"')) {
+                        char delim = line.charAt(i++);
+                        boolean esc = false;
+                        for (;; i++) {
+                            if (i >= line.length()) {
+                                break;
+                            }
+                            if (esc) {
+                                esc = false;
+                            } else if (line.charAt(i) == '\\') {
+                                esc = true;
+                            } else if (line.charAt(i) == delim) {
+                                break;
+                            }
+                        }
+                    }
+                    for (; i < line.length() && line.charAt(i) != ' ' && line.charAt(i) != '\t'; i++);
+                    String val = line.substring(Math.min(start, line.length()), Math.min(i, line.length()));
+                    if (keySeq.charAt(0) == '"') {
+                        keySeq = translateQuoted(keySeq);
+                    } else {
+                        // Bind key name
+                        String keyName = keySeq.lastIndexOf('-') > 0 ? keySeq.substring( keySeq.lastIndexOf('-') + 1 ) : keySeq;
+                        char key = getKeyFromName(keyName);
+                        keyName = keySeq.toLowerCase();
+                        keySeq = "";
+                        if (keyName.contains("meta-") || keyName.contains("m-")) {
+                            keySeq += "\u001b";
+                        }
+                        if (keyName.contains("control-") || keyName.contains("c-") || keyName.contains("ctrl-")) {
+                            key = (char)(Character.toUpperCase( key ) & 0x1f);
+                        }
+                        keySeq += key;
+                    }
+                    if (val.length() > 0 && (val.charAt(0) == '\'' || val.charAt(0) == '\"')) {
+                        keys.bind( keySeq, translateQuoted(val) );
+                    } else {
+                        String operationName = val.replace('-', '_').toUpperCase();
+                        try {
+                          keys.bind(keySeq, Operation.valueOf(operationName));
+                        } catch(IllegalArgumentException e) {
+                          Log.info("Unable to bind key for unsupported operation: ", val);
+                        }
+                    }
+                }
+            } catch (IllegalArgumentException e) {
+              Log.warn("Unable to parse user configuration: ", e);
+            }
+        }
+    }
+
+    private String translateQuoted(String keySeq) {
+        int i;
+        String str = keySeq.substring( 1, keySeq.length() - 1 );
+        keySeq = "";
+        for (i = 0; i < str.length(); i++) {
+            char c = str.charAt(i);
+            if (c == '\\') {
+                boolean ctrl = str.regionMatches(i, "\\C-", 0, 3)|| str.regionMatches(i, "\\M-\\C-", 0, 6);
+                boolean meta = str.regionMatches(i, "\\M-", 0, 3)|| str.regionMatches(i, "\\C-\\M-", 0, 6);
+                i += (meta ? 3 : 0) + (ctrl ? 3 : 0) + (!meta && !ctrl ? 1 : 0);
+                if (i >= str.length()) {
+                    break;
+                }
+                c = str.charAt(i);
+                if (meta) {
+                    keySeq += "\u001b";
+                }
+                if (ctrl) {
+                    c = c == '?' ? 0x7f : (char)(Character.toUpperCase( c ) & 0x1f);
+                }
+                if (!meta && !ctrl) {
+                    switch (c) {
+                        case 'a': c = 0x07; break;
+                        case 'b': c = '\b'; break;
+                        case 'd': c = 0x7f; break;
+                        case 'e': c = 0x1b; break;
+                        case 'f': c = '\f'; break;
+                        case 'n': c = '\n'; break;
+                        case 'r': c = '\r'; break;
+                        case 't': c = '\t'; break;
+                        case 'v': c = 0x0b; break;
+                        case '\\': c = '\\'; break;
+                        case '0': case '1': case '2': case '3':
+                        case '4': case '5': case '6': case '7':
+                            c = 0;
+                            for (int j = 0; j < 3; j++, i++) {
+                                if (i >= str.length()) {
+                                    break;
+                                }
+                                int k = Character.digit(str.charAt(i), 8);
+                                if (k < 0) {
+                                    break;
+                                }
+                                c = (char)(c * 8 + k);
+                            }
+                            c &= 0xFF;
+                            break;
+                        case 'x':
+                            i++;
+                            c = 0;
+                            for (int j = 0; j < 2; j++, i++) {
+                                if (i >= str.length()) {
+                                    break;
+                                }
+                                int k = Character.digit(str.charAt(i), 16);
+                                if (k < 0) {
+                                    break;
+                                }
+                                c = (char)(c * 16 + k);
+                            }
+                            c &= 0xFF;
+                            break;
+                        case 'u':
+                            i++;
+                            c = 0;
+                            for (int j = 0; j < 4; j++, i++) {
+                                if (i >= str.length()) {
+                                    break;
+                                }
+                                int k = Character.digit(str.charAt(i), 16);
+                                if (k < 0) {
+                                    break;
+                                }
+                                c = (char)(c * 16 + k);
+                            }
+                            break;
+                    }
+                }
+                keySeq += c;
+            } else {
+                keySeq += c;
+            }
+        }
+        return keySeq;
+    }
+
+    private char getKeyFromName(String name) {
+        if ("DEL".equalsIgnoreCase(name) || "Rubout".equalsIgnoreCase(name)) {
+            return 0x7f;
+        } else if ("ESC".equalsIgnoreCase(name) || "Escape".equalsIgnoreCase(name)) {
+            return '\033';
+        } else if ("LFD".equalsIgnoreCase(name) || "NewLine".equalsIgnoreCase(name)) {
+            return '\n';
+        } else if ("RET".equalsIgnoreCase(name) || "Return".equalsIgnoreCase(name)) {
+            return '\r';
+        } else if ("SPC".equalsIgnoreCase(name) || "Space".equalsIgnoreCase(name)) {
+            return ' ';
+        } else if ("Tab".equalsIgnoreCase(name)) {
+            return '\t';
+        } else {
+            return name.charAt(0);
+        }
+    }
+
+    private void setVar(String key, String val) {
+        if ("keymap".equalsIgnoreCase(key)) {
+            if (keyMaps.containsKey(val)) {
+                keys = keyMaps.get(val);
+            }
+        } else if ("editing-mode".equals(key)) {
+            if ("vi".equalsIgnoreCase(val)) {
+                keys = keyMaps.get(KeyMap.VI_INSERT);
+            } else if ("emacs".equalsIgnoreCase(key)) {
+                keys = keyMaps.get(KeyMap.EMACS);
+            }
+        } else if ("blink-matching-paren".equals(key)) {
+            if ("on".equalsIgnoreCase(val)) {
+              keys.setBlinkMatchingParen(true);
+            } else if ("off".equalsIgnoreCase(val)) {
+              keys.setBlinkMatchingParen(false);
+            }
+        }
+
+        /*
+         * Technically variables should be defined as a functor class
+         * so that validation on the variable value can be done at parse
+         * time. This is a stop-gap.
+         */
+        variables.put(key, val);
+    }
+
+    /**
+     * Retrieves the value of a variable that was set in the .inputrc file
+     * during processing
+     * @param var The variable name
+     * @return The variable value.
+     */
+    public String getVariable(String var) {
+        return variables.get (var);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/ConsoleReader.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,4006 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console;
+
+//import java.awt.*;
+//import java.awt.datatransfer.Clipboard;
+//import java.awt.datatransfer.DataFlavor;
+//import java.awt.datatransfer.Transferable;
+//import java.awt.datatransfer.UnsupportedFlavorException;
+//import java.awt.event.ActionListener;
+//import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+//import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+//import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+//import java.util.Map;
+import java.util.ResourceBundle;
+import java.util.Stack;
+import java.util.regex.Pattern;
+
+import jdk.internal.jline.Terminal;
+import jdk.internal.jline.TerminalFactory;
+import jdk.internal.jline.UnixTerminal;
+import jdk.internal.jline.console.completer.CandidateListCompletionHandler;
+import jdk.internal.jline.console.completer.Completer;
+import jdk.internal.jline.console.completer.CompletionHandler;
+import jdk.internal.jline.console.history.History;
+import jdk.internal.jline.console.history.MemoryHistory;
+import jdk.internal.jline.internal.Configuration;
+import jdk.internal.jline.internal.InputStreamReader;
+import jdk.internal.jline.internal.Log;
+import jdk.internal.jline.internal.NonBlockingInputStream;
+import jdk.internal.jline.internal.Nullable;
+import jdk.internal.jline.internal.Urls;
+//import org.fusesource.jansi.AnsiOutputStream;
+
+import static jdk.internal.jline.internal.Preconditions.checkNotNull;
+
+/**
+ * A reader for console applications. It supports custom tab-completion,
+ * saveable command history, and command line editing. On some platforms,
+ * platform-specific commands will need to be issued before the reader will
+ * function properly. See {@link jline.Terminal#init} for convenience
+ * methods for issuing platform-specific setup commands.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
+ */
+public class ConsoleReader
+{
+    public static final String JLINE_NOBELL = "jline.nobell";
+
+    public static final String JLINE_ESC_TIMEOUT = "jline.esc.timeout";
+
+    public static final String JLINE_INPUTRC = "jline.inputrc";
+
+    public static final String INPUT_RC = ".inputrc";
+
+    public static final String DEFAULT_INPUT_RC = "/etc/inputrc";
+
+    public static final char BACKSPACE = '\b';
+
+    public static final char RESET_LINE = '\r';
+
+    public static final char KEYBOARD_BELL = '\07';
+
+    public static final char NULL_MASK = 0;
+
+    public static final int TAB_WIDTH = 4;
+
+    private static final ResourceBundle
+        resources = ResourceBundle.getBundle(CandidateListCompletionHandler.class.getName());
+
+    private final Terminal terminal;
+
+    private final Writer out;
+
+    private final CursorBuffer buf = new CursorBuffer();
+
+    private String prompt;
+    private int    promptLen;
+
+    private boolean expandEvents = true;
+
+    private boolean bellEnabled = !Configuration.getBoolean(JLINE_NOBELL, true);
+
+    private boolean handleUserInterrupt = false;
+
+    private Character mask;
+
+    private Character echoCharacter;
+
+    private StringBuffer searchTerm = null;
+
+    private String previousSearchTerm = "";
+
+    private int searchIndex = -1;
+
+    private int parenBlinkTimeout = 500;
+
+    /*
+     * The reader and the nonBlockingInput go hand-in-hand.  The reader wraps
+     * the nonBlockingInput, but we have to retain a handle to it so that
+     * we can shut down its blocking read thread when we go away.
+     */
+    private NonBlockingInputStream in;
+    private long                   escapeTimeout;
+    private Reader                 reader;
+
+    /*
+     * TODO: Please read the comments about this in setInput(), but this needs
+     * to be done away with.
+     */
+    private boolean                isUnitTestInput;
+
+    /**
+     * Last character searched for with a vi character search
+     */
+    private char  charSearchChar = 0;           // Character to search for
+    private char  charSearchLastInvokeChar = 0; // Most recent invocation key
+    private char  charSearchFirstInvokeChar = 0;// First character that invoked
+
+    /**
+     * The vi yank buffer
+     */
+    private String yankBuffer = "";
+
+    private KillRing killRing = new KillRing();
+
+    private String encoding;
+
+    private boolean recording;
+
+    private String macro = "";
+
+    private String appName;
+
+    private URL inputrcUrl;
+
+    private ConsoleKeys consoleKeys;
+
+    private String commentBegin = null;
+
+    private boolean skipLF = false;
+
+    /**
+     * Set to true if the reader should attempt to detect copy-n-paste. The
+     * effect of this that an attempt is made to detect if tab is quickly
+     * followed by another character, then it is assumed that the tab was
+     * a literal tab as part of a copy-and-paste operation and is inserted as
+     * such.
+     */
+    private boolean copyPasteDetection = false;
+
+    /*
+     * Current internal state of the line reader
+     */
+    private State   state = State.NORMAL;
+
+    /**
+     * Possible states in which the current readline operation may be in.
+     */
+    private static enum State {
+        /**
+         * The user is just typing away
+         */
+        NORMAL,
+        /**
+         * In the middle of a emacs seach
+         */
+        SEARCH,
+        FORWARD_SEARCH,
+        /**
+         * VI "yank-to" operation ("y" during move mode)
+         */
+        VI_YANK_TO,
+        /**
+         * VI "delete-to" operation ("d" during move mode)
+         */
+        VI_DELETE_TO,
+        /**
+         * VI "change-to" operation ("c" during move mode)
+         */
+        VI_CHANGE_TO
+    }
+
+    public ConsoleReader() throws IOException {
+        this(null, new FileInputStream(FileDescriptor.in), System.out, null);
+    }
+
+    public ConsoleReader(final InputStream in, final OutputStream out) throws IOException {
+        this(null, in, out, null);
+    }
+
+    public ConsoleReader(final InputStream in, final OutputStream out, final Terminal term) throws IOException {
+        this(null, in, out, term);
+    }
+
+    public ConsoleReader(final @Nullable String appName, final InputStream in, final OutputStream out, final @Nullable Terminal term) throws IOException {
+        this(appName, in, out, term, null);
+    }
+
+    public ConsoleReader(final @Nullable String appName, final InputStream in, final OutputStream out, final @Nullable Terminal term, final @Nullable String encoding)
+        throws IOException
+    {
+        this.appName = appName != null ? appName : "JLine";
+        this.encoding = encoding != null ? encoding : Configuration.getEncoding();
+        this.terminal = term != null ? term : TerminalFactory.get();
+        String outEncoding = terminal.getOutputEncoding() != null? terminal.getOutputEncoding() : this.encoding;
+        this.out = new OutputStreamWriter(terminal.wrapOutIfNeeded(out), outEncoding);
+        setInput( in );
+
+        this.inputrcUrl = getInputRc();
+
+        consoleKeys = new ConsoleKeys(this.appName, inputrcUrl);
+    }
+
+    private URL getInputRc() throws IOException {
+        String path = Configuration.getString(JLINE_INPUTRC);
+        if (path == null) {
+            File f = new File(Configuration.getUserHome(), INPUT_RC);
+            if (!f.exists()) {
+                f = new File(DEFAULT_INPUT_RC);
+            }
+            return f.toURI().toURL();
+        } else {
+            return Urls.create(path);
+        }
+    }
+
+    public KeyMap getKeys() {
+        return consoleKeys.getKeys();
+    }
+
+    void setInput(final InputStream in) throws IOException {
+        this.escapeTimeout = Configuration.getLong(JLINE_ESC_TIMEOUT, 100);
+        /*
+         * This is gross and here is how to fix it. In getCurrentPosition()
+         * and getCurrentAnsiRow(), the logic is disabled when running unit
+         * tests and the fact that it is a unit test is determined by knowing
+         * if the original input stream was a ByteArrayInputStream. So, this
+         * is our test to do this.  What SHOULD happen is that the unit
+         * tests should pass in a terminal that is appropriately configured
+         * such that whatever behavior they expect to happen (or not happen)
+         * happens (or doesn't).
+         *
+         * So, TODO, get rid of this and fix the unit tests.
+         */
+        this.isUnitTestInput = in instanceof ByteArrayInputStream;
+        boolean nonBlockingEnabled =
+               escapeTimeout > 0L
+            && terminal.isSupported()
+            && in != null;
+
+        /*
+         * If we had a non-blocking thread already going, then shut it down
+         * and start a new one.
+         */
+        if (this.in != null) {
+            this.in.shutdown();
+        }
+
+        final InputStream wrapped = terminal.wrapInIfNeeded( in );
+
+        this.in = new NonBlockingInputStream(wrapped, nonBlockingEnabled);
+        this.reader = new InputStreamReader( this.in, encoding );
+    }
+
+    /**
+     * Shuts the console reader down.  This method should be called when you
+     * have completed using the reader as it shuts down and cleans up resources
+     * that would otherwise be "leaked".
+     */
+    public void shutdown() {
+        if (in != null) {
+            in.shutdown();
+        }
+    }
+
+    /**
+     * Shuts down the ConsoleReader if the JVM attempts to clean it up.
+     */
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            shutdown();
+        }
+        finally {
+            super.finalize();
+        }
+    }
+
+    public InputStream getInput() {
+        return in;
+    }
+
+    public Writer getOutput() {
+        return out;
+    }
+
+    public Terminal getTerminal() {
+        return terminal;
+    }
+
+    public CursorBuffer getCursorBuffer() {
+        return buf;
+    }
+
+    public void setExpandEvents(final boolean expand) {
+        this.expandEvents = expand;
+    }
+
+    public boolean getExpandEvents() {
+        return expandEvents;
+    }
+
+    /**
+     * Enables or disables copy and paste detection. The effect of enabling this
+     * this setting is that when a tab is received immediately followed by another
+     * character, the tab will not be treated as a completion, but as a tab literal.
+     * @param onoff true if detection is enabled
+     */
+    public void setCopyPasteDetection(final boolean onoff) {
+        copyPasteDetection = onoff;
+    }
+
+    /**
+     * @return true if copy and paste detection is enabled.
+     */
+    public boolean isCopyPasteDetectionEnabled() {
+        return copyPasteDetection;
+    }
+
+    /**
+     * Set whether the console bell is enabled.
+     *
+     * @param enabled true if enabled; false otherwise
+     * @since 2.7
+     */
+    public void setBellEnabled(boolean enabled) {
+        this.bellEnabled = enabled;
+    }
+
+    /**
+     * Get whether the console bell is enabled
+     *
+     * @return true if enabled; false otherwise
+     * @since 2.7
+     */
+    public boolean getBellEnabled() {
+        return bellEnabled;
+    }
+
+    /**
+     * Set whether user interrupts (ctrl-C) are handled by having JLine
+     * throw {@link UserInterruptException} from {@link #readLine}.
+     * Otherwise, the JVM will handle {@code SIGINT} as normal, which
+     * usually causes it to exit. The default is {@code false}.
+     *
+     * @since 2.10
+     */
+    public void setHandleUserInterrupt(boolean enabled)
+    {
+        this.handleUserInterrupt = enabled;
+    }
+
+    /**
+     * Get whether user interrupt handling is enabled
+     *
+     * @return true if enabled; false otherwise
+     * @since 2.10
+     */
+    public boolean getHandleUserInterrupt()
+    {
+        return handleUserInterrupt;
+    }
+
+    /**
+     * Sets the string that will be used to start a comment when the
+     * insert-comment key is struck.
+     * @param commentBegin The begin comment string.
+     * @since 2.7
+     */
+    public void setCommentBegin(String commentBegin) {
+        this.commentBegin = commentBegin;
+    }
+
+    /**
+     * @return the string that will be used to start a comment when the
+     * insert-comment key is struck.
+     * @since 2.7
+     */
+    public String getCommentBegin() {
+        String str = commentBegin;
+
+        if (str == null) {
+            str = consoleKeys.getVariable("comment-begin");
+            if (str == null) {
+                str = "#";
+            }
+        }
+        return str;
+    }
+
+    public void setPrompt(final String prompt) {
+        this.prompt = prompt;
+        this.promptLen = ((prompt == null) ? 0 : stripAnsi(lastLine(prompt)).length());
+    }
+
+    public String getPrompt() {
+        return prompt;
+    }
+
+    /**
+     * Set the echo character. For example, to have "*" entered when a password is typed:
+     * <p/>
+     * <pre>
+     * myConsoleReader.setEchoCharacter(new Character('*'));
+     * </pre>
+     * <p/>
+     * Setting the character to
+     * <p/>
+     * <pre>
+     * null
+     * </pre>
+     * <p/>
+     * will restore normal character echoing. Setting the character to
+     * <p/>
+     * <pre>
+     * new Character(0)
+     * </pre>
+     * <p/>
+     * will cause nothing to be echoed.
+     *
+     * @param c the character to echo to the console in place of the typed character.
+     */
+    public void setEchoCharacter(final Character c) {
+        this.echoCharacter = c;
+    }
+
+    /**
+     * Returns the echo character.
+     */
+    public Character getEchoCharacter() {
+        return echoCharacter;
+    }
+
+    /**
+     * Erase the current line.
+     *
+     * @return false if we failed (e.g., the buffer was empty)
+     */
+    protected final boolean resetLine() throws IOException {
+        if (buf.cursor == 0) {
+            return false;
+        }
+
+        StringBuilder killed = new StringBuilder();
+
+        while (buf.cursor > 0) {
+            char c = buf.current();
+            if (c == 0) {
+                break;
+            }
+
+            killed.append(c);
+            backspace();
+        }
+
+        String copy = killed.reverse().toString();
+        killRing.addBackwards(copy);
+
+        return true;
+    }
+
+    int getCursorPosition() {
+        // FIXME: does not handle anything but a line with a prompt absolute position
+        return promptLen + buf.cursor;
+    }
+
+    /**
+     * Returns the text after the last '\n'.
+     * prompt is returned if no '\n' characters are present.
+     * null is returned if prompt is null.
+     */
+    private String lastLine(String str) {
+        if (str == null) return "";
+        int last = str.lastIndexOf("\n");
+
+        if (last >= 0) {
+            return str.substring(last + 1, str.length());
+        }
+
+        return str;
+    }
+
+    String stripAnsi(String str) {
+        if (str == null) return "";
+        return ANSI_CODE_PATTERN.matcher(str).replaceAll("");
+//        try {
+//            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+//            AnsiOutputStream aos = new AnsiOutputStream(baos);
+//            aos.write(str.getBytes());
+//            aos.flush();
+//            return baos.toString();
+//        } catch (IOException e) {
+//            return str;
+//        }
+    }
+    //where:
+        private static final Pattern ANSI_CODE_PATTERN = Pattern.compile("\033\\[[^@-~]*[@-~]");
+
+    /**
+     * Move the cursor position to the specified absolute index.
+     */
+    public final boolean setCursorPosition(final int position) throws IOException {
+        if (position == buf.cursor) {
+            return true;
+        }
+
+        return moveCursor(position - buf.cursor) != 0;
+    }
+
+    /**
+     * Set the current buffer's content to the specified {@link String}. The
+     * visual console will be modified to show the current buffer.
+     *
+     * @param buffer the new contents of the buffer.
+     */
+    private void setBuffer(final String buffer) throws IOException {
+        // don't bother modifying it if it is unchanged
+        if (buffer.equals(buf.buffer.toString())) {
+            return;
+        }
+
+        // obtain the difference between the current buffer and the new one
+        int sameIndex = 0;
+
+        for (int i = 0, l1 = buffer.length(), l2 = buf.buffer.length(); (i < l1)
+            && (i < l2); i++) {
+            if (buffer.charAt(i) == buf.buffer.charAt(i)) {
+                sameIndex++;
+            }
+            else {
+                break;
+            }
+        }
+
+        int diff = buf.cursor - sameIndex;
+        if (diff < 0) { // we can't backspace here so try from the end of the buffer
+            moveToEnd();
+            diff = buf.buffer.length() - sameIndex;
+        }
+
+        backspace(diff); // go back for the differences
+        killLine(); // clear to the end of the line
+        buf.buffer.setLength(sameIndex); // the new length
+        putString(buffer.substring(sameIndex)); // append the differences
+    }
+
+    private void setBuffer(final CharSequence buffer) throws IOException {
+        setBuffer(String.valueOf(buffer));
+    }
+
+    private void setBufferKeepPos(final String buffer) throws IOException {
+        int pos = buf.cursor;
+        setBuffer(buffer);
+        setCursorPosition(pos);
+    }
+
+    private void setBufferKeepPos(final CharSequence buffer) throws IOException {
+        setBufferKeepPos(String.valueOf(buffer));
+    }
+
+    /**
+     * Output put the prompt + the current buffer
+     */
+    public final void drawLine() throws IOException {
+        String prompt = getPrompt();
+        if (prompt != null) {
+            print(prompt);
+        }
+
+        print(buf.buffer.toString());
+
+        if (buf.length() != buf.cursor) { // not at end of line
+            back(buf.length() - buf.cursor - 1);
+        }
+        // force drawBuffer to check for weird wrap (after clear screen)
+        drawBuffer();
+    }
+
+    /**
+     * Clear the line and redraw it.
+     */
+    public final void redrawLine() throws IOException {
+        print(RESET_LINE);
+//        flush();
+        drawLine();
+    }
+
+    /**
+     * Clear the buffer and add its contents to the history.
+     *
+     * @return the former contents of the buffer.
+     */
+    final String finishBuffer() throws IOException { // FIXME: Package protected because used by tests
+        String str = buf.buffer.toString();
+        String historyLine = str;
+
+        if (expandEvents) {
+            try {
+                str = expandEvents(str);
+                // all post-expansion occurrences of '!' must have been escaped, so re-add escape to each
+                historyLine = str.replace("!", "\\!");
+                // only leading '^' results in expansion, so only re-add escape for that case
+                historyLine = historyLine.replaceAll("^\\^", "\\\\^");
+            } catch(IllegalArgumentException e) {
+                Log.error("Could not expand event", e);
+                beep();
+                buf.clear();
+                str = "";
+            }
+        }
+
+        // we only add it to the history if the buffer is not empty
+        // and if mask is null, since having a mask typically means
+        // the string was a password. We clear the mask after this call
+        if (str.length() > 0) {
+            if (mask == null && isHistoryEnabled()) {
+                history.add(historyLine);
+            }
+            else {
+                mask = null;
+            }
+        }
+
+        history.moveToEnd();
+
+        buf.buffer.setLength(0);
+        buf.cursor = 0;
+
+        return str;
+    }
+
+    /**
+     * Expand event designator such as !!, !#, !3, etc...
+     * See http://www.gnu.org/software/bash/manual/html_node/Event-Designators.html
+     */
+    @SuppressWarnings("fallthrough")
+    protected String expandEvents(String str) throws IOException {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < str.length(); i++) {
+            char c = str.charAt(i);
+            switch (c) {
+                case '\\':
+                    // any '\!' should be considered an expansion escape, so skip expansion and strip the escape character
+                    // a leading '\^' should be considered an expansion escape, so skip expansion and strip the escape character
+                    // otherwise, add the escape
+                    if (i + 1 < str.length()) {
+                        char nextChar = str.charAt(i+1);
+                        if (nextChar == '!' || (nextChar == '^' && i == 0)) {
+                            c = nextChar;
+                            i++;
+                        }
+                    }
+                    sb.append(c);
+                    break;
+                case '!':
+                    if (i + 1 < str.length()) {
+                        c = str.charAt(++i);
+                        boolean neg = false;
+                        String rep = null;
+                        int i1, idx;
+                        switch (c) {
+                            case '!':
+                                if (history.size() == 0) {
+                                    throw new IllegalArgumentException("!!: event not found");
+                                }
+                                rep = history.get(history.index() - 1).toString();
+                                break;
+                            case '#':
+                                sb.append(sb.toString());
+                                break;
+                            case '?':
+                                i1 = str.indexOf('?', i + 1);
+                                if (i1 < 0) {
+                                    i1 = str.length();
+                                }
+                                String sc = str.substring(i + 1, i1);
+                                i = i1;
+                                idx = searchBackwards(sc);
+                                if (idx < 0) {
+                                    throw new IllegalArgumentException("!?" + sc + ": event not found");
+                                } else {
+                                    rep = history.get(idx).toString();
+                                }
+                                break;
+                            case '$':
+                                if (history.size() == 0) {
+                                    throw new IllegalArgumentException("!$: event not found");
+                                }
+                                String previous = history.get(history.index() - 1).toString().trim();
+                                int lastSpace = previous.lastIndexOf(' ');
+                                if(lastSpace != -1) {
+                                    rep = previous.substring(lastSpace+1);
+                                } else {
+                                    rep = previous;
+                                }
+                                break;
+                            case ' ':
+                            case '\t':
+                                sb.append('!');
+                                sb.append(c);
+                                break;
+                            case '-':
+                                neg = true;
+                                i++;
+                                // fall through
+                            case '0':
+                            case '1':
+                            case '2':
+                            case '3':
+                            case '4':
+                            case '5':
+                            case '6':
+                            case '7':
+                            case '8':
+                            case '9':
+                                i1 = i;
+                                for (; i < str.length(); i++) {
+                                    c = str.charAt(i);
+                                    if (c < '0' || c > '9') {
+                                        break;
+                                    }
+                                }
+                                idx = 0;
+                                try {
+                                    idx = Integer.parseInt(str.substring(i1, i));
+                                } catch (NumberFormatException e) {
+                                    throw new IllegalArgumentException((neg ? "!-" : "!") + str.substring(i1, i) + ": event not found");
+                                }
+                                if (neg) {
+                                    if (idx > 0 && idx <= history.size()) {
+                                        rep = (history.get(history.index() - idx)).toString();
+                                    } else {
+                                        throw new IllegalArgumentException((neg ? "!-" : "!") + str.substring(i1, i) + ": event not found");
+                                    }
+                                } else {
+                                    if (idx > history.index() - history.size() && idx <= history.index()) {
+                                        rep = (history.get(idx - 1)).toString();
+                                    } else {
+                                        throw new IllegalArgumentException((neg ? "!-" : "!") + str.substring(i1, i) + ": event not found");
+                                    }
+                                }
+                                break;
+                            default:
+                                String ss = str.substring(i);
+                                i = str.length();
+                                idx = searchBackwards(ss, history.index(), true);
+                                if (idx < 0) {
+                                    throw new IllegalArgumentException("!" + ss + ": event not found");
+                                } else {
+                                    rep = history.get(idx).toString();
+                                }
+                                break;
+                        }
+                        if (rep != null) {
+                            sb.append(rep);
+                        }
+                    } else {
+                        sb.append(c);
+                    }
+                    break;
+                case '^':
+                    if (i == 0) {
+                        int i1 = str.indexOf('^', i + 1);
+                        int i2 = str.indexOf('^', i1 + 1);
+                        if (i2 < 0) {
+                            i2 = str.length();
+                        }
+                        if (i1 > 0 && i2 > 0) {
+                            String s1 = str.substring(i + 1, i1);
+                            String s2 = str.substring(i1 + 1, i2);
+                            String s = history.get(history.index() - 1).toString().replace(s1, s2);
+                            sb.append(s);
+                            i = i2 + 1;
+                            break;
+                        }
+                    }
+                    sb.append(c);
+                    break;
+                default:
+                    sb.append(c);
+                    break;
+            }
+        }
+        String result = sb.toString();
+        if (!str.equals(result)) {
+            print(result);
+            println();
+            flush();
+        }
+        return result;
+
+    }
+
+    /**
+     * Write out the specified string to the buffer and the output stream.
+     */
+    public final void putString(final CharSequence str) throws IOException {
+        buf.write(str);
+        if (mask == null) {
+            // no masking
+            print(str);
+        } else if (mask == NULL_MASK) {
+            // don't print anything
+        } else {
+            print(mask, str.length());
+        }
+        drawBuffer();
+    }
+
+    /**
+     * Redraw the rest of the buffer from the cursor onwards. This is necessary
+     * for inserting text into the buffer.
+     *
+     * @param clear the number of characters to clear after the end of the buffer
+     */
+    private void drawBuffer(final int clear) throws IOException {
+        // debug ("drawBuffer: " + clear);
+        if (buf.cursor == buf.length() && clear == 0) {
+        } else {
+            char[] chars = buf.buffer.substring(buf.cursor).toCharArray();
+            if (mask != null) {
+                Arrays.fill(chars, mask);
+            }
+            if (terminal.hasWeirdWrap()) {
+                // need to determine if wrapping will occur:
+                int width = terminal.getWidth();
+                int pos = getCursorPosition();
+                for (int i = 0; i < chars.length; i++) {
+                    print(chars[i]);
+                    if ((pos + i + 1) % width == 0) {
+                        print(32); // move cursor to next line by printing dummy space
+                        print(13); // CR / not newline.
+                    }
+                }
+            } else {
+                print(chars);
+            }
+            clearAhead(clear, chars.length);
+            if (terminal.isAnsiSupported()) {
+                if (chars.length > 0) {
+                    back(chars.length);
+                }
+            } else {
+                back(chars.length);
+            }
+        }
+        if (terminal.hasWeirdWrap()) {
+            int width = terminal.getWidth();
+            // best guess on whether the cursor is in that weird location...
+            // Need to do this without calling ansi cursor location methods
+            // otherwise it breaks paste of wrapped lines in xterm.
+            if (getCursorPosition() > 0 && (getCursorPosition() % width == 0)
+                    && buf.cursor == buf.length() && clear == 0) {
+                // the following workaround is reverse-engineered from looking
+                // at what bash sent to the terminal in the same situation
+                print(32); // move cursor to next line by printing dummy space
+                print(13); // CR / not newline.
+            }
+        }
+    }
+
+    /**
+     * Redraw the rest of the buffer from the cursor onwards. This is necessary
+     * for inserting text into the buffer.
+     */
+    private void drawBuffer() throws IOException {
+        drawBuffer(0);
+    }
+
+    /**
+     * Clear ahead the specified number of characters without moving the cursor.
+     *
+     * @param num the number of characters to clear
+     * @param delta the difference between the internal cursor and the screen
+     * cursor - if > 0, assume some stuff was printed and weird wrap has to be
+     * checked
+     */
+    private void clearAhead(final int num, int delta) throws IOException {
+        if (num == 0) {
+            return;
+        }
+
+        if (terminal.isAnsiSupported()) {
+            int width = terminal.getWidth();
+            int screenCursorCol = getCursorPosition() + delta;
+            // clear current line
+            printAnsiSequence("K");
+            // if cursor+num wraps, then we need to clear the line(s) below too
+            int curCol = screenCursorCol % width;
+            int endCol = (screenCursorCol + num - 1) % width;
+            int lines = num / width;
+            if (endCol < curCol) lines++;
+            for (int i = 0; i < lines; i++) {
+                printAnsiSequence("B");
+                printAnsiSequence("2K");
+            }
+            for (int i = 0; i < lines; i++) {
+                printAnsiSequence("A");
+            }
+            return;
+        }
+
+        // print blank extra characters
+        print(' ', num);
+
+        // we need to flush here so a "clever" console doesn't just ignore the redundancy
+        // of a space followed by a backspace.
+//        flush();
+
+        // reset the visual cursor
+        back(num);
+
+//        flush();
+    }
+
+    /**
+     * Move the visual cursor backwards without modifying the buffer cursor.
+     */
+    protected void back(final int num) throws IOException {
+        if (num == 0) return;
+        if (terminal.isAnsiSupported()) {
+            int width = getTerminal().getWidth();
+            int cursor = getCursorPosition();
+            int realCursor = cursor + num;
+            int realCol  = realCursor % width;
+            int newCol = cursor % width;
+            int moveup = num / width;
+            int delta = realCol - newCol;
+            if (delta < 0) moveup++;
+            if (moveup > 0) {
+                printAnsiSequence(moveup + "A");
+            }
+            printAnsiSequence((1 + newCol) + "G");
+            return;
+        }
+        print(BACKSPACE, num);
+//        flush();
+    }
+
+    /**
+     * Flush the console output stream. This is important for printout out single characters (like a backspace or
+     * keyboard) that we want the console to handle immediately.
+     */
+    public void flush() throws IOException {
+        out.flush();
+    }
+
+    private int backspaceAll() throws IOException {
+        return backspace(Integer.MAX_VALUE);
+    }
+
+    /**
+     * Issue <em>num</em> backspaces.
+     *
+     * @return the number of characters backed up
+     */
+    private int backspace(final int num) throws IOException {
+        if (buf.cursor == 0) {
+            return 0;
+        }
+
+        int count = 0;
+
+        int termwidth = getTerminal().getWidth();
+        int lines = getCursorPosition() / termwidth;
+        count = moveCursor(-1 * num) * -1;
+        buf.buffer.delete(buf.cursor, buf.cursor + count);
+        if (getCursorPosition() / termwidth != lines) {
+            if (terminal.isAnsiSupported()) {
+                // debug("doing backspace redraw: " + getCursorPosition() + " on " + termwidth + ": " + lines);
+                printAnsiSequence("K");
+                // if cursor+num wraps, then we need to clear the line(s) below too
+                // last char printed is one pos less than cursor so we subtract
+                // one
+/*
+                // TODO: fixme (does not work - test with reverse search with wrapping line and CTRL-E)
+                int endCol = (getCursorPosition() + num - 1) % termwidth;
+                int curCol = getCursorPosition() % termwidth;
+                if (endCol < curCol) lines++;
+                for (int i = 1; i < lines; i++) {
+                    printAnsiSequence("B");
+                    printAnsiSequence("2K");
+                }
+                for (int i = 1; i < lines; i++) {
+                    printAnsiSequence("A");
+                }
+                return count;
+*/
+            }
+        }
+        drawBuffer(count);
+
+        return count;
+    }
+
+    /**
+     * Issue a backspace.
+     *
+     * @return true if successful
+     */
+    public boolean backspace() throws IOException {
+        return backspace(1) == 1;
+    }
+
+    protected boolean moveToEnd() throws IOException {
+        if (buf.cursor == buf.length()) {
+            return true;
+        }
+        return moveCursor(buf.length() - buf.cursor) > 0;
+    }
+
+    /**
+     * Delete the character at the current position and redraw the remainder of the buffer.
+     */
+    private boolean deleteCurrentCharacter() throws IOException {
+        if (buf.length() == 0 || buf.cursor == buf.length()) {
+            return false;
+        }
+
+        buf.buffer.deleteCharAt(buf.cursor);
+        drawBuffer(1);
+        return true;
+    }
+
+    /**
+     * This method is calling while doing a delete-to ("d"), change-to ("c"),
+     * or yank-to ("y") and it filters out only those movement operations
+     * that are allowable during those operations. Any operation that isn't
+     * allow drops you back into movement mode.
+     *
+     * @param op The incoming operation to remap
+     * @return The remaped operation
+     */
+    private Operation viDeleteChangeYankToRemap (Operation op) {
+        switch (op) {
+            case VI_EOF_MAYBE:
+            case ABORT:
+            case BACKWARD_CHAR:
+            case FORWARD_CHAR:
+            case END_OF_LINE:
+            case VI_MATCH:
+            case VI_BEGNNING_OF_LINE_OR_ARG_DIGIT:
+            case VI_ARG_DIGIT:
+            case VI_PREV_WORD:
+            case VI_END_WORD:
+            case VI_CHAR_SEARCH:
+            case VI_NEXT_WORD:
+            case VI_FIRST_PRINT:
+            case VI_GOTO_MARK:
+            case VI_COLUMN:
+            case VI_DELETE_TO:
+            case VI_YANK_TO:
+            case VI_CHANGE_TO:
+                return op;
+
+            default:
+                return Operation.VI_MOVEMENT_MODE;
+        }
+    }
+
+    /**
+     * Deletes the previous character from the cursor position
+     * @param count number of times to do it.
+     * @return true if it was done.
+     * @throws IOException
+     */
+    private boolean viRubout(int count) throws IOException {
+        boolean ok = true;
+        for (int i = 0; ok && i < count; i++) {
+            ok = backspace();
+        }
+        return ok;
+    }
+
+    /**
+     * Deletes the character you are sitting on and sucks the rest of
+     * the line in from the right.
+     * @param count Number of times to perform the operation.
+     * @return true if its works, false if it didn't
+     * @throws IOException
+     */
+    private boolean viDelete(int count) throws IOException {
+        boolean ok = true;
+        for (int i = 0; ok && i < count; i++) {
+            ok = deleteCurrentCharacter();
+        }
+        return ok;
+    }
+
+    /**
+     * Switches the case of the current character from upper to lower
+     * or lower to upper as necessary and advances the cursor one
+     * position to the right.
+     * @param count The number of times to repeat
+     * @return true if it completed successfully, false if not all
+     *   case changes could be completed.
+     * @throws IOException
+     */
+    private boolean viChangeCase(int count) throws IOException {
+        boolean ok = true;
+        for (int i = 0; ok && i < count; i++) {
+
+            ok = buf.cursor < buf.buffer.length ();
+            if (ok) {
+                char ch = buf.buffer.charAt(buf.cursor);
+                if (Character.isUpperCase(ch)) {
+                    ch = Character.toLowerCase(ch);
+                }
+                else if (Character.isLowerCase(ch)) {
+                    ch = Character.toUpperCase(ch);
+                }
+                buf.buffer.setCharAt(buf.cursor, ch);
+                drawBuffer(1);
+                moveCursor(1);
+            }
+        }
+        return ok;
+    }
+
+    /**
+     * Implements the vi change character command (in move-mode "r"
+     * followed by the character to change to).
+     * @param count Number of times to perform the action
+     * @param c The character to change to
+     * @return Whether or not there were problems encountered
+     * @throws IOException
+     */
+    private boolean viChangeChar(int count, int c) throws IOException {
+        // EOF, ESC, or CTRL-C aborts.
+        if (c < 0 || c == '\033' || c == '\003') {
+            return true;
+        }
+
+        boolean ok = true;
+        for (int i = 0; ok && i < count; i++) {
+            ok = buf.cursor < buf.buffer.length ();
+            if (ok) {
+                buf.buffer.setCharAt(buf.cursor, (char) c);
+                drawBuffer(1);
+                if (i < (count-1)) {
+                    moveCursor(1);
+                }
+            }
+        }
+        return ok;
+    }
+
+    /**
+     * This is a close facsimile of the actual vi previous word logic. In
+     * actual vi words are determined by boundaries of identity characterse.
+     * This logic is a bit more simple and simply looks at white space or
+     * digits or characters.  It should be revised at some point.
+     *
+     * @param count number of iterations
+     * @return true if the move was successful, false otherwise
+     * @throws IOException
+     */
+    private boolean viPreviousWord(int count) throws IOException {
+        boolean ok = true;
+        if (buf.cursor == 0) {
+            return false;
+        }
+
+        int pos = buf.cursor - 1;
+        for (int i = 0; pos > 0 && i < count; i++) {
+            // If we are on white space, then move back.
+            while (pos > 0 && isWhitespace(buf.buffer.charAt(pos))) {
+                --pos;
+            }
+
+            while (pos > 0 && !isDelimiter(buf.buffer.charAt(pos-1))) {
+                --pos;
+            }
+
+            if (pos > 0 && i < (count-1)) {
+                --pos;
+            }
+        }
+        setCursorPosition(pos);
+        return ok;
+    }
+
+    /**
+     * Performs the vi "delete-to" action, deleting characters between a given
+     * span of the input line.
+     * @param startPos The start position
+     * @param endPos The end position.
+     * @param isChange If true, then the delete is part of a change operationg
+     *    (e.g. "c$" is change-to-end-of line, so we first must delete to end
+     *    of line to start the change
+     * @return true if it succeeded, false otherwise
+     * @throws IOException
+     */
+    private boolean viDeleteTo(int startPos, int endPos, boolean isChange) throws IOException {
+        if (startPos == endPos) {
+            return true;
+        }
+
+        if (endPos < startPos) {
+            int tmp = endPos;
+            endPos = startPos;
+            startPos = tmp;
+        }
+
+        setCursorPosition(startPos);
+        buf.cursor = startPos;
+        buf.buffer.delete(startPos, endPos);
+        drawBuffer(endPos - startPos);
+
+        // If we are doing a delete operation (e.g. "d$") then don't leave the
+        // cursor dangling off the end. In reality the "isChange" flag is silly
+        // what is really happening is that if we are in "move-mode" then the
+        // cursor can't be moved off the end of the line, but in "edit-mode" it
+        // is ok, but I have no easy way of knowing which mode we are in.
+        if (! isChange && startPos > 0 && startPos == buf.length()) {
+            moveCursor(-1);
+        }
+        return true;
+    }
+
+    /**
+     * Implement the "vi" yank-to operation.  This operation allows you
+     * to yank the contents of the current line based upon a move operation,
+     * for exaple "yw" yanks the current word, "3yw" yanks 3 words, etc.
+     *
+     * @param startPos The starting position from which to yank
+     * @param endPos The ending position to which to yank
+     * @return true if the yank succeeded
+     * @throws IOException
+     */
+    private boolean viYankTo(int startPos, int endPos) throws IOException {
+        int cursorPos = startPos;
+
+        if (endPos < startPos) {
+            int tmp = endPos;
+            endPos = startPos;
+            startPos = tmp;
+        }
+
+        if (startPos == endPos) {
+            yankBuffer = "";
+            return true;
+        }
+
+        yankBuffer = buf.buffer.substring(startPos, endPos);
+
+        /*
+         * It was a movement command that moved the cursor to find the
+         * end position, so put the cursor back where it started.
+         */
+        setCursorPosition(cursorPos);
+        return true;
+    }
+
+    /**
+     * Pasts the yank buffer to the right of the current cursor position
+     * and moves the cursor to the end of the pasted region.
+     *
+     * @param count Number of times to perform the operation.
+     * @return true if it worked, false otherwise
+     * @throws IOException
+     */
+    private boolean viPut(int count) throws IOException {
+        if (yankBuffer.length () == 0) {
+            return true;
+        }
+        if (buf.cursor < buf.buffer.length ()) {
+            moveCursor(1);
+        }
+        for (int i = 0; i < count; i++) {
+            putString(yankBuffer);
+        }
+        moveCursor(-1);
+        return true;
+    }
+
+    /**
+     * Searches forward of the current position for a character and moves
+     * the cursor onto it.
+     * @param count Number of times to repeat the process.
+     * @param ch The character to search for
+     * @return true if the char was found, false otherwise
+     * @throws IOException
+     */
+    private boolean viCharSearch(int count, int invokeChar, int ch) throws IOException {
+        if (ch < 0 || invokeChar < 0) {
+            return false;
+        }
+
+        char    searchChar = (char)ch;
+        boolean isForward;
+        boolean stopBefore;
+
+        /*
+         * The character stuff turns out to be hairy. Here is how it works:
+         *   f - search forward for ch
+         *   F - search backward for ch
+         *   t - search forward for ch, but stop just before the match
+         *   T - search backward for ch, but stop just after the match
+         *   ; - After [fFtT;], repeat the last search, after ',' reverse it
+         *   , - After [fFtT;], reverse the last search, after ',' repeat it
+         */
+        if (invokeChar == ';' || invokeChar == ',') {
+            // No recent search done? Then bail
+            if (charSearchChar == 0) {
+                return false;
+            }
+
+            // Reverse direction if switching between ',' and ';'
+            if (charSearchLastInvokeChar == ';' || charSearchLastInvokeChar == ',') {
+                if (charSearchLastInvokeChar != invokeChar) {
+                    charSearchFirstInvokeChar = switchCase(charSearchFirstInvokeChar);
+                }
+            }
+            else {
+                if (invokeChar == ',') {
+                    charSearchFirstInvokeChar = switchCase(charSearchFirstInvokeChar);
+                }
+            }
+
+            searchChar = charSearchChar;
+        }
+        else {
+            charSearchChar            = searchChar;
+            charSearchFirstInvokeChar = (char) invokeChar;
+        }
+
+        charSearchLastInvokeChar = (char)invokeChar;
+
+        isForward = Character.isLowerCase(charSearchFirstInvokeChar);
+        stopBefore = (Character.toLowerCase(charSearchFirstInvokeChar) == 't');
+
+        boolean ok = false;
+
+        if (isForward) {
+            while (count-- > 0) {
+                int pos = buf.cursor + 1;
+                while (pos < buf.buffer.length()) {
+                    if (buf.buffer.charAt(pos) == searchChar) {
+                        setCursorPosition(pos);
+                        ok = true;
+                        break;
+                    }
+                    ++pos;
+                }
+            }
+
+            if (ok) {
+                if (stopBefore)
+                    moveCursor(-1);
+
+                /*
+                 * When in yank-to, move-to, del-to state we actually want to
+                 * go to the character after the one we landed on to make sure
+                 * that the character we ended up on is included in the
+                 * operation
+                 */
+                if (isInViMoveOperationState()) {
+                    moveCursor(1);
+                }
+            }
+        }
+        else {
+            while (count-- > 0) {
+                int pos = buf.cursor - 1;
+                while (pos >= 0) {
+                    if (buf.buffer.charAt(pos) == searchChar) {
+                        setCursorPosition(pos);
+                        ok = true;
+                        break;
+                    }
+                    --pos;
+                }
+            }
+
+            if (ok && stopBefore)
+                moveCursor(1);
+        }
+
+        return ok;
+    }
+
+    private char switchCase(char ch) {
+        if (Character.isUpperCase(ch)) {
+            return Character.toLowerCase(ch);
+        }
+        return Character.toUpperCase(ch);
+    }
+
+    /**
+     * @return true if line reader is in the middle of doing a change-to
+     *   delete-to or yank-to.
+     */
+    private final boolean isInViMoveOperationState() {
+        return state == State.VI_CHANGE_TO
+            || state == State.VI_DELETE_TO
+            || state == State.VI_YANK_TO;
+    }
+
+    /**
+     * This is a close facsimile of the actual vi next word logic.
+     * As with viPreviousWord() this probably needs to be improved
+     * at some point.
+     *
+     * @param count number of iterations
+     * @return true if the move was successful, false otherwise
+     * @throws IOException
+     */
+    private boolean viNextWord(int count) throws IOException {
+        int pos = buf.cursor;
+        int end = buf.buffer.length();
+
+        for (int i = 0; pos < end && i < count; i++) {
+            // Skip over letter/digits
+            while (pos < end && !isDelimiter(buf.buffer.charAt(pos))) {
+                ++pos;
+            }
+
+            /*
+             * Don't you love special cases? During delete-to and yank-to
+             * operations the word movement is normal. However, during a
+             * change-to, the trailing spaces behind the last word are
+             * left in tact.
+             */
+            if (i < (count-1) || !(state == State.VI_CHANGE_TO)) {
+                while (pos < end && isDelimiter(buf.buffer.charAt(pos))) {
+                    ++pos;
+                }
+            }
+        }
+
+        setCursorPosition(pos);
+        return true;
+    }
+
+    /**
+     * Implements a close facsimile of the vi end-of-word movement.
+     * If the character is on white space, it takes you to the end
+     * of the next word.  If it is on the last character of a word
+     * it takes you to the next of the next word.  Any other character
+     * of a word, takes you to the end of the current word.
+     *
+     * @param count Number of times to repeat the action
+     * @return true if it worked.
+     * @throws IOException
+     */
+    private boolean viEndWord(int count) throws IOException {
+        int pos = buf.cursor;
+        int end = buf.buffer.length();
+
+        for (int i = 0; pos < end && i < count; i++) {
+            if (pos < (end-1)
+                    && !isDelimiter(buf.buffer.charAt(pos))
+                    && isDelimiter(buf.buffer.charAt (pos+1))) {
+                ++pos;
+            }
+
+            // If we are on white space, then move back.
+            while (pos < end && isDelimiter(buf.buffer.charAt(pos))) {
+                ++pos;
+            }
+
+            while (pos < (end-1) && !isDelimiter(buf.buffer.charAt(pos+1))) {
+                ++pos;
+            }
+        }
+        setCursorPosition(pos);
+        return true;
+    }
+
+    private boolean previousWord() throws IOException {
+        while (isDelimiter(buf.current()) && (moveCursor(-1) != 0)) {
+            // nothing
+        }
+
+        while (!isDelimiter(buf.current()) && (moveCursor(-1) != 0)) {
+            // nothing
+        }
+
+        return true;
+    }
+
+    private boolean nextWord() throws IOException {
+        while (isDelimiter(buf.nextChar()) && (moveCursor(1) != 0)) {
+            // nothing
+        }
+
+        while (!isDelimiter(buf.nextChar()) && (moveCursor(1) != 0)) {
+            // nothing
+        }
+
+        return true;
+    }
+
+    /**
+     * Deletes to the beginning of the word that the cursor is sitting on.
+     * If the cursor is on white-space, it deletes that and to the beginning
+     * of the word before it.  If the user is not on a word or whitespace
+     * it deletes up to the end of the previous word.
+     *
+     * @param count Number of times to perform the operation
+     * @return true if it worked, false if you tried to delete too many words
+     * @throws IOException
+     */
+    private boolean unixWordRubout(int count) throws IOException {
+        boolean success = true;
+        StringBuilder killed = new StringBuilder();
+
+        for (; count > 0; --count) {
+            if (buf.cursor == 0) {
+                success = false;
+                break;
+            }
+
+            while (isWhitespace(buf.current())) {
+                char c = buf.current();
+                if (c == 0) {
+                    break;
+                }
+
+                killed.append(c);
+                backspace();
+            }
+
+            while (!isWhitespace(buf.current())) {
+                char c = buf.current();
+                if (c == 0) {
+                    break;
+                }
+
+                killed.append(c);
+                backspace();
+            }
+        }
+
+        String copy = killed.reverse().toString();
+        killRing.addBackwards(copy);
+
+        return success;
+    }
+
+    private String insertComment(boolean isViMode) throws IOException {
+        String comment = this.getCommentBegin ();
+        setCursorPosition(0);
+        putString(comment);
+        if (isViMode) {
+            consoleKeys.setKeyMap(KeyMap.VI_INSERT);
+        }
+        return accept();
+    }
+
+    /**
+     * Similar to putString() but allows the string to be repeated a specific
+     * number of times, allowing easy support of vi digit arguments to a given
+     * command. The string is placed as the current cursor position.
+     *
+     * @param count The count of times to insert the string.
+     * @param str The string to insert
+     * @return true if the operation is a success, false otherwise
+     * @throws IOException
+     */
+    private boolean insert(int count, final CharSequence str) throws IOException {
+        for (int i = 0; i < count; i++) {
+            buf.write(str);
+            if (mask == null) {
+                // no masking
+                print(str);
+            } else if (mask == NULL_MASK) {
+                // don't print anything
+            } else {
+                print(mask, str.length());
+            }
+        }
+        drawBuffer();
+        return true;
+    }
+
+    /**
+     * Implements vi search ("/" or "?").
+     * @throws IOException
+     */
+    @SuppressWarnings("fallthrough")
+    private int viSearch(char searchChar) throws IOException {
+        boolean isForward = (searchChar == '/');
+
+        /*
+         * This is a little gross, I'm sure there is a more appropriate way
+         * of saving and restoring state.
+         */
+        CursorBuffer origBuffer = buf.copy();
+
+        // Clear the contents of the current line and
+        setCursorPosition (0);
+        killLine();
+
+        // Our new "prompt" is the character that got us into search mode.
+        putString(Character.toString(searchChar));
+        flush();
+
+        boolean isAborted = false;
+        boolean isComplete = false;
+
+        /*
+         * Readline doesn't seem to do any special character map handling
+         * here, so I think we are safe.
+         */
+        int ch = -1;
+        while (!isAborted && !isComplete && (ch = readCharacter()) != -1) {
+            switch (ch) {
+                case '\033':  // ESC
+                    /*
+                     * The ESC behavior doesn't appear to be readline behavior,
+                     * but it is a little tweak of my own. I like it.
+                     */
+                    isAborted = true;
+                    break;
+                case '\010':  // Backspace
+                case '\177':  // Delete
+                    backspace();
+                    /*
+                     * Backspacing through the "prompt" aborts the search.
+                     */
+                    if (buf.cursor == 0) {
+                        isAborted = true;
+                    }
+                    break;
+                case '\012': // NL
+                case '\015': // CR
+                    isComplete = true;
+                    break;
+                default:
+                    putString(Character.toString((char) ch));
+            }
+
+            flush();
+        }
+
+        // If we aborted, then put ourself at the end of the original buffer.
+        if (ch == -1 || isAborted) {
+            setCursorPosition(0);
+            killLine();
+            putString(origBuffer.buffer);
+            setCursorPosition(origBuffer.cursor);
+            return -1;
+        }
+
+        /*
+         * The first character of the buffer was the search character itself
+         * so we discard it.
+         */
+        String searchTerm = buf.buffer.substring(1);
+        int idx = -1;
+
+        /*
+         * The semantics of the history thing is gross when you want to
+         * explicitly iterate over entries (without an iterator) as size()
+         * returns the actual number of entries in the list but get()
+         * doesn't work the way you think.
+         */
+        int end   = history.index();
+        int start = (end <= history.size()) ? 0 : end - history.size();
+
+        if (isForward) {
+            for (int i = start; i < end; i++) {
+                if (history.get(i).toString().contains(searchTerm)) {
+                    idx = i;
+                    break;
+                }
+            }
+        }
+        else {
+            for (int i = end-1; i >= start; i--) {
+                if (history.get(i).toString().contains(searchTerm)) {
+                    idx = i;
+                    break;
+                }
+            }
+        }
+
+        /*
+         * No match? Then restore what we were working on, but make sure
+         * the cursor is at the beginning of the line.
+         */
+        if (idx == -1) {
+            setCursorPosition(0);
+            killLine();
+            putString(origBuffer.buffer);
+            setCursorPosition(0);
+            return -1;
+        }
+
+        /*
+         * Show the match.
+         */
+        setCursorPosition(0);
+        killLine();
+        putString(history.get(idx));
+        setCursorPosition(0);
+        flush();
+
+        /*
+         * While searching really only the "n" and "N" keys are interpreted
+         * as movement, any other key is treated as if you are editing the
+         * line with it, so we return it back up to the caller for interpretation.
+         */
+        isComplete = false;
+        while (!isComplete && (ch = readCharacter()) != -1) {
+            boolean forward = isForward;
+            switch (ch) {
+                case 'p': case 'P':
+                    forward = !isForward;
+                    // Fallthru
+                case 'n': case 'N':
+                    boolean isMatch = false;
+                    if (forward) {
+                        for (int i = idx+1; !isMatch && i < end; i++) {
+                            if (history.get(i).toString().contains(searchTerm)) {
+                                idx = i;
+                                isMatch = true;
+                            }
+                        }
+                    }
+                    else {
+                        for (int i = idx - 1; !isMatch && i >= start; i--) {
+                            if (history.get(i).toString().contains(searchTerm)) {
+                                idx = i;
+                                isMatch = true;
+                            }
+                        }
+                    }
+                    if (isMatch) {
+                        setCursorPosition(0);
+                        killLine();
+                        putString(history.get(idx));
+                        setCursorPosition(0);
+                    }
+                    break;
+                default:
+                    isComplete = true;
+            }
+            flush();
+        }
+
+        /*
+         * Complete?
+         */
+        return ch;
+    }
+
+    public void setParenBlinkTimeout(int timeout) {
+        parenBlinkTimeout = timeout;
+    }
+
+    private void insertClose(String s) throws IOException {
+         putString(s);
+         int closePosition = buf.cursor;
+
+         moveCursor(-1);
+         viMatch();
+
+
+         if (in.isNonBlockingEnabled()) {
+            in.peek(parenBlinkTimeout);
+         }
+
+         setCursorPosition(closePosition);
+    }
+
+    /**
+     * Implements vi style bracket matching ("%" command). The matching
+     * bracket for the current bracket type that you are sitting on is matched.
+     * The logic works like so:
+     * @return true if it worked, false if the cursor was not on a bracket
+     *   character or if there was no matching bracket.
+     * @throws IOException
+     */
+    private boolean viMatch() throws IOException {
+        int pos        = buf.cursor;
+
+        if (pos == buf.length()) {
+            return false;
+        }
+
+        int type       = getBracketType(buf.buffer.charAt (pos));
+        int move       = (type < 0) ? -1 : 1;
+        int count      = 1;
+
+        if (type == 0)
+            return false;
+
+        while (count > 0) {
+            pos += move;
+
+            // Fell off the start or end.
+            if (pos < 0 || pos >= buf.buffer.length ()) {
+                return false;
+            }
+
+            int curType = getBracketType(buf.buffer.charAt (pos));
+            if (curType == type) {
+                ++count;
+            }
+            else if (curType == -type) {
+                --count;
+            }
+        }
+
+        /*
+         * Slight adjustment for delete-to, yank-to, change-to to ensure
+         * that the matching paren is consumed
+         */
+        if (move > 0 && isInViMoveOperationState())
+            ++pos;
+
+        setCursorPosition(pos);
+        return true;
+    }
+
+    /**
+     * Given a character determines what type of bracket it is (paren,
+     * square, curly, or none).
+     * @param ch The character to check
+     * @return 1 is square, 2 curly, 3 parent, or zero for none.  The value
+     *   will be negated if it is the closing form of the bracket.
+     */
+    private int getBracketType (char ch) {
+        switch (ch) {
+            case '[': return  1;
+            case ']': return -1;
+            case '{': return  2;
+            case '}': return -2;
+            case '(': return  3;
+            case ')': return -3;
+            default:
+                return 0;
+        }
+    }
+
+    private boolean deletePreviousWord() throws IOException {
+        StringBuilder killed = new StringBuilder();
+        char c;
+
+        while (isDelimiter((c = buf.current()))) {
+            if (c == 0) {
+                break;
+            }
+
+            killed.append(c);
+            backspace();
+        }
+
+        while (!isDelimiter((c = buf.current()))) {
+            if (c == 0) {
+                break;
+            }
+
+            killed.append(c);
+            backspace();
+        }
+
+        String copy = killed.reverse().toString();
+        killRing.addBackwards(copy);
+        return true;
+    }
+
+    private boolean deleteNextWord() throws IOException {
+        StringBuilder killed = new StringBuilder();
+        char c;
+
+        while (isDelimiter((c = buf.nextChar()))) {
+            if (c == 0) {
+                break;
+            }
+            killed.append(c);
+            delete();
+        }
+
+        while (!isDelimiter((c = buf.nextChar()))) {
+            if (c == 0) {
+                break;
+            }
+            killed.append(c);
+            delete();
+        }
+
+        String copy = killed.toString();
+        killRing.add(copy);
+
+        return true;
+    }
+
+    private boolean capitalizeWord() throws IOException {
+        boolean first = true;
+        int i = 1;
+        char c;
+        while (buf.cursor + i  - 1< buf.length() && !isDelimiter((c = buf.buffer.charAt(buf.cursor + i - 1)))) {
+            buf.buffer.setCharAt(buf.cursor + i - 1, first ? Character.toUpperCase(c) : Character.toLowerCase(c));
+            first = false;
+            i++;
+        }
+        drawBuffer();
+        moveCursor(i - 1);
+        return true;
+    }
+
+    private boolean upCaseWord() throws IOException {
+        int i = 1;
+        char c;
+        while (buf.cursor + i - 1 < buf.length() && !isDelimiter((c = buf.buffer.charAt(buf.cursor + i - 1)))) {
+            buf.buffer.setCharAt(buf.cursor + i - 1, Character.toUpperCase(c));
+            i++;
+        }
+        drawBuffer();
+        moveCursor(i - 1);
+        return true;
+    }
+
+    private boolean downCaseWord() throws IOException {
+        int i = 1;
+        char c;
+        while (buf.cursor + i - 1 < buf.length() && !isDelimiter((c = buf.buffer.charAt(buf.cursor + i - 1)))) {
+            buf.buffer.setCharAt(buf.cursor + i - 1, Character.toLowerCase(c));
+            i++;
+        }
+        drawBuffer();
+        moveCursor(i - 1);
+        return true;
+    }
+
+    /**
+     * Performs character transpose. The character prior to the cursor and the
+     * character under the cursor are swapped and the cursor is advanced one
+     * character unless you are already at the end of the line.
+     *
+     * @param count The number of times to perform the transpose
+     * @return true if the operation succeeded, false otherwise (e.g. transpose
+     *   cannot happen at the beginning of the line).
+     * @throws IOException
+     */
+    private boolean transposeChars(int count) throws IOException {
+        for (; count > 0; --count) {
+            if (buf.cursor == 0 || buf.cursor == buf.buffer.length()) {
+                return false;
+            }
+
+            int first  = buf.cursor-1;
+            int second = buf.cursor;
+
+            char tmp = buf.buffer.charAt (first);
+            buf.buffer.setCharAt(first, buf.buffer.charAt(second));
+            buf.buffer.setCharAt(second, tmp);
+
+            // This could be done more efficiently by only re-drawing at the end.
+            moveInternal(-1);
+            drawBuffer();
+            moveInternal(2);
+        }
+
+        return true;
+    }
+
+    public boolean isKeyMap(String name) {
+        // Current keymap.
+        KeyMap map = consoleKeys.getKeys();
+        KeyMap mapByName = consoleKeys.getKeyMaps().get(name);
+
+        if (mapByName == null)
+            return false;
+
+        /*
+         * This may not be safe to do, but there doesn't appear to be a
+         * clean way to find this information out.
+         */
+        return map == mapByName;
+    }
+
+
+    /**
+     * The equivalent of hitting &lt;RET&gt;.  The line is considered
+     * complete and is returned.
+     *
+     * @return The completed line of text.
+     * @throws IOException
+     */
+    public String accept() throws IOException {
+        moveToEnd();
+        println(); // output newline
+        flush();
+        return finishBuffer();
+    }
+
+    private void abort() throws IOException {
+        beep();
+        buf.clear();
+        println();
+        redrawLine();
+    }
+
+    /**
+     * Move the cursor <i>where</i> characters.
+     *
+     * @param num   If less than 0, move abs(<i>where</i>) to the left, otherwise move <i>where</i> to the right.
+     * @return      The number of spaces we moved
+     */
+    public int moveCursor(final int num) throws IOException {
+        int where = num;
+
+        if ((buf.cursor == 0) && (where <= 0)) {
+            return 0;
+        }
+
+        if ((buf.cursor == buf.buffer.length()) && (where >= 0)) {
+            return 0;
+        }
+
+        if ((buf.cursor + where) < 0) {
+            where = -buf.cursor;
+        }
+        else if ((buf.cursor + where) > buf.buffer.length()) {
+            where = buf.buffer.length() - buf.cursor;
+        }
+
+        moveInternal(where);
+
+        return where;
+    }
+
+    /**
+     * Move the cursor <i>where</i> characters, without checking the current buffer.
+     *
+     * @param where the number of characters to move to the right or left.
+     */
+    private void moveInternal(final int where) throws IOException {
+        // debug ("move cursor " + where + " ("
+        // + buf.cursor + " => " + (buf.cursor + where) + ")");
+        buf.cursor += where;
+
+        if (terminal.isAnsiSupported()) {
+            if (where < 0) {
+                back(Math.abs(where));
+            } else {
+                int width = getTerminal().getWidth();
+                int cursor = getCursorPosition();
+                int oldLine = (cursor - where) / width;
+                int newLine = cursor / width;
+                if (newLine > oldLine) {
+                    printAnsiSequence((newLine - oldLine) + "B");
+                }
+                printAnsiSequence(1 +(cursor % width) + "G");
+            }
+//            flush();
+            return;
+        }
+
+        char c;
+
+        if (where < 0) {
+            int len = 0;
+            for (int i = buf.cursor; i < buf.cursor - where; i++) {
+                if (buf.buffer.charAt(i) == '\t') {
+                    len += TAB_WIDTH;
+                }
+                else {
+                    len++;
+                }
+            }
+
+            char chars[] = new char[len];
+            Arrays.fill(chars, BACKSPACE);
+            out.write(chars);
+
+            return;
+        }
+        else if (buf.cursor == 0) {
+            return;
+        }
+        else if (mask != null) {
+            c = mask;
+        }
+        else {
+            print(buf.buffer.substring(buf.cursor - where, buf.cursor).toCharArray());
+            return;
+        }
+
+        // null character mask: don't output anything
+        if (mask == NULL_MASK) {
+            return;
+        }
+
+        print(c, Math.abs(where));
+    }
+
+    // FIXME: replace() is not used
+
+    public final boolean replace(final int num, final String replacement) {
+        buf.buffer.replace(buf.cursor - num, buf.cursor, replacement);
+        try {
+            moveCursor(-num);
+            drawBuffer(Math.max(0, num - replacement.length()));
+            moveCursor(replacement.length());
+        }
+        catch (IOException e) {
+            e.printStackTrace();
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Read a character from the console.
+     *
+     * @return the character, or -1 if an EOF is received.
+     */
+    public final int readCharacter() throws IOException {
+        int c = reader.read();
+        if (c >= 0) {
+            Log.trace("Keystroke: ", c);
+            // clear any echo characters
+            if (terminal.isSupported()) {
+                clearEcho(c);
+            }
+        }
+        return c;
+    }
+
+    /**
+     * Clear the echoed characters for the specified character code.
+     */
+    private int clearEcho(final int c) throws IOException {
+        // if the terminal is not echoing, then ignore
+        if (!terminal.isEchoEnabled()) {
+            return 0;
+        }
+
+        // otherwise, clear
+        int num = countEchoCharacters(c);
+        back(num);
+        drawBuffer(num);
+
+        return num;
+    }
+
+    private int countEchoCharacters(final int c) {
+        // tabs as special: we need to determine the number of spaces
+        // to cancel based on what out current cursor position is
+        if (c == 9) {
+            int tabStop = 8; // will this ever be different?
+            int position = getCursorPosition();
+
+            return tabStop - (position % tabStop);
+        }
+
+        return getPrintableCharacters(c).length();
+    }
+
+    /**
+     * Return the number of characters that will be printed when the specified
+     * character is echoed to the screen
+     *
+     * Adapted from cat by Torbjorn Granlund, as repeated in stty by David MacKenzie.
+     */
+    private StringBuilder getPrintableCharacters(final int ch) {
+        StringBuilder sbuff = new StringBuilder();
+
+        if (ch >= 32) {
+            if (ch < 127) {
+                sbuff.append(ch);
+            }
+            else if (ch == 127) {
+                sbuff.append('^');
+                sbuff.append('?');
+            }
+            else {
+                sbuff.append('M');
+                sbuff.append('-');
+
+                if (ch >= (128 + 32)) {
+                    if (ch < (128 + 127)) {
+                        sbuff.append((char) (ch - 128));
+                    }
+                    else {
+                        sbuff.append('^');
+                        sbuff.append('?');
+                    }
+                }
+                else {
+                    sbuff.append('^');
+                    sbuff.append((char) (ch - 128 + 64));
+                }
+            }
+        }
+        else {
+            sbuff.append('^');
+            sbuff.append((char) (ch + 64));
+        }
+
+        return sbuff;
+    }
+
+    public final int readCharacter(final char... allowed) throws IOException {
+        // if we restrict to a limited set and the current character is not in the set, then try again.
+        char c;
+
+        Arrays.sort(allowed); // always need to sort before binarySearch
+
+        while (Arrays.binarySearch(allowed, c = (char) readCharacter()) < 0) {
+            // nothing
+        }
+
+        return c;
+    }
+
+    //
+    // Key Bindings
+    //
+
+    public static final String JLINE_COMPLETION_THRESHOLD = "jline.completion.threshold";
+
+    //
+    // Line Reading
+    //
+
+    /**
+     * Read the next line and return the contents of the buffer.
+     */
+    public String readLine() throws IOException {
+        return readLine((String) null);
+    }
+
+    /**
+     * Read the next line with the specified character mask. If null, then
+     * characters will be echoed. If 0, then no characters will be echoed.
+     */
+    public String readLine(final Character mask) throws IOException {
+        return readLine(null, mask);
+    }
+
+    public String readLine(final String prompt) throws IOException {
+        return readLine(prompt, null);
+    }
+
+    /**
+     * Sets the current keymap by name. Supported keymaps are "emacs",
+     * "vi-insert", "vi-move".
+     * @param name The name of the keymap to switch to
+     * @return true if the keymap was set, or false if the keymap is
+     *    not recognized.
+     */
+    public boolean setKeyMap(String name) {
+        return consoleKeys.setKeyMap(name);
+    }
+
+    /**
+     * Returns the name of the current key mapping.
+     * @return the name of the key mapping. This will be the canonical name
+     *   of the current mode of the key map and may not reflect the name that
+     *   was used with {@link #setKeyMap(String)}.
+     */
+    public String getKeyMap() {
+        return consoleKeys.getKeys().getName();
+    }
+
+    /**
+     * Read a line from the <i>in</i> {@link InputStream}, and return the line
+     * (without any trailing newlines).
+     *
+     * @param prompt    The prompt to issue to the console, may be null.
+     * @return          A line that is read from the terminal, or null if there was null input (e.g., <i>CTRL-D</i>
+     *                  was pressed).
+     */
+    public String readLine(String prompt, final Character mask) throws IOException {
+        // prompt may be null
+        // mask may be null
+
+        /*
+         * This is the accumulator for VI-mode repeat count. That is, while in
+         * move mode, if you type 30x it will delete 30 characters. This is
+         * where the "30" is accumulated until the command is struck.
+         */
+        int repeatCount = 0;
+
+        // FIXME: This blows, each call to readLine will reset the console's state which doesn't seem very nice.
+        this.mask = mask;
+        if (prompt != null) {
+            setPrompt(prompt);
+        }
+        else {
+            prompt = getPrompt();
+        }
+
+        try {
+            if (!terminal.isSupported()) {
+                beforeReadLine(prompt, mask);
+            }
+
+            if (prompt != null && prompt.length() > 0) {
+                out.write(prompt);
+                out.flush();
+            }
+
+            // if the terminal is unsupported, just use plain-java reading
+            if (!terminal.isSupported()) {
+                return readLineSimple();
+            }
+
+            if (handleUserInterrupt && (terminal instanceof UnixTerminal)) {
+                ((UnixTerminal) terminal).disableInterruptCharacter();
+            }
+
+            String originalPrompt = this.prompt;
+
+            state = State.NORMAL;
+
+            boolean success = true;
+
+            StringBuilder sb = new StringBuilder();
+            Stack<Character> pushBackChar = new Stack<Character>();
+            while (true) {
+                int c = pushBackChar.isEmpty() ? readCharacter() : pushBackChar.pop ();
+                if (c == -1) {
+                    return null;
+                }
+                sb.appendCodePoint(c);
+
+                if (recording) {
+                    macro += new String(new int[]{c}, 0, 1);
+                }
+
+                Object o = getKeys().getBound( sb );
+                /*
+                 * The kill ring keeps record of whether or not the
+                 * previous command was a yank or a kill. We reset
+                 * that state here if needed.
+                 */
+                if (!recording && !(o instanceof KeyMap)) {
+                    if (o != Operation.YANK_POP && o != Operation.YANK) {
+                        killRing.resetLastYank();
+                    }
+                    if (o != Operation.KILL_LINE && o != Operation.KILL_WHOLE_LINE
+                        && o != Operation.BACKWARD_KILL_WORD && o != Operation.KILL_WORD
+                        && o != Operation.UNIX_LINE_DISCARD && o != Operation.UNIX_WORD_RUBOUT) {
+                        killRing.resetLastKill();
+                    }
+                }
+
+                if (o == Operation.DO_LOWERCASE_VERSION) {
+                    sb.setLength( sb.length() - 1);
+                    sb.append( Character.toLowerCase( (char) c ));
+                    o = getKeys().getBound( sb );
+                }
+
+                /*
+                 * A KeyMap indicates that the key that was struck has a
+                 * number of keys that can follow it as indicated in the
+                 * map. This is used primarily for Emacs style ESC-META-x
+                 * lookups. Since more keys must follow, go back to waiting
+                 * for the next key.
+                 */
+                if ( o instanceof KeyMap ) {
+                    /*
+                     * The ESC key (#27) is special in that it is ambiguous until
+                     * you know what is coming next.  The ESC could be a literal
+                     * escape, like the user entering vi-move mode, or it could
+                     * be part of a terminal control sequence.  The following
+                     * logic attempts to disambiguate things in the same
+                     * fashion as regular vi or readline.
+                     *
+                     * When ESC is encountered and there is no other pending
+                     * character in the pushback queue, then attempt to peek
+                     * into the input stream (if the feature is enabled) for
+                     * 150ms. If nothing else is coming, then assume it is
+                     * not a terminal control sequence, but a raw escape.
+                     */
+                    if (c == 27
+                            && pushBackChar.isEmpty()
+                            && in.isNonBlockingEnabled()
+                            && in.peek(escapeTimeout) == -2) {
+                        o = ((KeyMap) o).getAnotherKey();
+                        if (o == null || o instanceof KeyMap) {
+                            continue;
+                        }
+                        sb.setLength(0);
+                    }
+                    else {
+                        continue;
+                    }
+                }
+
+                /*
+                 * If we didn't find a binding for the key and there is
+                 * more than one character accumulated then start checking
+                 * the largest span of characters from the beginning to
+                 * see if there is a binding for them.
+                 *
+                 * For example if our buffer has ESC,CTRL-M,C the getBound()
+                 * called previously indicated that there is no binding for
+                 * this sequence, so this then checks ESC,CTRL-M, and failing
+                 * that, just ESC. Each keystroke that is pealed off the end
+                 * during these tests is stuffed onto the pushback buffer so
+                 * they won't be lost.
+                 *
+                 * If there is no binding found, then we go back to waiting for
+                 * input.
+                 */
+                while ( o == null && sb.length() > 0 ) {
+                    c = sb.charAt( sb.length() - 1 );
+                    sb.setLength( sb.length() - 1 );
+                    Object o2 = getKeys().getBound( sb );
+                    if ( o2 instanceof KeyMap ) {
+                        o = ((KeyMap) o2).getAnotherKey();
+                        if ( o == null ) {
+                            continue;
+                        } else {
+                            pushBackChar.push( (char) c );
+                        }
+                    }
+                }
+
+                if ( o == null ) {
+                    continue;
+                }
+                Log.trace("Binding: ", o);
+
+
+                // Handle macros
+                if (o instanceof String) {
+                    String macro = (String) o;
+                    for (int i = 0; i < macro.length(); i++) {
+                        pushBackChar.push(macro.charAt(macro.length() - 1 - i));
+                    }
+                    sb.setLength( 0 );
+                    continue;
+                }
+
+                // Handle custom callbacks
+                //original code:
+//                if (o instanceof ActionListener) {
+//                    ((ActionListener) o).actionPerformed(null);
+//                    sb.setLength( 0 );
+//                    continue;
+//                }
+                //using reflection to avoid dependency on java.desktop:
+                try {
+                    Class<?> actionListener =
+                            Class.forName("java.awt.event.ActionListener", false, ClassLoader.getSystemClassLoader());
+                    Class<?> actionEvent =
+                            Class.forName("java.awt.event.ActionEvent", false, ClassLoader.getSystemClassLoader());
+                    if (actionListener.isAssignableFrom(o.getClass())) {
+                        Method actionPerformed =
+                                actionListener.getMethod("actionPerformed", actionEvent);
+                        try {
+                            actionPerformed.invoke(o, (Object) null);
+                        } catch (InvocationTargetException ex ) {
+                            Log.error("Exception while running registered action", ex);
+                        }
+                        sb.setLength( 0 );
+                        continue;
+                    }
+                } catch (ReflectiveOperationException ex) {
+                    //ignore
+                }
+
+                // Search mode.
+                //
+                // Note that we have to do this first, because if there is a command
+                // not linked to a search command, we leave the search mode and fall
+                // through to the normal state.
+                if (state == State.SEARCH || state == State.FORWARD_SEARCH) {
+                    int cursorDest = -1;
+                    switch ( ((Operation) o )) {
+                        case ABORT:
+                            state = State.NORMAL;
+                            buf.clear();
+                            buf.buffer.append(searchTerm);
+                            break;
+
+                        case REVERSE_SEARCH_HISTORY:
+                            state = State.SEARCH;
+                            if (searchTerm.length() == 0) {
+                                searchTerm.append(previousSearchTerm);
+                            }
+
+                            if (searchIndex > 0) {
+                                searchIndex = searchBackwards(searchTerm.toString(), searchIndex);
+                            }
+                            break;
+
+                        case FORWARD_SEARCH_HISTORY:
+                            state = State.FORWARD_SEARCH;
+                            if (searchTerm.length() == 0) {
+                                searchTerm.append(previousSearchTerm);
+                            }
+
+                            if (searchIndex > -1 && searchIndex < history.size() - 1) {
+                                searchIndex = searchForwards(searchTerm.toString(), searchIndex);
+                            }
+                            break;
+
+                        case BACKWARD_DELETE_CHAR:
+                            if (searchTerm.length() > 0) {
+                                searchTerm.deleteCharAt(searchTerm.length() - 1);
+                                if (state == State.SEARCH) {
+                                    searchIndex = searchBackwards(searchTerm.toString());
+                                } else {
+                                    searchIndex = searchForwards(searchTerm.toString());
+                                }
+                            }
+                            break;
+
+                        case SELF_INSERT:
+                            searchTerm.appendCodePoint(c);
+                            if (state == State.SEARCH) {
+                                searchIndex = searchBackwards(searchTerm.toString());
+                            } else {
+                                searchIndex = searchForwards(searchTerm.toString());
+                            }
+                            break;
+
+                        default:
+                            // Set buffer and cursor position to the found string.
+                            if (searchIndex != -1) {
+                                history.moveTo(searchIndex);
+                                // set cursor position to the found string
+                                cursorDest = history.current().toString().indexOf(searchTerm.toString());
+                            }
+                            state = State.NORMAL;
+                            break;
+                    }
+
+                    // if we're still in search mode, print the search status
+                    if (state == State.SEARCH || state == State.FORWARD_SEARCH) {
+                        if (searchTerm.length() == 0) {
+                            if (state == State.SEARCH) {
+                                printSearchStatus("", "");
+                            } else {
+                                printForwardSearchStatus("", "");
+                            }
+                            searchIndex = -1;
+                        } else {
+                            if (searchIndex == -1) {
+                                beep();
+                                printSearchStatus(searchTerm.toString(), "");
+                            } else if (state == State.SEARCH) {
+                                printSearchStatus(searchTerm.toString(), history.get(searchIndex).toString());
+                            } else {
+                                printForwardSearchStatus(searchTerm.toString(), history.get(searchIndex).toString());
+                            }
+                        }
+                    }
+                    // otherwise, restore the line
+                    else {
+                        restoreLine(originalPrompt, cursorDest);
+                    }
+                }
+                if (state != State.SEARCH && state != State.FORWARD_SEARCH) {
+                    /*
+                     * If this is still false at the end of the switch, then
+                     * we reset our repeatCount to 0.
+                     */
+                    boolean isArgDigit = false;
+
+                    /*
+                     * Every command that can be repeated a specified number
+                     * of times, needs to know how many times to repeat, so
+                     * we figure that out here.
+                     */
+                    int count = (repeatCount == 0) ? 1 : repeatCount;
+
+                    /*
+                     * Default success to true. You only need to explicitly
+                     * set it if something goes wrong.
+                     */
+                    success = true;
+
+                    if (o instanceof Operation) {
+                        Operation op = (Operation)o;
+                        /*
+                         * Current location of the cursor (prior to the operation).
+                         * These are used by vi *-to operation (e.g. delete-to)
+                         * so we know where we came from.
+                         */
+                        int     cursorStart = buf.cursor;
+                        State   origState   = state;
+
+                        /*
+                         * If we are on a "vi" movement based operation, then we
+                         * need to restrict the sets of inputs pretty heavily.
+                         */
+                        if (state == State.VI_CHANGE_TO
+                            || state == State.VI_YANK_TO
+                            || state == State.VI_DELETE_TO) {
+
+                            op = viDeleteChangeYankToRemap(op);
+                        }
+
+                        switch ( op ) {
+                            case COMPLETE: // tab
+                                // There is an annoyance with tab completion in that
+                                // sometimes the user is actually pasting input in that
+                                // has physical tabs in it.  This attempts to look at how
+                                // quickly a character follows the tab, if the character
+                                // follows *immediately*, we assume it is a tab literal.
+                                boolean isTabLiteral = false;
+                                if (copyPasteDetection
+                                    && c == 9
+                                    && (!pushBackChar.isEmpty()
+                                        || (in.isNonBlockingEnabled() && in.peek(escapeTimeout) != -2))) {
+                                    isTabLiteral = true;
+                                }
+
+                                if (! isTabLiteral) {
+                                    success = complete();
+                                }
+                                else {
+                                    putString(sb);
+                                }
+                                break;
+
+                            case POSSIBLE_COMPLETIONS:
+                                printCompletionCandidates();
+                                break;
+
+                            case BEGINNING_OF_LINE:
+                                success = setCursorPosition(0);
+                                break;
+
+                            case YANK:
+                                success = yank();
+                                break;
+
+                            case YANK_POP:
+                                success = yankPop();
+                                break;
+
+                            case KILL_LINE: // CTRL-K
+                                success = killLine();
+                                break;
+
+                            case KILL_WHOLE_LINE:
+                                success = setCursorPosition(0) && killLine();
+                                break;
+
+                            case CLEAR_SCREEN: // CTRL-L
+                                success = clearScreen();
+                                redrawLine();
+                                break;
+
+                            case OVERWRITE_MODE:
+                                buf.setOverTyping(!buf.isOverTyping());
+                                break;
+
+                            case SELF_INSERT:
+                                putString(sb);
+                                break;
+
+                            case ACCEPT_LINE:
+                                return accept();
+
+                            case ABORT:
+                                if (searchTerm == null) {
+                                    abort();
+                                }
+                                break;
+
+                            case INTERRUPT:
+                                if (handleUserInterrupt) {
+                                    println();
+                                    flush();
+                                    String partialLine = buf.buffer.toString();
+                                    buf.clear();
+                                    history.moveToEnd();
+                                    throw new UserInterruptException(partialLine);
+                                }
+                                break;
+
+                            /*
+                             * VI_MOVE_ACCEPT_LINE is the result of an ENTER
+                             * while in move mode. This is the same as a normal
+                             * ACCEPT_LINE, except that we need to enter
+                             * insert mode as well.
+                             */
+                            case VI_MOVE_ACCEPT_LINE:
+                                consoleKeys.setKeyMap(KeyMap.VI_INSERT);
+                                return accept();
+
+                            case BACKWARD_WORD:
+                                success = previousWord();
+                                break;
+
+                            case FORWARD_WORD:
+                                success = nextWord();
+                                break;
+
+                            case PREVIOUS_HISTORY:
+                                success = moveHistory(false);
+                                break;
+
+                            /*
+                             * According to bash/readline move through history
+                             * in "vi" mode will move the cursor to the
+                             * start of the line. If there is no previous
+                             * history, then the cursor doesn't move.
+                             */
+                            case VI_PREVIOUS_HISTORY:
+                                success = moveHistory(false, count)
+                                    && setCursorPosition(0);
+                                break;
+
+                            case NEXT_HISTORY:
+                                success = moveHistory(true);
+                                break;
+
+                            /*
+                             * According to bash/readline move through history
+                             * in "vi" mode will move the cursor to the
+                             * start of the line. If there is no next history,
+                             * then the cursor doesn't move.
+                             */
+                            case VI_NEXT_HISTORY:
+                                success = moveHistory(true, count)
+                                    && setCursorPosition(0);
+                                break;
+
+                            case BACKWARD_DELETE_CHAR: // backspace
+                                success = backspace();
+                                break;
+
+                            case EXIT_OR_DELETE_CHAR:
+                                if (buf.buffer.length() == 0) {
+                                    return null;
+                                }
+                                success = deleteCurrentCharacter();
+                                break;
+
+                            case DELETE_CHAR: // delete
+                                success = deleteCurrentCharacter();
+                                break;
+
+                            case BACKWARD_CHAR:
+                                success = moveCursor(-(count)) != 0;
+                                break;
+
+                            case FORWARD_CHAR:
+                                success = moveCursor(count) != 0;
+                                break;
+
+                            case UNIX_LINE_DISCARD:
+                                success = resetLine();
+                                break;
+
+                            case UNIX_WORD_RUBOUT:
+                                success = unixWordRubout(count);
+                                break;
+
+                            case BACKWARD_KILL_WORD:
+                                success = deletePreviousWord();
+                                break;
+
+                            case KILL_WORD:
+                                success = deleteNextWord();
+                                break;
+
+                            case BEGINNING_OF_HISTORY:
+                                success = history.moveToFirst();
+                                if (success) {
+                                    setBuffer(history.current());
+                                }
+                                break;
+
+                            case END_OF_HISTORY:
+                                success = history.moveToLast();
+                                if (success) {
+                                    setBuffer(history.current());
+                                }
+                                break;
+
+                            case HISTORY_SEARCH_BACKWARD:
+                                searchTerm = new StringBuffer(buf.upToCursor());
+                                searchIndex = searchBackwards(searchTerm.toString(), history.index(), true);
+
+                                if (searchIndex == -1) {
+                                    beep();
+                                } else {
+                                    // Maintain cursor position while searching.
+                                    success = history.moveTo(searchIndex);
+                                    if (success) {
+                                        setBufferKeepPos(history.current());
+                                    }
+                                }
+                                break;
+
+                            case HISTORY_SEARCH_FORWARD:
+                                searchTerm = new StringBuffer(buf.upToCursor());
+                                int index = history.index() + 1;
+
+                                if (index == history.size()) {
+                                    history.moveToEnd();
+                                    setBufferKeepPos(searchTerm.toString());
+                                } else if (index < history.size()) {
+                                    searchIndex = searchForwards(searchTerm.toString(), index, true);
+                                    if (searchIndex == -1) {
+                                        beep();
+                                    } else {
+                                        // Maintain cursor position while searching.
+                                        success = history.moveTo(searchIndex);
+                                        if (success) {
+                                            setBufferKeepPos(history.current());
+                                        }
+                                    }
+                                }
+                                break;
+
+                            case REVERSE_SEARCH_HISTORY:
+                                if (searchTerm != null) {
+                                    previousSearchTerm = searchTerm.toString();
+                                }
+                                searchTerm = new StringBuffer(buf.buffer);
+                                state = State.SEARCH;
+                                if (searchTerm.length() > 0) {
+                                    searchIndex = searchBackwards(searchTerm.toString());
+                                    if (searchIndex == -1) {
+                                        beep();
+                                    }
+                                    printSearchStatus(searchTerm.toString(),
+                                            searchIndex > -1 ? history.get(searchIndex).toString() : "");
+                                } else {
+                                    searchIndex = -1;
+                                    printSearchStatus("", "");
+                                }
+                                break;
+
+                            case FORWARD_SEARCH_HISTORY:
+                                if (searchTerm != null) {
+                                    previousSearchTerm = searchTerm.toString();
+                                }
+                                searchTerm = new StringBuffer(buf.buffer);
+                                state = State.FORWARD_SEARCH;
+                                if (searchTerm.length() > 0) {
+                                    searchIndex = searchForwards(searchTerm.toString());
+                                    if (searchIndex == -1) {
+                                        beep();
+                                    }
+                                    printForwardSearchStatus(searchTerm.toString(),
+                                            searchIndex > -1 ? history.get(searchIndex).toString() : "");
+                                } else {
+                                    searchIndex = -1;
+                                    printForwardSearchStatus("", "");
+                                }
+                                break;
+
+                            case CAPITALIZE_WORD:
+                                success = capitalizeWord();
+                                break;
+
+                            case UPCASE_WORD:
+                                success = upCaseWord();
+                                break;
+
+                            case DOWNCASE_WORD:
+                                success = downCaseWord();
+                                break;
+
+                            case END_OF_LINE:
+                                success = moveToEnd();
+                                break;
+
+                            case TAB_INSERT:
+                                putString( "\t" );
+                                break;
+
+                            case RE_READ_INIT_FILE:
+                                consoleKeys.loadKeys(appName, inputrcUrl);
+                                break;
+
+                            case START_KBD_MACRO:
+                                recording = true;
+                                break;
+
+                            case END_KBD_MACRO:
+                                recording = false;
+                                macro = macro.substring(0, macro.length() - sb.length());
+                                break;
+
+                            case CALL_LAST_KBD_MACRO:
+                                for (int i = 0; i < macro.length(); i++) {
+                                    pushBackChar.push(macro.charAt(macro.length() - 1 - i));
+                                }
+                                sb.setLength( 0 );
+                                break;
+
+                            case VI_EDITING_MODE:
+                                consoleKeys.setKeyMap(KeyMap.VI_INSERT);
+                                break;
+
+                            case VI_MOVEMENT_MODE:
+                                /*
+                                 * If we are re-entering move mode from an
+                                 * aborted yank-to, delete-to, change-to then
+                                 * don't move the cursor back. The cursor is
+                                 * only move on an expclit entry to movement
+                                 * mode.
+                                 */
+                                if (state == State.NORMAL) {
+                                    moveCursor(-1);
+                                }
+                                consoleKeys.setKeyMap(KeyMap.VI_MOVE);
+                                break;
+
+                            case VI_INSERTION_MODE:
+                                consoleKeys.setKeyMap(KeyMap.VI_INSERT);
+                                break;
+
+                            case VI_APPEND_MODE:
+                                moveCursor(1);
+                                consoleKeys.setKeyMap(KeyMap.VI_INSERT);
+                                break;
+
+                            case VI_APPEND_EOL:
+                                success = moveToEnd();
+                                consoleKeys.setKeyMap(KeyMap.VI_INSERT);
+                                break;
+
+                            /*
+                             * Handler for CTRL-D. Attempts to follow readline
+                             * behavior. If the line is empty, then it is an EOF
+                             * otherwise it is as if the user hit enter.
+                             */
+                            case VI_EOF_MAYBE:
+                                if (buf.buffer.length() == 0) {
+                                    return null;
+                                }
+                                return accept();
+
+                            case TRANSPOSE_CHARS:
+                                success = transposeChars(count);
+                                break;
+
+                            case INSERT_COMMENT:
+                                return insertComment (false);
+
+                            case INSERT_CLOSE_CURLY:
+                                insertClose("}");
+                                break;
+
+                            case INSERT_CLOSE_PAREN:
+                                insertClose(")");
+                                break;
+
+                            case INSERT_CLOSE_SQUARE:
+                                insertClose("]");
+                                break;
+
+                            case VI_INSERT_COMMENT:
+                                return insertComment (true);
+
+                            case VI_MATCH:
+                                success = viMatch ();
+                                break;
+
+                            case VI_SEARCH:
+                                int lastChar = viSearch(sb.charAt (0));
+                                if (lastChar != -1) {
+                                    pushBackChar.push((char)lastChar);
+                                }
+                                break;
+
+                            case VI_ARG_DIGIT:
+                                repeatCount = (repeatCount * 10) + sb.charAt(0) - '0';
+                                isArgDigit = true;
+                                break;
+
+                            case VI_BEGNNING_OF_LINE_OR_ARG_DIGIT:
+                                if (repeatCount > 0) {
+                                    repeatCount = (repeatCount * 10) + sb.charAt(0) - '0';
+                                    isArgDigit = true;
+                                }
+                                else {
+                                    success = setCursorPosition(0);
+                                }
+                                break;
+
+                            case VI_FIRST_PRINT:
+                                success = setCursorPosition(0) && viNextWord(1);
+                                break;
+
+                            case VI_PREV_WORD:
+                                success = viPreviousWord(count);
+                                break;
+
+                            case VI_NEXT_WORD:
+                                success = viNextWord(count);
+                                break;
+
+                            case VI_END_WORD:
+                                success = viEndWord(count);
+                                break;
+
+                            case VI_INSERT_BEG:
+                                success = setCursorPosition(0);
+                                consoleKeys.setKeyMap(KeyMap.VI_INSERT);
+                                break;
+
+                            case VI_RUBOUT:
+                                success = viRubout(count);
+                                break;
+
+                            case VI_DELETE:
+                                success = viDelete(count);
+                                break;
+
+                            case VI_DELETE_TO:
+                                /*
+                                 * This is a weird special case. In vi
+                                 * "dd" deletes the current line. So if we
+                                 * get a delete-to, followed by a delete-to,
+                                 * we delete the line.
+                                 */
+                                if (state == State.VI_DELETE_TO) {
+                                    success = setCursorPosition(0) && killLine();
+                                    state = origState = State.NORMAL;
+                                }
+                                else {
+                                    state = State.VI_DELETE_TO;
+                                }
+                                break;
+
+                            case VI_YANK_TO:
+                                // Similar to delete-to, a "yy" yanks the whole line.
+                                if (state == State.VI_YANK_TO) {
+                                    yankBuffer = buf.buffer.toString();
+                                    state = origState = State.NORMAL;
+                                }
+                                else {
+                                    state = State.VI_YANK_TO;
+                                }
+                                break;
+
+                            case VI_CHANGE_TO:
+                                if (state == State.VI_CHANGE_TO) {
+                                    success = setCursorPosition(0) && killLine();
+                                    state = origState = State.NORMAL;
+                                    consoleKeys.setKeyMap(KeyMap.VI_INSERT);
+                                }
+                                else {
+                                    state = State.VI_CHANGE_TO;
+                                }
+                                break;
+
+                            case VI_KILL_WHOLE_LINE:
+                                success = setCursorPosition(0) && killLine();
+                                consoleKeys.setKeyMap(KeyMap.VI_INSERT);
+                                break;
+
+                            case VI_PUT:
+                                success = viPut(count);
+                                break;
+
+                            case VI_CHAR_SEARCH: {
+                                 // ';' and ',' don't need another character. They indicate repeat next or repeat prev.
+                                int searchChar = (c != ';' && c != ',')
+                                    ? (pushBackChar.isEmpty()
+                                        ? readCharacter()
+                                        : pushBackChar.pop ())
+                                    : 0;
+
+                                    success = viCharSearch(count, c, searchChar);
+                                }
+                                break;
+
+                            case VI_CHANGE_CASE:
+                                success = viChangeCase(count);
+                                break;
+
+                            case VI_CHANGE_CHAR:
+                                success = viChangeChar(count,
+                                    pushBackChar.isEmpty()
+                                        ? readCharacter()
+                                        : pushBackChar.pop());
+                                break;
+
+                            case VI_DELETE_TO_EOL:
+                                success = viDeleteTo(buf.cursor, buf.buffer.length(), false);
+                                break;
+
+                            case VI_CHANGE_TO_EOL:
+                                success = viDeleteTo(buf.cursor, buf.buffer.length(), true);
+                                consoleKeys.setKeyMap(KeyMap.VI_INSERT);
+                                break;
+
+                            case EMACS_EDITING_MODE:
+                                consoleKeys.setKeyMap(KeyMap.EMACS);
+                                break;
+
+                            default:
+                                break;
+                        }
+
+                        /*
+                         * If we were in a yank-to, delete-to, move-to
+                         * when this operation started, then fall back to
+                         */
+                        if (origState != State.NORMAL) {
+                            if (origState == State.VI_DELETE_TO) {
+                                success = viDeleteTo(cursorStart, buf.cursor, false);
+                            }
+                            else if (origState == State.VI_CHANGE_TO) {
+                                success = viDeleteTo(cursorStart, buf.cursor, true);
+                                consoleKeys.setKeyMap(KeyMap.VI_INSERT);
+                            }
+                            else if (origState == State.VI_YANK_TO) {
+                                success = viYankTo(cursorStart, buf.cursor);
+                            }
+                            state = State.NORMAL;
+                        }
+
+                        /*
+                         * Another subtly. The check for the NORMAL state is
+                         * to ensure that we do not clear out the repeat
+                         * count when in delete-to, yank-to, or move-to modes.
+                         */
+                        if (state == State.NORMAL && !isArgDigit) {
+                            /*
+                             * If the operation performed wasn't a vi argument
+                             * digit, then clear out the current repeatCount;
+                             */
+                            repeatCount = 0;
+                        }
+
+                        if (state != State.SEARCH && state != State.FORWARD_SEARCH) {
+                            previousSearchTerm = "";
+                            searchTerm = null;
+                            searchIndex = -1;
+                        }
+                    }
+                }
+                if (!success) {
+                    beep();
+                }
+                sb.setLength( 0 );
+                flush();
+            }
+        }
+        finally {
+            if (!terminal.isSupported()) {
+                afterReadLine();
+            }
+            if (handleUserInterrupt && (terminal instanceof UnixTerminal)) {
+                ((UnixTerminal) terminal).enableInterruptCharacter();
+            }
+        }
+    }
+
+    /**
+     * Read a line for unsupported terminals.
+     */
+    private String readLineSimple() throws IOException {
+        StringBuilder buff = new StringBuilder();
+
+        if (skipLF) {
+            skipLF = false;
+
+            int i = readCharacter();
+
+            if (i == -1 || i == '\r') {
+                return buff.toString();
+            } else if (i == '\n') {
+                // ignore
+            } else {
+                buff.append((char) i);
+            }
+        }
+
+        while (true) {
+            int i = readCharacter();
+
+            if (i == -1 && buff.length() == 0) {
+              return null;
+            }
+
+            if (i == -1 || i == '\n') {
+                return buff.toString();
+            } else if (i == '\r') {
+                skipLF = true;
+                return buff.toString();
+            } else {
+                buff.append((char) i);
+            }
+        }
+    }
+
+    //
+    // Completion
+    //
+
+    private final List<Completer> completers = new LinkedList<Completer>();
+
+    private CompletionHandler completionHandler = new CandidateListCompletionHandler();
+
+    /**
+     * Add the specified {@link jline.console.completer.Completer} to the list of handlers for tab-completion.
+     *
+     * @param completer the {@link jline.console.completer.Completer} to add
+     * @return true if it was successfully added
+     */
+    public boolean addCompleter(final Completer completer) {
+        return completers.add(completer);
+    }
+
+    /**
+     * Remove the specified {@link jline.console.completer.Completer} from the list of handlers for tab-completion.
+     *
+     * @param completer     The {@link Completer} to remove
+     * @return              True if it was successfully removed
+     */
+    public boolean removeCompleter(final Completer completer) {
+        return completers.remove(completer);
+    }
+
+    /**
+     * Returns an unmodifiable list of all the completers.
+     */
+    public Collection<Completer> getCompleters() {
+        return Collections.unmodifiableList(completers);
+    }
+
+    public void setCompletionHandler(final CompletionHandler handler) {
+        this.completionHandler = checkNotNull(handler);
+    }
+
+    public CompletionHandler getCompletionHandler() {
+        return this.completionHandler;
+    }
+
+    /**
+     * Use the completers to modify the buffer with the appropriate completions.
+     *
+     * @return true if successful
+     */
+    protected boolean complete() throws IOException {
+        // debug ("tab for (" + buf + ")");
+        if (completers.size() == 0) {
+            return false;
+        }
+
+        List<CharSequence> candidates = new LinkedList<CharSequence>();
+        String bufstr = buf.buffer.toString();
+        int cursor = buf.cursor;
+
+        int position = -1;
+
+        for (Completer comp : completers) {
+            if ((position = comp.complete(bufstr, cursor, candidates)) != -1) {
+                break;
+            }
+        }
+
+        return candidates.size() != 0 && getCompletionHandler().complete(this, candidates, position);
+    }
+
+    protected void printCompletionCandidates() throws IOException {
+        // debug ("tab for (" + buf + ")");
+        if (completers.size() == 0) {
+            return;
+        }
+
+        List<CharSequence> candidates = new LinkedList<CharSequence>();
+        String bufstr = buf.buffer.toString();
+        int cursor = buf.cursor;
+
+        for (Completer comp : completers) {
+            if (comp.complete(bufstr, cursor, candidates) != -1) {
+                break;
+            }
+        }
+        CandidateListCompletionHandler.printCandidates(this, candidates);
+        drawLine();
+    }
+
+    /**
+     * The number of tab-completion candidates above which a warning will be
+     * prompted before showing all the candidates.
+     */
+    private int autoprintThreshold = Configuration.getInteger(JLINE_COMPLETION_THRESHOLD, 100); // same default as bash
+
+    /**
+     * @param threshold the number of candidates to print without issuing a warning.
+     */
+    public void setAutoprintThreshold(final int threshold) {
+        this.autoprintThreshold = threshold;
+    }
+
+    /**
+     * @return the number of candidates to print without issuing a warning.
+     */
+    public int getAutoprintThreshold() {
+        return autoprintThreshold;
+    }
+
+    private boolean paginationEnabled;
+
+    /**
+     * Whether to use pagination when the number of rows of candidates exceeds the height of the terminal.
+     */
+    public void setPaginationEnabled(final boolean enabled) {
+        this.paginationEnabled = enabled;
+    }
+
+    /**
+     * Whether to use pagination when the number of rows of candidates exceeds the height of the terminal.
+     */
+    public boolean isPaginationEnabled() {
+        return paginationEnabled;
+    }
+
+    //
+    // History
+    //
+
+    private History history = new MemoryHistory();
+
+    public void setHistory(final History history) {
+        this.history = history;
+    }
+
+    public History getHistory() {
+        return history;
+    }
+
+    private boolean historyEnabled = true;
+
+    /**
+     * Whether or not to add new commands to the history buffer.
+     */
+    public void setHistoryEnabled(final boolean enabled) {
+        this.historyEnabled = enabled;
+    }
+
+    /**
+     * Whether or not to add new commands to the history buffer.
+     */
+    public boolean isHistoryEnabled() {
+        return historyEnabled;
+    }
+
+    /**
+     * Used in "vi" mode for argumented history move, to move a specific
+     * number of history entries forward or back.
+     *
+     * @param next If true, move forward
+     * @param count The number of entries to move
+     * @return true if the move was successful
+     * @throws IOException
+     */
+    private boolean moveHistory(final boolean next, int count) throws IOException {
+        boolean ok = true;
+        for (int i = 0; i < count && (ok = moveHistory(next)); i++) {
+            /* empty */
+        }
+        return ok;
+    }
+
+    /**
+     * Move up or down the history tree.
+     */
+    private boolean moveHistory(final boolean next) throws IOException {
+        if (next && !history.next()) {
+            return false;
+        }
+        else if (!next && !history.previous()) {
+            return false;
+        }
+
+        setBuffer(history.current());
+
+        return true;
+    }
+
+    //
+    // Printing
+    //
+
+    public static final String CR = Configuration.getLineSeparator();
+
+    /**
+     * Output the specified character to the output stream without manipulating the current buffer.
+     */
+    private void print(final int c) throws IOException {
+        if (c == '\t') {
+            char chars[] = new char[TAB_WIDTH];
+            Arrays.fill(chars, ' ');
+            out.write(chars);
+            return;
+        }
+
+        out.write(c);
+    }
+
+    /**
+     * Output the specified characters to the output stream without manipulating the current buffer.
+     */
+    private void print(final char... buff) throws IOException {
+        int len = 0;
+        for (char c : buff) {
+            if (c == '\t') {
+                len += TAB_WIDTH;
+            }
+            else {
+                len++;
+            }
+        }
+
+        char chars[];
+        if (len == buff.length) {
+            chars = buff;
+        }
+        else {
+            chars = new char[len];
+            int pos = 0;
+            for (char c : buff) {
+                if (c == '\t') {
+                    Arrays.fill(chars, pos, pos + TAB_WIDTH, ' ');
+                    pos += TAB_WIDTH;
+                }
+                else {
+                    chars[pos] = c;
+                    pos++;
+                }
+            }
+        }
+
+        out.write(chars);
+    }
+
+    private void print(final char c, final int num) throws IOException {
+        if (num == 1) {
+            print(c);
+        }
+        else {
+            char[] chars = new char[num];
+            Arrays.fill(chars, c);
+            print(chars);
+        }
+    }
+
+    /**
+     * Output the specified string to the output stream (but not the buffer).
+     */
+    public final void print(final CharSequence s) throws IOException {
+        print(checkNotNull(s).toString().toCharArray());
+    }
+
+    public final void println(final CharSequence s) throws IOException {
+        print(checkNotNull(s).toString().toCharArray());
+        println();
+    }
+
+    /**
+     * Output a platform-dependant newline.
+     */
+    public final void println() throws IOException {
+        print(CR);
+//        flush();
+    }
+
+    //
+    // Actions
+    //
+
+    /**
+     * Issue a delete.
+     *
+     * @return true if successful
+     */
+    public final boolean delete() throws IOException {
+        if (buf.cursor == buf.buffer.length()) {
+          return false;
+        }
+
+        buf.buffer.delete(buf.cursor, buf.cursor + 1);
+        drawBuffer(1);
+
+        return true;
+    }
+
+    /**
+     * Kill the buffer ahead of the current cursor position.
+     *
+     * @return true if successful
+     */
+    public boolean killLine() throws IOException {
+        int cp = buf.cursor;
+        int len = buf.buffer.length();
+
+        if (cp >= len) {
+            return false;
+        }
+
+        int num = len - cp;
+        clearAhead(num, 0);
+
+        char[] killed = new char[num];
+        buf.buffer.getChars(cp, (cp + num), killed, 0);
+        buf.buffer.delete(cp, (cp + num));
+
+        String copy = new String(killed);
+        killRing.add(copy);
+
+        return true;
+    }
+
+    public boolean yank() throws IOException {
+        String yanked = killRing.yank();
+
+        if (yanked == null) {
+            return false;
+        }
+        putString(yanked);
+        return true;
+    }
+
+    public boolean yankPop() throws IOException {
+        if (!killRing.lastYank()) {
+            return false;
+        }
+        String current = killRing.yank();
+        if (current == null) {
+            // This shouldn't happen.
+            return false;
+        }
+        backspace(current.length());
+        String yanked = killRing.yankPop();
+        if (yanked == null) {
+            // This shouldn't happen.
+            return false;
+        }
+
+        putString(yanked);
+        return true;
+    }
+
+    /**
+     * Clear the screen by issuing the ANSI "clear screen" code.
+     */
+    public boolean clearScreen() throws IOException {
+        if (!terminal.isAnsiSupported()) {
+            return false;
+        }
+
+        // send the ANSI code to clear the screen
+        printAnsiSequence("2J");
+
+        // then send the ANSI code to go to position 1,1
+        printAnsiSequence("1;1H");
+
+        return true;
+    }
+
+    /**
+     * Issue an audible keyboard bell.
+     */
+    public void beep() throws IOException {
+        if (bellEnabled) {
+            print(KEYBOARD_BELL);
+            // need to flush so the console actually beeps
+            flush();
+        }
+    }
+
+    //disabled to avoid dependency on java.desktop:
+//    /**
+//     * Paste the contents of the clipboard into the console buffer
+//     *
+//     * @return true if clipboard contents pasted
+//     */
+//    public boolean paste() throws IOException {
+//        Clipboard clipboard;
+//        try { // May throw ugly exception on system without X
+//            clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+//        }
+//        catch (Exception e) {
+//            return false;
+//        }
+//
+//        if (clipboard == null) {
+//            return false;
+//        }
+//
+//        Transferable transferable = clipboard.getContents(null);
+//
+//        if (transferable == null) {
+//            return false;
+//        }
+//
+//        try {
+//            @SuppressWarnings("deprecation")
+//            Object content = transferable.getTransferData(DataFlavor.plainTextFlavor);
+//
+//            // This fix was suggested in bug #1060649 at
+//            // http://sourceforge.net/tracker/index.php?func=detail&aid=1060649&group_id=64033&atid=506056
+//            // to get around the deprecated DataFlavor.plainTextFlavor, but it
+//            // raises a UnsupportedFlavorException on Mac OS X
+//
+//            if (content == null) {
+//                try {
+//                    content = new DataFlavor().getReaderForText(transferable);
+//                }
+//                catch (Exception e) {
+//                    // ignore
+//                }
+//            }
+//
+//            if (content == null) {
+//                return false;
+//            }
+//
+//            String value;
+//
+//            if (content instanceof Reader) {
+//                // TODO: we might want instead connect to the input stream
+//                // so we can interpret individual lines
+//                value = "";
+//                String line;
+//
+//                BufferedReader read = new BufferedReader((Reader) content);
+//                while ((line = read.readLine()) != null) {
+//                    if (value.length() > 0) {
+//                        value += "\n";
+//                    }
+//
+//                    value += line;
+//                }
+//            }
+//            else {
+//                value = content.toString();
+//            }
+//
+//            if (value == null) {
+//                return true;
+//            }
+//
+//            putString(value);
+//
+//            return true;
+//        }
+//        catch (UnsupportedFlavorException e) {
+//            Log.error("Paste failed: ", e);
+//
+//            return false;
+//        }
+//    }
+
+    //disabled to avoid dependency on java.desktop:
+//    //
+//    // Triggered Actions
+//    //
+//
+//    private final Map<Character, ActionListener> triggeredActions = new HashMap<Character, ActionListener>();
+//
+//    /**
+//     * Adding a triggered Action allows to give another curse of action if a character passed the pre-processing.
+//     * <p/>
+//     * Say you want to close the application if the user enter q.
+//     * addTriggerAction('q', new ActionListener(){ System.exit(0); }); would do the trick.
+//     */
+//    public void addTriggeredAction(final char c, final ActionListener listener) {
+//        triggeredActions.put(c, listener);
+//    }
+
+    //
+    // Formatted Output
+    //
+
+    /**
+     * Output the specified {@link Collection} in proper columns.
+     */
+    public void printColumns(final Collection<? extends CharSequence> items) throws IOException {
+        if (items == null || items.isEmpty()) {
+            return;
+        }
+
+        int width = getTerminal().getWidth();
+        int height = getTerminal().getHeight();
+
+        int maxWidth = 0;
+        for (CharSequence item : items) {
+            maxWidth = Math.max(maxWidth, item.length());
+        }
+        maxWidth = maxWidth + 3;
+        Log.debug("Max width: ", maxWidth);
+
+        int showLines;
+        if (isPaginationEnabled()) {
+            showLines = height - 1; // page limit
+        }
+        else {
+            showLines = Integer.MAX_VALUE;
+        }
+
+        StringBuilder buff = new StringBuilder();
+        for (CharSequence item : items) {
+            if ((buff.length() + maxWidth) > width) {
+                println(buff);
+                buff.setLength(0);
+
+                if (--showLines == 0) {
+                    // Overflow
+                    print(resources.getString("DISPLAY_MORE"));
+                    flush();
+                    int c = readCharacter();
+                    if (c == '\r' || c == '\n') {
+                        // one step forward
+                        showLines = 1;
+                    }
+                    else if (c != 'q') {
+                        // page forward
+                        showLines = height - 1;
+                    }
+
+                    back(resources.getString("DISPLAY_MORE").length());
+                    if (c == 'q') {
+                        // cancel
+                        break;
+                    }
+                }
+            }
+
+            // NOTE: toString() is important here due to AnsiString being retarded
+            buff.append(item.toString());
+            for (int i = 0; i < (maxWidth - item.length()); i++) {
+                buff.append(' ');
+            }
+        }
+
+        if (buff.length() > 0) {
+            println(buff);
+        }
+    }
+
+    //
+    // Non-supported Terminal Support
+    //
+
+    private Thread maskThread;
+
+    private void beforeReadLine(final String prompt, final Character mask) {
+        if (mask != null && maskThread == null) {
+            final String fullPrompt = "\r" + prompt
+                + "                 "
+                + "                 "
+                + "                 "
+                + "\r" + prompt;
+
+            maskThread = new Thread()
+            {
+                public void run() {
+                    while (!interrupted()) {
+                        try {
+                            Writer out = getOutput();
+                            out.write(fullPrompt);
+                            out.flush();
+                            sleep(3);
+                        }
+                        catch (IOException e) {
+                            return;
+                        }
+                        catch (InterruptedException e) {
+                            return;
+                        }
+                    }
+                }
+            };
+
+            maskThread.setPriority(Thread.MAX_PRIORITY);
+            maskThread.setDaemon(true);
+            maskThread.start();
+        }
+    }
+
+    private void afterReadLine() {
+        if (maskThread != null && maskThread.isAlive()) {
+            maskThread.interrupt();
+        }
+
+        maskThread = null;
+    }
+
+    /**
+     * Erases the current line with the existing prompt, then redraws the line
+     * with the provided prompt and buffer
+     * @param prompt
+     *            the new prompt
+     * @param buffer
+     *            the buffer to be drawn
+     * @param cursorDest
+     *            where you want the cursor set when the line has been drawn.
+     *            -1 for end of line.
+     * */
+    public void resetPromptLine(String prompt, String buffer, int cursorDest) throws IOException {
+        // move cursor to end of line
+        moveToEnd();
+
+        // backspace all text, including prompt
+        buf.buffer.append(this.prompt);
+        int promptLength = 0;
+        if (this.prompt != null) {
+            promptLength = this.prompt.length();
+        }
+
+        buf.cursor += promptLength;
+        setPrompt("");
+        backspaceAll();
+
+        setPrompt(prompt);
+        redrawLine();
+        setBuffer(buffer);
+
+        // move cursor to destination (-1 will move to end of line)
+        if (cursorDest < 0) cursorDest = buffer.length();
+        setCursorPosition(cursorDest);
+
+        flush();
+    }
+
+    public void printSearchStatus(String searchTerm, String match) throws IOException {
+        printSearchStatus(searchTerm, match, "(reverse-i-search)`");
+    }
+
+    public void printForwardSearchStatus(String searchTerm, String match) throws IOException {
+        printSearchStatus(searchTerm, match, "(i-search)`");
+    }
+
+    private void printSearchStatus(String searchTerm, String match, String searchLabel) throws IOException {
+        String prompt = searchLabel + searchTerm + "': ";
+        int cursorDest = match.indexOf(searchTerm);
+        resetPromptLine(prompt, match, cursorDest);
+    }
+
+    public void restoreLine(String originalPrompt, int cursorDest) throws IOException {
+        // TODO move cursor to matched string
+        String prompt = lastLine(originalPrompt);
+        String buffer = buf.buffer.toString();
+        resetPromptLine(prompt, buffer, cursorDest);
+    }
+
+    //
+    // History search
+    //
+    /**
+     * Search backward in history from a given position.
+     *
+     * @param searchTerm substring to search for.
+     * @param startIndex the index from which on to search
+     * @return index where this substring has been found, or -1 else.
+     */
+    public int searchBackwards(String searchTerm, int startIndex) {
+        return searchBackwards(searchTerm, startIndex, false);
+    }
+
+    /**
+     * Search backwards in history from the current position.
+     *
+     * @param searchTerm substring to search for.
+     * @return index where the substring has been found, or -1 else.
+     */
+    public int searchBackwards(String searchTerm) {
+        return searchBackwards(searchTerm, history.index());
+    }
+
+
+    public int searchBackwards(String searchTerm, int startIndex, boolean startsWith) {
+        ListIterator<History.Entry> it = history.entries(startIndex);
+        while (it.hasPrevious()) {
+            History.Entry e = it.previous();
+            if (startsWith) {
+                if (e.value().toString().startsWith(searchTerm)) {
+                    return e.index();
+                }
+            } else {
+                if (e.value().toString().contains(searchTerm)) {
+                    return e.index();
+                }
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Search forward in history from a given position.
+     *
+     * @param searchTerm substring to search for.
+     * @param startIndex the index from which on to search
+     * @return index where this substring has been found, or -1 else.
+     */
+    public int searchForwards(String searchTerm, int startIndex) {
+        return searchForwards(searchTerm, startIndex, false);
+    }
+    /**
+     * Search forwards in history from the current position.
+     *
+     * @param searchTerm substring to search for.
+     * @return index where the substring has been found, or -1 else.
+     */
+    public int searchForwards(String searchTerm) {
+        return searchForwards(searchTerm, history.index());
+    }
+
+    public int searchForwards(String searchTerm, int startIndex, boolean startsWith) {
+        if (startIndex >= history.size()) {
+            startIndex = history.size() - 1;
+        }
+
+        ListIterator<History.Entry> it = history.entries(startIndex);
+
+        if (searchIndex != -1 && it.hasNext()) {
+            it.next();
+        }
+
+        while (it.hasNext()) {
+            History.Entry e = it.next();
+            if (startsWith) {
+                if (e.value().toString().startsWith(searchTerm)) {
+                    return e.index();
+                }
+            } else {
+                if (e.value().toString().contains(searchTerm)) {
+                    return e.index();
+                }
+            }
+        }
+        return -1;
+    }
+
+    //
+    // Helpers
+    //
+
+    /**
+     * Checks to see if the specified character is a delimiter. We consider a
+     * character a delimiter if it is anything but a letter or digit.
+     *
+     * @param c     The character to test
+     * @return      True if it is a delimiter
+     */
+    private boolean isDelimiter(final char c) {
+        return !Character.isLetterOrDigit(c);
+    }
+
+    /**
+     * Checks to see if a character is a whitespace character. Currently
+     * this delegates to {@link Character#isWhitespace(char)}, however
+     * eventually it should be hooked up so that the definition of whitespace
+     * can be configured, as readline does.
+     *
+     * @param c The character to check
+     * @return true if the character is a whitespace
+     */
+    private boolean isWhitespace(final char c) {
+        return Character.isWhitespace (c);
+    }
+
+    private void printAnsiSequence(String sequence) throws IOException {
+        print(27);
+        print('[');
+        print(sequence);
+        flush(); // helps with step debugging
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/CursorBuffer.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console;
+
+import static jdk.internal.jline.internal.Preconditions.checkNotNull;
+
+/**
+ * A holder for a {@link StringBuilder} that also contains the current cursor position.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.0
+ */
+public class CursorBuffer
+{
+    private boolean overTyping = false;
+
+    public int cursor = 0;
+
+    public final StringBuilder buffer = new StringBuilder();
+
+    public CursorBuffer copy () {
+        CursorBuffer that = new CursorBuffer();
+        that.overTyping = this.overTyping;
+        that.cursor = this.cursor;
+        that.buffer.append (this.toString());
+
+        return that;
+    }
+
+    public boolean isOverTyping() {
+        return overTyping;
+    }
+
+    public void setOverTyping(final boolean b) {
+        overTyping = b;
+    }
+
+    public int length() {
+        return buffer.length();
+    }
+
+    public char nextChar() {
+        if (cursor == buffer.length()) {
+            return 0;
+        } else {
+            return buffer.charAt(cursor);
+        }
+    }
+
+    public char current() {
+        if (cursor <= 0) {
+            return 0;
+        }
+
+        return buffer.charAt(cursor - 1);
+    }
+
+    /**
+     * Write the specific character into the buffer, setting the cursor position
+     * ahead one. The text may overwrite or insert based on the current setting
+     * of {@link #isOverTyping}.
+     *
+     * @param c the character to insert
+     */
+    public void write(final char c) {
+        buffer.insert(cursor++, c);
+        if (isOverTyping() && cursor < buffer.length()) {
+            buffer.deleteCharAt(cursor);
+        }
+    }
+
+    /**
+     * Insert the specified chars into the buffer, setting the cursor to the end of the insertion point.
+     */
+    public void write(final CharSequence str) {
+        checkNotNull(str);
+
+        if (buffer.length() == 0) {
+            buffer.append(str);
+        }
+        else {
+            buffer.insert(cursor, str);
+        }
+
+        cursor += str.length();
+
+        if (isOverTyping() && cursor < buffer.length()) {
+            buffer.delete(cursor, (cursor + str.length()));
+        }
+    }
+
+    public boolean clear() {
+        if (buffer.length() == 0) {
+            return false;
+        }
+
+        buffer.delete(0, buffer.length());
+        cursor = 0;
+        return true;
+    }
+
+    public String upToCursor() {
+        if (cursor <= 0) {
+            return "";
+        }
+
+        return buffer.substring(0, cursor);
+    }
+
+    @Override
+    public String toString() {
+        return buffer.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/KeyMap.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,578 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The KeyMap class contains all bindings from keys to operations.
+ *
+ * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
+ * @since 2.6
+ */
+public class KeyMap {
+
+    public static final String VI_MOVE        = "vi-move";
+    public static final String VI_INSERT      = "vi-insert";
+    public static final String EMACS          = "emacs";
+    public static final String EMACS_STANDARD = "emacs-standard";
+    public static final String EMACS_CTLX     = "emacs-ctlx";
+    public static final String EMACS_META     = "emacs-meta";
+
+    private static final int KEYMAP_LENGTH = 256;
+
+    private static final Object NULL_FUNCTION = new Object();
+
+    private Object[] mapping = new Object[KEYMAP_LENGTH];
+    private Object anotherKey = null;
+    private String name;
+    private boolean isViKeyMap;
+
+    public KeyMap(String name, boolean isViKeyMap) {
+        this(name, new Object[KEYMAP_LENGTH], isViKeyMap);
+    }
+
+    protected KeyMap(String name, Object[] mapping, boolean isViKeyMap) {
+        this.mapping = mapping;
+        this.name = name;
+        this.isViKeyMap = isViKeyMap;
+    }
+
+    public boolean isViKeyMap() {
+        return isViKeyMap;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public Object getAnotherKey() {
+        return anotherKey;
+    }
+
+    public void from(KeyMap other) {
+        this.mapping = other.mapping;
+        this.anotherKey = other.anotherKey;
+    }
+
+    public Object getBound( CharSequence keySeq ) {
+        if (keySeq != null && keySeq.length() > 0) {
+            KeyMap map = this;
+            for (int i = 0; i < keySeq.length(); i++) {
+                char c = keySeq.charAt(i);
+                if (c > 255) {
+                    return Operation.SELF_INSERT;
+                }
+                if (map.mapping[c] instanceof KeyMap) {
+                    if (i == keySeq.length() - 1) {
+                        return map.mapping[c];
+                    } else {
+                        map = (KeyMap) map.mapping[c];
+                    }
+                } else {
+                    return map.mapping[c];
+                }
+            }
+        }
+        return null;
+    }
+
+    public void bindIfNotBound( CharSequence keySeq, Object function ) {
+
+        bind (this, keySeq, function, true);
+    }
+
+    public void bind( CharSequence keySeq, Object function ) {
+
+        bind (this, keySeq, function, false);
+    }
+
+    private static void bind( KeyMap map, CharSequence keySeq, Object function ) {
+
+        bind (map, keySeq, function, false);
+    }
+
+    private static void bind( KeyMap map, CharSequence keySeq, Object function,
+            boolean onlyIfNotBound ) {
+
+        if (keySeq != null && keySeq.length() > 0) {
+            for (int i = 0; i < keySeq.length(); i++) {
+                char c = keySeq.charAt(i);
+                if (c >= map.mapping.length) {
+                    return;
+                }
+                if (i < keySeq.length() - 1) {
+                    if (!(map.mapping[c] instanceof KeyMap)) {
+                        KeyMap m = new KeyMap("anonymous", false);
+                        if (map.mapping[c] != Operation.DO_LOWERCASE_VERSION) {
+                            m.anotherKey = map.mapping[c];
+                        }
+                        map.mapping[c] = m;
+                    }
+                    map = (KeyMap) map.mapping[c];
+                } else {
+                    if (function == null) {
+                        function = NULL_FUNCTION;
+                    }
+                    if (map.mapping[c] instanceof KeyMap) {
+                        map.anotherKey = function;
+                    } else {
+                        Object op = map.mapping[c];
+                        if (onlyIfNotBound == false
+                            || op == null
+                            || op == Operation.DO_LOWERCASE_VERSION
+                            || op == Operation.VI_MOVEMENT_MODE ) {
+
+                        }
+
+                        map.mapping[c] = function;
+                    }
+                }
+            }
+        }
+    }
+
+    public void setBlinkMatchingParen(boolean on) {
+        if (on) {
+            bind( "}", Operation.INSERT_CLOSE_CURLY );
+            bind( ")", Operation.INSERT_CLOSE_PAREN );
+            bind( "]", Operation.INSERT_CLOSE_SQUARE );
+        }
+    }
+
+    private static void bindArrowKeys(KeyMap map) {
+
+        // MS-DOS
+        bind( map, "\033[0A", Operation.PREVIOUS_HISTORY );
+        bind( map, "\033[0B", Operation.BACKWARD_CHAR );
+        bind( map, "\033[0C", Operation.FORWARD_CHAR );
+        bind( map, "\033[0D", Operation.NEXT_HISTORY );
+
+        // Windows
+        bind( map, "\340\000", Operation.KILL_WHOLE_LINE );
+        bind( map, "\340\107", Operation.BEGINNING_OF_LINE );
+        bind( map, "\340\110", Operation.PREVIOUS_HISTORY );
+        bind( map, "\340\111", Operation.BEGINNING_OF_HISTORY );
+        bind( map, "\340\113", Operation.BACKWARD_CHAR );
+        bind( map, "\340\115", Operation.FORWARD_CHAR );
+        bind( map, "\340\117", Operation.END_OF_LINE );
+        bind( map, "\340\120", Operation.NEXT_HISTORY );
+        bind( map, "\340\121", Operation.END_OF_HISTORY );
+        bind( map, "\340\122", Operation.OVERWRITE_MODE );
+        bind( map, "\340\123", Operation.DELETE_CHAR );
+
+        bind( map, "\000\107", Operation.BEGINNING_OF_LINE );
+        bind( map, "\000\110", Operation.PREVIOUS_HISTORY );
+        bind( map, "\000\111", Operation.BEGINNING_OF_HISTORY );
+        bind( map, "\000\110", Operation.PREVIOUS_HISTORY );
+        bind( map, "\000\113", Operation.BACKWARD_CHAR );
+        bind( map, "\000\115", Operation.FORWARD_CHAR );
+        bind( map, "\000\117", Operation.END_OF_LINE );
+        bind( map, "\000\120", Operation.NEXT_HISTORY );
+        bind( map, "\000\121", Operation.END_OF_HISTORY );
+        bind( map, "\000\122", Operation.OVERWRITE_MODE );
+        bind( map, "\000\123", Operation.DELETE_CHAR );
+
+        bind( map, "\033[A", Operation.PREVIOUS_HISTORY );
+        bind( map, "\033[B", Operation.NEXT_HISTORY );
+        bind( map, "\033[C", Operation.FORWARD_CHAR );
+        bind( map, "\033[D", Operation.BACKWARD_CHAR );
+        bind( map, "\033[H", Operation.BEGINNING_OF_LINE );
+        bind( map, "\033[F", Operation.END_OF_LINE );
+
+        bind( map, "\033OA", Operation.PREVIOUS_HISTORY );
+        bind( map, "\033OB", Operation.NEXT_HISTORY );
+        bind( map, "\033OC", Operation.FORWARD_CHAR );
+        bind( map, "\033OD", Operation.BACKWARD_CHAR );
+        bind( map, "\033OH", Operation.BEGINNING_OF_LINE );
+        bind( map, "\033OF", Operation.END_OF_LINE );
+
+        bind( map, "\033[1~", Operation.BEGINNING_OF_LINE);
+        bind( map, "\033[4~", Operation.END_OF_LINE);
+        bind( map, "\033[3~", Operation.DELETE_CHAR);
+
+        // MINGW32
+        bind( map, "\0340H", Operation.PREVIOUS_HISTORY );
+        bind( map, "\0340P", Operation.NEXT_HISTORY );
+        bind( map, "\0340M", Operation.FORWARD_CHAR );
+        bind( map, "\0340K", Operation.BACKWARD_CHAR );
+    }
+
+//    public boolean isConvertMetaCharsToAscii() {
+//        return convertMetaCharsToAscii;
+//    }
+
+//    public void setConvertMetaCharsToAscii(boolean convertMetaCharsToAscii) {
+//        this.convertMetaCharsToAscii = convertMetaCharsToAscii;
+//    }
+
+    public static boolean isMeta( char c ) {
+        return c > 0x7f && c <= 0xff;
+    }
+
+    public static char unMeta( char c ) {
+        return (char) (c & 0x7F);
+    }
+
+    public static char meta( char c ) {
+        return (char) (c | 0x80);
+    }
+
+    public static Map<String, KeyMap> keyMaps() {
+        Map<String, KeyMap> keyMaps = new HashMap<String, KeyMap>();
+
+        KeyMap emacs = emacs();
+        bindArrowKeys(emacs);
+        keyMaps.put(EMACS, emacs);
+        keyMaps.put(EMACS_STANDARD, emacs);
+        keyMaps.put(EMACS_CTLX, (KeyMap) emacs.getBound("\u0018"));
+        keyMaps.put(EMACS_META, (KeyMap) emacs.getBound("\u001b"));
+
+        KeyMap viMov = viMovement();
+        bindArrowKeys(viMov);
+        keyMaps.put(VI_MOVE, viMov);
+        keyMaps.put("vi-command", viMov);
+
+        KeyMap viIns = viInsertion();
+        bindArrowKeys(viIns);
+        keyMaps.put(VI_INSERT, viIns);
+        keyMaps.put("vi", viIns);
+
+        return keyMaps;
+    }
+
+    public static KeyMap emacs() {
+        Object[] map = new Object[KEYMAP_LENGTH];
+        Object[] ctrl = new Object[] {
+                        // Control keys.
+                        Operation.SET_MARK,                 /* Control-@ */
+                        Operation.BEGINNING_OF_LINE,        /* Control-A */
+                        Operation.BACKWARD_CHAR,            /* Control-B */
+                        Operation.INTERRUPT,                /* Control-C */
+                        Operation.EXIT_OR_DELETE_CHAR,      /* Control-D */
+                        Operation.END_OF_LINE,              /* Control-E */
+                        Operation.FORWARD_CHAR,             /* Control-F */
+                        Operation.ABORT,                    /* Control-G */
+                        Operation.BACKWARD_DELETE_CHAR,     /* Control-H */
+                        Operation.COMPLETE,                 /* Control-I */
+                        Operation.ACCEPT_LINE,              /* Control-J */
+                        Operation.KILL_LINE,                /* Control-K */
+                        Operation.CLEAR_SCREEN,             /* Control-L */
+                        Operation.ACCEPT_LINE,              /* Control-M */
+                        Operation.NEXT_HISTORY,             /* Control-N */
+                        null,                               /* Control-O */
+                        Operation.PREVIOUS_HISTORY,         /* Control-P */
+                        Operation.QUOTED_INSERT,            /* Control-Q */
+                        Operation.REVERSE_SEARCH_HISTORY,   /* Control-R */
+                        Operation.FORWARD_SEARCH_HISTORY,   /* Control-S */
+                        Operation.TRANSPOSE_CHARS,          /* Control-T */
+                        Operation.UNIX_LINE_DISCARD,        /* Control-U */
+                        Operation.QUOTED_INSERT,            /* Control-V */
+                        Operation.UNIX_WORD_RUBOUT,         /* Control-W */
+                        emacsCtrlX(),                       /* Control-X */
+                        Operation.YANK,                     /* Control-Y */
+                        null,                               /* Control-Z */
+                        emacsMeta(),                        /* Control-[ */
+                        null,                               /* Control-\ */
+                        Operation.CHARACTER_SEARCH,         /* Control-] */
+                        null,                               /* Control-^ */
+                        Operation.UNDO,                     /* Control-_ */
+                };
+        System.arraycopy( ctrl, 0, map, 0, ctrl.length );
+        for (int i = 32; i < 256; i++) {
+            map[i] = Operation.SELF_INSERT;
+        }
+        map[DELETE] = Operation.BACKWARD_DELETE_CHAR;
+        return new KeyMap(EMACS, map, false);
+    }
+
+    public static final char CTRL_D = (char) 4;
+    public static final char CTRL_G = (char) 7;
+    public static final char CTRL_H = (char) 8;
+    public static final char CTRL_I = (char) 9;
+    public static final char CTRL_J = (char) 10;
+    public static final char CTRL_M = (char) 13;
+    public static final char CTRL_R = (char) 18;
+    public static final char CTRL_S = (char) 19;
+    public static final char CTRL_U = (char) 21;
+    public static final char CTRL_X = (char) 24;
+    public static final char CTRL_Y = (char) 25;
+    public static final char ESCAPE = (char) 27; /* Ctrl-[ */
+    public static final char CTRL_OB = (char) 27; /* Ctrl-[ */
+    public static final char CTRL_CB = (char) 29; /* Ctrl-] */
+
+    public static final int DELETE = (char) 127;
+
+    public static KeyMap emacsCtrlX() {
+        Object[] map = new Object[KEYMAP_LENGTH];
+        map[CTRL_G] = Operation.ABORT;
+        map[CTRL_R] = Operation.RE_READ_INIT_FILE;
+        map[CTRL_U] = Operation.UNDO;
+        map[CTRL_X] = Operation.EXCHANGE_POINT_AND_MARK;
+        map['('] = Operation.START_KBD_MACRO;
+        map[')'] = Operation.END_KBD_MACRO;
+        for (int i = 'A'; i <= 'Z'; i++) {
+            map[i] = Operation.DO_LOWERCASE_VERSION;
+        }
+        map['e'] = Operation.CALL_LAST_KBD_MACRO;
+        map[DELETE] = Operation.KILL_LINE;
+        return new KeyMap(EMACS_CTLX, map, false);
+    }
+
+    public static KeyMap emacsMeta() {
+        Object[] map = new Object[KEYMAP_LENGTH];
+        map[CTRL_G] = Operation.ABORT;
+        map[CTRL_H] = Operation.BACKWARD_KILL_WORD;
+        map[CTRL_I] = Operation.TAB_INSERT;
+        map[CTRL_J] = Operation.VI_EDITING_MODE;
+        map[CTRL_M] = Operation.VI_EDITING_MODE;
+        map[CTRL_R] = Operation.REVERT_LINE;
+        map[CTRL_Y] = Operation.YANK_NTH_ARG;
+        map[CTRL_OB] = Operation.COMPLETE;
+        map[CTRL_CB] = Operation.CHARACTER_SEARCH_BACKWARD;
+        map[' '] = Operation.SET_MARK;
+        map['#'] = Operation.INSERT_COMMENT;
+        map['&'] = Operation.TILDE_EXPAND;
+        map['*'] = Operation.INSERT_COMPLETIONS;
+        map['-'] = Operation.DIGIT_ARGUMENT;
+        map['.'] = Operation.YANK_LAST_ARG;
+        map['<'] = Operation.BEGINNING_OF_HISTORY;
+        map['='] = Operation.POSSIBLE_COMPLETIONS;
+        map['>'] = Operation.END_OF_HISTORY;
+        map['?'] = Operation.POSSIBLE_COMPLETIONS;
+        for (int i = 'A'; i <= 'Z'; i++) {
+            map[i] = Operation.DO_LOWERCASE_VERSION;
+        }
+        map['\\'] = Operation.DELETE_HORIZONTAL_SPACE;
+        map['_'] = Operation.YANK_LAST_ARG;
+        map['b'] = Operation.BACKWARD_WORD;
+        map['c'] = Operation.CAPITALIZE_WORD;
+        map['d'] = Operation.KILL_WORD;
+        map['f'] = Operation.FORWARD_WORD;
+        map['l'] = Operation.DOWNCASE_WORD;
+        map['p'] = Operation.NON_INCREMENTAL_REVERSE_SEARCH_HISTORY;
+        map['r'] = Operation.REVERT_LINE;
+        map['t'] = Operation.TRANSPOSE_WORDS;
+        map['u'] = Operation.UPCASE_WORD;
+        map['y'] = Operation.YANK_POP;
+        map['~'] = Operation.TILDE_EXPAND;
+        map[DELETE] = Operation.BACKWARD_KILL_WORD;
+        return new KeyMap(EMACS_META, map, false);
+    }
+
+    public static KeyMap viInsertion() {
+        Object[] map = new Object[KEYMAP_LENGTH];
+        Object[] ctrl = new Object[] {
+                        // Control keys.
+                        null,                               /* Control-@ */
+                        Operation.SELF_INSERT,              /* Control-A */
+                        Operation.SELF_INSERT,              /* Control-B */
+                        Operation.SELF_INSERT,              /* Control-C */
+                        Operation.VI_EOF_MAYBE,             /* Control-D */
+                        Operation.SELF_INSERT,              /* Control-E */
+                        Operation.SELF_INSERT,              /* Control-F */
+                        Operation.SELF_INSERT,              /* Control-G */
+                        Operation.BACKWARD_DELETE_CHAR,     /* Control-H */
+                        Operation.COMPLETE,                 /* Control-I */
+                        Operation.ACCEPT_LINE,              /* Control-J */
+                        Operation.SELF_INSERT,              /* Control-K */
+                        Operation.SELF_INSERT,              /* Control-L */
+                        Operation.ACCEPT_LINE,              /* Control-M */
+                        Operation.MENU_COMPLETE,            /* Control-N */
+                        Operation.SELF_INSERT,              /* Control-O */
+                        Operation.MENU_COMPLETE_BACKWARD,   /* Control-P */
+                        Operation.SELF_INSERT,              /* Control-Q */
+                        Operation.REVERSE_SEARCH_HISTORY,   /* Control-R */
+                        Operation.FORWARD_SEARCH_HISTORY,   /* Control-S */
+                        Operation.TRANSPOSE_CHARS,          /* Control-T */
+                        Operation.UNIX_LINE_DISCARD,        /* Control-U */
+                        Operation.QUOTED_INSERT,            /* Control-V */
+                        Operation.UNIX_WORD_RUBOUT,         /* Control-W */
+                        Operation.SELF_INSERT,              /* Control-X */
+                        Operation.YANK,                     /* Control-Y */
+                        Operation.SELF_INSERT,              /* Control-Z */
+                        Operation.VI_MOVEMENT_MODE,         /* Control-[ */
+                        Operation.SELF_INSERT,              /* Control-\ */
+                        Operation.SELF_INSERT,              /* Control-] */
+                        Operation.SELF_INSERT,              /* Control-^ */
+                        Operation.UNDO,                     /* Control-_ */
+                };
+        System.arraycopy( ctrl, 0, map, 0, ctrl.length );
+        for (int i = 32; i < 256; i++) {
+            map[i] = Operation.SELF_INSERT;
+        }
+        map[DELETE] = Operation.BACKWARD_DELETE_CHAR;
+        return new KeyMap(VI_INSERT, map, false);
+    }
+
+    public static KeyMap viMovement() {
+        Object[] map = new Object[KEYMAP_LENGTH];
+        Object[] low = new Object[] {
+                        // Control keys.
+                        null,                               /* Control-@ */
+                        null,                               /* Control-A */
+                        null,                               /* Control-B */
+                        Operation.INTERRUPT,                /* Control-C */
+                        /*
+                         * ^D is supposed to move down half a screen. In bash
+                         * appears to be ignored.
+                         */
+                        Operation.VI_EOF_MAYBE,             /* Control-D */
+                        Operation.EMACS_EDITING_MODE,       /* Control-E */
+                        null,                               /* Control-F */
+                        Operation.ABORT,                    /* Control-G */
+                        Operation.BACKWARD_CHAR,            /* Control-H */
+                        null,                               /* Control-I */
+                        Operation.VI_MOVE_ACCEPT_LINE,      /* Control-J */
+                        Operation.KILL_LINE,                /* Control-K */
+                        Operation.CLEAR_SCREEN,             /* Control-L */
+                        Operation.VI_MOVE_ACCEPT_LINE,      /* Control-M */
+                        Operation.VI_NEXT_HISTORY,          /* Control-N */
+                        null,                               /* Control-O */
+                        Operation.VI_PREVIOUS_HISTORY,      /* Control-P */
+                        /*
+                         * My testing with readline is the ^Q is ignored.
+                         * Maybe this should be null?
+                         */
+                        Operation.QUOTED_INSERT,            /* Control-Q */
+
+                        /*
+                         * TODO - Very broken.  While in forward/reverse
+                         * history search the VI keyset should go out the
+                         * window and we need to enter a very simple keymap.
+                         */
+                        Operation.REVERSE_SEARCH_HISTORY,   /* Control-R */
+                        /* TODO */
+                        Operation.FORWARD_SEARCH_HISTORY,   /* Control-S */
+                        Operation.TRANSPOSE_CHARS,          /* Control-T */
+                        Operation.UNIX_LINE_DISCARD,        /* Control-U */
+                        /* TODO */
+                        Operation.QUOTED_INSERT,            /* Control-V */
+                        Operation.UNIX_WORD_RUBOUT,         /* Control-W */
+                        null,                               /* Control-X */
+                        /* TODO */
+                        Operation.YANK,                     /* Control-Y */
+                        null,                               /* Control-Z */
+                        emacsMeta(),                        /* Control-[ */
+                        null,                               /* Control-\ */
+                        /* TODO */
+                        Operation.CHARACTER_SEARCH,         /* Control-] */
+                        null,                               /* Control-^ */
+                        /* TODO */
+                        Operation.UNDO,                     /* Control-_ */
+                        Operation.FORWARD_CHAR,             /* SPACE */
+                        null,                               /* ! */
+                        null,                               /* " */
+                        Operation.VI_INSERT_COMMENT,        /* # */
+                        Operation.END_OF_LINE,              /* $ */
+                        Operation.VI_MATCH,                 /* % */
+                        Operation.VI_TILDE_EXPAND,          /* & */
+                        null,                               /* ' */
+                        null,                               /* ( */
+                        null,                               /* ) */
+                        /* TODO */
+                        Operation.VI_COMPLETE,              /* * */
+                        Operation.VI_NEXT_HISTORY,          /* + */
+                        Operation.VI_CHAR_SEARCH,           /* , */
+                        Operation.VI_PREVIOUS_HISTORY,      /* - */
+                        /* TODO */
+                        Operation.VI_REDO,                  /* . */
+                        Operation.VI_SEARCH,                /* / */
+                        Operation.VI_BEGNNING_OF_LINE_OR_ARG_DIGIT, /* 0 */
+                        Operation.VI_ARG_DIGIT,             /* 1 */
+                        Operation.VI_ARG_DIGIT,             /* 2 */
+                        Operation.VI_ARG_DIGIT,             /* 3 */
+                        Operation.VI_ARG_DIGIT,             /* 4 */
+                        Operation.VI_ARG_DIGIT,             /* 5 */
+                        Operation.VI_ARG_DIGIT,             /* 6 */
+                        Operation.VI_ARG_DIGIT,             /* 7 */
+                        Operation.VI_ARG_DIGIT,             /* 8 */
+                        Operation.VI_ARG_DIGIT,             /* 9 */
+                        null,                               /* : */
+                        Operation.VI_CHAR_SEARCH,           /* ; */
+                        null,                               /* < */
+                        Operation.VI_COMPLETE,              /* = */
+                        null,                               /* > */
+                        Operation.VI_SEARCH,                /* ? */
+                        null,                               /* @ */
+                        Operation.VI_APPEND_EOL,            /* A */
+                        Operation.VI_PREV_WORD,             /* B */
+                        Operation.VI_CHANGE_TO_EOL,         /* C */
+                        Operation.VI_DELETE_TO_EOL,         /* D */
+                        Operation.VI_END_WORD,              /* E */
+                        Operation.VI_CHAR_SEARCH,           /* F */
+                        /* I need to read up on what this does */
+                        Operation.VI_FETCH_HISTORY,         /* G */
+                        null,                               /* H */
+                        Operation.VI_INSERT_BEG,            /* I */
+                        null,                               /* J */
+                        null,                               /* K */
+                        null,                               /* L */
+                        null,                               /* M */
+                        Operation.VI_SEARCH_AGAIN,          /* N */
+                        null,                               /* O */
+                        Operation.VI_PUT,                   /* P */
+                        null,                               /* Q */
+                        /* TODO */
+                        Operation.VI_REPLACE,               /* R */
+                        Operation.VI_KILL_WHOLE_LINE,       /* S */
+                        Operation.VI_CHAR_SEARCH,           /* T */
+                        /* TODO */
+                        Operation.REVERT_LINE,              /* U */
+                        null,                               /* V */
+                        Operation.VI_NEXT_WORD,             /* W */
+                        Operation.VI_RUBOUT,                /* X */
+                        Operation.VI_YANK_TO,               /* Y */
+                        null,                               /* Z */
+                        null,                               /* [ */
+                        Operation.VI_COMPLETE,              /* \ */
+                        null,                               /* ] */
+                        Operation.VI_FIRST_PRINT,           /* ^ */
+                        Operation.VI_YANK_ARG,              /* _ */
+                        Operation.VI_GOTO_MARK,             /* ` */
+                        Operation.VI_APPEND_MODE,           /* a */
+                        Operation.VI_PREV_WORD,             /* b */
+                        Operation.VI_CHANGE_TO,             /* c */
+                        Operation.VI_DELETE_TO,             /* d */
+                        Operation.VI_END_WORD,              /* e */
+                        Operation.VI_CHAR_SEARCH,           /* f */
+                        null,                               /* g */
+                        Operation.BACKWARD_CHAR,            /* h */
+                        Operation.VI_INSERTION_MODE,        /* i */
+                        Operation.NEXT_HISTORY,             /* j */
+                        Operation.PREVIOUS_HISTORY,         /* k */
+                        Operation.FORWARD_CHAR,             /* l */
+                        Operation.VI_SET_MARK,              /* m */
+                        Operation.VI_SEARCH_AGAIN,          /* n */
+                        null,                               /* o */
+                        Operation.VI_PUT,                   /* p */
+                        null,                               /* q */
+                        Operation.VI_CHANGE_CHAR,           /* r */
+                        Operation.VI_SUBST,                 /* s */
+                        Operation.VI_CHAR_SEARCH,           /* t */
+                        Operation.UNDO,                     /* u */
+                        null,                               /* v */
+                        Operation.VI_NEXT_WORD,             /* w */
+                        Operation.VI_DELETE,                /* x */
+                        Operation.VI_YANK_TO,               /* y */
+                        null,                               /* z */
+                        null,                               /* { */
+                        Operation.VI_COLUMN,                /* | */
+                        null,                               /* } */
+                        Operation.VI_CHANGE_CASE,           /* ~ */
+                        Operation.VI_DELETE                 /* DEL */
+                };
+        System.arraycopy( low, 0, map, 0, low.length );
+        for (int i = 128; i < 256; i++) {
+            map[i] = null;
+        }
+        return new KeyMap(VI_MOVE, map, false);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/KillRing.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2002-2013, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console;
+
+/**
+ * The kill ring class keeps killed text in a fixed size ring. In this
+ * class we also keep record of whether or not the last command was a
+ * kill or a yank. Depending on this, the class may behave
+ * different. For instance, two consecutive kill-word commands fill
+ * the same slot such that the next yank will return the two
+ * previously killed words instead that only the last one. Likewise
+ * yank pop requires that the previous command was either a yank or a
+ * yank-pop.
+ */
+public final class KillRing {
+
+    /**
+     * Default size is 60, like in emacs.
+     */
+    private static final int DEFAULT_SIZE = 60;
+
+    private final String[] slots;
+    private int head = 0;
+    private boolean lastKill = false;
+    private boolean lastYank = false;
+
+    /**
+     * Creates a new kill ring of the given size.
+     */
+    public KillRing(int size) {
+        slots = new String[size];
+    }
+
+    /**
+     * Creates a new kill ring of the default size. {@see DEFAULT_SIZE}.
+     */
+    public KillRing() {
+        this(DEFAULT_SIZE);
+    }
+
+    /**
+     * Resets the last-yank state.
+     */
+    public void resetLastYank() {
+        lastYank = false;
+    }
+
+    /**
+     * Resets the last-kill state.
+     */
+    public void resetLastKill() {
+        lastKill = false;
+    }
+
+    /**
+     * Returns {@code true} if the last command was a yank.
+     */
+    public boolean lastYank() {
+        return lastYank;
+    }
+
+    /**
+     * Adds the string to the kill-ring. Also sets lastYank to false
+     * and lastKill to true.
+     */
+    public void add(String str) {
+        lastYank = false;
+
+        if (lastKill) {
+            if (slots[head] != null) {
+                slots[head] += str;
+                return;
+            }
+        }
+
+        lastKill = true;
+        next();
+        slots[head] = str;
+    }
+
+    /**
+     * Adds the string to the kill-ring product of killing
+     * backwards. If the previous command was a kill text one then
+     * adds the text at the beginning of the previous kill to avoid
+     * that two consecutive backwards kills followed by a yank leaves
+     * things reversed.
+     */
+    public void addBackwards(String str) {
+        lastYank = false;
+
+        if (lastKill) {
+            if (slots[head] != null) {
+                slots[head] = str + slots[head];
+                return;
+            }
+        }
+
+        lastKill = true;
+        next();
+        slots[head] = str;
+    }
+
+    /**
+     * Yanks a previously killed text. Returns {@code null} if the
+     * ring is empty.
+     */
+    public String yank() {
+        lastKill = false;
+        lastYank = true;
+        return slots[head];
+    }
+
+    /**
+     * Moves the pointer to the current slot back and returns the text
+     * in that position. If the previous command was not yank returns
+     * null.
+     */
+    public String yankPop() {
+        lastKill = false;
+        if (lastYank) {
+            prev();
+            return slots[head];
+        }
+        return null;
+    }
+
+    /**
+     * Moves the pointer to the current slot forward. If the end of
+     * the slots is reached then points back to the beginning.
+     */
+    private void next() {
+        if (head == 0 && slots[0] == null) {
+            return;
+        }
+        head++;
+        if (head == slots.length) {
+            head = 0;
+        }
+    }
+
+    /**
+     * Moves the pointer to the current slot backwards. If the
+     * beginning of the slots is reached then traverses the slot
+     * backwards until one with not null content is found.
+     */
+    private void prev() {
+        head--;
+        if (head == -1) {
+            int x = (slots.length - 1);
+            for (; x >= 0; x--) {
+                if (slots[x] != null) {
+                    break;
+                }
+            }
+            head = x;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/Operation.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console;
+
+/**
+ * List of all operations.
+ *
+ * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
+ * @since 2.6
+ */
+public enum Operation {
+
+    ABORT,
+    ACCEPT_LINE,
+    ARROW_KEY_PREFIX,
+    BACKWARD_BYTE,
+    BACKWARD_CHAR,
+    BACKWARD_DELETE_CHAR,
+    BACKWARD_KILL_LINE,
+    BACKWARD_KILL_WORD,
+    BACKWARD_WORD,
+    BEGINNING_OF_HISTORY,
+    BEGINNING_OF_LINE,
+    CALL_LAST_KBD_MACRO,
+    CAPITALIZE_WORD,
+    CHARACTER_SEARCH,
+    CHARACTER_SEARCH_BACKWARD,
+    CLEAR_SCREEN,
+    COMPLETE,
+    COPY_BACKWARD_WORD,
+    COPY_FORWARD_WORD,
+    COPY_REGION_AS_KILL,
+    DELETE_CHAR,
+    DELETE_CHAR_OR_LIST,
+    DELETE_HORIZONTAL_SPACE,
+    DIGIT_ARGUMENT,
+    DO_LOWERCASE_VERSION,
+    DOWNCASE_WORD,
+    DUMP_FUNCTIONS,
+    DUMP_MACROS,
+    DUMP_VARIABLES,
+    EMACS_EDITING_MODE,
+    END_KBD_MACRO,
+    END_OF_HISTORY,
+    END_OF_LINE,
+    EXCHANGE_POINT_AND_MARK,
+    EXIT_OR_DELETE_CHAR,
+    FORWARD_BACKWARD_DELETE_CHAR,
+    FORWARD_BYTE,
+    FORWARD_CHAR,
+    FORWARD_SEARCH_HISTORY,
+    FORWARD_WORD,
+    HISTORY_SEARCH_BACKWARD,
+    HISTORY_SEARCH_FORWARD,
+    INSERT_CLOSE_CURLY,
+    INSERT_CLOSE_PAREN,
+    INSERT_CLOSE_SQUARE,
+    INSERT_COMMENT,
+    INSERT_COMPLETIONS,
+    INTERRUPT,
+    KILL_WHOLE_LINE,
+    KILL_LINE,
+    KILL_REGION,
+    KILL_WORD,
+    MENU_COMPLETE,
+    MENU_COMPLETE_BACKWARD,
+    NEXT_HISTORY,
+    NON_INCREMENTAL_FORWARD_SEARCH_HISTORY,
+    NON_INCREMENTAL_REVERSE_SEARCH_HISTORY,
+    NON_INCREMENTAL_FORWARD_SEARCH_HISTORY_AGAIN,
+    NON_INCREMENTAL_REVERSE_SEARCH_HISTORY_AGAIN,
+    OLD_MENU_COMPLETE,
+    OVERWRITE_MODE,
+    PASTE_FROM_CLIPBOARD,
+    POSSIBLE_COMPLETIONS,
+    PREVIOUS_HISTORY,
+    QUOTED_INSERT,
+    RE_READ_INIT_FILE,
+    REDRAW_CURRENT_LINE,
+    REVERSE_SEARCH_HISTORY,
+    REVERT_LINE,
+    SELF_INSERT,
+    SET_MARK,
+    SKIP_CSI_SEQUENCE,
+    START_KBD_MACRO,
+    TAB_INSERT,
+    TILDE_EXPAND,
+    TRANSPOSE_CHARS,
+    TRANSPOSE_WORDS,
+    TTY_STATUS,
+    UNDO,
+    UNIVERSAL_ARGUMENT,
+    UNIX_FILENAME_RUBOUT,
+    UNIX_LINE_DISCARD,
+    UNIX_WORD_RUBOUT,
+    UPCASE_WORD,
+    YANK,
+    YANK_LAST_ARG,
+    YANK_NTH_ARG,
+    YANK_POP,
+    VI_APPEND_EOL,
+    VI_APPEND_MODE,
+    VI_ARG_DIGIT,
+    VI_BACK_TO_INDENT,
+    VI_BACKWARD_BIGWORD,
+    VI_BACKWARD_WORD,
+    VI_BWORD,
+    VI_CHANGE_CASE,
+    VI_CHANGE_CHAR,
+    VI_CHANGE_TO,
+    VI_CHANGE_TO_EOL,
+    VI_CHAR_SEARCH,
+    VI_COLUMN,
+    VI_COMPLETE,
+    VI_DELETE,
+    VI_DELETE_TO,
+    VI_DELETE_TO_EOL,
+    VI_EDITING_MODE,
+    VI_END_BIGWORD,
+    VI_END_WORD,
+    VI_EOF_MAYBE,
+    VI_EWORD,
+    VI_FWORD,
+    VI_FETCH_HISTORY,
+    VI_FIRST_PRINT,
+    VI_FORWARD_BIGWORD,
+    VI_FORWARD_WORD,
+    VI_GOTO_MARK,
+    VI_INSERT_BEG,
+    VI_INSERTION_MODE,
+    VI_KILL_WHOLE_LINE,
+    VI_MATCH,
+    VI_MOVEMENT_MODE,
+    VI_NEXT_WORD,
+    VI_OVERSTRIKE,
+    VI_OVERSTRIKE_DELETE,
+    VI_PREV_WORD,
+    VI_PUT,
+    VI_REDO,
+    VI_REPLACE,
+    VI_RUBOUT,
+    VI_SEARCH,
+    VI_SEARCH_AGAIN,
+    VI_SET_MARK,
+    VI_SUBST,
+    VI_TILDE_EXPAND,
+    VI_YANK_ARG,
+    VI_YANK_TO,
+    VI_MOVE_ACCEPT_LINE,
+    VI_NEXT_HISTORY,
+    VI_PREVIOUS_HISTORY,
+    VI_INSERT_COMMENT,
+    VI_BEGNNING_OF_LINE_OR_ARG_DIGIT,
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/UserInterruptException.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console;
+
+/**
+ * This exception is thrown by {@link ConsoleReader#readLine} when
+ * user interrupt handling is enabled and the user types the
+ * interrupt character (ctrl-C). The partially entered line is
+ * available via the {@link #getPartialLine()} method.
+ */
+public class UserInterruptException
+    extends RuntimeException
+{
+    private static final long serialVersionUID = 6172232572140736750L;
+
+    private final String partialLine;
+
+    public UserInterruptException(String partialLine)
+    {
+        this.partialLine = partialLine;
+    }
+
+    /**
+     * @return the partially entered line when ctrl-C was pressed
+     */
+    public String getPartialLine()
+    {
+        return partialLine;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/AggregateCompleter.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console.completer;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+
+import static jdk.internal.jline.internal.Preconditions.checkNotNull;
+
+/**
+ * Completer which contains multiple completers and aggregates them together.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public class AggregateCompleter
+    implements Completer
+{
+    private final List<Completer> completers = new ArrayList<Completer>();
+
+    public AggregateCompleter() {
+        // empty
+    }
+
+    /**
+     * Construct an AggregateCompleter with the given collection of completers.
+     * The completers will be used in the iteration order of the collection.
+     *
+     * @param completers the collection of completers
+     */
+    public AggregateCompleter(final Collection<Completer> completers) {
+        checkNotNull(completers);
+        this.completers.addAll(completers);
+    }
+
+    /**
+     * Construct an AggregateCompleter with the given completers.
+     * The completers will be used in the order given.
+     *
+     * @param completers the completers
+     */
+    public AggregateCompleter(final Completer... completers) {
+        this(Arrays.asList(completers));
+    }
+
+    /**
+     * Retrieve the collection of completers currently being aggregated.
+     *
+     * @return the aggregated completers
+     */
+    public Collection<Completer> getCompleters() {
+        return completers;
+    }
+
+    /**
+     * Perform a completion operation across all aggregated completers.
+     *
+     * @see Completer#complete(String, int, java.util.List)
+     * @return the highest completion return value from all completers
+     */
+    public int complete(final String buffer, final int cursor, final List<CharSequence> candidates) {
+        // buffer could be null
+        checkNotNull(candidates);
+
+        List<Completion> completions = new ArrayList<Completion>(completers.size());
+
+        // Run each completer, saving its completion results
+        int max = -1;
+        for (Completer completer : completers) {
+            Completion completion = new Completion(candidates);
+            completion.complete(completer, buffer, cursor);
+
+            // Compute the max cursor position
+            max = Math.max(max, completion.cursor);
+
+            completions.add(completion);
+        }
+
+        // Append candidates from completions which have the same cursor position as max
+        for (Completion completion : completions) {
+            if (completion.cursor == max) {
+                candidates.addAll(completion.candidates);
+            }
+        }
+
+        return max;
+    }
+
+    /**
+     * @return a string representing the aggregated completers
+     */
+    @Override
+    public String toString() {
+        return getClass().getSimpleName() + "{" +
+            "completers=" + completers +
+            '}';
+    }
+
+    private class Completion
+    {
+        public final List<CharSequence> candidates;
+
+        public int cursor;
+
+        public Completion(final List<CharSequence> candidates) {
+            checkNotNull(candidates);
+            this.candidates = new LinkedList<CharSequence>(candidates);
+        }
+
+        public void complete(final Completer completer, final String buffer, final int cursor) {
+            checkNotNull(completer);
+            this.cursor = completer.complete(buffer, cursor, candidates);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/ArgumentCompleter.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,461 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console.completer;
+
+import jdk.internal.jline.internal.Log;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+
+import static jdk.internal.jline.internal.Preconditions.checkNotNull;
+
+/**
+ * A {@link Completer} implementation that invokes a child completer using the appropriate <i>separator</i> argument.
+ * This can be used instead of the individual completers having to know about argument parsing semantics.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public class ArgumentCompleter
+    implements Completer
+{
+    private final ArgumentDelimiter delimiter;
+
+    private final List<Completer> completers = new ArrayList<Completer>();
+
+    private boolean strict = true;
+
+    /**
+     * Create a new completer with the specified argument delimiter.
+     *
+     * @param delimiter     The delimiter for parsing arguments
+     * @param completers    The embedded completers
+     */
+    public ArgumentCompleter(final ArgumentDelimiter delimiter, final Collection<Completer> completers) {
+        this.delimiter = checkNotNull(delimiter);
+        checkNotNull(completers);
+        this.completers.addAll(completers);
+    }
+
+    /**
+     * Create a new completer with the specified argument delimiter.
+     *
+     * @param delimiter     The delimiter for parsing arguments
+     * @param completers    The embedded completers
+     */
+    public ArgumentCompleter(final ArgumentDelimiter delimiter, final Completer... completers) {
+        this(delimiter, Arrays.asList(completers));
+    }
+
+    /**
+     * Create a new completer with the default {@link WhitespaceArgumentDelimiter}.
+     *
+     * @param completers    The embedded completers
+     */
+    public ArgumentCompleter(final Completer... completers) {
+        this(new WhitespaceArgumentDelimiter(), completers);
+    }
+
+    /**
+     * Create a new completer with the default {@link WhitespaceArgumentDelimiter}.
+     *
+     * @param completers    The embedded completers
+     */
+    public ArgumentCompleter(final List<Completer> completers) {
+        this(new WhitespaceArgumentDelimiter(), completers);
+    }
+
+    /**
+     * If true, a completion at argument index N will only succeed
+     * if all the completions from 0-(N-1) also succeed.
+     */
+    public void setStrict(final boolean strict) {
+        this.strict = strict;
+    }
+
+    /**
+     * Returns whether a completion at argument index N will success
+     * if all the completions from arguments 0-(N-1) also succeed.
+     *
+     * @return  True if strict.
+     * @since 2.3
+     */
+    public boolean isStrict() {
+        return this.strict;
+    }
+
+    /**
+     * @since 2.3
+     */
+    public ArgumentDelimiter getDelimiter() {
+        return delimiter;
+    }
+
+    /**
+     * @since 2.3
+     */
+    public List<Completer> getCompleters() {
+        return completers;
+    }
+
+    public int complete(final String buffer, final int cursor, final List<CharSequence> candidates) {
+        // buffer can be null
+        checkNotNull(candidates);
+
+        ArgumentDelimiter delim = getDelimiter();
+        ArgumentList list = delim.delimit(buffer, cursor);
+        int argpos = list.getArgumentPosition();
+        int argIndex = list.getCursorArgumentIndex();
+
+        if (argIndex < 0) {
+            return -1;
+        }
+
+        List<Completer> completers = getCompleters();
+        Completer completer;
+
+        // if we are beyond the end of the completers, just use the last one
+        if (argIndex >= completers.size()) {
+            completer = completers.get(completers.size() - 1);
+        }
+        else {
+            completer = completers.get(argIndex);
+        }
+
+        // ensure that all the previous completers are successful before allowing this completer to pass (only if strict).
+        for (int i = 0; isStrict() && (i < argIndex); i++) {
+            Completer sub = completers.get(i >= completers.size() ? (completers.size() - 1) : i);
+            String[] args = list.getArguments();
+            String arg = (args == null || i >= args.length) ? "" : args[i];
+
+            List<CharSequence> subCandidates = new LinkedList<CharSequence>();
+
+            if (sub.complete(arg, arg.length(), subCandidates) == -1) {
+                return -1;
+            }
+
+            if (subCandidates.size() == 0) {
+                return -1;
+            }
+        }
+
+        int ret = completer.complete(list.getCursorArgument(), argpos, candidates);
+
+        if (ret == -1) {
+            return -1;
+        }
+
+        int pos = ret + list.getBufferPosition() - argpos;
+
+        // Special case: when completing in the middle of a line, and the area under the cursor is a delimiter,
+        // then trim any delimiters from the candidates, since we do not need to have an extra delimiter.
+        //
+        // E.g., if we have a completion for "foo", and we enter "f bar" into the buffer, and move to after the "f"
+        // and hit TAB, we want "foo bar" instead of "foo  bar".
+
+        if ((cursor != buffer.length()) && delim.isDelimiter(buffer, cursor)) {
+            for (int i = 0; i < candidates.size(); i++) {
+                CharSequence val = candidates.get(i);
+
+                while (val.length() > 0 && delim.isDelimiter(val, val.length() - 1)) {
+                    val = val.subSequence(0, val.length() - 1);
+                }
+
+                candidates.set(i, val);
+            }
+        }
+
+        Log.trace("Completing ", buffer, " (pos=", cursor, ") with: ", candidates, ": offset=", pos);
+
+        return pos;
+    }
+
+    /**
+     * The {@link ArgumentCompleter.ArgumentDelimiter} allows custom breaking up of a {@link String} into individual
+     * arguments in order to dispatch the arguments to the nested {@link Completer}.
+     *
+     * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+     */
+    public static interface ArgumentDelimiter
+    {
+        /**
+         * Break the specified buffer into individual tokens that can be completed on their own.
+         *
+         * @param buffer    The buffer to split
+         * @param pos       The current position of the cursor in the buffer
+         * @return          The tokens
+         */
+        ArgumentList delimit(CharSequence buffer, int pos);
+
+        /**
+         * Returns true if the specified character is a whitespace parameter.
+         *
+         * @param buffer    The complete command buffer
+         * @param pos       The index of the character in the buffer
+         * @return          True if the character should be a delimiter
+         */
+        boolean isDelimiter(CharSequence buffer, int pos);
+    }
+
+    /**
+     * Abstract implementation of a delimiter that uses the {@link #isDelimiter} method to determine if a particular
+     * character should be used as a delimiter.
+     *
+     * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+     */
+    public abstract static class AbstractArgumentDelimiter
+        implements ArgumentDelimiter
+    {
+        private char[] quoteChars = {'\'', '"'};
+
+        private char[] escapeChars = {'\\'};
+
+        public void setQuoteChars(final char[] chars) {
+            this.quoteChars = chars;
+        }
+
+        public char[] getQuoteChars() {
+            return this.quoteChars;
+        }
+
+        public void setEscapeChars(final char[] chars) {
+            this.escapeChars = chars;
+        }
+
+        public char[] getEscapeChars() {
+            return this.escapeChars;
+        }
+
+        public ArgumentList delimit(final CharSequence buffer, final int cursor) {
+            List<String> args = new LinkedList<String>();
+            StringBuilder arg = new StringBuilder();
+            int argpos = -1;
+            int bindex = -1;
+            int quoteStart = -1;
+
+            for (int i = 0; (buffer != null) && (i < buffer.length()); i++) {
+                // once we reach the cursor, set the
+                // position of the selected index
+                if (i == cursor) {
+                    bindex = args.size();
+                    // the position in the current argument is just the
+                    // length of the current argument
+                    argpos = arg.length();
+                }
+
+                if (quoteStart < 0 && isQuoteChar(buffer, i)) {
+                    // Start a quote block
+                    quoteStart = i;
+                } else if (quoteStart >= 0) {
+                    // In a quote block
+                    if (buffer.charAt(quoteStart) == buffer.charAt(i) && !isEscaped(buffer, i)) {
+                        // End the block; arg could be empty, but that's fine
+                        args.add(arg.toString());
+                        arg.setLength(0);
+                        quoteStart = -1;
+                    } else if (!isEscapeChar(buffer, i)) {
+                        // Take the next character
+                        arg.append(buffer.charAt(i));
+                    }
+                } else {
+                    // Not in a quote block
+                    if (isDelimiter(buffer, i)) {
+                        if (arg.length() > 0) {
+                            args.add(arg.toString());
+                            arg.setLength(0); // reset the arg
+                        }
+                    } else if (!isEscapeChar(buffer, i)) {
+                        arg.append(buffer.charAt(i));
+                    }
+                }
+            }
+
+            if (cursor == buffer.length()) {
+                bindex = args.size();
+                // the position in the current argument is just the
+                // length of the current argument
+                argpos = arg.length();
+            }
+            if (arg.length() > 0) {
+                args.add(arg.toString());
+            }
+
+            return new ArgumentList(args.toArray(new String[args.size()]), bindex, argpos, cursor);
+        }
+
+        /**
+         * Returns true if the specified character is a whitespace parameter. Check to ensure that the character is not
+         * escaped by any of {@link #getQuoteChars}, and is not escaped by ant of the {@link #getEscapeChars}, and
+         * returns true from {@link #isDelimiterChar}.
+         *
+         * @param buffer    The complete command buffer
+         * @param pos       The index of the character in the buffer
+         * @return          True if the character should be a delimiter
+         */
+        public boolean isDelimiter(final CharSequence buffer, final int pos) {
+            return !isQuoted(buffer, pos) && !isEscaped(buffer, pos) && isDelimiterChar(buffer, pos);
+        }
+
+        public boolean isQuoted(final CharSequence buffer, final int pos) {
+            return false;
+        }
+
+        public boolean isQuoteChar(final CharSequence buffer, final int pos) {
+            if (pos < 0) {
+                return false;
+            }
+
+            for (int i = 0; (quoteChars != null) && (i < quoteChars.length); i++) {
+                if (buffer.charAt(pos) == quoteChars[i]) {
+                    return !isEscaped(buffer, pos);
+                }
+            }
+
+            return false;
+        }
+
+        /**
+         * Check if this character is a valid escape char (i.e. one that has not been escaped)
+         *
+         * @param buffer
+         * @param pos
+         * @return
+         */
+        public boolean isEscapeChar(final CharSequence buffer, final int pos) {
+            if (pos < 0) {
+                return false;
+            }
+
+            for (int i = 0; (escapeChars != null) && (i < escapeChars.length); i++) {
+                if (buffer.charAt(pos) == escapeChars[i]) {
+                    return !isEscaped(buffer, pos); // escape escape
+                }
+            }
+
+            return false;
+        }
+
+        /**
+         * Check if a character is escaped (i.e. if the previous character is an escape)
+         *
+         * @param buffer
+         *          the buffer to check in
+         * @param pos
+         *          the position of the character to check
+         * @return true if the character at the specified position in the given buffer is an escape character and the character immediately preceding it is not an
+         *         escape character.
+         */
+        public boolean isEscaped(final CharSequence buffer, final int pos) {
+            if (pos <= 0) {
+                return false;
+            }
+
+            return isEscapeChar(buffer, pos - 1);
+        }
+
+        /**
+         * Returns true if the character at the specified position if a delimiter. This method will only be called if
+         * the character is not enclosed in any of the {@link #getQuoteChars}, and is not escaped by ant of the
+         * {@link #getEscapeChars}. To perform escaping manually, override {@link #isDelimiter} instead.
+         */
+        public abstract boolean isDelimiterChar(CharSequence buffer, int pos);
+    }
+
+    /**
+     * {@link ArgumentCompleter.ArgumentDelimiter} implementation that counts all whitespace (as reported by
+     * {@link Character#isWhitespace}) as being a delimiter.
+     *
+     * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+     */
+    public static class WhitespaceArgumentDelimiter
+        extends AbstractArgumentDelimiter
+    {
+        /**
+         * The character is a delimiter if it is whitespace, and the
+         * preceding character is not an escape character.
+         */
+        @Override
+        public boolean isDelimiterChar(final CharSequence buffer, final int pos) {
+            return Character.isWhitespace(buffer.charAt(pos));
+        }
+    }
+
+    /**
+     * The result of a delimited buffer.
+     *
+     * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+     */
+    public static class ArgumentList
+    {
+        private String[] arguments;
+
+        private int cursorArgumentIndex;
+
+        private int argumentPosition;
+
+        private int bufferPosition;
+
+        /**
+         * @param arguments             The array of tokens
+         * @param cursorArgumentIndex   The token index of the cursor
+         * @param argumentPosition      The position of the cursor in the current token
+         * @param bufferPosition        The position of the cursor in the whole buffer
+         */
+        public ArgumentList(final String[] arguments, final int cursorArgumentIndex, final int argumentPosition, final int bufferPosition) {
+            this.arguments = checkNotNull(arguments);
+            this.cursorArgumentIndex = cursorArgumentIndex;
+            this.argumentPosition = argumentPosition;
+            this.bufferPosition = bufferPosition;
+        }
+
+        public void setCursorArgumentIndex(final int i) {
+            this.cursorArgumentIndex = i;
+        }
+
+        public int getCursorArgumentIndex() {
+            return this.cursorArgumentIndex;
+        }
+
+        public String getCursorArgument() {
+            if ((cursorArgumentIndex < 0) || (cursorArgumentIndex >= arguments.length)) {
+                return null;
+            }
+
+            return arguments[cursorArgumentIndex];
+        }
+
+        public void setArgumentPosition(final int pos) {
+            this.argumentPosition = pos;
+        }
+
+        public int getArgumentPosition() {
+            return this.argumentPosition;
+        }
+
+        public void setArguments(final String[] arguments) {
+            this.arguments = arguments;
+        }
+
+        public String[] getArguments() {
+            return this.arguments;
+        }
+
+        public void setBufferPosition(final int pos) {
+            this.bufferPosition = pos;
+        }
+
+        public int getBufferPosition() {
+            return this.bufferPosition;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/CandidateListCompletionHandler.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console.completer;
+
+import jdk.internal.jline.console.ConsoleReader;
+import jdk.internal.jline.console.CursorBuffer;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.util.Set;
+
+/**
+ * A {@link CompletionHandler} that deals with multiple distinct completions
+ * by outputting the complete list of possibilities to the console. This
+ * mimics the behavior of the
+ * <a href="http://www.gnu.org/directory/readline.html">readline</a> library.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public class CandidateListCompletionHandler
+    implements CompletionHandler
+{
+    // TODO: handle quotes and escaped quotes && enable automatic escaping of whitespace
+
+    public boolean complete(final ConsoleReader reader, final List<CharSequence> candidates, final int pos) throws
+        IOException
+    {
+        CursorBuffer buf = reader.getCursorBuffer();
+
+        // if there is only one completion, then fill in the buffer
+        if (candidates.size() == 1) {
+            CharSequence value = candidates.get(0);
+
+            // fail if the only candidate is the same as the current buffer
+            if (value.equals(buf.toString())) {
+                return false;
+            }
+
+            setBuffer(reader, value, pos);
+
+            return true;
+        }
+        else if (candidates.size() > 1) {
+            String value = getUnambiguousCompletions(candidates);
+            setBuffer(reader, value, pos);
+        }
+
+        printCandidates(reader, candidates);
+
+        // redraw the current console buffer
+        reader.drawLine();
+
+        return true;
+    }
+
+    public static void setBuffer(final ConsoleReader reader, final CharSequence value, final int offset) throws
+        IOException
+    {
+        while ((reader.getCursorBuffer().cursor > offset) && reader.backspace()) {
+            // empty
+        }
+
+        reader.putString(value);
+        reader.setCursorPosition(offset + value.length());
+    }
+
+    /**
+     * Print out the candidates. If the size of the candidates is greater than the
+     * {@link ConsoleReader#getAutoprintThreshold}, they prompt with a warning.
+     *
+     * @param candidates the list of candidates to print
+     */
+    public static void printCandidates(final ConsoleReader reader, Collection<CharSequence> candidates) throws
+        IOException
+    {
+        Set<CharSequence> distinct = new HashSet<CharSequence>(candidates);
+
+        if (distinct.size() > reader.getAutoprintThreshold()) {
+            //noinspection StringConcatenation
+            reader.print(Messages.DISPLAY_CANDIDATES.format(candidates.size()));
+            reader.flush();
+
+            int c;
+
+            String noOpt = Messages.DISPLAY_CANDIDATES_NO.format();
+            String yesOpt = Messages.DISPLAY_CANDIDATES_YES.format();
+            char[] allowed = {yesOpt.charAt(0), noOpt.charAt(0)};
+
+            while ((c = reader.readCharacter(allowed)) != -1) {
+                String tmp = new String(new char[]{(char) c});
+
+                if (noOpt.startsWith(tmp)) {
+                    reader.println();
+                    return;
+                }
+                else if (yesOpt.startsWith(tmp)) {
+                    break;
+                }
+                else {
+                    reader.beep();
+                }
+            }
+        }
+
+        // copy the values and make them distinct, without otherwise affecting the ordering. Only do it if the sizes differ.
+        if (distinct.size() != candidates.size()) {
+            Collection<CharSequence> copy = new ArrayList<CharSequence>();
+
+            for (CharSequence next : candidates) {
+                if (!copy.contains(next)) {
+                    copy.add(next);
+                }
+            }
+
+            candidates = copy;
+        }
+
+        reader.println();
+        reader.printColumns(candidates);
+    }
+
+    /**
+     * Returns a root that matches all the {@link String} elements of the specified {@link List},
+     * or null if there are no commonalities. For example, if the list contains
+     * <i>foobar</i>, <i>foobaz</i>, <i>foobuz</i>, the method will return <i>foob</i>.
+     */
+    private String getUnambiguousCompletions(final List<CharSequence> candidates) {
+        if (candidates == null || candidates.isEmpty()) {
+            return null;
+        }
+
+        // convert to an array for speed
+        String[] strings = candidates.toArray(new String[candidates.size()]);
+
+        String first = strings[0];
+        StringBuilder candidate = new StringBuilder();
+
+        for (int i = 0; i < first.length(); i++) {
+            if (startsWith(first.substring(0, i + 1), strings)) {
+                candidate.append(first.charAt(i));
+            }
+            else {
+                break;
+            }
+        }
+
+        return candidate.toString();
+    }
+
+    /**
+     * @return true is all the elements of <i>candidates</i> start with <i>starts</i>
+     */
+    private boolean startsWith(final String starts, final String[] candidates) {
+        for (String candidate : candidates) {
+            if (!candidate.startsWith(starts)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    private static enum Messages
+    {
+        DISPLAY_CANDIDATES,
+        DISPLAY_CANDIDATES_YES,
+        DISPLAY_CANDIDATES_NO,;
+
+        private static final
+        ResourceBundle
+            bundle =
+            ResourceBundle.getBundle(CandidateListCompletionHandler.class.getName(), Locale.getDefault());
+
+        public String format(final Object... args) {
+            if (bundle == null)
+                return "";
+            else
+                return String.format(bundle.getString(name()), args);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/CandidateListCompletionHandler.properties	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,13 @@
+#
+# Copyright (c) 2002-2012, the original author or authors.
+#
+# This software is distributable under the BSD license. See the terms of the
+# BSD license in the documentation provided with this software.
+#
+# http://www.opensource.org/licenses/bsd-license.php
+#
+
+DISPLAY_CANDIDATES=Display all %d possibilities? (y or n)
+DISPLAY_CANDIDATES_YES=y
+DISPLAY_CANDIDATES_NO=n
+DISPLAY_MORE=--More--
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/Completer.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console.completer;
+
+import java.util.List;
+
+/**
+ * A completer is the mechanism by which tab-completion candidates will be resolved.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public interface Completer
+{
+    //
+    // FIXME: Check if we can use CharSequece for buffer?
+    //
+
+    /**
+     * Populates <i>candidates</i> with a list of possible completions for the <i>buffer</i>.
+     *
+     * The <i>candidates</i> list will not be sorted before being displayed to the user: thus, the
+     * complete method should sort the {@link List} before returning.
+     *
+     * @param buffer        The buffer
+     * @param cursor        The current position of the cursor in the <i>buffer</i>
+     * @param candidates    The {@link List} of candidates to populate
+     * @return              The index of the <i>buffer</i> for which the completion will be relative
+     */
+    int complete(String buffer, int cursor, List<CharSequence> candidates);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/CompletionHandler.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console.completer;
+
+import jdk.internal.jline.console.ConsoleReader;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * Handler for dealing with candidates for tab-completion.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public interface CompletionHandler
+{
+    boolean complete(ConsoleReader reader, List<CharSequence> candidates, int position) throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/EnumCompleter.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console.completer;
+
+import static jdk.internal.jline.internal.Preconditions.checkNotNull;
+
+/**
+ * {@link Completer} for {@link Enum} names.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public class EnumCompleter
+    extends StringsCompleter
+{
+    public EnumCompleter(Class<? extends Enum<?>> source) {
+        checkNotNull(source);
+
+        for (Enum<?> n : source.getEnumConstants()) {
+            this.getStrings().add(n.name().toLowerCase());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/FileNameCompleter.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console.completer;
+
+import jdk.internal.jline.internal.Configuration;
+
+import java.io.File;
+import java.util.List;
+
+import static jdk.internal.jline.internal.Preconditions.checkNotNull;
+
+/**
+ * A file name completer takes the buffer and issues a list of
+ * potential completions.
+ * <p/>
+ * This completer tries to behave as similar as possible to
+ * <i>bash</i>'s file name completion (using GNU readline)
+ * with the following exceptions:
+ * <p/>
+ * <ul>
+ * <li>Candidates that are directories will end with "/"</li>
+ * <li>Wildcard regular expressions are not evaluated or replaced</li>
+ * <li>The "~" character can be used to represent the user's home,
+ * but it cannot complete to other users' homes, since java does
+ * not provide any way of determining that easily</li>
+ * </ul>
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public class FileNameCompleter
+    implements Completer
+{
+    // TODO: Handle files with spaces in them
+
+    private static final boolean OS_IS_WINDOWS;
+
+    static {
+        String os = Configuration.getOsName();
+        OS_IS_WINDOWS = os.contains("windows");
+    }
+
+    public int complete(String buffer, final int cursor, final List<CharSequence> candidates) {
+        // buffer can be null
+        checkNotNull(candidates);
+
+        if (buffer == null) {
+            buffer = "";
+        }
+
+        if (OS_IS_WINDOWS) {
+            buffer = buffer.replace('/', '\\');
+        }
+
+        String translated = buffer;
+
+        File homeDir = getUserHome();
+
+        // Special character: ~ maps to the user's home directory
+        if (translated.startsWith("~" + separator())) {
+            translated = homeDir.getPath() + translated.substring(1);
+        }
+        else if (translated.startsWith("~")) {
+            translated = homeDir.getParentFile().getAbsolutePath();
+        }
+        else if (!(new File(translated).isAbsolute())) {
+            String cwd = getUserDir().getAbsolutePath();
+            translated = cwd + separator() + translated;
+        }
+
+        File file = new File(translated);
+        final File dir;
+
+        if (translated.endsWith(separator())) {
+            dir = file;
+        }
+        else {
+            dir = file.getParentFile();
+        }
+
+        File[] entries = dir == null ? new File[0] : dir.listFiles();
+
+        return matchFiles(buffer, translated, entries, candidates);
+    }
+
+    protected String separator() {
+        return File.separator;
+    }
+
+    protected File getUserHome() {
+        return Configuration.getUserHome();
+    }
+
+    protected File getUserDir() {
+        return new File(".");
+    }
+
+    protected int matchFiles(final String buffer, final String translated, final File[] files, final List<CharSequence> candidates) {
+        if (files == null) {
+            return -1;
+        }
+
+        int matches = 0;
+
+        // first pass: just count the matches
+        for (File file : files) {
+            if (file.getAbsolutePath().startsWith(translated)) {
+                matches++;
+            }
+        }
+        for (File file : files) {
+            if (file.getAbsolutePath().startsWith(translated)) {
+                CharSequence name = file.getName() + (matches == 1 && file.isDirectory() ? separator() : " ");
+                candidates.add(render(file, name).toString());
+            }
+        }
+
+        final int index = buffer.lastIndexOf(separator());
+
+        return index + separator().length();
+    }
+
+    protected CharSequence render(final File file, final CharSequence name) {
+        return name;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/NullCompleter.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console.completer;
+
+import java.util.List;
+
+/**
+ * Null completer.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public final class NullCompleter
+    implements Completer
+{
+    public static final NullCompleter INSTANCE = new NullCompleter();
+
+    public int complete(final String buffer, final int cursor, final List<CharSequence> candidates) {
+        return -1;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/StringsCompleter.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console.completer;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import static jdk.internal.jline.internal.Preconditions.checkNotNull;
+
+/**
+ * Completer for a set of strings.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public class StringsCompleter
+    implements Completer
+{
+    private final SortedSet<String> strings = new TreeSet<String>();
+
+    public StringsCompleter() {
+        // empty
+    }
+
+    public StringsCompleter(final Collection<String> strings) {
+        checkNotNull(strings);
+        getStrings().addAll(strings);
+    }
+
+    public StringsCompleter(final String... strings) {
+        this(Arrays.asList(strings));
+    }
+
+    public Collection<String> getStrings() {
+        return strings;
+    }
+
+    public int complete(final String buffer, final int cursor, final List<CharSequence> candidates) {
+        // buffer could be null
+        checkNotNull(candidates);
+
+        if (buffer == null) {
+            candidates.addAll(strings);
+        }
+        else {
+            for (String match : strings.tailSet(buffer)) {
+                if (!match.startsWith(buffer)) {
+                    break;
+                }
+
+                candidates.add(match);
+            }
+        }
+
+        if (candidates.size() == 1) {
+            candidates.set(0, candidates.get(0) + " ");
+        }
+
+        return candidates.isEmpty() ? -1 : 0;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/package-info.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+/**
+ * Console completer support.
+ *
+ * @since 2.3
+ */
+package jdk.internal.jline.console.completer;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/FileHistory.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console.history;
+
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.Flushable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.io.Reader;
+
+import jdk.internal.jline.internal.Log;
+import static jdk.internal.jline.internal.Preconditions.checkNotNull;
+
+/**
+ * {@link History} using a file for persistent backing.
+ * <p/>
+ * Implementers should install shutdown hook to call {@link FileHistory#flush}
+ * to save history to disk.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.0
+ */
+public class FileHistory
+    extends MemoryHistory
+    implements PersistentHistory, Flushable
+{
+    private final File file;
+
+    public FileHistory(final File file) throws IOException {
+        this.file = checkNotNull(file);
+        load(file);
+    }
+
+    public File getFile() {
+        return file;
+    }
+
+    public void load(final File file) throws IOException {
+        checkNotNull(file);
+        if (file.exists()) {
+            Log.trace("Loading history from: ", file);
+            load(new FileReader(file));
+        }
+    }
+
+    public void load(final InputStream input) throws IOException {
+        checkNotNull(input);
+        load(new InputStreamReader(input));
+    }
+
+    public void load(final Reader reader) throws IOException {
+        checkNotNull(reader);
+        BufferedReader input = new BufferedReader(reader);
+
+        String item;
+        while ((item = input.readLine()) != null) {
+            internalAdd(item);
+        }
+    }
+
+    public void flush() throws IOException {
+        Log.trace("Flushing history");
+
+        if (!file.exists()) {
+            File dir = file.getParentFile();
+            if (!dir.exists() && !dir.mkdirs()) {
+                Log.warn("Failed to create directory: ", dir);
+            }
+            if (!file.createNewFile()) {
+                Log.warn("Failed to create file: ", file);
+            }
+        }
+
+        PrintStream out = new PrintStream(new BufferedOutputStream(new FileOutputStream(file)));
+        try {
+            for (Entry entry : this) {
+                out.println(entry.value());
+            }
+        }
+        finally {
+            out.close();
+        }
+    }
+
+    public void purge() throws IOException {
+        Log.trace("Purging history");
+
+        clear();
+
+        if (!file.delete()) {
+            Log.warn("Failed to delete history file: ", file);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/History.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console.history;
+
+import java.util.Iterator;
+import java.util.ListIterator;
+
+/**
+ * Console history.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public interface History
+    extends Iterable<History.Entry>
+{
+    int size();
+
+    boolean isEmpty();
+
+    int index();
+
+    void clear();
+
+    CharSequence get(int index);
+
+    void add(CharSequence line);
+
+    /**
+     * Set the history item at the given index to the given CharSequence.
+     *
+     * @param index the index of the history offset
+     * @param item the new item
+     * @since 2.7
+     */
+    void set(int index, CharSequence item);
+
+    /**
+     * Remove the history element at the given index.
+     *
+     * @param i the index of the element to remove
+     * @return the removed element
+     * @since 2.7
+     */
+    CharSequence remove(int i);
+
+    /**
+     * Remove the first element from history.
+     *
+     * @return the removed element
+     * @since 2.7
+     */
+    CharSequence removeFirst();
+
+    /**
+     * Remove the last element from history
+     *
+     * @return the removed element
+     * @since 2.7
+     */
+    CharSequence removeLast();
+
+    void replace(CharSequence item);
+
+    //
+    // Entries
+    //
+
+    interface Entry
+    {
+        int index();
+
+        CharSequence value();
+    }
+
+    ListIterator<Entry> entries(int index);
+
+    ListIterator<Entry> entries();
+
+    Iterator<Entry> iterator();
+
+    //
+    // Navigation
+    //
+
+    CharSequence current();
+
+    boolean previous();
+
+    boolean next();
+
+    boolean moveToFirst();
+
+    boolean moveToLast();
+
+    boolean moveTo(int index);
+
+    void moveToEnd();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/MemoryHistory.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console.history;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+
+import static jdk.internal.jline.internal.Preconditions.checkNotNull;
+
+/**
+ * Non-persistent {@link History}.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public class MemoryHistory
+    implements History
+{
+    public static final int DEFAULT_MAX_SIZE = 500;
+
+    private final LinkedList<CharSequence> items = new LinkedList<CharSequence>();
+
+    private int maxSize = DEFAULT_MAX_SIZE;
+
+    private boolean ignoreDuplicates = true;
+
+    private boolean autoTrim = false;
+
+    // NOTE: These are all ideas from looking at the Bash man page:
+
+    // TODO: Add ignore space? (lines starting with a space are ignored)
+
+    // TODO: Add ignore patterns?
+
+    // TODO: Add history timestamp?
+
+    // TODO: Add erase dups?
+
+    private int offset = 0;
+
+    private int index = 0;
+
+    public void setMaxSize(final int maxSize) {
+        this.maxSize = maxSize;
+        maybeResize();
+    }
+
+    public int getMaxSize() {
+        return maxSize;
+    }
+
+    public boolean isIgnoreDuplicates() {
+        return ignoreDuplicates;
+    }
+
+    public void setIgnoreDuplicates(final boolean flag) {
+        this.ignoreDuplicates = flag;
+    }
+
+    public boolean isAutoTrim() {
+        return autoTrim;
+    }
+
+    public void setAutoTrim(final boolean flag) {
+        this.autoTrim = flag;
+    }
+
+    public int size() {
+        return items.size();
+    }
+
+    public boolean isEmpty() {
+        return items.isEmpty();
+    }
+
+    public int index() {
+        return offset + index;
+    }
+
+    public void clear() {
+        items.clear();
+        offset = 0;
+        index = 0;
+    }
+
+    public CharSequence get(final int index) {
+        return items.get(index - offset);
+    }
+
+    public void set(int index, CharSequence item) {
+        items.set(index - offset, item);
+    }
+
+    public void add(CharSequence item) {
+        checkNotNull(item);
+
+        if (isAutoTrim()) {
+            item = String.valueOf(item).trim();
+        }
+
+        if (isIgnoreDuplicates()) {
+            if (!items.isEmpty() && item.equals(items.getLast())) {
+                return;
+            }
+        }
+
+        internalAdd(item);
+    }
+
+    public CharSequence remove(int i) {
+        return items.remove(i);
+    }
+
+    public CharSequence removeFirst() {
+        return items.removeFirst();
+    }
+
+    public CharSequence removeLast() {
+        return items.removeLast();
+    }
+
+    protected void internalAdd(CharSequence item) {
+        items.add(item);
+
+        maybeResize();
+    }
+
+    public void replace(final CharSequence item) {
+        items.removeLast();
+        add(item);
+    }
+
+    private void maybeResize() {
+        while (size() > getMaxSize()) {
+            items.removeFirst();
+            offset++;
+        }
+
+        index = size();
+    }
+
+    public ListIterator<Entry> entries(final int index) {
+        return new EntriesIterator(index - offset);
+    }
+
+    public ListIterator<Entry> entries() {
+        return entries(offset);
+    }
+
+    public Iterator<Entry> iterator() {
+        return entries();
+    }
+
+    private static class EntryImpl
+        implements Entry
+    {
+        private final int index;
+
+        private final CharSequence value;
+
+        public EntryImpl(int index, CharSequence value) {
+            this.index = index;
+            this.value = value;
+        }
+
+        public int index() {
+            return index;
+        }
+
+        public CharSequence value() {
+            return value;
+        }
+
+        @Override
+        public String toString() {
+            return String.format("%d: %s", index, value);
+        }
+    }
+
+    private class EntriesIterator
+        implements ListIterator<Entry>
+    {
+        private final ListIterator<CharSequence> source;
+
+        private EntriesIterator(final int index) {
+            source = items.listIterator(index);
+        }
+
+        public Entry next() {
+            if (!source.hasNext()) {
+                throw new NoSuchElementException();
+            }
+            return new EntryImpl(offset + source.nextIndex(), source.next());
+        }
+
+        public Entry previous() {
+            if (!source.hasPrevious()) {
+                throw new NoSuchElementException();
+            }
+            return new EntryImpl(offset + source.previousIndex(), source.previous());
+        }
+
+        public int nextIndex() {
+            return offset + source.nextIndex();
+        }
+
+        public int previousIndex() {
+            return offset + source.previousIndex();
+        }
+
+        public boolean hasNext() {
+            return source.hasNext();
+        }
+
+        public boolean hasPrevious() {
+            return source.hasPrevious();
+        }
+
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+
+        public void set(final Entry entry) {
+            throw new UnsupportedOperationException();
+        }
+
+        public void add(final Entry entry) {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    //
+    // Navigation
+    //
+
+    /**
+     * This moves the history to the last entry. This entry is one position
+     * before the moveToEnd() position.
+     *
+     * @return Returns false if there were no history entries or the history
+     *         index was already at the last entry.
+     */
+    public boolean moveToLast() {
+        int lastEntry = size() - 1;
+        if (lastEntry >= 0 && lastEntry != index) {
+            index = size() - 1;
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Move to the specified index in the history
+     * @param index
+     * @return
+     */
+    public boolean moveTo(int index) {
+        index -= offset;
+        if (index >= 0 && index < size() ) {
+            this.index = index;
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Moves the history index to the first entry.
+     *
+     * @return Return false if there are no entries in the history or if the
+     *         history is already at the beginning.
+     */
+    public boolean moveToFirst() {
+        if (size() > 0 && index != 0) {
+            index = 0;
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Move to the end of the history buffer. This will be a blank entry, after
+     * all of the other entries.
+     */
+    public void moveToEnd() {
+        index = size();
+    }
+
+    /**
+     * Return the content of the current buffer.
+     */
+    public CharSequence current() {
+        if (index >= size()) {
+            return "";
+        }
+
+        return items.get(index);
+    }
+
+    /**
+     * Move the pointer to the previous element in the buffer.
+     *
+     * @return true if we successfully went to the previous element
+     */
+    public boolean previous() {
+        if (index <= 0) {
+            return false;
+        }
+
+        index--;
+
+        return true;
+    }
+
+    /**
+     * Move the pointer to the next element in the buffer.
+     *
+     * @return true if we successfully went to the next element
+     */
+    public boolean next() {
+        if (index >= size()) {
+            return false;
+        }
+
+        index++;
+
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        for (Entry e : this) {
+            sb.append(e.toString() + "\n");
+        }
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/PersistentHistory.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console.history;
+
+import java.io.IOException;
+
+/**
+ * Persistent {@link History}.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public interface PersistentHistory
+    extends History
+{
+    /**
+     * Flush all items to persistent storage.
+     *
+     * @throws IOException  Flush failed
+     */
+    void flush() throws IOException;
+
+    /**
+     * Purge persistent storage and {@link #clear}.
+     *
+     * @throws IOException  Purge failed
+     */
+    void purge() throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/package-info.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+/**
+ * Console history support.
+ *
+ * @since 2.0
+ */
+package jdk.internal.jline.console.history;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/internal/ConsoleReaderInputStream.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console.internal;
+
+import jdk.internal.jline.console.ConsoleReader;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.SequenceInputStream;
+import java.util.Enumeration;
+
+// FIXME: Clean up API and move to jline.console.runner package
+
+/**
+ * An {@link InputStream} implementation that wraps a {@link ConsoleReader}.
+ * It is useful for setting up the {@link System#in} for a generic console.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @since 2.7
+ */
+class ConsoleReaderInputStream
+    extends SequenceInputStream
+{
+    private static InputStream systemIn = System.in;
+
+    public static void setIn() throws IOException {
+        setIn(new ConsoleReader());
+    }
+
+    public static void setIn(final ConsoleReader reader) {
+        System.setIn(new ConsoleReaderInputStream(reader));
+    }
+
+    /**
+     * Restore the original {@link System#in} input stream.
+     */
+    public static void restoreIn() {
+        System.setIn(systemIn);
+    }
+
+    public ConsoleReaderInputStream(final ConsoleReader reader) {
+        super(new ConsoleEnumeration(reader));
+    }
+
+    private static class ConsoleEnumeration
+        implements Enumeration<InputStream>
+    {
+        private final ConsoleReader reader;
+        private ConsoleLineInputStream next = null;
+        private ConsoleLineInputStream prev = null;
+
+        public ConsoleEnumeration(final ConsoleReader reader) {
+            this.reader = reader;
+        }
+
+        public InputStream nextElement() {
+            if (next != null) {
+                InputStream n = next;
+                prev = next;
+                next = null;
+
+                return n;
+            }
+
+            return new ConsoleLineInputStream(reader);
+        }
+
+        public boolean hasMoreElements() {
+            // the last line was null
+            if ((prev != null) && (prev.wasNull == true)) {
+                return false;
+            }
+
+            if (next == null) {
+                next = (ConsoleLineInputStream) nextElement();
+            }
+
+            return next != null;
+        }
+    }
+
+    private static class ConsoleLineInputStream
+        extends InputStream
+    {
+        private final ConsoleReader reader;
+        private String line = null;
+        private int index = 0;
+        private boolean eol = false;
+        protected boolean wasNull = false;
+
+        public ConsoleLineInputStream(final ConsoleReader reader) {
+            this.reader = reader;
+        }
+
+        public int read() throws IOException {
+            if (eol) {
+                return -1;
+            }
+
+            if (line == null) {
+                line = reader.readLine();
+            }
+
+            if (line == null) {
+                wasNull = true;
+                return -1;
+            }
+
+            if (index >= line.length()) {
+                eol = true;
+                return '\n'; // lines are ended with a newline
+            }
+
+            return line.charAt(index++);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/internal/ConsoleRunner.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console.internal;
+
+import jdk.internal.jline.console.ConsoleReader;
+import jdk.internal.jline.console.completer.ArgumentCompleter;
+import jdk.internal.jline.console.completer.Completer;
+import jdk.internal.jline.console.history.FileHistory;
+import jdk.internal.jline.internal.Configuration;
+
+import java.io.File;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.StringTokenizer;
+
+// FIXME: Clean up API and move to jline.console.runner package
+
+/**
+ * A pass-through application that sets the system input stream to a
+ * {@link ConsoleReader} and invokes the specified main method.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @since 2.7
+ */
+public class ConsoleRunner
+{
+    public static final String property = "jline.history";
+
+    // FIXME: This is really ugly... re-write this
+
+    public static void main(final String[] args) throws Exception {
+        List<String> argList = new ArrayList<String>(Arrays.asList(args));
+        if (argList.size() == 0) {
+            usage();
+            return;
+        }
+
+        String historyFileName = System.getProperty(ConsoleRunner.property, null);
+
+        String mainClass = argList.remove(0);
+        ConsoleReader reader = new ConsoleReader();
+
+        if (historyFileName != null) {
+            reader.setHistory(new FileHistory(new File(Configuration.getUserHome(),
+                String.format(".jline-%s.%s.history", mainClass, historyFileName))));
+        }
+        else {
+            reader.setHistory(new FileHistory(new File(Configuration.getUserHome(),
+                String.format(".jline-%s.history", mainClass))));
+        }
+
+        String completors = System.getProperty(ConsoleRunner.class.getName() + ".completers", "");
+        List<Completer> completorList = new ArrayList<Completer>();
+
+        for (StringTokenizer tok = new StringTokenizer(completors, ","); tok.hasMoreTokens();) {
+            Object obj = Class.forName(tok.nextToken()).newInstance();
+            completorList.add((Completer) obj);
+        }
+
+        if (completorList.size() > 0) {
+            reader.addCompleter(new ArgumentCompleter(completorList));
+        }
+
+        ConsoleReaderInputStream.setIn(reader);
+
+        try {
+            Class<?> type = Class.forName(mainClass);
+            Method method = type.getMethod("main", String[].class);
+            method.invoke(null);
+        }
+        finally {
+            // just in case this main method is called from another program
+            ConsoleReaderInputStream.restoreIn();
+        }
+    }
+
+    private static void usage() {
+        System.out.println("Usage: \n   java " + "[-Djline.history='name'] "
+            + ConsoleRunner.class.getName()
+            + " <target class name> [args]"
+            + "\n\nThe -Djline.history option will avoid history"
+            + "\nmangling when running ConsoleRunner on the same application."
+            + "\n\nargs will be passed directly to the target class name.");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/package-info.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+/**
+ * Console support.
+ *
+ * @since 2.0
+ */
+package jdk.internal.jline.console;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Configuration.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.internal;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.nio.charset.Charset;
+import java.util.Map;
+import java.util.Properties;
+
+import static jdk.internal.jline.internal.Preconditions.checkNotNull;
+
+/**
+ * Provides access to configuration values.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
+ * @since 2.4
+ */
+public class Configuration
+{
+    /**
+     * System property which can point to a file or URL containing configuration properties to load.
+     *
+     * @since 2.7
+     */
+    public static final String JLINE_CONFIGURATION = "jline.configuration";
+
+    /**
+     * Default configuration file name loaded from user's home directory.
+     */
+    public static final String JLINE_RC = ".jline.rc";
+
+    private static volatile Properties properties;
+
+    private static Properties initProperties() {
+        URL url = determineUrl();
+        Properties props = new Properties();
+        try {
+            loadProperties(url, props);
+        }
+        catch (IOException e) {
+            // debug here instead of warn, as this can happen normally if default jline.rc file is missing
+            Log.debug("Unable to read configuration from: ", url, e);
+        }
+        return props;
+    }
+
+    private static void loadProperties(final URL url, final Properties props) throws IOException {
+        Log.debug("Loading properties from: ", url);
+        InputStream input = url.openStream();
+        try {
+            props.load(new BufferedInputStream(input));
+        }
+        finally {
+            try {
+                input.close();
+            }
+            catch (IOException e) {
+                // ignore
+            }
+        }
+
+        if (Log.DEBUG) {
+            Log.debug("Loaded properties:");
+            for (Map.Entry<Object,Object> entry : props.entrySet()) {
+                Log.debug("  ", entry.getKey(), "=", entry.getValue());
+            }
+        }
+    }
+
+    private static URL determineUrl() {
+        // See if user has customized the configuration location via sysprop
+        String tmp = System.getProperty(JLINE_CONFIGURATION);
+        if (tmp != null) {
+            return Urls.create(tmp);
+        }
+        else {
+            // Otherwise try the default
+            File file = new File(getUserHome(), JLINE_RC);
+            return Urls.create(file);
+        }
+    }
+
+    /**
+     * @since 2.7
+     */
+    public static void reset() {
+        Log.debug("Resetting");
+        properties = null;
+
+        // force new properties to load
+        getProperties();
+    }
+
+    /**
+     * @since 2.7
+     */
+    public static Properties getProperties() {
+        // Not sure its worth to guard this with any synchronization, volatile field probably sufficient
+        if (properties == null) {
+            properties = initProperties();
+        }
+        return properties;
+    }
+
+    public static String getString(final String name, final String defaultValue) {
+        checkNotNull(name);
+
+        String value;
+
+        // Check sysprops first, it always wins
+        value = System.getProperty(name);
+
+        if (value == null) {
+            // Next try userprops
+            value = getProperties().getProperty(name);
+
+            if (value == null) {
+                // else use the default
+                value = defaultValue;
+            }
+        }
+
+        return value;
+    }
+
+    public static String getString(final String name) {
+        return getString(name, null);
+    }
+
+    public static boolean getBoolean(final String name, final boolean defaultValue) {
+        String value = getString(name);
+        if (value == null) {
+            return defaultValue;
+        }
+        return value.length() == 0
+            || value.equalsIgnoreCase("1")
+            || value.equalsIgnoreCase("on")
+            || value.equalsIgnoreCase("true");
+    }
+
+    /**
+     * @since 2.6
+     */
+    public static int getInteger(final String name, final int defaultValue) {
+        String str = getString(name);
+        if (str == null) {
+            return defaultValue;
+        }
+        return Integer.parseInt(str);
+    }
+
+    /**
+     * @since 2.6
+     */
+    public static long getLong(final String name, final long defaultValue) {
+        String str = getString(name);
+        if (str == null) {
+            return defaultValue;
+        }
+        return Long.parseLong(str);
+    }
+
+    //
+    // System property helpers
+    //
+
+    /**
+     * @since 2.7
+     */
+    public static String getLineSeparator() {
+        return System.getProperty("line.separator");
+    }
+
+    public static File getUserHome() {
+        return new File(System.getProperty("user.home"));
+    }
+
+    public static String getOsName() {
+        return System.getProperty("os.name").toLowerCase();
+    }
+
+    /**
+     * @since 2.7
+     */
+    public static boolean isWindows() {
+        return getOsName().startsWith("windows");
+    }
+
+    // FIXME: Sort out use of property access of file.encoding in InputStreamReader, consolidate should configuration access here
+
+    public static String getFileEncoding() {
+        return System.getProperty("file.encoding");
+    }
+
+    /**
+     * Get the default encoding.  Will first look at the LC_CTYPE environment variable, then the input.encoding
+     * system property, then the default charset according to the JVM.
+     *
+     * @return The default encoding to use when none is specified.
+     */
+    public static String getEncoding() {
+        // LC_CTYPE is usually in the form en_US.UTF-8
+        String envEncoding = extractEncodingFromCtype(System.getenv("LC_CTYPE"));
+        if (envEncoding != null) {
+            return envEncoding;
+        }
+        return System.getProperty("input.encoding", Charset.defaultCharset().name());
+    }
+
+    /**
+     * Parses the LC_CTYPE value to extract the encoding according to the POSIX standard, which says that the LC_CTYPE
+     * environment variable may be of the format <code>[language[_territory][.codeset][@modifier]]</code>
+     *
+     * @param ctype The ctype to parse, may be null
+     * @return The encoding, if one was present, otherwise null
+     */
+    static String extractEncodingFromCtype(String ctype) {
+        if (ctype != null && ctype.indexOf('.') > 0) {
+            String encodingAndModifier = ctype.substring(ctype.indexOf('.') + 1);
+            if (encodingAndModifier.indexOf('@') > 0) {
+                return encodingAndModifier.substring(0, encodingAndModifier.indexOf('@'));
+            } else {
+                return encodingAndModifier;
+            }
+        }
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/InputStreamReader.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.internal;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+import java.nio.charset.MalformedInputException;
+import java.nio.charset.UnmappableCharacterException;
+
+
+/**
+ *
+ * NOTE for JLine: the default InputStreamReader that comes from the JRE
+ * usually read more bytes than needed from the input stream, which
+ * is not usable in a character per character model used in the console.
+ * We thus use the harmony code which only reads the minimal number of bytes,
+ * with a modification to ensure we can read larger characters (UTF-16 has
+ * up to 4 bytes, and UTF-32, rare as it is, may have up to 8).
+ */
+/**
+ * A class for turning a byte stream into a character stream. Data read from the
+ * source input stream is converted into characters by either a default or a
+ * provided character converter. The default encoding is taken from the
+ * "file.encoding" system property. {@code InputStreamReader} contains a buffer
+ * of bytes read from the source stream and converts these into characters as
+ * needed. The buffer size is 8K.
+ *
+ * @see OutputStreamWriter
+ */
+public class InputStreamReader extends Reader {
+    private InputStream in;
+
+    private static final int BUFFER_SIZE = 8192;
+
+    private boolean endOfInput = false;
+
+    String encoding;
+
+    CharsetDecoder decoder;
+
+    ByteBuffer bytes = ByteBuffer.allocate(BUFFER_SIZE);
+
+    /**
+     * Constructs a new {@code InputStreamReader} on the {@link InputStream}
+     * {@code in}. This constructor sets the character converter to the encoding
+     * specified in the "file.encoding" property and falls back to ISO 8859_1
+     * (ISO-Latin-1) if the property doesn't exist.
+     *
+     * @param in
+     *            the input stream from which to read characters.
+     */
+    public InputStreamReader(InputStream in) {
+        super(in);
+        this.in = in;
+        // FIXME: This should probably use Configuration.getFileEncoding()
+        encoding = System.getProperty("file.encoding", "ISO8859_1"); //$NON-NLS-1$//$NON-NLS-2$
+        decoder = Charset.forName(encoding).newDecoder().onMalformedInput(
+                CodingErrorAction.REPLACE).onUnmappableCharacter(
+                CodingErrorAction.REPLACE);
+        bytes.limit(0);
+    }
+
+    /**
+     * Constructs a new InputStreamReader on the InputStream {@code in}. The
+     * character converter that is used to decode bytes into characters is
+     * identified by name by {@code enc}. If the encoding cannot be found, an
+     * UnsupportedEncodingException error is thrown.
+     *
+     * @param in
+     *            the InputStream from which to read characters.
+     * @param enc
+     *            identifies the character converter to use.
+     * @throws NullPointerException
+     *             if {@code enc} is {@code null}.
+     * @throws UnsupportedEncodingException
+     *             if the encoding specified by {@code enc} cannot be found.
+     */
+    public InputStreamReader(InputStream in, final String enc)
+            throws UnsupportedEncodingException {
+        super(in);
+        if (enc == null) {
+            throw new NullPointerException();
+        }
+        this.in = in;
+        try {
+            decoder = Charset.forName(enc).newDecoder().onMalformedInput(
+                    CodingErrorAction.REPLACE).onUnmappableCharacter(
+                    CodingErrorAction.REPLACE);
+        } catch (IllegalArgumentException e) {
+            throw (UnsupportedEncodingException)
+                    new UnsupportedEncodingException(enc).initCause(e);
+        }
+        bytes.limit(0);
+    }
+
+    /**
+     * Constructs a new InputStreamReader on the InputStream {@code in} and
+     * CharsetDecoder {@code dec}.
+     *
+     * @param in
+     *            the source InputStream from which to read characters.
+     * @param dec
+     *            the CharsetDecoder used by the character conversion.
+     */
+    public InputStreamReader(InputStream in, CharsetDecoder dec) {
+        super(in);
+        dec.averageCharsPerByte();
+        this.in = in;
+        decoder = dec;
+        bytes.limit(0);
+    }
+
+    /**
+     * Constructs a new InputStreamReader on the InputStream {@code in} and
+     * Charset {@code charset}.
+     *
+     * @param in
+     *            the source InputStream from which to read characters.
+     * @param charset
+     *            the Charset that defines the character converter
+     */
+    public InputStreamReader(InputStream in, Charset charset) {
+        super(in);
+        this.in = in;
+        decoder = charset.newDecoder().onMalformedInput(
+                CodingErrorAction.REPLACE).onUnmappableCharacter(
+                CodingErrorAction.REPLACE);
+        bytes.limit(0);
+    }
+
+    /**
+     * Closes this reader. This implementation closes the source InputStream and
+     * releases all local storage.
+     *
+     * @throws IOException
+     *             if an error occurs attempting to close this reader.
+     */
+    @Override
+    public void close() throws IOException {
+        synchronized (lock) {
+            decoder = null;
+            if (in != null) {
+                in.close();
+                in = null;
+            }
+        }
+    }
+
+    /**
+     * Returns the name of the encoding used to convert bytes into characters.
+     * The value {@code null} is returned if this reader has been closed.
+     *
+     * @return the name of the character converter or {@code null} if this
+     *         reader is closed.
+     */
+    public String getEncoding() {
+        if (!isOpen()) {
+            return null;
+        }
+        return encoding;
+    }
+
+    /**
+     * Reads a single character from this reader and returns it as an integer
+     * with the two higher-order bytes set to 0. Returns -1 if the end of the
+     * reader has been reached. The byte value is either obtained from
+     * converting bytes in this reader's buffer or by first filling the buffer
+     * from the source InputStream and then reading from the buffer.
+     *
+     * @return the character read or -1 if the end of the reader has been
+     *         reached.
+     * @throws IOException
+     *             if this reader is closed or some other I/O error occurs.
+     */
+    @Override
+    public int read() throws IOException {
+        synchronized (lock) {
+            if (!isOpen()) {
+                throw new IOException("InputStreamReader is closed.");
+            }
+
+            char buf[] = new char[4];
+            return read(buf, 0, 4) != -1 ? Character.codePointAt(buf, 0) : -1;
+        }
+    }
+
+    /**
+     * Reads at most {@code length} characters from this reader and stores them
+     * at position {@code offset} in the character array {@code buf}. Returns
+     * the number of characters actually read or -1 if the end of the reader has
+     * been reached. The bytes are either obtained from converting bytes in this
+     * reader's buffer or by first filling the buffer from the source
+     * InputStream and then reading from the buffer.
+     *
+     * @param buf
+     *            the array to store the characters read.
+     * @param offset
+     *            the initial position in {@code buf} to store the characters
+     *            read from this reader.
+     * @param length
+     *            the maximum number of characters to read.
+     * @return the number of characters read or -1 if the end of the reader has
+     *         been reached.
+     * @throws IndexOutOfBoundsException
+     *             if {@code offset < 0} or {@code length < 0}, or if
+     *             {@code offset + length} is greater than the length of
+     *             {@code buf}.
+     * @throws IOException
+     *             if this reader is closed or some other I/O error occurs.
+     */
+    @Override
+    public int read(char[] buf, int offset, int length) throws IOException {
+        synchronized (lock) {
+            if (!isOpen()) {
+                throw new IOException("InputStreamReader is closed.");
+            }
+            if (offset < 0 || offset > buf.length - length || length < 0) {
+                throw new IndexOutOfBoundsException();
+            }
+            if (length == 0) {
+                return 0;
+            }
+
+            CharBuffer out = CharBuffer.wrap(buf, offset, length);
+            CoderResult result = CoderResult.UNDERFLOW;
+
+            // bytes.remaining() indicates number of bytes in buffer
+            // when 1-st time entered, it'll be equal to zero
+            boolean needInput = !bytes.hasRemaining();
+
+            while (out.hasRemaining()) {
+                // fill the buffer if needed
+                if (needInput) {
+                    try {
+                        if ((in.available() == 0)
+                            && (out.position() > offset)) {
+                            // we could return the result without blocking read
+                            break;
+                        }
+                    } catch (IOException e) {
+                        // available didn't work so just try the read
+                    }
+
+                    int to_read = bytes.capacity() - bytes.limit();
+                    int off = bytes.arrayOffset() + bytes.limit();
+                    int was_red = in.read(bytes.array(), off, to_read);
+
+                    if (was_red == -1) {
+                        endOfInput = true;
+                        break;
+                    } else if (was_red == 0) {
+                        break;
+                    }
+                    bytes.limit(bytes.limit() + was_red);
+                    needInput = false;
+                }
+
+                // decode bytes
+                result = decoder.decode(bytes, out, false);
+
+                if (result.isUnderflow()) {
+                    // compact the buffer if no space left
+                    if (bytes.limit() == bytes.capacity()) {
+                        bytes.compact();
+                        bytes.limit(bytes.position());
+                        bytes.position(0);
+                    }
+                    needInput = true;
+                } else {
+                    break;
+                }
+            }
+
+            if (result == CoderResult.UNDERFLOW && endOfInput) {
+                result = decoder.decode(bytes, out, true);
+                decoder.flush(out);
+                decoder.reset();
+            }
+            if (result.isMalformed()) {
+                throw new MalformedInputException(result.length());
+            } else if (result.isUnmappable()) {
+                throw new UnmappableCharacterException(result.length());
+            }
+
+            return out.position() - offset == 0 ? -1 : out.position() - offset;
+        }
+    }
+
+    /*
+     * Answer a boolean indicating whether or not this InputStreamReader is
+     * open.
+     */
+    private boolean isOpen() {
+        return in != null;
+    }
+
+    /**
+     * Indicates whether this reader is ready to be read without blocking. If
+     * the result is {@code true}, the next {@code read()} will not block. If
+     * the result is {@code false} then this reader may or may not block when
+     * {@code read()} is called. This implementation returns {@code true} if
+     * there are bytes available in the buffer or the source stream has bytes
+     * available.
+     *
+     * @return {@code true} if the receiver will not block when {@code read()}
+     *         is called, {@code false} if unknown or blocking will occur.
+     * @throws IOException
+     *             if this reader is closed or some other I/O error occurs.
+     */
+    @Override
+    public boolean ready() throws IOException {
+        synchronized (lock) {
+            if (in == null) {
+                throw new IOException("InputStreamReader is closed.");
+            }
+            try {
+                return bytes.hasRemaining() || in.available() > 0;
+            } catch (IOException e) {
+                return false;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Log.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.internal;
+
+import java.io.PrintStream;
+
+import static jdk.internal.jline.internal.Preconditions.checkNotNull;
+
+/**
+ * Internal logger.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.0
+ */
+public final class Log
+{
+    ///CLOVER:OFF
+
+    public static enum Level
+    {
+        TRACE,
+        DEBUG,
+        INFO,
+        WARN,
+        ERROR
+    }
+
+    @SuppressWarnings({"StringConcatenation"})
+    public static final boolean TRACE = Boolean.getBoolean(Log.class.getName() + ".trace");
+
+    @SuppressWarnings({"StringConcatenation"})
+    public static final boolean DEBUG = TRACE || Boolean.getBoolean(Log.class.getName() + ".debug");
+
+    private static PrintStream output = System.err;
+
+    public static PrintStream getOutput() {
+        return output;
+    }
+
+    public static void setOutput(final PrintStream out) {
+        output = checkNotNull(out);
+    }
+
+    /**
+     * Helper to support rendering messages.
+     */
+    @TestAccessible
+    static void render(final PrintStream out, final Object message) {
+        if (message.getClass().isArray()) {
+            Object[] array = (Object[]) message;
+
+            out.print("[");
+            for (int i = 0; i < array.length; i++) {
+                out.print(array[i]);
+                if (i + 1 < array.length) {
+                    out.print(",");
+                }
+            }
+            out.print("]");
+        }
+        else {
+            out.print(message);
+        }
+    }
+
+    @TestAccessible
+    static void log(final Level level, final Object... messages) {
+        //noinspection SynchronizeOnNonFinalField
+        synchronized (output) {
+            output.format("[%s] ", level);
+
+            for (int i=0; i<messages.length; i++) {
+                // Special handling for the last message if its a throwable, render its stack on the next line
+                if (i + 1 == messages.length && messages[i] instanceof Throwable) {
+                    output.println();
+                    ((Throwable)messages[i]).printStackTrace(output);
+                }
+                else {
+                    render(output, messages[i]);
+                }
+            }
+
+            output.println();
+            output.flush();
+        }
+    }
+
+    public static void trace(final Object... messages) {
+        if (TRACE) {
+            log(Level.TRACE, messages);
+        }
+    }
+
+    public static void debug(final Object... messages) {
+        if (TRACE || DEBUG) {
+            log(Level.DEBUG, messages);
+        }
+    }
+
+    /**
+     * @since 2.7
+     */
+    public static void info(final Object... messages) {
+        log(Level.INFO, messages);
+    }
+
+    public static void warn(final Object... messages) {
+        log(Level.WARN, messages);
+    }
+
+    public static void error(final Object... messages) {
+        log(Level.ERROR, messages);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/NonBlockingInputStream.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.internal;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * This class wraps a regular input stream and allows it to appear as if it
+ * is non-blocking; that is, reads can be performed against it that timeout
+ * if no data is seen for a period of time.  This effect is achieved by having
+ * a separate thread perform all non-blocking read requests and then
+ * waiting on the thread to complete.
+ *
+ * <p>VERY IMPORTANT NOTES
+ * <ul>
+ *   <li> This class is not thread safe. It expects at most one reader.
+ *   <li> The {@link #shutdown()} method must be called in order to shut down
+ *          the thread that handles blocking I/O.
+ * </ul>
+ * @since 2.7
+ * @author Scott C. Gray <scottgray1@gmail.com>
+ */
+public class NonBlockingInputStream
+    extends InputStream
+    implements Runnable
+{
+    private InputStream in;               // The actual input stream
+    private int    ch   = -2;             // Recently read character
+
+    private boolean     threadIsReading      = false;
+    private boolean     isShutdown           = false;
+    private IOException exception            = null;
+    private boolean     nonBlockingEnabled;
+
+    /**
+     * Creates a <code>NonBlockingInputStream</code> out of a normal blocking
+     * stream. Note that this call also spawn a separate thread to perform the
+     * blocking I/O on behalf of the thread that is using this class. The
+     * {@link #shutdown()} method must be called in order to shut this thread down.
+     * @param in The input stream to wrap
+     * @param isNonBlockingEnabled If true, then the non-blocking methods
+     *   {@link #read(long)} and {@link #peek(long)} will be available and,
+     *   more importantly, the thread will be started to provide support for the
+     *   feature.  If false, then this class acts as a clean-passthru for the
+     *   underlying I/O stream and provides very little overhead.
+     */
+    public NonBlockingInputStream (InputStream in, boolean isNonBlockingEnabled) {
+        this.in                 = in;
+        this.nonBlockingEnabled = isNonBlockingEnabled;
+
+        if (isNonBlockingEnabled) {
+            Thread t = new Thread(this);
+            t.setName("NonBlockingInputStreamThread");
+            t.setDaemon(true);
+            t.start();
+        }
+    }
+
+    /**
+     * Shuts down the thread that is handling blocking I/O. Note that if the
+     * thread is currently blocked waiting for I/O it will not actually
+     * shut down until the I/O is received.  Shutting down the I/O thread
+     * does not prevent this class from being used, but causes the
+     * non-blocking methods to fail if called and causes {@link #isNonBlockingEnabled()}
+     * to return false.
+     */
+    public synchronized void shutdown() {
+        if (!isShutdown && nonBlockingEnabled) {
+            isShutdown = true;
+            notify();
+        }
+    }
+
+    /**
+     * Non-blocking is considered enabled if the feature is enabled and the
+     * I/O thread has not been shut down.
+     * @return true if non-blocking mode is enabled.
+     */
+    public boolean isNonBlockingEnabled() {
+        return nonBlockingEnabled && !isShutdown;
+    }
+
+    @Override
+    public void close() throws IOException {
+        /*
+         * The underlying input stream is closed first. This means that if the
+         * I/O thread was blocked waiting on input, it will be woken for us.
+         */
+        in.close();
+        shutdown();
+    }
+
+    @Override
+    public int read() throws IOException {
+        if (nonBlockingEnabled)
+            return read(0L, false);
+        return in.read ();
+    }
+
+    /**
+     * Peeks to see if there is a byte waiting in the input stream without
+     * actually consuming the byte.
+     *
+     * @param timeout The amount of time to wait, 0 == forever
+     * @return -1 on eof, -2 if the timeout expired with no available input
+     *   or the character that was read (without consuming it).
+     * @throws IOException
+     */
+    public int peek(long timeout) throws IOException {
+        if (!nonBlockingEnabled || isShutdown) {
+            throw new UnsupportedOperationException ("peek() "
+                + "cannot be called as non-blocking operation is disabled");
+        }
+        return read(timeout, true);
+    }
+
+    /**
+     * Attempts to read a character from the input stream for a specific
+     * period of time.
+     * @param timeout The amount of time to wait for the character
+     * @return The character read, -1 if EOF is reached, or -2 if the
+     *   read timed out.
+     * @throws IOException
+     */
+    public int read(long timeout) throws IOException {
+        if (!nonBlockingEnabled || isShutdown) {
+            throw new UnsupportedOperationException ("read() with timeout "
+                + "cannot be called as non-blocking operation is disabled");
+        }
+        return read(timeout, false);
+    }
+
+    /**
+     * Attempts to read a character from the input stream for a specific
+     * period of time.
+     * @param timeout The amount of time to wait for the character
+     * @return The character read, -1 if EOF is reached, or -2 if the
+     *   read timed out.
+     * @throws IOException
+     */
+    private synchronized int read(long timeout, boolean isPeek) throws IOException {
+        /*
+         * If the thread hit an IOException, we report it.
+         */
+        if (exception != null) {
+            assert ch == -2;
+            IOException toBeThrown = exception;
+            if (!isPeek)
+                exception = null;
+            throw toBeThrown;
+        }
+
+        /*
+         * If there was a pending character from the thread, then
+         * we send it. If the timeout is 0L or the thread was shut down
+         * then do a local read.
+         */
+        if (ch >= -1) {
+            assert exception == null;
+        }
+        else if ((timeout == 0L || isShutdown) && !threadIsReading) {
+            ch = in.read();
+        }
+        else {
+            /*
+             * If the thread isn't reading already, then ask it to do so.
+             */
+            if (!threadIsReading) {
+                threadIsReading = true;
+                notify();
+            }
+
+            boolean isInfinite = (timeout <= 0L);
+
+            /*
+             * So the thread is currently doing the reading for us. So
+             * now we play the waiting game.
+             */
+            while (isInfinite || timeout > 0L)  {
+                long start = System.currentTimeMillis ();
+
+                try {
+                    wait(timeout);
+                }
+                catch (InterruptedException e) {
+                    /* IGNORED */
+                }
+
+                if (exception != null) {
+                    assert ch == -2;
+
+                    IOException toBeThrown = exception;
+                    if (!isPeek)
+                        exception = null;
+                    throw toBeThrown;
+                }
+
+                if (ch >= -1) {
+                    assert exception == null;
+                    break;
+                }
+
+                if (!isInfinite) {
+                    timeout -= System.currentTimeMillis() - start;
+                }
+            }
+        }
+
+        /*
+         * ch is the character that was just read. Either we set it because
+         * a local read was performed or the read thread set it (or failed to
+         * change it).  We will return it's value, but if this was a peek
+         * operation, then we leave it in place.
+         */
+        int ret = ch;
+        if (!isPeek) {
+            ch = -2;
+        }
+        return ret;
+    }
+
+    /**
+     * This version of read() is very specific to jline's purposes, it
+     * will always always return a single byte at a time, rather than filling
+     * the entire buffer.
+     */
+    @Override
+    public int read (byte[] b, int off, int len) throws IOException {
+        if (b == null) {
+            throw new NullPointerException();
+        } else if (off < 0 || len < 0 || len > b.length - off) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return 0;
+        }
+
+        int c;
+        if (nonBlockingEnabled)
+            c = this.read(0L);
+        else
+            c = in.read();
+
+        if (c == -1) {
+            return -1;
+        }
+        b[off] = (byte)c;
+        return 1;
+    }
+
+    //@Override
+    public void run () {
+        Log.debug("NonBlockingInputStream start");
+        boolean needToShutdown = false;
+        boolean needToRead = false;
+
+        while (!needToShutdown) {
+
+            /*
+             * Synchronize to grab variables accessed by both this thread
+             * and the accessing thread.
+             */
+            synchronized (this) {
+                needToShutdown = this.isShutdown;
+                needToRead     = this.threadIsReading;
+
+                try {
+                    /*
+                     * Nothing to do? Then wait.
+                     */
+                    if (!needToShutdown && !needToRead) {
+                        wait(0);
+                    }
+                }
+                catch (InterruptedException e) {
+                    /* IGNORED */
+                }
+            }
+
+            /*
+             * We're not shutting down, but we need to read. This cannot
+             * happen while we are holding the lock (which we aren't now).
+             */
+            if (!needToShutdown && needToRead) {
+                int          charRead = -2;
+                IOException  failure = null;
+                try {
+                    charRead = in.read();
+                }
+                catch (IOException e) {
+                    failure = e;
+                }
+
+                /*
+                 * Re-grab the lock to update the state.
+                 */
+                synchronized (this) {
+                    exception       = failure;
+                    ch              = charRead;
+                    threadIsReading = false;
+                    notify();
+                }
+            }
+        }
+
+        Log.debug("NonBlockingInputStream shutdown");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Nullable.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.internal;
+
+import java.lang.annotation.*;
+
+/**
+ * Marker for reference which can be a null value.
+ *
+ * @since 2.7
+ */
+@Documented
+@Retention(RetentionPolicy.CLASS)
+@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE})
+public @interface Nullable
+{
+    String value() default "";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Preconditions.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.internal;
+
+// Some bits lifted from Guava's ( http://code.google.com/p/guava-libraries/ ) Preconditions.
+
+/**
+ * Preconditions.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.7
+ */
+public class Preconditions
+{
+    public static <T> T checkNotNull(final T reference) {
+        if (reference == null) {
+            throw new NullPointerException();
+        }
+        return reference;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/ShutdownHooks.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static jdk.internal.jline.internal.Preconditions.checkNotNull;
+
+/**
+ * Manages the JLine shutdown-hook thread and tasks to execute on shutdown.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.7
+ */
+public class ShutdownHooks
+{
+    public static final String JLINE_SHUTDOWNHOOK = "jline.shutdownhook";
+
+    private static final boolean enabled = Configuration.getBoolean(JLINE_SHUTDOWNHOOK, true);
+
+    private static final List<Task> tasks = new ArrayList<Task>();
+
+    private static Thread hook;
+
+    public static synchronized <T extends Task> T add(final T task) {
+        checkNotNull(task);
+
+        // If not enabled ignore
+        if (!enabled) {
+            Log.debug("Shutdown-hook is disabled; not installing: ", task);
+            return task;
+        }
+
+        // Install the hook thread if needed
+        if (hook == null) {
+            hook = addHook(new Thread("JLine Shutdown Hook")
+            {
+                @Override
+                public void run() {
+                    runTasks();
+                }
+            });
+        }
+
+        // Track the task
+        Log.debug("Adding shutdown-hook task: ", task);
+        tasks.add(task);
+
+        return task;
+    }
+
+    private static synchronized void runTasks() {
+        Log.debug("Running all shutdown-hook tasks");
+
+        // Iterate through copy of tasks list
+        for (Task task : tasks.toArray(new Task[tasks.size()])) {
+            Log.debug("Running task: ", task);
+            try {
+                task.run();
+            }
+            catch (Throwable e) {
+                Log.warn("Task failed", e);
+            }
+        }
+
+        tasks.clear();
+    }
+
+    private static Thread addHook(final Thread thread) {
+        Log.debug("Registering shutdown-hook: ", thread);
+        try {
+            Runtime.getRuntime().addShutdownHook(thread);
+        }
+        catch (AbstractMethodError e) {
+            // JDK 1.3+ only method. Bummer.
+            Log.debug("Failed to register shutdown-hook", e);
+        }
+        return thread;
+    }
+
+    public static synchronized void remove(final Task task) {
+        checkNotNull(task);
+
+        // ignore if not enabled or hook never installed
+        if (!enabled || hook == null) {
+            return;
+        }
+
+        // Drop the task
+        tasks.remove(task);
+
+        // If there are no more tasks, then remove the hook thread
+        if (tasks.isEmpty()) {
+            removeHook(hook);
+            hook = null;
+        }
+    }
+
+    private static void removeHook(final Thread thread) {
+        Log.debug("Removing shutdown-hook: ", thread);
+
+        try {
+            Runtime.getRuntime().removeShutdownHook(thread);
+        }
+        catch (AbstractMethodError e) {
+            // JDK 1.3+ only method. Bummer.
+            Log.debug("Failed to remove shutdown-hook", e);
+        }
+        catch (IllegalStateException e) {
+            // The VM is shutting down, not a big deal; ignore
+        }
+    }
+
+    /**
+     * Essentially a {@link Runnable} which allows running to throw an exception.
+     */
+    public static interface Task
+    {
+        void run() throws Exception;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/TerminalLineSettings.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.internal;
+
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.text.MessageFormat;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static jdk.internal.jline.internal.Preconditions.checkNotNull;
+
+/**
+ * Provides access to terminal line settings via <tt>stty</tt>.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:dwkemp@gmail.com">Dale Kemp</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @author <a href="mailto:jbonofre@apache.org">Jean-Baptiste Onofr\u00E9</a>
+ * @since 2.0
+ */
+public final class TerminalLineSettings
+{
+    public static final String JLINE_STTY = "jline.stty";
+
+    public static final String DEFAULT_STTY = "stty";
+
+    public static final String JLINE_SH = "jline.sh";
+
+    public static final String DEFAULT_SH = "sh";
+
+    private String sttyCommand;
+
+    private String shCommand;
+
+    private String config;
+    private String initialConfig;
+
+    private long configLastFetched;
+
+    public TerminalLineSettings() throws IOException, InterruptedException {
+        sttyCommand = Configuration.getString(JLINE_STTY, DEFAULT_STTY);
+        shCommand = Configuration.getString(JLINE_SH, DEFAULT_SH);
+        initialConfig = get("-g").trim();
+        config = get("-a");
+        configLastFetched = System.currentTimeMillis();
+
+        Log.debug("Config: ", config);
+
+        // sanity check
+        if (config.length() == 0) {
+            throw new IOException(MessageFormat.format("Unrecognized stty code: {0}", config));
+        }
+    }
+
+    public String getConfig() {
+        return config;
+    }
+
+    public void restore() throws IOException, InterruptedException {
+        set(initialConfig);
+    }
+
+    public String get(final String args) throws IOException, InterruptedException {
+        return stty(args);
+    }
+
+    public void set(final String args) throws IOException, InterruptedException {
+        stty(args);
+    }
+
+    /**
+     * <p>
+     * Get the value of a stty property, including the management of a cache.
+     * </p>
+     *
+     * @param name the stty property.
+     * @return the stty property value.
+     */
+    public int getProperty(String name) {
+        checkNotNull(name);
+        long currentTime = System.currentTimeMillis();
+        try {
+            // tty properties are cached so we don't have to worry too much about getting term width/height
+            if (config == null || currentTime - configLastFetched > 1000) {
+                config = get("-a");
+            }
+        } catch (Exception e) {
+            if (e instanceof InterruptedException) {
+                Thread.currentThread().interrupt();
+            }
+            Log.debug("Failed to query stty ", name, "\n", e);
+            if (config == null) {
+                return -1;
+            }
+        }
+
+        // always update the last fetched time and try to parse the output
+        if (currentTime - configLastFetched > 1000) {
+            configLastFetched = currentTime;
+        }
+
+        return getProperty(name, config);
+    }
+
+    /**
+     * <p>
+     * Parses a stty output (provided by stty -a) and return the value of a given property.
+     * </p>
+     *
+     * @param name property name.
+     * @param stty string resulting of stty -a execution.
+     * @return value of the given property.
+     */
+    protected static int getProperty(String name, String stty) {
+        // try the first kind of regex
+        Pattern pattern = Pattern.compile(name + "\\s+=\\s+(.*?)[;\\n\\r]");
+        Matcher matcher = pattern.matcher(stty);
+        if (!matcher.find()) {
+            // try a second kind of regex
+            pattern = Pattern.compile(name + "\\s+([^;]*)[;\\n\\r]");
+            matcher = pattern.matcher(stty);
+            if (!matcher.find()) {
+                // try a second try of regex
+                pattern = Pattern.compile("(\\S*)\\s+" + name);
+                matcher = pattern.matcher(stty);
+                if (!matcher.find()) {
+                    return -1;
+                }
+            }
+        }
+        return parseControlChar(matcher.group(1));
+    }
+
+    private static int parseControlChar(String str) {
+        // under
+        if ("<undef>".equals(str)) {
+            return -1;
+        }
+        // octal
+        if (str.charAt(0) == '0') {
+            return Integer.parseInt(str, 8);
+        }
+        // decimal
+        if (str.charAt(0) >= '1' && str.charAt(0) <= '9') {
+            return Integer.parseInt(str, 10);
+        }
+        // control char
+        if (str.charAt(0) == '^') {
+            if (str.charAt(1) == '?') {
+                return 127;
+            } else {
+                return str.charAt(1) - 64;
+            }
+        } else if (str.charAt(0) == 'M' && str.charAt(1) == '-') {
+            if (str.charAt(2) == '^') {
+                if (str.charAt(3) == '?') {
+                    return 127 + 128;
+                } else {
+                    return str.charAt(3) - 64 + 128;
+                }
+            } else {
+                return str.charAt(2) + 128;
+            }
+        } else {
+            return str.charAt(0);
+        }
+    }
+
+    private String stty(final String args) throws IOException, InterruptedException {
+        checkNotNull(args);
+        return exec(String.format("%s %s < /dev/tty", sttyCommand, args));
+    }
+
+    private String exec(final String cmd) throws IOException, InterruptedException {
+        checkNotNull(cmd);
+        return exec(shCommand, "-c", cmd);
+    }
+
+    private String exec(final String... cmd) throws IOException, InterruptedException {
+        checkNotNull(cmd);
+
+        ByteArrayOutputStream bout = new ByteArrayOutputStream();
+
+        Log.trace("Running: ", cmd);
+
+        Process p = Runtime.getRuntime().exec(cmd);
+
+        InputStream in = null;
+        InputStream err = null;
+        OutputStream out = null;
+        try {
+            int c;
+            in = p.getInputStream();
+            while ((c = in.read()) != -1) {
+                bout.write(c);
+            }
+            err = p.getErrorStream();
+            while ((c = err.read()) != -1) {
+                bout.write(c);
+            }
+            out = p.getOutputStream();
+            p.waitFor();
+        }
+        finally {
+            close(in, out, err);
+        }
+
+        String result = bout.toString();
+
+        Log.trace("Result: ", result);
+
+        return result;
+    }
+
+    private static void close(final Closeable... closeables) {
+        for (Closeable c : closeables) {
+            try {
+                c.close();
+            }
+            catch (Exception e) {
+                // Ignore
+            }
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/TestAccessible.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.internal;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Marker annotation for members which are exposed for testing access.
+ *
+ * @since 2.7
+ */
+@Retention(RUNTIME)
+@Target({TYPE, CONSTRUCTOR, METHOD, FIELD, PARAMETER})
+@Documented
+public @interface TestAccessible
+{
+    // empty
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Urls.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.internal;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+/**
+ * URL helpers.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
+ * @since 2.7
+ */
+public class Urls
+{
+    public static URL create(final String input) {
+        if (input == null) {
+            return null;
+        }
+        try {
+            return new URL(input);
+        }
+        catch (MalformedURLException e) {
+            return create(new File(input));
+        }
+    }
+
+    public static URL create(final File file) {
+        try {
+            return file != null ? file.toURI().toURL() : null;
+        }
+        catch (MalformedURLException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/package-info.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+/**
+ * Internal support.
+ *
+ * @since 2.0
+ */
+package jdk.internal.jline.internal;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/package-info.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+/**
+ * JLine 2.
+ *
+ * @since 2.0
+ */
+package jdk.internal.jline;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/windows/native/lible/WindowsTerminal.cpp	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "jni.h"
+#include "jni_util.h"
+#include "jvm.h"
+#include "jdk_internal_jline_WindowsTerminal.h"
+
+#include <stdlib.h>
+#include <Wincon.h>
+#include <Winuser.h>
+
+static jclass recordClass;
+static jmethodID recordConstructor;
+
+JNIEXPORT void JNICALL Java_jdk_internal_jline_WindowsTerminal_initIDs
+  (JNIEnv *env, jclass) {
+    jclass cls = env->FindClass("jdk/internal/jline/WindowsTerminal$KEY_EVENT_RECORD");
+    CHECK_NULL(cls);
+    recordClass = (jclass) env->NewGlobalRef(cls);
+    CHECK_NULL(recordClass);
+    recordConstructor = env->GetMethodID(cls, "<init>", "(ZCIII)V");
+    CHECK_NULL(recordConstructor);
+}
+
+JNIEXPORT jint JNICALL Java_jdk_internal_jline_WindowsTerminal_getConsoleMode
+  (JNIEnv *, jobject) {
+    HANDLE hStdIn;
+    if ((hStdIn = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
+        return -1;
+    }
+    DWORD fdwMode;
+    if (! GetConsoleMode(hStdIn, &fdwMode)) {
+        return -1;
+    }
+    return fdwMode;
+}
+
+JNIEXPORT void JNICALL Java_jdk_internal_jline_WindowsTerminal_setConsoleMode
+  (JNIEnv *, jobject, jint mode) {
+    HANDLE hStdIn;
+    if ((hStdIn = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
+        return ;
+    }
+    DWORD fdwMode = mode;
+    SetConsoleMode(hStdIn, fdwMode);
+}
+
+JNIEXPORT jobject JNICALL Java_jdk_internal_jline_WindowsTerminal_readKeyEvent
+  (JNIEnv *env, jobject) {
+    HANDLE hStdIn;
+    if ((hStdIn = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
+        return NULL;
+    }
+    INPUT_RECORD record;
+    DWORD n;
+    while (TRUE) {
+        if (ReadConsoleInput(hStdIn, &record, 1, &n) == 0) {
+            return NULL;
+        }
+        if (record.EventType == KEY_EVENT) {
+            jclass clazz = env->FindClass("jdk/internal/jline/WindowsTerminal$KEY_EVENT_RECORD");
+            jmethodID constr = env->GetMethodID(clazz, "<init>", "(ZCIII)V");
+            return env->NewObject(recordClass,
+                                  recordConstructor,
+                                  record.Event.KeyEvent.bKeyDown,
+                                  record.Event.KeyEvent.uChar.UnicodeChar,
+                                  record.Event.KeyEvent.dwControlKeyState,
+                                  record.Event.KeyEvent.wVirtualKeyCode,
+                                  record.Event.KeyEvent.wRepeatCount);
+        }
+        continue;
+    }
+}
+
+JNIEXPORT jint JNICALL Java_jdk_internal_jline_WindowsTerminal_getConsoleOutputCodepage
+  (JNIEnv *, jobject) {
+    return GetConsoleCP();
+}
+
+JNIEXPORT jint JNICALL Java_jdk_internal_jline_WindowsTerminal_getWindowsTerminalWidth
+  (JNIEnv *, jobject) {
+    HANDLE hStdIn;
+    if ((hStdIn = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
+        return -1;
+    }
+    CONSOLE_SCREEN_BUFFER_INFO info;
+    if (! GetConsoleScreenBufferInfo(hStdIn, &info)) {
+        return -1;
+    }
+    return info.dwSize.X;
+}
+
+JNIEXPORT jint JNICALL Java_jdk_internal_jline_WindowsTerminal_getWindowsTerminalHeight
+  (JNIEnv *, jobject) {
+    HANDLE hStdIn;
+    if ((hStdIn = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
+        return -1;
+    }
+    CONSOLE_SCREEN_BUFFER_INFO info;
+    if (! GetConsoleScreenBufferInfo(hStdIn, &info)) {
+        return -1;
+    }
+    return info.dwSize.Y;
+}
--- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Crypt.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Crypt.java	Thu Jul 09 16:37:55 2015 -0700
@@ -377,7 +377,7 @@
      *
      */
 
-    public static void main(String arg[]) {
+    public static void main(String[] arg) {
 
         if (arg.length!=2) {
             System.err.println("usage: Crypt password salt");
@@ -386,7 +386,7 @@
 
         Crypt c = new Crypt();
         try {
-            byte result[] = c.crypt
+            byte[] result = c.crypt
                 (arg[0].getBytes("ISO-8859-1"), arg[1].getBytes("ISO-8859-1"));
             for (int i=0; i<result.length; i++) {
                 System.out.println(" "+i+" "+(char)result[i]);
--- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/JndiLoginModule.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/JndiLoginModule.java	Thu Jul 09 16:37:55 2015 -0700
@@ -729,8 +729,8 @@
 
         Crypt c = new Crypt();
         try {
-            byte oldCrypt[] = encryptedPassword.getBytes("UTF8");
-            byte newCrypt[] = c.crypt(password.getBytes("UTF8"),
+            byte[] oldCrypt = encryptedPassword.getBytes("UTF8");
+            byte[] newCrypt = c.crypt(password.getBytes("UTF8"),
                                       oldCrypt);
             if (newCrypt.length != oldCrypt.length)
                 return false;
--- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/NTLoginModule.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/NTLoginModule.java	Thu Jul 09 16:37:55 2015 -0700
@@ -81,7 +81,7 @@
     private NTDomainPrincipal userDomain;               // user domain
     private NTSidDomainPrincipal domainSID;             // domain SID
     private NTSidPrimaryGroupPrincipal primaryGroup;    // primary group
-    private NTSidGroupPrincipal groups[];               // supplementary groups
+    private NTSidGroupPrincipal[] groups;               // supplementary groups
     private NTNumericCredential iToken;                 // impersonation token
 
     /**
@@ -194,7 +194,7 @@
         if (ntSystem.getGroupIDs() != null &&
             ntSystem.getGroupIDs().length > 0) {
 
-            String groupSIDs[] = ntSystem.getGroupIDs();
+            String[] groupSIDs = ntSystem.getGroupIDs();
             groups = new NTSidGroupPrincipal[groupSIDs.length];
             for (int i = 0; i < groupSIDs.length; i++) {
                 groups[i] = new NTSidGroupPrincipal(groupSIDs[i]);
--- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/NTSystem.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/NTSystem.java	Thu Jul 09 16:37:55 2015 -0700
@@ -40,7 +40,7 @@
     private String domain;
     private String domainSID;
     private String userSID;
-    private String groupIDs[];
+    private String[] groupIDs;
     private String primaryGroupID;
     private long   impersonationToken;
 
--- a/jdk/src/jdk.security.jgss/share/classes/com/sun/security/sasl/gsskerb/FactoryImpl.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/src/jdk.security.jgss/share/classes/com/sun/security/sasl/gsskerb/FactoryImpl.java	Thu Jul 09 16:37:55 2015 -0700
@@ -38,10 +38,10 @@
   * @author Rosanna Lee
   */
 public final class FactoryImpl implements SaslClientFactory, SaslServerFactory {
-    private static final String myMechs[] = {
+    private static final String[] myMechs = {
         "GSSAPI"};
 
-    private static final int mechPolicies[] = {
+    private static final int[] mechPolicies = {
         PolicyUtils.NOPLAINTEXT|PolicyUtils.NOANONYMOUS|PolicyUtils.NOACTIVE
     };
 
--- a/jdk/test/TEST.groups	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/test/TEST.groups	Thu Jul 09 16:37:55 2015 -0700
@@ -243,6 +243,7 @@
     javax/xml \
     -javax/xml/crypto \
     jdk/asm \
+    jdk/internal/jline \
     com/sun/jndi \
     com/sun/corba \
     lib/testlibrary \
--- a/jdk/test/java/lang/ProcessHandle/InfoTest.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/test/java/lang/ProcessHandle/InfoTest.java	Thu Jul 09 16:37:55 2015 -0700
@@ -32,24 +32,24 @@
 import java.nio.file.attribute.UserPrincipal;
 import java.time.Duration;
 import java.time.Instant;
-import java.time.temporal.ChronoUnit;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Random;
-import java.util.Scanner;
-import java.util.StringTokenizer;
 import java.util.concurrent.TimeUnit;
 
 import jdk.testlibrary.Platform;
+import jdk.testlibrary.Utils;
+
 import org.testng.Assert;
 import org.testng.annotations.Test;
 import org.testng.TestNG;
 
 /*
  * @test
+ * @build jdk.testlibrary.*
  * @library /lib/testlibrary
  * @summary Functions of ProcessHandle.Info
  * @author Roger Riggs
@@ -91,16 +91,16 @@
                 "test runner is included.");
         ProcessHandle self = ProcessHandle.current();
 
-        Duration somecpu = Duration.ofMillis(200L);
-        Instant end = Instant.now().plus(somecpu);
+        Duration someCPU = Duration.ofMillis(200L);
+        Instant end = Instant.now().plus(someCPU);
         while (Instant.now().isBefore(end)) {
             // waste the cpu
         }
         ProcessHandle.Info info = self.info();
         System.out.printf(" info: %s%n", info);
         Optional<Duration> totalCpu = info.totalCpuDuration();
-        if (totalCpu.isPresent() && (totalCpu.get().compareTo(somecpu) < 0)) {
-            Assert.fail("reported cputime less than expected: " + somecpu + ", " +
+        if (totalCpu.isPresent() && (totalCpu.get().compareTo(someCPU) < 0)) {
+            Assert.fail("reported cputime less than expected: " + someCPU + ", " +
                     "actual: " + info.totalCpuDuration());
         }
     }
@@ -111,17 +111,16 @@
     @Test
     public static void test2() {
         try {
-            long cpulooptime = 1 << 8;
+            long cpuLoopTime = 100;             // 100 ms
             String[] extraArgs = {"pid", "parent", "stdin"};
-            Instant beforeStart = Instant.now().truncatedTo(ChronoUnit.SECONDS);
             JavaChild p1 = JavaChild.spawnJavaChild((Object[])extraArgs);
             Instant afterStart = Instant.now();
 
             try (BufferedReader lines = p1.outputReader()) {
                 Duration lastCpu = Duration.ofMillis(0L);
-                for (int j = 0; j < 20; j++) {
+                for (int j = 0; j < 10; j++) {
 
-                    p1.sendAction("cpuloop", cpulooptime);
+                    p1.sendAction("cpuloop", cpuLoopTime);
                     p1.sendAction("cputime", "");
 
                     // Read cputime from child
@@ -187,17 +186,21 @@
                     if (info.totalCpuDuration().isPresent()) {
                         Duration totalCPU = info.totalCpuDuration().get();
                         Duration epsilon = Duration.ofMillis(200L);
-                        Assert.assertTrue(totalCPU.toNanos() > 0L,
-                                "total cpu time expected > 0ms, actual: " + totalCPU);
-                        Assert.assertTrue(totalCPU.toNanos() < lastCpu.toNanos() + 10_000_000_000L,
-                                "total cpu time expected < 10s more than previous iteration, actual: " + totalCPU);
                         if (childCpuTime != null) {
                             System.out.printf(" info.totalCPU: %s, childCpuTime: %s, diff: %s%n",
-                                    totalCPU.toNanos(), childCpuTime.toNanos(), childCpuTime.toNanos() - totalCPU.toNanos());
+                                    totalCPU.toNanos(), childCpuTime.toNanos(),
+                                    childCpuTime.toNanos() - totalCPU.toNanos());
                             Assert.assertTrue(checkEpsilon(childCpuTime, totalCPU, epsilon),
                                     childCpuTime + " should be within " +
                                             epsilon + " of " + totalCPU);
                         }
+                        Assert.assertTrue(totalCPU.toNanos() > 0L,
+                                "total cpu time expected > 0ms, actual: " + totalCPU);
+                        long t = Utils.adjustTimeout(10L);  // Adjusted timeout seconds
+                        Assert.assertTrue(totalCPU.toNanos() < lastCpu.toNanos() + t * 1_000_000_000L,
+                                "total cpu time expected < " + t
+                                        + " seconds more than previous iteration, actual: "
+                                        + (totalCPU.toNanos() - lastCpu.toNanos()));
                         lastCpu = totalCPU;
                     }
 
@@ -209,7 +212,7 @@
                     }
                 }
             }
-            p1.waitFor(5, TimeUnit.SECONDS);
+            p1.waitFor(Utils.adjustTimeout(5), TimeUnit.SECONDS);
         } catch (IOException | InterruptedException ie) {
             ie.printStackTrace(System.out);
             Assert.fail("unexpected exception", ie);
@@ -252,7 +255,7 @@
                 Assert.assertTrue(p.waitFor(15, TimeUnit.SECONDS));
             }
         } catch (IOException | InterruptedException ex) {
-            ex.printStackTrace(System.out);;
+            ex.printStackTrace(System.out);
         } finally {
             // Destroy any children that still exist
             ProcessUtil.destroyProcessTree(ProcessHandle.current());
@@ -274,7 +277,7 @@
 
         if (dur1.isPresent() && dur2.isPresent()) {
             Duration total1 = dur1.get();
-            Duration total2 = dur2.get();       ;
+            Duration total2 = dur2.get();
             System.out.printf(" total1 vs. mbean: %s, getProcessCpuTime: %s, diff: %s%n",
                     Objects.toString(total1), myCputime1, myCputime1.minus(total1));
             System.out.printf(" total2 vs. mbean: %s, getProcessCpuTime: %s, diff: %s%n",
@@ -326,7 +329,7 @@
      * @param d1 a Duration - presumed to be shorter
      * @param d2 a 2nd Duration - presumed to be greater (or within Epsilon)
      * @param epsilon Epsilon the amount of overlap allowed
-     * @return
+     * @return true if d2 is greater than d1 or within epsilon, false otherwise
      */
     static boolean checkEpsilon(Duration d1, Duration d2, Duration epsilon) {
         if (d1.toNanos() <= d2.toNanos()) {
@@ -339,7 +342,7 @@
     /**
      * Spawn a native process with the provided arguments.
      * @param command the executable of native process
-     * @args
+     * @param args to start a new process
      * @return the Process that was started
      * @throws IOException thrown by ProcessBuilder.start
      */
--- a/jdk/test/java/lang/ProcessHandle/JavaChild.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/test/java/lang/ProcessHandle/JavaChild.java	Thu Jul 09 16:37:55 2015 -0700
@@ -281,12 +281,12 @@
                         sendResult(action, Integer.toString(millis));
                         break;
                     case "cpuloop":
-                        long times = Long.valueOf(args[nextArg++]);
-                        Instant end = Instant.now().plusMillis(times);
-                        while (Instant.now().isBefore(end)) {
-                            // burn the cpu til the time is up
+                        long cpuMillis = Long.valueOf(args[nextArg++]);
+                        long cpuTarget = getCpuTime() + cpuMillis * 1_000_000L;
+                        while (getCpuTime() < cpuTarget) {
+                            // burn the cpu until the time is up
                         }
-                        sendResult(action, times);
+                        sendResult(action, cpuMillis);
                         break;
                     case "cputime":
                         sendResult(action, getCpuTime());
--- a/jdk/test/java/lang/ProcessHandle/OnExitTest.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/test/java/lang/ProcessHandle/OnExitTest.java	Thu Jul 09 16:37:55 2015 -0700
@@ -27,16 +27,19 @@
 import java.time.Instant;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutionException;
+
+import jdk.testlibrary.Utils;
+
 import org.testng.annotations.Test;
 import org.testng.Assert;
 import org.testng.TestNG;
 
 /*
  * @test
+ * @build jdk.testlibrary.Utils
  * @summary Functions of Process.onExit and ProcessHandle.onExit
  * @author Roger Riggs
  */
@@ -88,6 +91,7 @@
      */
     @Test
     public static void test2() {
+        ProcessHandle procHandle = null;
         try {
             ConcurrentHashMap<ProcessHandle, ProcessHandle> processes = new ConcurrentHashMap<>();
             List<ProcessHandle> children = getChildren(ProcessHandle.current());
@@ -96,7 +100,7 @@
                     "Expected to start with zero children; " + children);
 
             JavaChild proc = JavaChild.spawnJavaChild("stdin");
-            ProcessHandle procHandle = proc.toHandle();
+            procHandle = proc.toHandle();
             printf(" spawned: %d%n", proc.getPid());
 
             proc.forEachOutputLine((s) -> {
@@ -114,7 +118,8 @@
 
             // Poll until all 9 child processes exist or the timeout is reached
             int expected = 9;
-            Instant endTimeout = Instant.now().plusSeconds(10L);
+            long timeout = Utils.adjustTimeout(10L);
+            Instant endTimeout = Instant.now().plusSeconds(timeout);
             do {
                 Thread.sleep(200L);
                 printf(" subprocess count: %d, waiting for %d%n", processes.size(), expected);
@@ -123,16 +128,17 @@
 
             children = getAllChildren(procHandle);
 
-            ArrayBlockingQueue<ProcessHandle> completions = new ArrayBlockingQueue<>(expected + 1);
+            ConcurrentHashMap<ProcessHandle, CompletableFuture<ProcessHandle>> completions =
+                    new ConcurrentHashMap<>();
             Instant startTime = Instant.now();
             // Create a future for each of the 9 children
             processes.forEach( (p, parent) -> {
-                        p.onExit().whenComplete((ph, ex) -> {
+                        CompletableFuture<ProcessHandle> cf = p.onExit().whenComplete((ph, ex) -> {
                             Duration elapsed = Duration.between(startTime, Instant.now());
-                            completions.add(ph);
                             printf("whenComplete: pid: %s, exception: %s, thread: %s, elapsed: %s%n",
                                     ph, ex, Thread.currentThread(), elapsed);
                         });
+                        completions.put(p, cf);
                     });
 
             // Check that each of the spawned processes is included in the children
@@ -153,20 +159,23 @@
             proc.destroy();  // kill off the parent
             proc.waitFor();
 
-            // Wait for all the processes to be completed
+            // Wait for all the processes and corresponding onExit CF to be completed
             processes.forEach((p, parent) -> {
                 try {
                     p.onExit().get();
+                    completions.get(p).join();
                 } catch (InterruptedException | ExecutionException ex) {
                     // ignore
                 }
             });
 
-            // Verify that all 9 exit handlers were called
-            processes.forEach((p, parent) ->
-                Assert.assertTrue(completions.contains(p), "Child onExit not called: " + p
-                        + ", parent: " + parent
-                        + ": " + p.info()));
+            // Verify that all 9 exit handlers were called with the correct ProcessHandle
+            processes.forEach((p, parent) -> {
+                ProcessHandle value = completions.get(p).getNow(null);
+                Assert.assertEquals(p, value, "onExit.get value expected: " + p
+                        + ", actual: " + value
+                        + ": " + p.info());
+            });
 
             // Show the status of the original children
             children.forEach(p -> printProcess(p, "after onExit:"));
@@ -176,13 +185,12 @@
             List<ProcessHandle> children2 = getAllChildren(procHandle);
             printf(" children2: %s%n", children2.toString());
             Assert.assertEquals(children2.size(), 0, "After onExit, expected no children");
-
-            Assert.assertEquals(remaining.size(), 0, "Unaccounted for children");
-
         } catch (IOException | InterruptedException ex) {
             Assert.fail(ex.getMessage());
         } finally {
-            destroyProcessTree(ProcessHandle.current());
+            if (procHandle != null) {
+                destroyProcessTree(procHandle);
+            }
         }
     }
 
--- a/jdk/test/java/lang/ProcessHandle/TreeTest.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/test/java/lang/ProcessHandle/TreeTest.java	Thu Jul 09 16:37:55 2015 -0700
@@ -75,10 +75,12 @@
                 spawned.add(JavaChild.spawnJavaChild("pid", "stdin"));
             }
 
-            List<ProcessHandle> subprocesses = getChildren(self);
-            subprocesses.forEach(ProcessUtil::printProcess);
-            count = subprocesses.size();
-            Assert.assertEquals(count, MAXCHILDREN, "Wrong number of spawned children");
+            // Verify spawned Process is in list of children
+            final List<ProcessHandle> initialChildren = getChildren(self);
+            spawned.stream()
+                    .map(Process::toHandle)
+                    .filter(p -> !initialChildren.contains(p))
+                    .forEach(p -> Assert.fail("Spawned process missing from children: " + p));
 
             // Send exit command to each spawned Process
             spawned.forEach(p -> {
@@ -102,20 +104,25 @@
                 });
 
             // Verify that ProcessHandle.isAlive sees each of them as not alive
-            for (ProcessHandle ph : subprocesses) {
+            for (Process p : spawned) {
+                ProcessHandle ph = p.toHandle();
                 Assert.assertFalse(ph.isAlive(),
                         "ProcessHandle.isAlive for exited process: " + ph);
             }
 
-            // Verify no current children are visible
-            count = getChildren(self).size();
-            Assert.assertEquals(count, 0, "Children destroyed, should be zero");
+            // Verify spawned processes are not visible as children
+            final List<ProcessHandle> afterChildren = getChildren(self);
+            spawned.stream()
+                    .map(Process::toHandle)
+                    .filter(p -> afterChildren.contains(p))
+                    .forEach(p -> Assert.fail("Spawned process missing from children: " + p));
 
         } catch (IOException ioe) {
             Assert.fail("unable to spawn process", ioe);
         } finally {
             // Cleanup any left over processes
-            spawned.stream().map(Process::toHandle)
+            spawned.stream()
+                    .map(Process::toHandle)
                     .filter(ProcessHandle::isAlive)
                     .forEach(ph -> printDeep(ph, "test1 cleanup: "));
             destroyProcessTree(ProcessHandle.current());
@@ -127,7 +134,6 @@
      */
     @Test
     public static void test2() {
-        ProcessHandle p1Handle = null;
         try {
             ProcessHandle self = ProcessHandle.current();
             List<ProcessHandle> initialChildren = getChildren(self);
@@ -138,7 +144,7 @@
             }
 
             JavaChild p1 = JavaChild.spawnJavaChild("stdin");
-            p1Handle = p1.toHandle();
+            ProcessHandle p1Handle = p1.toHandle();
             printf("  p1 pid: %d%n", p1.getPid());
 
             int spawnNew = 3;
@@ -187,9 +193,6 @@
             throw new RuntimeException(t);
         } finally {
             // Cleanup any left over processes
-            if (p1Handle.isAlive()) {
-                printDeep(p1Handle, "test2 cleanup: ");
-            }
             destroyProcessTree(ProcessHandle.current());
         }
     }
@@ -205,7 +208,10 @@
             JavaChild p1 = JavaChild.spawnJavaChild("stdin");
             ProcessHandle p1Handle = p1.toHandle();
             printf(" p1: %s%n", p1.getPid());
-            long count = getChildren(self).size();
+
+            List<ProcessHandle> subprocesses = getChildren(self);
+            subprocesses.forEach(ProcessUtil::printProcess);
+            long count = subprocesses.size();
             Assert.assertEquals(count, 1, "Wrong number of spawned children");
 
             int newChildren = 3;
@@ -213,7 +219,7 @@
             p1.sendAction("spawn", newChildren, "stdin");
 
             // Wait for the new processes and save the list
-            List<ProcessHandle> subprocesses = waitForAllChildren(p1Handle, newChildren);
+            subprocesses = waitForAllChildren(p1Handle, newChildren);
             printDeep(p1Handle, "allChildren");
 
             Assert.assertEquals(subprocesses.size(), newChildren, "Wrong number of children");
@@ -249,6 +255,9 @@
             Assert.fail("Spawn of subprocess failed", ioe);
         } catch (InterruptedException inte) {
             Assert.fail("InterruptedException", inte);
+        } finally {
+            // Cleanup any left over processes
+            destroyProcessTree(ProcessHandle.current());
         }
     }
 
@@ -299,16 +308,15 @@
     }
 
     /**
-     * A test for scale; launch a large number (39) of subprocesses.
+     * A test for scale; launch a large number (14) of subprocesses.
      */
     @Test
     public static void test5() {
         int factor = 2;
-        ProcessHandle p1Handle = null;
         Instant start = Instant.now();
         try {
             JavaChild p1 = JavaChild.spawnJavaChild("stdin");
-            p1Handle = p1.toHandle();
+            ProcessHandle p1Handle = p1.toHandle();
 
             printf("Spawning %d x %d x %d processes, pid: %d%n",
                     factor, factor, factor, p1.getPid());
@@ -325,18 +333,14 @@
             int newChildren = factor * (1 + factor * (1 + factor));
             List<ProcessHandle> children = ProcessUtil.waitForAllChildren(p1Handle, newChildren);
 
-            Assert.assertEquals(p1.children()
-                    .filter(ProcessUtil::isNotWindowsConsole)
-                    .count(), factor, "expected direct children");
-            Assert.assertEquals(p1.allChildren()
-                    .filter(ProcessUtil::isNotWindowsConsole)
-                    .count(),
-                    factor * factor * factor + factor * factor + factor,
-                    "expected all children");
+            Assert.assertEquals(getChildren(p1Handle).size(),
+                    factor, "expected direct children");
+            long count = getAllChildren(p1Handle).size();
+            long totalChildren = factor * factor * factor + factor * factor + factor;
+            Assert.assertTrue(count >= totalChildren,
+                    "expected at least " + totalChildren + ", actual: " + count);
 
-            List<ProcessHandle> subprocesses = p1.allChildren()
-                    .filter(ProcessUtil::isNotWindowsConsole)
-                    .collect(Collectors.toList());
+            List<ProcessHandle> subprocesses = getAllChildren(p1Handle);
             printf(" allChildren:  %s%n",
                     subprocesses.stream().map(p -> p.getPid())
                     .collect(Collectors.toList()));
@@ -347,10 +351,6 @@
             Assert.fail("Unexpected Exception", ex);
         } finally {
             printf("Duration: %s%n", Duration.between(start, Instant.now()));
-            // Cleanup any left over processes
-            if (p1Handle.isAlive()) {
-                printDeep(p1Handle, "test5 cleanup: ");
-            }
             destroyProcessTree(ProcessHandle.current());
         }
     }
--- a/jdk/test/java/net/Socks/SocksProxyVersion.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/test/java/net/Socks/SocksProxyVersion.java	Thu Jul 09 16:37:55 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 6964547 5001942
+ * @bug 6964547 5001942 8129444
  * @run main/othervm SocksProxyVersion
  * @summary test socksProxyVersion system property
  */
@@ -32,13 +32,15 @@
 import java.net.ServerSocket;
 import java.net.Socket;
 import java.net.SocketException;
-import java.io.DataInputStream;
 import java.io.IOException;
 import java.net.InetAddress;
+import java.net.Proxy;
 
 public class SocksProxyVersion implements Runnable {
     final ServerSocket ss;
     volatile boolean failed;
+    volatile boolean stopped = false;
+    volatile int expected;
 
     public static void main(String[] args) throws Exception {
         if (InetAddress.getLocalHost().isLoopbackAddress()) {
@@ -48,21 +50,26 @@
         new SocksProxyVersion();
     }
 
-    @SuppressWarnings("try")
     public SocksProxyVersion() throws Exception {
         ss = new ServerSocket(0);
+        int port = ss.getLocalPort();
+        Thread serverThread = new Thread(this);
+        serverThread.start();
         try (ServerSocket socket = ss) {
-            runTest();
+            runTest(port);
+        } finally {
+            stopped = true;
+        }
+
+        serverThread.join();
+        if (failed) {
+            throw new RuntimeException("socksProxyVersion not being set correctly");
         }
     }
 
-    void runTest() throws Exception {
-        int port = ss.getLocalPort();
-        Thread serverThread = new Thread(this);
-        serverThread.start();
-
+    final void runTest(int port) throws Exception {
         /*
-         * Retreving the IP Address of the machine
+         * Retrieving the IP Address of the machine
          * since "localhost" is bypassed as a non-proxy host
          */
         String addr = InetAddress.getLocalHost().getHostAddress();
@@ -70,46 +77,54 @@
         System.setProperty("socksProxyHost", addr);
         System.setProperty("socksProxyPort", Integer.toString(port));
 
+        Proxy proxy = new Proxy(Proxy.Type.SOCKS,
+                                new InetSocketAddress(addr, port));
+
         // SOCKS V4
         System.setProperty("socksProxyVersion", Integer.toString(4));
-        try (Socket s = new Socket()) {
-            s.connect(new InetSocketAddress(addr, port));
+        this.expected = 4;
+        check(new Socket(), addr, port);
+        check(new Socket(proxy), addr, port);
+
+        // SOCKS V5
+        System.setProperty("socksProxyVersion", Integer.toString(5));
+        this.expected = 5;
+        check(new Socket(), addr, port);
+        check(new Socket(proxy), addr, port);
+    }
+
+    private void check(Socket socket, String addr, int port)
+        throws IOException
+    {
+        try (Socket s = socket) {
+            socket.connect(new InetSocketAddress(addr, port));
         } catch (SocketException e) {
             // java.net.SocketException: Malformed reply from SOCKS server
             // This exception is OK, since the "server" does not implement
             // the socks protocol. It just verifies the version and closes.
         }
-
-        // SOCKS V5
-        System.setProperty("socksProxyVersion", Integer.toString(5));
-        try (Socket s = new Socket()) {
-            s.connect(new InetSocketAddress(addr, port));
-        } catch (SocketException e) { /* OK */ }
-
-        serverThread.join();
-        if (failed) {
-            throw new RuntimeException("socksProxyVersion not being set correctly");
-        }
     }
 
+    @Override
     public void run() {
+        int count = 0;
         try {
-            try (Socket s = ss.accept()) {
-                int version = (s.getInputStream()).read();
-                if (version != 4) {
-                    System.out.println("Got " + version + ", expected 4");
-                    failed = true;
+            while (!stopped) {
+                try (Socket s = ss.accept()) {
+                    int version = (s.getInputStream()).read();
+                    if (version != expected) {
+                        System.out.printf("Iteration: %d, Got: %d, expected: %d%n",
+                                          count, version, expected);
+                        failed = true;
+                    }
                 }
-            }
-            try (Socket s = ss.accept()) {
-                int version = (s.getInputStream()).read();
-                if (version != 5) {
-                    System.out.println("Got " + version + ", expected 5");
-                    failed = true;
-                }
+                count++;
             }
         } catch (IOException e) {
-            e.printStackTrace();
+            if (!ss.isClosed()) {
+                e.printStackTrace();
+            }
+            // ignore, server socket was closed
         }
     }
 }
--- a/jdk/test/java/util/Collection/MOAT.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/test/java/util/Collection/MOAT.java	Thu Jul 09 16:37:55 2015 -0700
@@ -356,13 +356,7 @@
             }
 
             check(c.toArray().length == c.size());
-            check(c.toArray().getClass() == Object[].class
-                  ||
-                  // !!!!
-                  // 6260652: (coll) Arrays.asList(x).toArray().getClass()
-                  // should be Object[].class
-                  (c.getClass().getName().equals("java.util.Arrays$ArrayList"))
-                  );
+            check(c.toArray().getClass() == Object[].class);
             for (int size : new int[]{0,1,c.size(), c.size()+1}) {
                 Integer[] a = c.toArray(new Integer[size]);
                 check((size > c.size()) || a.length == c.size());
--- a/jdk/test/java/util/logging/LoggingDeadlock2.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/test/java/util/logging/LoggingDeadlock2.java	Thu Jul 09 16:37:55 2015 -0700
@@ -57,35 +57,59 @@
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.logging.LogManager;
 import java.io.File;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.Reader;
+import java.util.concurrent.TimeUnit;
 
 public class LoggingDeadlock2 {
 
+    // ask child process to dumpstack after 60secs
+    public static final long DUMP_STACK_FREQUENCY_MS = 60000;
+
+    // A marker that allows to validate the subprocess output.
+    public static final String MARKER = "$";
+
     public static void realMain(String arg[]) throws Throwable {
         try {
             System.out.println(javaChildArgs);
             ProcessBuilder pb = new ProcessBuilder(javaChildArgs);
             ProcessResults r = run(pb.start());
             equal(r.exitValue(), 99);
-            equal(r.out(), "");
+
+            // output of subprocess should end with "$"
+            final String out = r.out();
+            final String trailingOutput = out.indexOf(MARKER) > -1
+                    ? out.substring(out.indexOf(MARKER)+MARKER.length())
+                    : out;
+            equal(trailingOutput, "");
             equal(r.err(), "");
+            equal(out.startsWith("JavaChild started"), true);
+            equal(out.endsWith("$"), true);
         } catch (Throwable t) { unexpected(t); }
     }
 
     public static class JavaChild {
         public static void main(String args[]) throws Throwable {
+            System.out.println("JavaChild started");
+
             final CyclicBarrier startingGate = new CyclicBarrier(2);
             final Throwable[] thrown = new Throwable[1];
 
             // Some random variation, to help tickle races.
             final Random rnd = new Random();
+            final long seed = rnd.nextLong();
+            rnd.setSeed(seed);
+            System.out.println("seed=" + seed);
             final boolean dojoin = rnd.nextBoolean();
             final int JITTER = 1024;
             final int iters1 = rnd.nextInt(JITTER);
             final int iters2 = JITTER - iters1;
             final AtomicInteger counter = new AtomicInteger(0);
+            System.out.println("dojoin=" + dojoin);
+            System.out.println("iters1=" + iters1);
+            System.out.println("iters2=" + iters2);
 
             Thread exiter = new Thread() {
                 public void run() {
@@ -101,6 +125,12 @@
                 }};
             exiter.start();
 
+            System.out.println("exiter started");
+
+            // signal end of verbose output
+            System.out.print(MARKER);
+            System.out.flush();
+
             startingGate.await();
             for (int i = 0; i < iters2; i++)
                 counter.getAndIncrement();
@@ -124,6 +154,9 @@
     private static final String javaExe =
         System.getProperty("java.home") +
         File.separator + "bin" + File.separator + "java";
+    private static final String jstackExe =
+        System.getProperty("java.home") +
+        File.separator + "bin" + File.separator + "jstack";
 
     private static final String classpath =
         System.getProperty("java.class.path");
@@ -182,10 +215,15 @@
         public void run() {
             try {
                 Reader r = new InputStreamReader(is);
-                char[] buf = new char[4096];
                 int n;
-                while ((n = r.read(buf)) > 0) {
-                    sb.append(buf,0,n);
+                while ((n = r.read()) > 0) {
+                    sb.append((char)n);
+
+                    // prints everything immediately to System.out so that we can
+                    // see the traces even in the event of a test timeout
+                    System.out.write((char)n);
+                    System.out.flush();
+
                 }
             } catch (Throwable t) {
                 throwable = t;
@@ -196,6 +234,56 @@
         }
     }
 
+    /**
+     * If the child process deadlocks, then the parent may fail in timeout.
+     * In that case, we won't have any interesting traces, unless we manage
+     * to get a thread dump from the child.
+     * It is unsure whether obtaining a thread dump from a deadlocked child
+     * will work - but maybe we could see something if the timeout is a false
+     * positive (the child has not deadlocked but hasn't managed to fully start
+     * yet, for instance).
+     * The idea here is to periodically try to obtain a thread dump from the
+     * child, every 60sec - which should be always less than the jtreg timeout.
+     */
+    private static class TimeoutThread extends Thread {
+        final long ms;
+        final Process process;
+        TimeoutThread(long ms, Process p) {
+            super("TimeoutThread");
+            setDaemon(true);
+            this.ms = ms;
+            this.process = p;
+        }
+
+        @Override
+        public void run() {
+            long start = System.nanoTime();
+            try {
+                while (true) {
+                    sleep(ms);
+                    System.err.println("Timeout reached: " + ms);
+                    if (process.isAlive()) {
+                        long pid = process.getPid();
+                        ProcessBuilder jstack = new ProcessBuilder(jstackExe, String.valueOf(pid));
+                        System.err.println("Dumping subprocess stack: " + pid);
+                        Process p = jstack.inheritIO().start();
+                        p.waitFor(ms, TimeUnit.MILLISECONDS);
+                    } else {
+                        System.err.println("Process is not alive!");
+                        break;
+                    }
+                }
+            } catch (InterruptedException ex) {
+                System.err.println("Interrupted: " + ex);
+            } catch (IOException io) {
+                System.err.println("Failed to get stack from subprocess");
+                io.printStackTrace();
+            }
+        }
+
+
+    }
+
     private static ProcessResults run(Process p) {
         Throwable throwable = null;
         int exitValue = -1;
@@ -208,10 +296,15 @@
             new StreamAccumulator(p.getErrorStream());
 
         try {
+            System.out.println("Waiting for child process to exit");
             outAccumulator.start();
             errAccumulator.start();
 
+            // ask subprocess to dump stack every 60 secs.
+            new TimeoutThread(DUMP_STACK_FREQUENCY_MS, p).start();
+
             exitValue = p.waitFor();
+            System.out.println("\nChild exited with status: " + exitValue);
 
             outAccumulator.join();
             errAccumulator.join();
--- a/jdk/test/javax/net/ssl/DTLS/DTLSOverDatagram.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/test/javax/net/ssl/DTLS/DTLSOverDatagram.java	Thu Jul 09 16:37:55 2015 -0700
@@ -46,8 +46,8 @@
  * An example to show the way to use SSLEngine in datagram connections.
  */
 public class DTLSOverDatagram {
-    private static int MAX_HANDSHAKE_LOOPS = 60;
-    private static int MAX_APP_READ_LOOPS = 10;
+    private static int MAX_HANDSHAKE_LOOPS = 200;
+    private static int MAX_APP_READ_LOOPS = 60;
 
     /*
      * The following is to set up the keystores.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/internal/jline/KeyConversionTest.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8080679
+ * @summary Verify the conversion from key events to escape sequences works properly.
+ * @requires os.family == "windows"
+ */
+
+import jdk.internal.jline.WindowsTerminal;
+import jdk.internal.jline.WindowsTerminal.KEY_EVENT_RECORD;
+
+public class KeyConversionTest {
+    public static void main(String... args) throws Exception {
+        new KeyConversionTest().run();
+    }
+
+    void run() throws Exception {
+        checkKeyConversion(new KEY_EVENT_RECORD(true, '\0', 256, 37, 1), "\033[D"); //LEFT
+        checkKeyConversion(new KEY_EVENT_RECORD(true, '\0', 264, 37, 1), "\033[1;5D"); //Ctrl-LEFT
+        checkKeyConversion(new KEY_EVENT_RECORD(true, '\0', 258, 37, 1), "\033[1;3D"); //Alt-LEFT
+        checkKeyConversion(new KEY_EVENT_RECORD(true, '\0', 256, 46, 1), "\033[3~"); //delete
+        checkKeyConversion(new KEY_EVENT_RECORD(true, '\0', 264, 46, 1), "\033[3;5~"); //Ctrl-delete
+        checkKeyConversion(new KEY_EVENT_RECORD(true, '\0', 258, 46, 1), "\033[3;3~"); //Alt-delete
+        checkKeyConversion(new KEY_EVENT_RECORD(true, '\0', 272, 46, 1), "\033[3;2~"); //Shift-delete
+        checkKeyConversion(new KEY_EVENT_RECORD(true, '\0', 280, 46, 1), "\033[3;6~"); //Ctrl-Shift-delete
+        checkKeyConversion(new KEY_EVENT_RECORD(true, '\0', 274, 46, 1), "\033[3;4~"); //Alt-Shift-delete
+        checkKeyConversion(new KEY_EVENT_RECORD(true, '\0', 282, 46, 1), "\033[3;8~"); //Ctrl-Alt-Shift-delete
+    }
+
+    void checkKeyConversion(KEY_EVENT_RECORD event, String expected) {
+        String actual = WindowsTerminal.convertKeys(event);
+
+        if (!expected.equals(actual)) {
+            throw new AssertionError("Expected: " + expected + "; actual: " + actual);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/internal/jline/console/StripAnsiTest.java	Thu Jul 09 16:37:55 2015 -0700
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8080679
+ * @summary Verify ConsoleReader.stripAnsi strips escape sequences from its input correctly.
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.lang.reflect.Method;
+import jdk.internal.jline.console.ConsoleReader;
+
+public class StripAnsiTest {
+    public static void main(String... args) throws Exception {
+        new StripAnsiTest().run();
+    }
+
+    void run() throws Exception {
+        ByteArrayInputStream in = new ByteArrayInputStream(new byte[0]);
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        ConsoleReader reader = new ConsoleReader(in, out);
+
+        String withAnsi = "0\033[s1\033[2J2\033[37;4m3";
+        String expected = "0123";
+
+        Method stripAnsi = ConsoleReader.class.getDeclaredMethod("stripAnsi", String.class);
+        stripAnsi.setAccessible(true);
+        String actual = (String) stripAnsi.invoke(reader, withAnsi);
+
+        if (!expected.equals(actual)) {
+            throw new IllegalStateException("Did not correctly strip escape sequences: " + actual);
+        }
+    }
+}
--- a/jdk/test/sun/security/krb5/auto/BadKdc1.java	Thu Jul 09 13:49:36 2015 -0700
+++ b/jdk/test/sun/security/krb5/auto/BadKdc1.java	Thu Jul 09 16:37:55 2015 -0700
@@ -53,7 +53,7 @@
                // k3 off k2 on
                "(122212(22){1,2}|1222323232-)", // 1
                // k1 on
-               "(12(12){1,2}|122232-)"  // empty
+               "(12(12){1,2}|122212|122232-)"  // empty
        );
    }
 }