Java tutorial
/* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* * SimpleCLIPanel.java * Copyright (C) 2009-2018 University of Waikato, Hamilton, New Zealand */ package weka.gui; import weka.core.ClassDiscovery; import weka.core.Defaults; import weka.core.Instances; import weka.core.Trie; import weka.core.Utils; import weka.core.WekaPackageManager; import weka.gui.knowledgeflow.StepVisual; import weka.gui.scripting.ScriptingPanel; import weka.gui.simplecli.AbstractCommand; import weka.gui.simplecli.Help; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JOptionPane; import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.JTextPane; import javax.swing.SwingUtilities; import java.awt.BorderLayout; import java.awt.Cursor; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.PrintStream; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Vector; /** * Creates a very simple command line for invoking the main method of classes. * System.out and System.err are redirected to an output area. Features a simple * command history -- use up and down arrows to move through previous commmands. * This gui uses only AWT (i.e. no Swing). * * @author Len Trigg (trigg@cs.waikato.ac.nz) * @author FracPete (fracpete at waikato dot ac dot nz) */ @PerspectiveInfo(ID = "simplecli", title = "Simple CLI", toolTipText = "Simple CLI for Weka", iconPath = "weka/gui/weka_icon_new_small.png") public class SimpleCLIPanel extends ScriptingPanel implements ActionListener, Perspective { /** for serialization. */ private static final long serialVersionUID = 1089039734615114942L; /** The filename of the properties file. */ protected static String FILENAME = "SimpleCLI.props"; /** The default location of the properties file. */ protected static String PROPERTY_FILE = "weka/gui/" + FILENAME; /** Contains the SimpleCLI properties. */ protected static Properties PROPERTIES; /** Main application (if any) owning this perspective */ protected GUIApplication m_mainApp; /** The Icon for this perspective */ protected Icon m_perspectiveIcon; static { // Allow a properties file in the current directory to override try { PROPERTIES = Utils.readProperties(PROPERTY_FILE); java.util.Enumeration<?> keys = PROPERTIES.propertyNames(); if (!keys.hasMoreElements()) { throw new Exception("Failed to read a property file for the SimpleCLI"); } } catch (Exception ex) { JOptionPane.showMessageDialog(null, "Could not read a configuration file for the SimpleCLI.\n" + "An example file is included with the Weka distribution.\n" + "This file should be named \"" + PROPERTY_FILE + "\" and\n" + "should be placed either in your user home (which is set\n" + "to \"" + System.getProperties().getProperty("user.home") + "\")\n" + "or the directory that java was started from\n", "SimpleCLI", JOptionPane.ERROR_MESSAGE); } } /** The output area canvas added to the frame. */ protected JTextPane m_OutputArea; /** The command input area. */ protected JTextField m_Input; /** The history of commands entered interactively. */ protected Vector<String> m_CommandHistory; /** The current position in the command history. */ protected int m_HistoryPos; /** The thread currently running a class main method. */ protected Thread m_RunThread; /** The commandline completion. */ protected CommandlineCompletion m_Completion; /** for storing variables. */ protected Map<String, Object> m_Variables; @Override public void instantiationComplete() { } @Override public boolean okToBeActive() { return true; } @Override public void setActive(boolean active) { } @Override public void setLoaded(boolean loaded) { } @Override public void setMainApplication(GUIApplication main) { m_mainApp = main; } @Override public GUIApplication getMainApplication() { return m_mainApp; } @Override public String getPerspectiveID() { return "simplecli"; } @Override public String getPerspectiveTitle() { return "Simple CLI"; } @Override public Icon getPerspectiveIcon() { if (m_perspectiveIcon != null) { return m_perspectiveIcon; } PerspectiveInfo perspectiveA = this.getClass().getAnnotation(PerspectiveInfo.class); if (perspectiveA != null && perspectiveA.iconPath() != null && perspectiveA.iconPath().length() > 0) { m_perspectiveIcon = StepVisual.loadIcon(perspectiveA.iconPath()); } return m_perspectiveIcon; } @Override public String getPerspectiveTipText() { return "Simple CLI interface for Weka"; } @Override public List<JMenu> getMenus() { return null; } @Override public Defaults getDefaultSettings() { return null; } @Override public void settingsChanged() { } @Override public boolean acceptsInstances() { return false; } @Override public void setInstances(Instances instances) { } @Override public boolean requiresLog() { return false; } @Override public void setLog(Logger log) { } /** * A class that handles running the main method of the class in a separate * thread. * * @author Len Trigg (trigg@cs.waikato.ac.nz) * @version $Revision$ */ public static class ClassRunner extends Thread { /** the owner. */ protected SimpleCLIPanel m_Owner; /** Stores the main method to call. */ protected Method m_MainMethod; /** Stores the command line arguments to pass to the main method. */ String[] m_CommandArgs; /** True if the class to be executed is weka.Run */ protected boolean m_classIsRun; /** * Sets up the class runner thread. * * @param theClass the Class to call the main method of * @param commandArgs an array of Strings to use as command line args * @throws Exception if an error occurs */ public ClassRunner(SimpleCLIPanel owner, Class<?> theClass, String[] commandArgs) throws Exception { m_Owner = owner; m_classIsRun = (theClass.getClass().getName().equals("weka.Run")); setDaemon(true); Class<?>[] argTemplate = { String[].class }; m_CommandArgs = commandArgs; if (m_classIsRun) { if (!commandArgs[0].equalsIgnoreCase("-h") && !commandArgs[0].equalsIgnoreCase("-help")) { m_CommandArgs = new String[commandArgs.length + 1]; System.arraycopy(commandArgs, 0, m_CommandArgs, 1, commandArgs.length); m_CommandArgs[0] = "-do-not-prompt-if-multiple-matches"; } } m_MainMethod = theClass.getMethod("main", argTemplate); if (((m_MainMethod.getModifiers() & Modifier.STATIC) == 0) || (m_MainMethod.getModifiers() & Modifier.PUBLIC) == 0) { throw new NoSuchMethodException( "main(String[]) method of " + theClass.getName() + " is not public and static."); } } /** * Starts running the main method. */ @Override public void run() { PrintStream outOld = null; PrintStream outNew = null; String outFilename = null; // is the output redirected? if (m_CommandArgs.length > 2) { String action = m_CommandArgs[m_CommandArgs.length - 2]; if (action.equals(">")) { outOld = System.out; try { outFilename = m_CommandArgs[m_CommandArgs.length - 1]; // since file may not yet exist, command-line completion doesn't // work, hence replace "~" manually with home directory if (outFilename.startsWith("~")) { outFilename = outFilename.replaceFirst("~", System.getProperty("user.home")); } outNew = new PrintStream(new File(outFilename)); System.setOut(outNew); m_CommandArgs[m_CommandArgs.length - 2] = ""; m_CommandArgs[m_CommandArgs.length - 1] = ""; // some main methods check the length of the "args" array // -> removed the two empty elements at the end String[] newArgs = new String[m_CommandArgs.length - 2]; System.arraycopy(m_CommandArgs, 0, newArgs, 0, m_CommandArgs.length - 2); m_CommandArgs = newArgs; } catch (Exception e) { System.setOut(outOld); outOld = null; } } } try { Object[] args = { m_CommandArgs }; m_MainMethod.invoke(null, args); if (isInterrupted()) { System.err.println("[...Interrupted]"); } } catch (Exception ex) { if (ex.getMessage() == null) { System.err.println("[...Killed]"); } else { System.err.println("[Run exception] " + ex.getMessage()); } } finally { m_Owner.stopThread(); } // restore old System.out stream if (outOld != null) { outNew.flush(); outNew.close(); System.setOut(outOld); System.out.println("Finished redirecting output to '" + outFilename + "'."); } } } /** * A class for commandline completion of classnames. * * @author FracPete (fracpete at waikato dot ac dot nz) * @version $Revision$ */ public static class CommandlineCompletion { /** all the available packages. */ protected Vector<String> m_Packages; /** a trie for storing the packages. */ protected Trie m_Trie; /** debug mode on/off. */ protected boolean m_Debug = false; /** * default constructor. */ public CommandlineCompletion() { super(); // build incremental list of packages if (m_Packages == null) { // get all packages Vector<String> list = ClassDiscovery.findPackages(); // create incremental list HashSet<String> set = new HashSet<String>(); for (int i = 0; i < list.size(); i++) { String[] parts = list.get(i).split("\\."); for (int n = 1; n < parts.length; n++) { String pkg = ""; for (int m = 0; m <= n; m++) { if (m > 0) { pkg += "."; } pkg += parts[m]; } set.add(pkg); } } // init packages m_Packages = new Vector<String>(); m_Packages.addAll(set); Collections.sort(m_Packages); m_Trie = new Trie(); m_Trie.addAll(m_Packages); } } /** * returns whether debug mode is on. * * @return true if debug is on */ public boolean getDebug() { return m_Debug; } /** * sets debug mode on/off. * * @param value if true then debug mode is on */ public void setDebug(boolean value) { m_Debug = value; } /** * tests whether the given partial string is the name of a class with * classpath - it basically tests, whether the string consists only of * alphanumeric literals, underscores and dots. * * @param partial the string to test * @return true if it looks like a classname */ public boolean isClassname(String partial) { return (partial.replaceAll("[a-zA-Z0-9\\-\\.]*", "").length() == 0); } /** * returns the packages part of the partial classname. * * @param partial the partial classname * @return the package part of the partial classname */ public String getPackage(String partial) { String result; int i; boolean wasDot; char c; result = ""; wasDot = false; for (i = 0; i < partial.length(); i++) { c = partial.charAt(i); // start of classname? if (wasDot && ((c >= 'A') && (c <= 'Z'))) { break; } // package/class separator else if (c == '.') { wasDot = true; result += "" + c; } // regular char else { wasDot = false; result += "" + c; } } // remove trailing "." if (result.endsWith(".")) { result = result.substring(0, result.length() - 1); } return result; } /** * returns the classname part of the partial classname. * * @param partial the partial classname * @return the class part of the classname */ public String getClassname(String partial) { String result; String pkg; pkg = getPackage(partial); if (pkg.length() + 1 < partial.length()) { result = partial.substring(pkg.length() + 1); } else { result = ""; } return result; } /** * returns all the file/dir matches with the partial search string. * * @param partial the partial search string * @return all the matches */ public Vector<String> getFileMatches(String partial) { Vector<String> result; File file; File dir; File[] files; int i; String prefix; boolean caseSensitive; String name; boolean match; result = new Vector<String>(); // is the OS case-sensitive? caseSensitive = (File.separatorChar != '\\'); if (m_Debug) { System.out.println("case-sensitive=" + caseSensitive); } // is "~" used for home directory? -> replace with actual home directory if (partial.startsWith("~")) { partial = System.getProperty("user.home") + partial.substring(1); } // determine dir and possible prefix file = new File(partial); dir = null; prefix = null; if (file.exists()) { // determine dir to read if (file.isDirectory()) { dir = file; prefix = null; // retrieve all } else { dir = file.getParentFile(); prefix = file.getName(); } } else { dir = file.getParentFile(); prefix = file.getName(); } if (m_Debug) { System.out.println("search in dir=" + dir + ", prefix=" + prefix); } // list all files in dir if (dir != null) { files = dir.listFiles(); if (files != null) { for (i = 0; i < files.length; i++) { name = files[i].getName(); // does the name match? if ((prefix != null) && caseSensitive) { match = name.startsWith(prefix); } else if ((prefix != null) && !caseSensitive) { match = name.toLowerCase().startsWith(prefix.toLowerCase()); } else { match = true; } if (match) { if (prefix != null) { result.add(partial.substring(0, partial.length() - prefix.length()) + name); } else { if (partial.endsWith("\\") || partial.endsWith("/")) { result.add(partial + name); } else { result.add(partial + File.separator + name); } } } } } else { System.err.println("Invalid path: " + partial); } } // sort the result if (result.size() > 1) { Collections.sort(result); } // print results if (m_Debug) { System.out.println("file matches:"); for (i = 0; i < result.size(); i++) { System.out.println(result.get(i)); } } return result; } /** * returns all the class/package matches with the partial search string. * * @param partial the partial search string * @return all the matches */ public Vector<String> getClassMatches(String partial) { String pkg; String cls; Vector<String> result; Vector<String> list; int i; int index; Trie tmpTrie; HashSet<String> set; String tmpStr; pkg = getPackage(partial); cls = getClassname(partial); if (getDebug()) { System.out.println("\nsearch for: '" + partial + "' => package=" + pkg + ", class=" + cls); } result = new Vector<String>(); // find all packages that start with that string if (cls.length() == 0) { list = m_Trie.getWithPrefix(pkg); set = new HashSet<String>(); for (i = 0; i < list.size(); i++) { tmpStr = list.get(i); if (tmpStr.length() < partial.length()) { continue; } if (tmpStr.equals(partial)) { continue; } index = tmpStr.indexOf('.', partial.length() + 1); if (index > -1) { set.add(tmpStr.substring(0, index)); } else { set.add(tmpStr); } } result.addAll(set); if (result.size() > 1) { Collections.sort(result); } } // find all classes that start with that string list = ClassDiscovery.find(Object.class, pkg); tmpTrie = new Trie(); tmpTrie.addAll(list); list = tmpTrie.getWithPrefix(partial); result.addAll(list); // sort the result if (result.size() > 1) { Collections.sort(result); } // print results if (m_Debug) { System.out.println("class/package matches:"); for (i = 0; i < result.size(); i++) { System.out.println(result.get(i)); } } return result; } /** * returns all the matches with the partial search string, files or classes. * * @param partial the partial search string * @return all the matches */ public Vector<String> getMatches(String partial) { if (isClassname(partial)) { return getClassMatches(partial); } else { return getFileMatches(partial); } } /** * returns the common prefix for all the items in the list. * * @param list the list to return the common prefix for * @return the common prefix of all the items */ public String getCommonPrefix(Vector<String> list) { String result; Trie trie; trie = new Trie(); trie.addAll(list); result = trie.getCommonPrefix(); if (m_Debug) { System.out.println(list + "\n --> common prefix: '" + result + "'"); } return result; } } /** * For initializing member variables. */ @Override protected void initialize() { super.initialize(); m_CommandHistory = new Vector<String>(); m_HistoryPos = 0; m_Completion = new CommandlineCompletion(); m_Variables = new HashMap<>(); } /** * Sets up the GUI after initializing the members. */ @Override protected void initGUI() { super.initGUI(); setLayout(new BorderLayout()); m_OutputArea = new JTextPane(); m_OutputArea.setEditable(false); m_OutputArea.setFont(new Font("Monospaced", Font.PLAIN, 12)); add(new JScrollPane(m_OutputArea), "Center"); m_Input = new JTextField(); m_Input.setFont(new Font("Monospaced", Font.PLAIN, 12)); m_Input.addActionListener(this); m_Input.setFocusTraversalKeysEnabled(false); m_Input.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { doHistory(e); doCommandlineCompletion(e); } }); add(m_Input, "South"); } /** * Finishes up after initializing members and setting up the GUI. */ @Override protected void initFinish() { super.initFinish(); System.out.println( "\nWelcome to the WEKA SimpleCLI\n\n" + "Enter commands in the textfield at the bottom of \n" + "the window. Use the up and down arrows to move \n" + "through previous commands.\n" + "Command completion for classnames and files is \n" + "initiated with <Tab>. In order to distinguish \n" + "between files and classnames, file names must \n" + "be either absolute or start with '." + File.separator + "' or '~/'\n" + "(the latter is a shortcut for the home directory).\n" + "<Alt+BackSpace> is used for deleting the text\n" + "in the commandline in chunks.\n" + "\n" + "Type 'help' followed by <Enter> to see an overview \n" + "of all commands."); loadHistory(); SwingUtilities.invokeLater(() -> m_Input.requestFocus()); } /** * Returns an icon to be used in a frame. * * @return the icon */ @Override public ImageIcon getIcon() { return ComponentHelper.getImageIcon("weka_icon_new_48.png"); } /** * Returns the current title for the frame/dialog. * * @return the title */ @Override public String getTitle() { return "SimpleCLI"; } /** * Returns the text area that is used for displaying output on stdout and * stderr. * * @return the JTextArea */ @Override public JTextPane getOutput() { return m_OutputArea; } /** * Not supported. * * @return always null */ @Override public JMenuBar getMenuBar() { return null; } /** * Checks whether a thread is currently running. * * @return true if thread active */ public boolean isBusy() { return (m_RunThread != null); } /** * Starts the thread. * * @param runner the thread to start */ public void startThread(ClassRunner runner) { m_RunThread = runner; m_RunThread.setPriority(Thread.MIN_PRIORITY); // UI has most priority m_RunThread.start(); } /** * Stops the currently running thread, if any. */ @SuppressWarnings("deprecation") public void stopThread() { if (m_RunThread != null) { if (m_RunThread.isAlive()) { try { m_RunThread.stop(); } catch (Throwable t) { // ignored } } m_RunThread = null; } } /** * Returns the variables. * * @return the variables */ public Map<String, Object> getVariables() { return m_Variables; } /** * The output area. * * @return the output area */ public JTextPane getOutputArea() { return m_OutputArea; } /** * Returns the command history. * * @return the history */ public List<String> getCommandHistory() { return m_CommandHistory; } /** * Executes a simple cli command. * * @param command the command string * @throws Exception if an error occurs */ public void runCommand(String command) throws Exception { System.out.println("> " + command + '\n'); System.out.flush(); String[] commandArgs; if (!System.getProperty("os.name").toLowerCase().contains("win")) { commandArgs = Utils.splitOptions(command); } else { // If we are on Windows, we must not replace \t, \n, etc., at this stage because \ is path separator commandArgs = Utils.splitOptions(command, new String[] { "\\\\", "\\\"" }, new char[] { '\\', '"' }); } // no command if (commandArgs.length == 0) { return; } // find command AbstractCommand cmd = AbstractCommand.getCommand(commandArgs[0]); // unknown command if (cmd == null) { System.err.println("Unknown command: " + commandArgs[0]); Help help = new Help(); help.setOwner(this); help.execute(new String[0]); return; } // execute command String[] params = new String[commandArgs.length - 1]; System.arraycopy(commandArgs, 1, params, 0, params.length); cmd.setOwner(this); try { cmd.execute(params); } catch (Exception e) { System.err.println("Error executing: " + command); e.printStackTrace(); } } /** * Changes the currently displayed command line when certain keys are pressed. * The up arrow moves back through history entries and the down arrow moves * forward through history entries. * * @param e a value of type 'KeyEvent' */ public void doHistory(KeyEvent e) { if (e.getSource() == m_Input) { switch (e.getKeyCode()) { case KeyEvent.VK_UP: if (m_HistoryPos > 0) { m_HistoryPos--; String command = m_CommandHistory.elementAt(m_HistoryPos); m_Input.setText(command); } break; case KeyEvent.VK_DOWN: if (m_HistoryPos < m_CommandHistory.size()) { m_HistoryPos++; String command = ""; if (m_HistoryPos < m_CommandHistory.size()) { command = m_CommandHistory.elementAt(m_HistoryPos); } m_Input.setText(command); } break; default: break; } } } /** * performs commandline completion on packages and classnames. * * @param e a value of type 'KeyEvent' */ public void doCommandlineCompletion(KeyEvent e) { if (e.getSource() == m_Input) { switch (e.getKeyCode()) { // completion case KeyEvent.VK_TAB: if (e.getModifiers() == 0) { // it might take a while before we determined all of the possible // matches (Java doesn't have an application wide cursor handling??) m_Input.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); m_OutputArea.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); try { String txt = m_Input.getText(); // java call? if (txt.trim().startsWith("java ")) { int pos = m_Input.getCaretPosition(); int nonNameCharPos = -1; // find first character not part of a name, back from current // position // i.e., " or blank for (int i = pos - 1; i >= 0; i--) { if ((txt.charAt(i) == '"') || (txt.charAt(i) == ' ')) { nonNameCharPos = i; break; } } if (nonNameCharPos > -1) { String search = txt.substring(nonNameCharPos + 1, pos); // find matches and common prefix Vector<String> list = m_Completion.getMatches(search); String common = m_Completion.getCommonPrefix(list); // just extending by separator is not a real extension if ((search.toLowerCase() + File.separator).equals(common.toLowerCase())) { common = search; } // can we complete the string? if (common.length() > search.length()) { try { m_Input.getDocument().remove(nonNameCharPos + 1, search.length()); m_Input.getDocument().insertString(nonNameCharPos + 1, common, null); } catch (Exception ex) { ex.printStackTrace(); } } // ambigiuous? -> print matches else if (list.size() > 1) { System.out.println("\nPossible matches:"); for (int i = 0; i < list.size(); i++) { System.out.println(" " + list.get(i)); } } else { // nothing found, don't do anything } } } } finally { // set cursor back to default m_Input.setCursor(null); m_OutputArea.setCursor(null); } } break; // delete last part up to next blank or dot case KeyEvent.VK_BACK_SPACE: if (e.getModifiers() == KeyEvent.ALT_MASK) { String txt = m_Input.getText(); int pos = m_Input.getCaretPosition(); // skip whitespaces int start = pos; start--; while (start >= 0) { if ((txt.charAt(start) == '.') || (txt.charAt(start) == ' ') || (txt.charAt(start) == '\\') || (txt.charAt(start) == '/')) { start--; } else { break; } } // find first blank or dot back from position int newPos = -1; for (int i = start; i >= 0; i--) { if ((txt.charAt(i) == '.') || (txt.charAt(i) == ' ') || (txt.charAt(i) == '\\') || (txt.charAt(i) == '/')) { newPos = i; break; } } // remove string try { m_Input.getDocument().remove(newPos + 1, pos - newPos - 1); } catch (Exception ex) { ex.printStackTrace(); } } break; } } } /** * Only gets called when return is pressed in the input area, which starts the * command running. * * @param e a value of type 'ActionEvent' */ @Override public void actionPerformed(ActionEvent e) { try { if (e.getSource() == m_Input) { String command = m_Input.getText(); int last = m_CommandHistory.size() - 1; if ((last < 0) || !command.equals(m_CommandHistory.elementAt(last))) { m_CommandHistory.addElement(command); saveHistory(); } m_HistoryPos = m_CommandHistory.size(); runCommand(command); m_Input.setText(""); } } catch (Exception ex) { System.err.println(ex.getMessage()); } } /** * loads the command history from the user's properties file. */ protected void loadHistory() { int size; int i; String cmd; size = Integer.parseInt(PROPERTIES.getProperty("HistorySize", "50")); m_CommandHistory.clear(); for (i = 0; i < size; i++) { cmd = PROPERTIES.getProperty("Command" + i, ""); if (cmd.length() != 0) { m_CommandHistory.add(cmd); } else { break; } } m_HistoryPos = m_CommandHistory.size(); } /** * saves the current command history in the user's home directory. */ protected void saveHistory() { int size; int from; int i; String filename; BufferedOutputStream stream; size = Integer.parseInt(PROPERTIES.getProperty("HistorySize", "50")); // determine first command to save from = m_CommandHistory.size() - size; if (from < 0) { from = 0; } // fill properties PROPERTIES.setProperty("HistorySize", "" + size); for (i = from; i < m_CommandHistory.size(); i++) { PROPERTIES.setProperty("Command" + (i - from), m_CommandHistory.get(i)); } try { filename = WekaPackageManager.PROPERTIES_DIR.getAbsolutePath() + File.separatorChar + FILENAME; stream = new BufferedOutputStream(new FileOutputStream(filename)); PROPERTIES.store(stream, "SimpleCLI"); stream.close(); } catch (Exception e) { e.printStackTrace(); } } /** * Displays the panel in a frame. * * @param args ignored */ public static void main(String[] args) { weka.core.logging.Logger.log(weka.core.logging.Logger.Level.INFO, "Logging started"); LookAndFeel.setLookAndFeel(); // make sure that packages are loaded and the GenericPropertiesCreator // executes to populate the lists correctly weka.gui.GenericObjectEditor.determineClasses(); showPanel(new SimpleCLIPanel(), args); } }