All Downloads are FREE. Search and download functionalities are using the official Maven repository.

acm.util.JTFTools Maven / Gradle / Ivy

Go to download

This the original Stanford Karel for Java, packaged for Maven. ACM Library is included. See also https://cs.stanford.edu/people/eroberts/karel-the-robot-learns-java.pdf

The newest version!
/*
 * @(#)JTFTools.java   1.99.1 08/12/08
 */

// ************************************************************************
// * Copyright (c) 2008 by the Association for Computing Machinery        *
// *                                                                      *
// * The Java Task Force seeks to impose few restrictions on the use of   *
// * these packages so that users have as much freedom as possible to     *
// * use this software in constructive ways and can make the benefits of  *
// * that work available to others.  In view of the legal complexities    *
// * of software development, however, it is essential for the ACM to     *
// * maintain its copyright to guard against attempts by others to        *
// * claim ownership rights.  The full text of the JTF Software License   *
// * is available at the following URL:                                   *
// *                                                                      *
// *          http://www.acm.org/jtf/jtf-software-license.pdf             *
// *                                                                      *
// ************************************************************************

// REVISION HISTORY
//
// -- V2.0 --
// Bug fix 2-Jan-07 (ESR, JTFBug 2007-001)
//   1. Fixed bug in the decodeFont method where it failed to take proper
//      account of the properties of the old font.
//
// Feature enhancement 2-Mar-07 (ESR)
//   1. Added methods to support the implementation of the "Export Applet" and
//      "Submit Project" menu items.
//
// Feature enhancement 4-May-07 (ESR)
//   1. Added getFontList and findFontFamily methods.
//
// Code cleanup 28-May-07 (ESR)
//   1. Added generic type tags.
//
// Feature enhancement 10-Oct-07 (ESR)
//   1. Significantly improved the operation of getMainClass by checking
//      to see whether classes in the current directory have been loaded.
//
// Feature enhancement 10-Jun-08 (ESR)
//   1. Added matchFilenamePattern method.

package acm.util;

import acm.gui.*;
import acm.io.*;
import acm.program.*;
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.lang.reflect.*;
import java.net.*;
import java.security.*;
import java.text.*;
import java.util.*;
import java.util.zip.*;
import javax.swing.*;
import javax.swing.event.*;

/* Class: JTFTools */
/**
 * This class provides a collection of static utility methods
 * that are used elsewhere in the ACM packages.
 */
public class JTFTools {

/* Private constructor */
/**
 * Prevent any clients from constructing objects of this class.
 */
	private JTFTools() {
		/* Empty */
	}

/* Static method: pause(milliseconds) */
/**
 * Delays the calling thread for the specified time, which is expressed in
 * milliseconds.  Unlike Thread.sleep, this method never throws an
 * exception.
 *
 * Example: JTFTools.pause(milliseconds);
 * @param milliseconds The sleep time in milliseconds
 */
	public static void pause(double milliseconds) {
		Applet applet = appletTable.get(Thread.currentThread());
		if (applet == null) {
			applet = mostRecentApplet;
			appletTable.put(Thread.currentThread(), applet);
		}
		try {
			int millis = (int) milliseconds;
			int nanos = (int) Math.round((milliseconds - millis) * 1000000);
			Thread.sleep(millis, nanos);
		} catch (InterruptedException ex) {
			/* Empty */
		}
	}

/* Static method: createEmptyContainer() */
/**
 * Returns an empty lightweight container.  Several packages need to create
 * such components as placeholders.  Defining it in JTFTools gives those
 * pacakges access to a common mechanism.
 *
 * Example: Container comp = JTFTools.createEmptyContainer();
 * @return An empty lightweight container that can be used as a placeholder
 */
	public static Container createEmptyContainer() {
		return new EmptyContainer();
	}

/* Static method: getEnclosingFrame(comp) */
/**
 * Returns the frame that encloses the specified component.
 *
 * Example: Frame frame = JTFTools.getEnclosingFrame(comp);
 * @param comp The component at which to start the search
 * @return The nearest enclosing Frame object
 */
	public static Frame getEnclosingFrame(Component comp) {
		if (comp instanceof Program) comp = ((Program) comp).getContentPane();
		while (comp != null && !(comp instanceof Frame)) {
			comp = comp.getParent();
		}
		return (Frame) comp;
	}

/* Static method: getStandardFont(font) */
/**
 * Returns a font that will approximate the specified font in this environment.
 * This method is required because some browsers do not support the standard
 * fonts Serif, SansSerif, and Monospaced.
 *
 * Example: Font newFont = JTFTools.getStandardFont(font);
 * @param font The font being checked
 * @return The new font
 */
	public static Font getStandardFont(Font font) {
		if (!fontFamilyTableInitialized) initFontFamilyTable();
		if (font == null || fontFamilyTable == null) return font;
		String family = font.getFamily();
		if (fontFamilyTable.get(trimFamilyName(family)) != null) return font;
		if (family.equals("Serif") || family.equals("Times")) {
			family = getFirstAvailableFontSubstitution(SERIF_SUBSTITUTIONS);
		} else if (family.equals("SansSerif")) {
			family = getFirstAvailableFontSubstitution(SANSSERIF_SUBSTITUTIONS);
		} else if (family.equals("Monospaced")) {
			family = getFirstAvailableFontSubstitution(MONOSPACED_SUBSTITUTIONS);
		} else {
			return font;
		}
		if (family == null) return font;
		return new Font(family, font.getStyle(), font.getSize());
	}

/* Static method: getFontList() */
/**
 * Returns an array of the available font family names.
 *
 * Example: String[] fonts = JTFTools.getFontList();
 * @return An array of the available font family names
 */
	public static String[] getFontList() {
		if (!fontFamilyTableInitialized) initFontFamilyTable();
		return fontFamilyArray;
	}

/* Static method: findFontFamily(str) */
/**
 * Finds the first font family in the string str that exists in
 * the current GraphicsEnvironment.  As in HTML font tags, the
 * str consists of a set of font names separated by semicolons.
 * The findFontFamily method returns the first family name that
 * exists in the list of loaded fonts, or null if there are none.
 *
 * Example: String familyName = JTFTools.findFontFamily(str);
 * @param str The list of family names separated by semicolons
 * @return The first family name that exists, or null if none
 */
	public static String findFontFamily(String str) {
		if (!fontFamilyTableInitialized) initFontFamilyTable();
		StringTokenizer tokenizer = new StringTokenizer(str, ";", false);
		while (tokenizer.hasMoreTokens()) {
			String familyName = fontFamilyTable.get(trimFamilyName(tokenizer.nextToken()));
			if (familyName != null) return familyName;
		}
		return null;
	}

/* Static method: decodeFont(str) */
/**
 * Decodes a font in the style of Font.decode.
 *
 * Example: Font font = JTFTools.decodeFont(str);
 * @param str The string to decode
 * @return The new font
 */
	public static Font decodeFont(String str) {
		return decodeFont(str, null);
	}

/* Static method: decodeFont(str, oldFont) */
/**
 * Decodes a font in the style of Font.decode.  The only difference
 * is that this method takes a font parameter that gives default values for
 * the different parts of the font.  If the family, size, or style is specified
 * as an asterisk, the corresponding value is taken from the supplied font.
 *
 * Example: Font font = JTFTools.decodeFont(str, oldFont);
 * @param str The string to decode
 * @param oldFont The font whose properties are used as defaults
 * @return The new font
 */
	public static Font decodeFont(String str, Font oldFont) {
		String familyName = str;
		int fontStyle = (oldFont == null) ? Font.PLAIN : oldFont.getStyle();
		int fontSize = (oldFont == null) ? 12 : oldFont.getSize();
		int hyphen = str.indexOf('-');
		if (hyphen >= 0) {
			familyName = str.substring(0, hyphen);
			str = str.substring(hyphen + 1).toLowerCase();
			String styleName = str;
			hyphen = str.indexOf('-');
			if (hyphen >= 0) {
				styleName = str.substring(0, hyphen);
				str = str.substring(hyphen + 1);
			} else {
				str = "*";
			}
			if (Character.isDigit(styleName.charAt(0))) {
				String tmp = styleName;
				styleName = str;
				str = tmp;
			}
			if (styleName.equals("plain")) {
				fontStyle = Font.PLAIN;
			} else if (styleName.equals("bold")) {
				fontStyle = Font.BOLD;
			} else if (styleName.equals("italic")) {
				fontStyle = Font.ITALIC;
			} else if (styleName.equals("bolditalic")) {
				fontStyle = Font.BOLD | Font.ITALIC;
			} else if (!styleName.equals("*")) {
				throw new ErrorException("Illegal font style");
			}
			if (!str.equals("*")) {
				try {
					fontSize = Integer.valueOf(str).intValue();
				} catch (NumberFormatException ex) {
					throw new ErrorException("Illegal font size");
				}
			}
		}
		if (familyName.equals("*")) {
			familyName = (oldFont == null) ? "Default" : oldFont.getName();
		} else {
			if (!fontFamilyTableInitialized) initFontFamilyTable();
			if (fontFamilyTable != null) {
				familyName = fontFamilyTable.get(trimFamilyName(familyName));
				if (familyName == null) familyName = "Default";
			}
		}
		return getStandardFont(new Font(familyName, fontStyle, fontSize));
	}

/* Static method: decodeColor(name) */
/**
 * Decodes a color name.  This method is similar to Color.decode
 * except in that it allows named colors and system colors.
 *
 * Example: color = JTFTools.decodeColor(name);
 * @param name The string name of the color
 * @return The color corresponding to the specified name
 */
	public static Color decodeColor(String name) {
		if (name.equalsIgnoreCase("desktop")) return SystemColor.desktop;
		if (name.equalsIgnoreCase("activeCaption")) return SystemColor.activeCaption;
		if (name.equalsIgnoreCase("activeCaptionText")) return SystemColor.activeCaptionText;
		if (name.equalsIgnoreCase("activeCaptionBorder")) return SystemColor.activeCaptionBorder;
		if (name.equalsIgnoreCase("inactiveCaption")) return SystemColor.inactiveCaption;
		if (name.equalsIgnoreCase("inactiveCaptionText")) return SystemColor.inactiveCaptionText;
		if (name.equalsIgnoreCase("inactiveCaptionBorder")) return SystemColor.inactiveCaptionBorder;
		if (name.equalsIgnoreCase("window")) return SystemColor.window;
		if (name.equalsIgnoreCase("windowBorder")) return SystemColor.windowBorder;
		if (name.equalsIgnoreCase("windowText")) return SystemColor.windowText;
		if (name.equalsIgnoreCase("menu")) return SystemColor.menu;
		if (name.equalsIgnoreCase("menuText")) return SystemColor.menuText;
		if (name.equalsIgnoreCase("text")) return SystemColor.text;
		if (name.equalsIgnoreCase("textText")) return SystemColor.textText;
		if (name.equalsIgnoreCase("textHighlight")) return SystemColor.textHighlight;
		if (name.equalsIgnoreCase("textHighlightText")) return SystemColor.textHighlightText;
		if (name.equalsIgnoreCase("textInactiveText")) return SystemColor.textInactiveText;
		if (name.equalsIgnoreCase("control")) return SystemColor.control;
		if (name.equalsIgnoreCase("controlText")) return SystemColor.controlText;
		if (name.equalsIgnoreCase("controlHighlight")) return SystemColor.controlHighlight;
		if (name.equalsIgnoreCase("controlLtHighlight")) return SystemColor.controlLtHighlight;
		if (name.equalsIgnoreCase("controlShadow")) return SystemColor.controlShadow;
		if (name.equalsIgnoreCase("controlDkShadow")) return SystemColor.controlDkShadow;
		if (name.equalsIgnoreCase("scrollbar")) return SystemColor.scrollbar;
		if (name.equalsIgnoreCase("info")) return SystemColor.info;
		if (name.equalsIgnoreCase("infoText")) return SystemColor.infoText;
		if (name.equalsIgnoreCase("black")) return Color.BLACK;
		if (name.equalsIgnoreCase("blue")) return Color.BLUE;
		if (name.equalsIgnoreCase("cyan")) return Color.CYAN;
		if (name.equalsIgnoreCase("darkGray")) return Color.DARK_GRAY;
		if (name.equalsIgnoreCase("DARK_GRAY")) return Color.DARK_GRAY;
		if (name.equalsIgnoreCase("gray")) return Color.GRAY;
		if (name.equalsIgnoreCase("green")) return Color.GREEN;
		if (name.equalsIgnoreCase("lightGray")) return Color.LIGHT_GRAY;
		if (name.equalsIgnoreCase("LIGHT_GRAY")) return Color.LIGHT_GRAY;
		if (name.equalsIgnoreCase("magenta")) return Color.MAGENTA;
		if (name.equalsIgnoreCase("orange")) return Color.ORANGE;
		if (name.equalsIgnoreCase("pink")) return Color.PINK;
		if (name.equalsIgnoreCase("red")) return Color.RED;
		if (name.equalsIgnoreCase("white")) return Color.WHITE;
		if (name.equalsIgnoreCase("yellow")) return Color.YELLOW;
		try {
			return Color.decode(name);
		} catch (NumberFormatException ex) {
			throw new ErrorException("Illegal color value");
		}
	}

/* Static method: matchFilenamePattern(filename, pattern) */
/**
 * Determines whether the filename matches the specified pattern.  The
 * pattern string is interpreted in much the same way that a Unix shell
 * expands filenames and supports the following wildcard options:
 *
 * 
 * 
 * 
 * 
 * 
 * 
Examples
?Matches any single character
*Matches any sequence of characters
[...]Matches any of the specified characters
[^...]Matches any character except the specified ones
* * The last two options allow a range of characters to be specified in the form * a-z. * * Example: if (JTFTools.matchFilenamePattern(filename, pattern)) . . . * @param filename The filename being tested * @param pattern The pattern including wildcards * @return true if the filename matches the pattern */ public static boolean matchFilenamePattern(String filename, String pattern) { return recursiveMatch(filename, 0, pattern, 0); } /* Static method: registerApplet(applet) */ /** * Adds this applet to a table indexed by the current thread. * * Example: JTFTools.registerApplet(applet); * @param applet The applet being registered * */ public static void registerApplet(Applet applet) { registerApplet(applet, Thread.currentThread()); mostRecentApplet = applet; } /* Static method: registerApplet(applet, thread) */ /** * Adds this applet to a table indexed by the specified thread. * * Example: JTFTools.registerApplet(applet); * @param applet The applet being registered * @param thread The thread used as the key * */ public static void registerApplet(Applet applet, Thread thread) { appletTable.put(thread, applet); } /* Static method: getApplet() */ /** * Returns the current applet. This implementation may fail in * multithreaded programs. Such programs should therefore not * rely on this facility. It is appropriate to use this facility, * for example, during the init method of a program, * which is the only context in which it is applied in the JTF tools. * * Example: Applet applet JTFTools.getApplet(); * @return The currently running applet * */ public static Applet getApplet() { Applet applet = appletTable.get(Thread.currentThread()); if (applet == null) applet = mostRecentApplet; return applet; } /* Static method: setDebugOptions(options) */ /** * Sets the debugging options in place for this run. The list of options are * a set of strings combined with the + sign character. * * Example: JTFTools.setDebugOption(options) * @param options The names of the enabled options separated by plus signs * */ public static void setDebugOptions(String options) { debugOptions = (options == null) ? null : "+" + options.toLowerCase() + "+"; } /* Static method: testDebugOption(option) */ /** * Tests to see whether the current program was invoked with a debug * parameter that contains the specified string as a lexical unit in a string * delimited by + signs. * * Example: if (JTFTools.testDebugOption(option)) . . . * @param option The name of the option * @return The constant true if the specified debug option is in effect * */ public static boolean testDebugOption(String option) { if (debugOptions == null) return false; return debugOptions.indexOf("+" + option.toLowerCase() + "+") >= 0; } /* Static method: getCommandLine() */ /** * Returns the command line that invoked this program, or null * if no command line is available. * * Example: String line = JTFTools.getCommandLine(); * @return The command line that invoked this program * */ public static String getCommandLine() { switch (Platform.getPlatform()) { case Platform.UNIX: case Platform.MAC: return getShellCommandLine(); case Platform.WINDOWS: return DOSCommandLine.getCommandLine(); default: return getShellCommandLine(); } } /* Static method: getMainClass() */ /** * Returns the name of the main class. * * Example: String className = JTFTools.getMainClass(); * @return The name of the main class, or null if that class cannot be identified * */ public static String getMainClass() { String className = null; try { className = System.getProperty("java.main"); } catch (Exception ex) { /* Empty */ } if (className == null) { className = readMainClassFromClassPath(); } if (className == null) { String commandLine = getCommandLine(); className = readMainClassFromCommandLine(commandLine); } return className; } /* Static method: checkIfLoaded(className) */ /** * Returns true if the specified class is already loaded. * * Example: if (JTFTools.checkIfLoaded(className)) . . . * @param className The name of the class * @return The boolean value true if the class is already loaded, and false otherwise * */ public static boolean checkIfLoaded(String className) { if (Platform.compareVersion("1.2") < 0) return false; boolean result = false; try { if (System.getSecurityManager() != null) return false; if (managerThatFails == null) { try { Class managerThatFailsClass = Class.forName("acm.util.SecurityManagerThatFails"); managerThatFails = (SecurityManager) managerThatFailsClass.newInstance(); } catch (Exception ex) { return false; } } System.setSecurityManager(managerThatFails); try { result = (Class.forName(className) != null); } catch (ExceptionInInitializerError err) { result = true; } catch (NoClassDefFoundError err) { /* Empty */; } finally { System.setSecurityManager(null); } } catch (Exception ex) { /* Empty */ } return result; } /* Static method: terminateAppletThreads(applet) */ /** * Terminates all of the threads that are registered as belonging to the * specified applet. * * Example: JTFTools.terminateAppletThreads(applet); * @param applet The applet whose threads are being terminated * */ public static void terminateAppletThreads(Applet applet) { try { Thread myThread = Thread.currentThread(); Class threadClass = Class.forName("java.lang.Thread"); Method stop = threadClass.getMethod("stop", new Class[0]); Iterator iterator = appletTable.keySet().iterator(); while (iterator.hasNext()) { Thread t = iterator.next(); if (t != myThread && t.isAlive() && isAnonymous(t) && applet == appletTable.get(t)) { stop.invoke(t, new Object[0]); } } } catch (Exception ex) { /* Empty */ } } /* Static method: isAnonymous(t) */ /** * Returns true if the supplied thread is an anonymous * one created automatically by the system. * * Example: if (JTFTools.isAnonymous(t)) . . . * @param t The thread being tested * @return yes or no * */ public static boolean isAnonymous(Thread t) { String name = t.getName(); if (!name.startsWith("Thread-")) return false; for (int i = 7; i < name.length(); i++) { if (!Character.isDigit(name.charAt(i))) return false; } return true; } /* Static method: openMailStream(smtpServer, from, to) */ /** * Opens a mail-sending process using the specified SMTP server, which will * send a message from the specified sender to the recipient. The return value * is a PrintStream that the client can use to write the data * in the message, including the headers. Closing the stream sends the message. * To cancel the message without sending it, use the cancelMail method. * * Example: JTFTools.openMailStream(smtpServer, from, to); * @param smtpServer A string indicating the host name of the SMTP server * @param from A string indicating the e-mail address of the sender * @param to A string indicating the e-mail address of this recipient * @return A PrintStream suitable for sending the message data * */ public static PrintStream openMailStream(String smtpServer, String from, String to) { return new MailStream(smtpServer, from, to); } /* Static method: cancelMail(out) */ /** * Cancels the mail-sending process without sending the message. The output stream * is closed after returning. * * Example: JTFTools.cancelMail(out); * @param out The output stream returned by openMailStream * */ public static void cancelMail(PrintStream out) { ((MailStream) out).cancel(); } /* Static method: sendStandardHeaders(out, senderName, subject) */ /** * Adds the standard "To", "From", "Subject", and "Date" headers to the message. * * Example: JTFTools.sendStandardHeaders(out, senderName, subject); * @param out The output stream returned by openMailStream * @param senderName The real name of the sender * @param subject The subject line * */ public static void sendStandardHeaders(PrintStream out, String senderName, String subject) { ((MailStream) out).sendStandardHeaders(senderName, subject); } /* Static method: openHexByteOutputStream(printStream) */ /** * Opens an output stream that allows the client to write data using pairs * of hex characters. The return value is an OutputStream that * the client can use to which the client can send binary data, which is then * written in encoded form to the underlying PrintStream object. * * Example: JTFTools.openHexByteOutputStream(printStream); * @param printStream The underlying PrintStream to which data is written * @return An OutputStream for writing binary data * */ public static OutputStream openHexByteOutputStream(PrintStream printStream) { return new HexByteOutputStream(printStream); } /* Static method: openBase64OutputStream(printStream) */ /** * Opens an output stream that allows the client to write data using Base64 encoding, * which is the most common encoding for mail attachments. The return value * is an OutputStream that the client can use to which the client * can send binary data, which is then written in encoded form to the underlying * PrintStream object. Closing the stream automatically pads the * data to complete a Base64 unit. To pad the data without closing the stream (as * one would need to do for a multi-attachment message, for example), call the * padBase64OutputStream method. * * Example: JTFTools.openBase64OutputStream(printStream); * @param printStream The underlying PrintStream to which data is written * @return An OutputStream for writing binary data * */ public static OutputStream openBase64OutputStream(PrintStream printStream) { return new Base64OutputStream(printStream); } /** * Pads the data in the specified output stream without closing it. This method * is automatically called when the stream is closed, but must be called explicitly * if you intend to write additional data to the underlying PrintStream. * * Example: JTFTools.padBase64OutputStream(out); * @param out The output stream returned by openBase64OutputStream * */ public static void padBase64OutputStream(OutputStream out) { ((Base64OutputStream) out).pad(); } /** * Exports a jar file consisting of all the .class files * in the directory, including those embedded inside jar files. * If the transformer method is not null, its * transform method is called to dump the bytes of the class * instead of simply copying them. * * Example: exportJar(jarFile, dir, libName, transformer); * @param jarFile A File object indicating the destination jar file * @param dir The directory being exported * @param imports A semicolon-separated list of .jar files to include (or null) * @param transformer An object to transform class data (or null) * */ public static void exportJar(File jarFile, File dir, String imports, Object transformer) { try { ZipOutputStream out = new ZipOutputStream(new FileOutputStream(jarFile)); dumpJarAndResources("", dir, out, null, imports, null, false, transformer); out.close(); } catch (IOException ex) { throw new ErrorException(ex); } } /* Static method: executeExportAction(program, actionCommand) */ /** * Checks to see if the action command corresponds to one of the export * actions. If so, it executes the method and returns true; * if not, the method returns false. * * Example: boolean ok = JTFTools.executeExportAction(program, command); * @param program The program to which the action is applied * @param command The command name being executed * @return A flag indicating whether the action was recognized * */ public static boolean executeExportAction(Program program, String command) { if (command.equals("Export Applet") || command.equals("Submit Project")) { new Thread(new ThreadedMenuAction(program, command)).start(); return true; } return false; } /* Static method: getLocalHostName() */ /** * Returns the canonical name of the local host. * * Example: String hostName = JTFTools.getLocalHostName(); * @return The fully qualified name of the local host, or null if unavailable * */ public static String getLocalHostName() { try { InetAddress myHost = InetAddress.getLocalHost(); Class inetAddressClass = myHost.getClass(); Method getCanonicalHostName = inetAddressClass.getMethod("getCanonicalHostName", new Class[0]); return (String) getCanonicalHostName.invoke(myHost, new Object[0]); } catch (Exception ex) { return null; } } /* Static method: copyFile(oldFile, newFile) */ /** * Copies a file from oldFile to newFile. * * Example: JTFTools.copyFile(oldFile, newFile); * @param oldFile A File object indicating the existing file * @param newFile A File object indicating the new file */ public static void copyFile(File oldFile, File newFile) { try { BufferedInputStream in = new BufferedInputStream(new FileInputStream(oldFile)); BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(newFile)); copyBytes(in, out, oldFile.length()); in.close(); out.close(); Platform.copyFileTypeAndCreator(oldFile, newFile); } catch (IOException ex) { throw new ErrorException(ex); } } /* Static method: copyBytes(in, out, nBytes) */ /** * Copies the specified number bytes from the input stream to the output stream. * @param in The input stream * @param out The output stream * @param nBytes The number of bytes to copy * @throws IOException when read/write fails */ public static void copyBytes(InputStream in, OutputStream out, long nBytes) throws IOException { byte[] buffer = new byte[BUFFER_SIZE]; while (nBytes > 0) { int chunkSize = (int) Math.min(BUFFER_SIZE, nBytes); chunkSize = in.read(buffer, 0, chunkSize); if (chunkSize == -1) return; out.write(buffer, 0, chunkSize); nBytes -= chunkSize; } } /**********************************************************************/ /* Package private methods */ /**********************************************************************/ /* Package private method: getURLSuffix(path) */ /** * Returns the last component of the URL path. * * Example: String suffix = getURLSuffix(path); * @param path The string version of the URL * @return The last component of the URL path */ static String getURLSuffix(String path) { return path.substring(path.lastIndexOf('/') + 1); } /* Package private method: exportApplet(program, progress) */ /** * Exports an applet version of the specified program. The directory used for the * applet is chosen by a popup dialog. * * Example: submitProject(program, progress); * @param program The program being submitted * @param progress An optional progress bar to keep track of the operation */ static void exportApplet(Program program, JProgressBar progress) { try { String className = program.getClass().getName(); String programName = className.substring(className.lastIndexOf(".") + 1); File dir = new File(System.getProperty("user.dir")); File home = new File(System.getProperty("user.home")); ExportAppletDialog dialog = new ExportAppletDialog(home, program); File outDir = dialog.chooseOutputDirectory(); if (outDir == null) return; if (outDir.exists()) { if (!outDir.isDirectory()) { outDir = new File(outDir.getParent()); } } else { outDir.mkdir(); } if (progress != null) { progress.setMaximum(countResources(dir, RESOURCE_EXTENSIONS, "acm.jar") + 1); ProgressBarDialog.popup(progress); } File indexFile = new File(dir, "index.html"); if (indexFile.canRead()) { JTFTools.copyFile(indexFile, new File(outDir, "index.html")); } else { dumpHTMLIndex(outDir, program, className, programName); } if (progress != null) { if (ProgressBarDialog.hasBeenCancelled(progress)) return; progress.setValue(progress.getValue() + 1); } dumpJarAndResources(dir, outDir, programName + ".jar", "acm.jar", progress, dialog.exportFiles(), null); if (progress != null) ProgressBarDialog.dismiss(progress); } catch (IOException ex) { throw new ErrorException(ex); } } /**********************************************************************/ /* Private methods */ /**********************************************************************/ /* Private static method: initFontFamilyTable() */ /** * Initializes the list of font families. */ private static void initFontFamilyTable() { fontFamilyTableInitialized = true; for (int pass = 1; fontFamilyArray == null && pass <= 2; pass++) { try { if (pass == 1) { Class classGE = Class.forName("java.awt.GraphicsEnvironment"); Method getLocalGraphicsEnvironment = classGE.getMethod("getLocalGraphicsEnvironment", new Class[0]); Method getAvailableFontFamilyNames = classGE.getMethod("getAvailableFontFamilyNames", new Class[0]); Object ge = getLocalGraphicsEnvironment.invoke(null, new Object[0]); fontFamilyArray = (String[]) getAvailableFontFamilyNames.invoke(ge, new Object[0]); } else { Class classToolkit = Class.forName("java.awt.Toolkit"); Method getFontList = classToolkit.getMethod("getFontList", new Class[0]); fontFamilyArray = (String[]) getFontList.invoke(Toolkit.getDefaultToolkit(), new Object[0]); } } catch (Exception ex) { /* Empty */ } } fontFamilyTable = new HashMap(); for (int i = 0; i < fontFamilyArray.length; i++) { fontFamilyTable.put(trimFamilyName(fontFamilyArray[i]), fontFamilyArray[i]); } fontFamilyTable.put("serif", getFirstAvailableFontSubstitution(SERIF_SUBSTITUTIONS)); fontFamilyTable.put("sansserif", getFirstAvailableFontSubstitution(SANSSERIF_SUBSTITUTIONS)); fontFamilyTable.put("monospaced", getFirstAvailableFontSubstitution(MONOSPACED_SUBSTITUTIONS)); } /* Private static method: getFirstAvailableFontSubstitution(fontOptions) */ /** * Returns the first family in the array of font options that is * actually installed. */ private static String getFirstAvailableFontSubstitution(String[] fontOptions) { for (int i = 0; i < fontOptions.length; i++) { if (fontFamilyTable.get(trimFamilyName(fontOptions[i])) != null) return fontOptions[i]; } return null; } /* Private static method: trimFamilyName(family) */ /** * Creates a canonical family name by converting the string to * lower case and removing spaces and hyphens. */ private static String trimFamilyName(String family) { String str = ""; for (int i = 0; i < family.length(); i++) { char ch = family.charAt(i); if (ch != ' ' && ch != '-') str += Character.toLowerCase(ch); } return str; } /* Private static method: recursiveMatch(str, sx, pattern, px) */ /** * This method implements the filename matcher in a way that requires no * string allocation. The sx and px parameters * are the current index in their respective strings. */ private static boolean recursiveMatch(String str, int sx, String pattern, int px) { int strlen = str.length(); int patlen = pattern.length(); if (px == patlen) return (sx == strlen); char pch = pattern.charAt(px); if (pch == '*') { for (int i = sx; i <= strlen; i++) { if (recursiveMatch(str, i, pattern, px + 1)) return true; } return false; } if (sx == strlen) return false; char sch = str.charAt(sx); if (pch == '[') { boolean match = false; boolean invert = false; px++; if (px == patlen) { throw new ErrorException("matchFilenamePattern: missing ]"); } if (pattern.charAt(px) == '^') { px++; invert = true; } while (px < patlen && pattern.charAt(px) != ']') { if (px + 2 < patlen && pattern.charAt(px + 1) == '-') { match |= (sch >= pattern.charAt(px) && sch <= pattern.charAt(px + 2)); px += 3; } else { match |= (sch == pattern.charAt(px)); px++; } } if (px == patlen) { throw new ErrorException("matchFilenamePattern: missing ]"); } if (match == invert) return false; } else if (pch != '?') { if (pch != sch) return false; } return recursiveMatch(str, sx + 1, pattern, px + 1); } /* Private static method: getShellCommandLine() */ /** * Attempts to return the command line for Unix systems and MacOS X. * This code is adapted from a more general command-line scanner written * by Erik Forslin. * * Example: String line = getShellCommandLine(); * @return The shell command line that invoked this process, or null * if no command line is available */ private static String getShellCommandLine() { try { String option = (Platform.isMac()) ? "command" : "args"; String[] argv = { "bash", "-c", "ps -p $PPID -o " + option }; Process p = Runtime.getRuntime().exec(argv); p.waitFor(); if (p.getErrorStream().read() != -1) return null; BufferedReader rd = new BufferedReader(new InputStreamReader(p.getInputStream())); rd.readLine(); /* Ignore header */ return rd.readLine(); } catch (Exception ex) { return null; } } /* Private static method: readMainClassFromManifest(jarName) */ /** * Attempts to read the name of the main class from the manifest of * the specified JAR file. * * Example: String className = readMainClassFromManifest(jarName); * @param jarName The name of the JAR file * @return The name of the main class, or null */ private static String readMainClassFromManifest(String jarName) { try { if (testDebugOption("main")) { System.out.println("Read class from JAR manifest in " + jarName); } ZipFile jarFile = new ZipFile(jarName); ZipEntry entry = jarFile.getEntry("META-INF/MANIFEST.MF"); if (entry == null) return null; BufferedReader rd = new BufferedReader(new InputStreamReader(jarFile.getInputStream(entry))); for (String line = rd.readLine(); line != null; line = rd.readLine()) { if (line.startsWith("Main-Class:")) { String mainClass = line.substring("Main-Class:".length()).trim(); if (testDebugOption("main")) { System.out.println("Main class = " + mainClass); } return mainClass; } } return null; } catch (IOException ex) { return null; } } /* Private static method: readMainClassFromCommandLine(line) */ /** * Attempts to read the name of the main class from the specified command * line. This strategy is a heuristic and will probably fail in many * cases, but it will probably work in enough contexts to be useful. * As noted in the documentation for the main method, * programs can always avoid the need for this method by supplying their * own version of main. * * Example: String className = readMainClassFromCommandLine(line); * @param line The command line * @return The name of the main class, or null */ private static String readMainClassFromCommandLine(String line) { if (testDebugOption("main")) { System.out.println("Read class from command line: " + line); } if (line == null) return null; boolean jarFlag = false; try { StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(line)); tokenizer.resetSyntax(); tokenizer.wordChars(33, 255); tokenizer.quoteChar('"'); tokenizer.quoteChar('\''); tokenizer.whitespaceChars(' ', ' '); tokenizer.whitespaceChars('\t', '\t'); boolean cmdRead = false; while (true) { int tt = tokenizer.nextToken(); String token = tokenizer.sval; switch (tt) { case StreamTokenizer.TT_EOF: return null; case StreamTokenizer.TT_WORD: case '"': case '\'': break; default: return null; } if (cmdRead) { if (token.startsWith("-")) { if (token.equals("-jar")) { jarFlag = true; } else if (token.equals("-cp") || token.equals("-classpath")) { tokenizer.nextToken(); } } else { if (jarFlag) return readMainClassFromManifest(token); if (testDebugOption("main")) { System.out.println("Main class = " + token); } return token; } } else { cmdRead = true; } } } catch (IOException ex) { /* Empty */ } return null; } /* Private static method: readMainClassFromClassPath() */ /** * Attempts to read the name of the main class by searching through * the class path to find any classes that are already loaded and that * extend Program. * * Example: String className = readMainClassFromClassPath(); * @return The name of the main class, or null */ private static String readMainClassFromClassPath() { String result = null; String classpath = System.getProperty("java.class.path"); if (classpath == null) classpath = System.getProperty("user.dir"); if (classpath == null) return null; if (testDebugOption("main")) { System.out.println("Read class from class path: " + classpath); } StringTokenizer tokenizer = new StringTokenizer(classpath, ":;"); while (tokenizer.hasMoreTokens()) { String token = tokenizer.nextToken(); File file = new File(token); String[] candidates = null; if (file.isDirectory()) { candidates = file.list(); } else if (token.endsWith(".jar") && !nameAppears(token, SKIP_JARS)) { try { ZipFile zf = new ZipFile(file); ArrayList list = new ArrayList(); Enumeration entries = zf.entries(); while (entries.hasMoreElements()) { list.add(((ZipEntry) entries.nextElement()).getName()); } candidates = new String[list.size()]; for (int i = 0; i < candidates.length; i++) { candidates[i] = list.get(i); } } catch (IOException ex) { candidates = null; } } if (candidates != null) { for (int i = 0; i < candidates.length; i++) { String fileName = candidates[i]; if (fileName.endsWith(".class")) { String className = fileName.substring(0, fileName.lastIndexOf(".class")); if (className.indexOf("/") == -1 && checkIfLoaded(className)) { try { Class c = Class.forName(className); Class[] types = { candidates.getClass() }; if (c.getMethod("main", types) != null) { if (testDebugOption("main")) { System.out.println("Main class = " + className); } if (result != null) return null; result = className; } } catch (Exception ex) { /* Empty */ } } } } } } return result; } /* Protected static method: submitProject(program, progress) */ /** * Submits this project as a mail message. * * Example: submitProject(program, progress); * @param program The program being submitted * @param progress An optional progress bar to keep track of the operation */ protected static void submitProject(Program program, JProgressBar progress) { SubmitOptions options = getOptions(program); if (options.popup() && options.isComplete()) { String className = program.getClass().getName(); String programName = className.substring(className.lastIndexOf(".") + 1); String boundary = "==" + System.currentTimeMillis() + "=="; String smtpServer = options.getSMTPServer(); String authorName = options.getAuthorName(); String authorEMail = options.getAuthorEMail(); String instructor = options.getSubmissionEMail(); String authorID = authorEMail; int atIndex = authorEMail.indexOf("@"); if (atIndex != -1) authorID = authorID.substring(0, atIndex); String zipName = programName + "_" + authorID; File dir = new File(System.getProperty("user.dir")); if (progress != null) { progress.setMaximum(countResources(dir, SUBMIT_EXTENSIONS, null)); ProgressBarDialog.popup(progress); } PrintStream out = openMailStream(smtpServer, authorEMail, instructor); sendStandardHeaders(out, authorName, programName); out.println("Mime-Version: 1.0"); out.println("Content-Type: multipart/mixed; boundary=" + '"' + boundary + '"'); out.println(); out.println("--" + boundary); out.println("Content-Transfer-Encoding: base64"); out.println("Content-Type: application/zip; name=" + zipName + ".zip"); out.println("Content-Disposition: attachment; filename=" + zipName + ".zip"); submitDirectory(out, zipName, progress); if (ProgressBarDialog.hasBeenCancelled(progress)) cancelMail(out); out.println("--" + boundary + "--"); out.close(); if (progress != null) ProgressBarDialog.dismiss(progress); } } /* Private static method: dumpHTMLIndex(outDir, program, className, programName) */ /** * Dumps a minimal index.html file. */ private static void dumpHTMLIndex(File outDir, Program program, String className, String programName) throws IOException { File outFile = new File(outDir, "index.html"); PrintWriter wr = new PrintWriter(new FileWriter(outFile)); Dimension size = program.getSize(); wr.println(""); wr.println(""); wr.println(""); wr.println("" + programName + ""); wr.println(""); wr.println(""); wr.println("
"); wr.println(""); wr.println(""); wr.println("
"); wr.println(""); wr.println(""); wr.println("
"); wr.println("
"); wr.println(""); wr.println(""); wr.close(); } /* Private static method: dumpJarAndResources(dir, outDir, filename, imports, progress, options, exportFiles, transformer) */ /** * Dumps all content enclosed in the directory dir into a jar file in * outDir. This code creates two copies of the resources: one in the * jar file and a second copy in the directory. Browsers that can read from the * jar file see increased performance; older browsers take the resources from the * code base. */ private static void dumpJarAndResources(File dir, File outDir, String filename, String imports, JProgressBar progress, boolean exportFiles, Object transformer) throws IOException { File outFile = new File(outDir, filename); ZipOutputStream out = new ZipOutputStream(new FileOutputStream(outFile)); dumpJarAndResources("", dir, out, outDir, imports, progress, exportFiles, transformer); out.close(); } /* Private static method: dumpJarAndResources(path, file, out, outDir, imports, progress, exportFiles, transformer) */ /** * Dumps the directory rooted at dir to the output stream. * The following tags describe the parameters: * * @param path The current path (/ separated) * @param dir The directory to be written * @param out The ZipOutputStream to which the data is written * @param outDir The output directory * @param imports A semicolon-separated list of .jar files to include (or null) * @param progress A JProgressBar to keep track of the progress * @param exportFiles A flag indicating whether files are to be exported * @param transformer An object to transform class data (or null) */ private static void dumpJarAndResources(String path, File dir, ZipOutputStream out, File outDir, String imports, JProgressBar progress, boolean exportFiles, Object transformer) throws IOException { if (ProgressBarDialog.hasBeenCancelled(progress)) return; dumpTree(path, dir, out, outDir, progress, 0, exportFiles, transformer); StringTokenizer tokenizer = new StringTokenizer(imports, ";"); while (tokenizer.hasMoreTokens()) { String jarName = tokenizer.nextToken().trim(); File libFile = getLibrary(jarName); if (libFile != null) { ZipFile jarFile = new ZipFile(libFile); Enumeration e = jarFile.entries(); while (e.hasMoreElements()) { ZipEntry entry = e.nextElement(); String entryName = entry.getName(); if (!nameAppears(entryName, SKIP_FILES)) { InputStream in = new BufferedInputStream(jarFile.getInputStream(entry)); if (transformer != null && entryName.endsWith(".class")) { entry = new ZipEntry(entryName); out.putNextEntry(entry); transformClass(transformer, in, out); } else { out.putNextEntry(entry); JTFTools.copyBytes(in, out, entry.getSize()); } while (true) { int ch = in.read(); if (ch == -1) break; out.write(ch); } out.closeEntry(); in.close(); } if (progress != null) progress.setValue(progress.getValue() + 1); } } } } /* Private static method: dumpTree(path, file, out, outDir, progress, options, exportFiles, transformer) */ /** * Dumps the file or subdirectory tree rooted at file to the output stream. */ private static void dumpTree(String path, File file, ZipOutputStream out, File outDir, JProgressBar progress, int level, boolean exportFiles, Object transformer) throws IOException { if (ProgressBarDialog.hasBeenCancelled(progress)) return; String filename = file.getName(); if (file.isDirectory()) { String[] files = file.list(); if (level > 0) path += filename + "/"; for (int i = 0; i < files.length; i++) { dumpTree(path, new File(file, files[i]), out, outDir, progress, level + 1, exportFiles, transformer); } } else if (isResourceComponent(filename)) { String entryName = path + filename; if (entryName.startsWith("Java Classes/")) { entryName = entryName.substring(entryName.indexOf('/') + 1); } ZipEntry entry = new ZipEntry(entryName); InputStream in = new BufferedInputStream(new FileInputStream(file)); out.putNextEntry(entry); if (transformer != null && filename.endsWith(".class")) { transformClass(transformer, in, out); } else { JTFTools.copyBytes(in, out, file.length()); } in.close(); if (exportFiles && outDir != null && !filename.endsWith(".class")) { in = new BufferedInputStream(new FileInputStream(file)); outDir = new File(outDir, path); File outFile = new File(outDir, filename); outDir.mkdirs(); BufferedOutputStream backup = new BufferedOutputStream(new FileOutputStream(outFile)); JTFTools.copyBytes(in, backup, file.length()); in.close(); backup.close(); } if (progress != null) progress.setValue(progress.getValue() + 1); } } private static void transformClass(Object transformer, InputStream in, OutputStream out) { Method transform = null; try { Class[] types = { Class.forName("java.io.inputStream"), Class.forName("java.io.outputStream") }; transform = transformer.getClass().getMethod("transform", types); } catch (Exception ex) { throw new ErrorException("exportJar: Illegal class transformer object"); } try { Object[] args = { in, out }; transform.invoke(transformer, args); } catch (Exception ex) { throw new ErrorException(ex); } } /* Private static method: countResources(file, extensions, libName) */ /** * Counts the number of files in the directory tree rooted at file whose extensions appear * in the specified list. If libName is non-null, the number of components in * the corresponding jar file are also included. */ private static int countResources(File file, String[] extensions, String libName) { String filename = file.getName(); int count = 0; if (file.isDirectory()) { String[] files = file.list(); for (int i = 0; i < files.length; i++) { count += countResources(new File(file, files[i]), extensions, null); } } else { for (int i = 0; i < extensions.length && count == 0; i++) { if (filename.endsWith(extensions[i])) count = 1; } } if (libName != null) { File libJar = getLibrary(libName); if (libJar != null) { try { ZipFile jarFile = new ZipFile(libJar); for (Enumeration e = jarFile.entries(); e.hasMoreElements(); e.nextElement()) { count++; } } catch (IOException ex) { /* Empty */ } } } return count; } /* Private static method: getLibrary(libName) */ /** * Returns a File object for the named library on the * class path, or null if no such library is available. */ private static File getLibrary(String libName) { if (libName == null) return null; File library = new File(libName); if (libName.startsWith(".") || library.isAbsolute()) return library; String classPath = System.getProperty("java.class.path"); if (classPath == null) classPath = ""; StringTokenizer tokenizer = new StringTokenizer(classPath, ":"); while (tokenizer.hasMoreTokens()) { String token = tokenizer.nextToken(); if (token.equals(libName) || token.endsWith("/" + libName)) { return new File(token); } } File dir = new File(System.getProperty("user.dir")); library = new File(dir, libName); return (library.exists()) ? library : null; } /* Private static method: isResourceComponent(filename) */ /** * Checks to see whether the file should be exported by its extension. */ private static boolean isResourceComponent(String filename) { for (int i = 0; i < RESOURCE_EXTENSIONS.length; i++) { if (filename.endsWith(RESOURCE_EXTENSIONS[i])) return true; } return false; } /* Private static method: submitDirectory(out, zipName, progress) */ /** * Submits a ZIP file containing all the relevant files in the current directory. */ private static void submitDirectory(PrintStream out, String zipName, JProgressBar progress) { try { OutputStream base64Stream = openBase64OutputStream(out); ZipOutputStream zip = new ZipOutputStream(new BufferedOutputStream(base64Stream)); ZipOutputStream dummy = new ZipOutputStream(new NullOutputStream()); File dir = new File(System.getProperty("user.dir")); dumpZip(zipName + "/", dir, zip, dummy, true, progress); dummy.close(); zip.finish(); zip.flush(); padBase64OutputStream(base64Stream); } catch (IOException ex) { throw new ErrorException(ex); } } /* Private static method: dumpZip(path, file, out, dummy, topLevel, progress) */ /** * Dumps the file or subdirectory rooted at file to the output stream. * The following tags describe the parameters: * * @param path The current path (/ separated) * @param file The file or subdirectory to be written * @param out The ZipOutputStream to which the data is written * @param dummy A ZipOutputStream attached to a null stream used to calculate checksums and sizes * @param topLevel This flag is true at the top level only */ private static void dumpZip(String path, File file, ZipOutputStream out, ZipOutputStream dummy, boolean topLevel, JProgressBar progress) throws IOException { if (ProgressBarDialog.hasBeenCancelled(progress)) return; String filename = file.getName(); if (file.isDirectory()) { String[] files = file.list(); if (!topLevel) path += filename + "/"; for (int i = 0; i < files.length; i++) { dumpZip(path, new File(file, files[i]), out, dummy, false, progress); } } else if (isSubmitComponent(filename)) { String entryName = path + filename; ZipEntry entry = new ZipEntry(entryName); InputStream in = new BufferedInputStream(new FileInputStream(file)); if (dummy != null) { dummy.putNextEntry(entry); JTFTools.copyBytes(in, dummy, file.length()); dummy.closeEntry(); in.close(); in = new BufferedInputStream(new FileInputStream(file)); } out.putNextEntry(entry); JTFTools.copyBytes(in, out, file.length()); out.closeEntry(); in.close(); if (progress != null) progress.setValue(progress.getValue() + 1); } } /* Private static method: isSubmitComponent(filename) */ /** * Checks to see whether the file should be exported by its extension. */ private static boolean isSubmitComponent(String filename) { for (int i = 0; i < SUBMIT_EXTENSIONS.length; i++) { if (filename.endsWith(SUBMIT_EXTENSIONS[i])) return true; } return false; } /* Private static method: getOptions(program) */ /** * Gets the SubmitOptions for the specified program, * creating it if necessary. */ private static SubmitOptions getOptions(Program program) { SubmitOptions options = optionsTable.get(program); if (options == null) { options = new SubmitOptions(program); optionsTable.put(program, options); } return options; } /* Private static method: nameAppears(name, array) */ /** * Returns true if the name appears in the array. */ private static boolean nameAppears(String name, String[] array) { for (int i = 0; i < array.length; i++) { if (array[i].equals(name)) return true; } return false; } /**********************************************************************/ /* Private constants */ /**********************************************************************/ /* List of files to skip in copying a jar */ private static final String[] SKIP_FILES = { ".DS_Store", "FINDER.DAT", "RESOURCE.FRK" }; /* List of extensions to export to the jar file */ private static final String[] RESOURCE_EXTENSIONS = { ".txt", ".dat", ".gif", ".jpg", ".jpeg", ".png", ".au", ".wav", ".class", }; /* List of extensions to export to the submission file */ private static final String[] SUBMIT_EXTENSIONS = { ".java", ".html", ".txt", ".dat", ".gif", ".jpg", ".jpeg", ".png", ".au", ".wav", }; /* Class variables */ private static HashMap optionsTable = new HashMap(); /* Size of the copy buffer */ private static final int BUFFER_SIZE = 4096; /* Font substitutions */ private static final String[] SERIF_SUBSTITUTIONS = { "Serif", "Times", "TimesRoman", "Times-Roman" }; private static final String[] SANSSERIF_SUBSTITUTIONS = { "SansSerif", "Helvetica", "Arial" }; private static final String[] MONOSPACED_SUBSTITUTIONS = { "Monospaced", "Courier", "Monaco" }; /* List of jar files to skip */ private static final String[] SKIP_JARS = { "acm.jar", "acm11.jar", "swingall.jar", "patchJTF.jar" }; /* Static variables */ private static boolean fontFamilyTableInitialized = false; private static String[] fontFamilyArray = null; private static HashMap fontFamilyTable = null; private static HashMap appletTable = new HashMap(); private static Applet mostRecentApplet = null; private static SecurityManager managerThatFails = null; private static String debugOptions = null; } /* Package class: EmptyContainer */ /** * This class represents a simple lightweight container. The only difference * between EmptyContainer and Container is that Container is abstract and * can therefore not be instantiated. */ class EmptyContainer extends Container { /* Override method: update(g) */ /** * Overrides the update method so that the container is painted * but not cleared. * * @param g The Graphics context passed from the component */ public void update(Graphics g) { paint(g); } } /* Package class: SecurityManagerThatFails */ /** * This class is an instance of the SecurityManager class * that invariably fails if it tries to read anything, even if executed * inside a doPrivileged block. */ class SecurityManagerThatFails extends SecurityManager { public void checkRead(String file) { throw new SecurityException("always fail"); } public void checkPermission(Permission perm) { /* Empty */ } } /* Package class: DOSCommandLine */ /** * This class contains code to return the command line from a DOS prompt * on a Windows system and was originally designed by Erik Forslin at * Stanford. The code requires the inclusion of a native library called * GCMDLN.DLL; if this library is not present, the code for getCommandLine * creates one in the current working directory. */ class DOSCommandLine { /* Method: getCommandLine() */ /** * Returns the command line that invoked this program. */ public static String getCommandLine() { try { System.loadLibrary("GCMDLN.DLL"); } catch (UnsatisfiedLinkError err) { try { String cwd = System.getProperty("user.home"); InputStream in = MediaTools.getHexInputStream(hexjar); ZipInputStream zin = new ZipInputStream(in); zin.getNextEntry(); String fullPath = cwd + "\\GCMDLN.DLL"; FileOutputStream out = new FileOutputStream(fullPath); for (int i = 0; i < UNCOMPRESSED_SIZE; i++) { out.write(zin.read()); } out.close(); System.load(fullPath); } catch (Exception ex) { throw new ErrorException(ex); } } return getLine(); } /* Native method: getLine() */ /** * This method header provides the link to the GCMDLN.DLL file. */ private static native String getLine(); /** * This hex string corresponds to the compressed contents of the GCMDLN.DLL * file. It would be easier to include the DLL in the acm.jar file, but * it is safer to make sure all data is part of the code. Some adopters * may not know how to work with jar files that contain data. */ private static final String[] hexjar = { "504B0304140008000800079966360000000000000000000000000A0000004743", "4D444C4E2E444C4CEDBD0B605355B6307CD2A4252D2909D042C50201AAE28098", "366993347DA4D0948A14022929155AA83498D6D2D6F49C429562EB69B5E9218A", "8E33E39DAB73EDA05E67F48EDC511966E46A4AB1056490878F2A8C96B1EAC120", "14A9A540ECF9D6DAE7A40F1F33DEFFCE7FFFC770CACA7EADBDF6DA7BAFBDF65A", "FBEC84BC3B7650728AA214008240517B28F1B1527FFFE10126CCFCD304EA95C8", "3FCFDA235BFAE759F9EEB21A6DB5A7EA2E4FC926ED8692CACA2A5A7BA74BEB61", "2AB56595DAECE50EEDA6AA52D782E8E8A80489C685E7A3C25F3D58EA0C414ABB", "D9B99BC45DCEAF20DCF5E6DDCE36125A9C1748A820E5BBDE34395F2161060957", "966D7063FD1FE2D56EA3A8A53205F5ABC77F9E15CAEBA126CC1A2F1B1745D911", "41CC6B9F081F1A80F524A921718D383E14351252BB243C78C2245431AD19CE27", "646A296A1384A67B286AEEDF1ACCA70127E26F8F373E47AB292A7774C67A711E", "7EE85940BBB6D0103E9E2731641FE13BF46881CA024F69095D42517F9E22D2C4", "4C690C861F2BFC5B20A25169384E0D12AD86EFE0F917785C15551BA05D95D837", "82B7E33B780BFF06EBD79E6BCFB5E7DA73EDB9F65C7BAE3DD79E6BCFB5E7DA73", "EDF9073EABB8B3422C387A1A3B97A7E427404ED13E257578F881F215DEBC2067", "5302427005B72AC885093B9E049797FBB4689F02EB7336153B2873AA9B7BA0F6", "9EC7E1839F02DE1ED7EFEC8AC09410AB04FACD7E75934106D9CB34DEE8382FA5", "E172143B1330742ABDB1733152AB6AFC4CB89FA2D8CB61DEE478C8A1558D47D0", "B91453ED3D4AF9BE72D94E2DC4F9D3C06AB3BF50DD848DF2EF86638A89E2AF57", "53D4993F63D68C09D832F66CA7E151A870161CD19D0AACDA310E91B72EE08D2A", "12D1F2572349646A39540B237499F1423805C8671E435A8F40397F879CA202BF", "8256E69B49D1B632211A4373783E7C32E1FC2C40E04B11F5568CED0006024E76", "308CC9766F072AE532FE6170F0B9BEE681C2427ABE53483634501A21B6D48B83", "E3A463F858A85628C42A8067769942F04604A6F25F40CF0AF5FE80861D94334A", "60F03505C9B0FA5CC1E2A27D2AAA5CE5E6A1027F170C39647B6DBD1CA3D20B96", "4B8CCA9C8EFCA99B5E86D6BDF5414B1F1DCE0E8531896D2618104B17AD12188D", "536094C251A865AEEF553735E3748999FCEC2141807CC0F370451A07C9BB02C3", "0B79EC908C9960E962A21C05983BF88D00ED21713973B388F82964C150C9BDF5", "48989E1C6A32CA31DC209B1714385B6F601A673BCB29B948FB0ABE01C8171676", "702E1E0BF57EFECF90017D6C53413F40C6E868A039814DD7405206239E3909D8", "A51314FC1BD079B740644D07830A34DC8A121CDC182279F414773F8AB810AB11", "D311584B384A3E63559077B85CC9D74F86D63B20F2C6248C38B9BEC0782E02B0", "C384A36CA7C24227283DE78B3BDA748F121AE3441A85CE823FAAA0CD37E2E043", "EFB7BCCD5DA8990A6C6672139A0F42D56358F592E74B141C77E64C98A91B6328", "EA75106B0DD7F986B20187A5B0463DBAA14B9E0B7AFFBA6260C5AD815EF0DB41", "9280ADBF205B7A0166523F90634E5E8D52A7C1D18C8D173B1707813719A5B1D5", "A6F9B51D65B35EC518CDE97381637A665B02042C0FAB0EE7221C333D511C05B3", "F2A9703470DAAD055EF6C4C3072F1304A1D03D17D30998BE00A2508853C2C7C1", "189BEB35CC2C2F691FA7FA3128D40BC852BD8656029F0D1371F8F889C0754739", "883D8C938AD7014976BFAAA35C0659143F4B4A0AB15A601AF4481B2E067650A0", "274047DC38DDD164799CF90BAA92EC044597357F3D647459634089501D2047B1", "73A1AAB88AB86E21763DAA10585CCC6DA1E536533EBCDC6EF9D672A3E3BB7244", "7A3984DE9855A72CD7F05E10E04287109BB01EE7A9784D47B9C6ADC5C9104069", "708C125798BA49850A2D270186709C9DCF04D551C8E5CC17538962CA20A6E688", "A93431152BA6B2C5D43831952BA62ECB482A3F1DB9C30C1E33CAA3F98F60200A", "61F2B99CF5E2B29C2C2819B525FC804FC4F3231E992416BBAFE2FF032B74D982", "D83F2EA7D46BEB814A7982D2BC653E1DCEE5CE1722CD5B0C1833604C87311DC6", "AC18B30A915CEE52C1FB0A54B684071F803626A53F8FC178B38981E63C1343CD", "6901C5C96761F37C3C8C0ECCA65E8021029E195CD01D1857F165629C4C2B7B59", "A0E7E0ACC2AA18B7429C3B3BFF2F2049E5D4E889EAE07F46F43C88D9499810BD", "BFC359E02E1D5ED9DC60B340DFCD25E3AA76AF86EC02E13DF7520C77AE45E97C", "CF6D2589F562C24412A524C1A66326B513458D99DB66C07D0273DA7418439CB6", "F910EB0A4742F7C7401E62BA6F8EC5B6D7127524EC4446E92CBD40046E7101FF", "3B6A58E0E67D5BE0A64902E7DD16335AD8B8AEC0385E0862DF70C5ABDC5B50C8", "7E194584AC79805ECDA62B76501A39632D57F02727E098BB8230DC67A6A034D8", "7A8172A4D3CE874F45CD49A6633C30C1D6F752CC74589D8128A8763E9AE8331C", "5A6A07B264C20DE39E285C9F1A770B3678B3D8A0FA2546E5657A6011C97250D3", "80A6EFD9EC0AB1B098ED54B39FF579191557D46399FE0A08DE663DD0CF46B666", "D5071D7CD20C912BC2C8121C8DFA5E98A24902D3534E15F0B7CE02D6F6AB9A05", "26D559AE0C719326CD24738339BD9783119DEEE43F05A12A0493A1B916144560", "026C69D0CE4DA41F5C17BF1B36D90EF66CAEE3B506D80D1D7CDD6C71D356B207", "40618020EED4EEC0B953C2274AA7AF05F1023358A5C0AE57529D560540781417", "8D68AC3FA1B11DCB2DED9E8F56390B7CD90931A0839602571BD9AD093994BAE9", "0C4574502EDA307FC1B8C9E756F814B77AB313347B2825541DDC1AC60D9AD3B1", "C1FA65AF2740E0E03F9945B8A24DACC8883742E263CAB7F998003CC8DF82F63F", "03F52F52D9FA4620822331FDC966615B3934AFE1285490F9AD79D440BB8C5E3A", "D0AE64C603A7B9E29E96C6BDC575B03D337D0A7FFBE5704EE5C3CEF90C8D624D", "6F44AB8D6AC951F87254EEA76125DAF9495AC25E21BD40C851B280A45864B37C", "BCF5E7FA93E2B8F81427A1369B213055CD273B73148D4C54F9C0EA801AC63850", "C775E45EEABEDECFFABF0606B2C904B2824067160CB363B801F763307FBC194C", "44C33285351089268C02A2CA11267C3325267E034C04A2081EA2342C62AFCAD5", "DB3D30FB42B2928889753DEEAFEB8A8BD6B0FB73410FBC8E4C7219205E89BE87", "C8B84E63EF575274946FB10A98B22353116C57423899DB41CF5F8514FE495868", "EC8DB0863A158D435AD800B7BE0EABCEA13F699E3E1F52CE02302A6E0633804B", "464B1174FC4566524097964ECB163BF94498CF421F1D216B8D48ED60BEF029FE", "0B5F06D9F9ABD0076ED072B5D09B6E2296208ED06A91C4AAC04F9CFC208C34C7", "DB1A32D20BE9EB56F16F01BEA5A3D03B8E36C2CA3D3993ACDC2E85FC6BD30CE6", "B840AAF117AF82F1351DA3DE995DE1C8296A71BDBFB0681DEC45423236C41F21", "4818C5167BD1547770452AFD71F32A6581770A77B94B8EB5E84830ED599B52E1", "353798663313F4079B8FAB1F6FB772C7FE7376E01621024630BC55D9A25EDCAA", "54EFFEC03AC09E8685AD00EB502C896B99B9D8DA741008D349CDC799BD0D97B5", "7478C3E548E6F750ACE85C2C50A8911A4CB04EDE83D65A95C30811D6C085DCC0", "6952F41AD14ACAD1CC0872FDC945FAE38130EBC206D35AFA323277E3C03E1933", "93AD0F52B4CA972B6B30CF66145C7B204C7F527FD09C1704B6C11939F645F371", "3005B1F5716B170B114B988BADCAA683742ED663A2B0FD74689F36359FA41700", "DA75EADDC7061E107B1501FDB40A11A4BF01B57AF7C18146B1400EB94284F58C", "1B244E244D0169E8F519B455C0FF019996B35A4A90AF5B73B003C77A85C359A0", "17CCE92839203717D00655C080BF5EED4551EA0CA75B61871162F34112DB0CC4", "FEF526E7A25B330E8684EB66C2B88F7CB6A0BDC0C70CEA0F721DBC05F63F8E01", "5F6BB0FDB33079A79D6F9B8E92256A4C22553720BE4F958155A0421456B00573", "0B77CE07B2207F3AAFB84680C3152BDAB640FB0ED0685CBA1BD7CE49FD80A5A3", "3CAC88B945789FEBB35CA4555DE18882321298219A53ECE01626927B7327E607", "C20905B0BB997A58084AA956DD46F30CAE939E207F73A3398EB92C065F71E9A5", "50DDE170CCEB741C1BB4DA9D0E07684703D4E12D013A6915FF6EBC28F5A068E8", "390EC72A3B9885098025BC8F363D2434FCD020D85CDEB5A0AE00C0BE5B8F4BB8", "2360B7BC492B2D1DB402DCA06CD87C311719E933CDA0A3ACA638E62A7E0CCCEB", "B472FC2A7E53BCB41A19855E088C87EEF3CA1964DB018AABB16E17EA10701160", "B37D02F7BE5BC04CECB2F5CEBF87D234D693A066368A3438271C28277A3C58C7", "E3C0B50AF925ACAD571178974F94E3FEA9723F8F34CE84111A069186E1C7D2F8", "320C37B2747487C39868361DFDE1708F0211CBE5AB3BF47E33D848E594FA71BF", "1B5FA0825AAB26DA7527EE9CF44FF87634A307E53B717F6666B807D1EF7C48F4", "8C1975687FAD208AB303898676F232A2F25E04C15FC5DD82D6C0369B934BDE05", "6910161AE5A053E5C6F7B36E7C712BA408EFBBD10F2F2751A156316C4ABCCB76", "C62CB2104A5B8FAC2B16088D91D2A235A399E8387CF8703AF6A366C2A56EF97E", "D6AF68A61EE7287BC70ADFD20465E3192CBA053F9A6522DAD97907B8FDCD32EE", "34F88756859DAC3A5874BC7011E4BE5EC9F571CEFCB65EB4FF0F99CD74B42FDE", "CAB6AB7CF1BFB4BCE539EF53587D8A072C076A145014063AEFA0BA69129AEB85", "CAE693DE22A5BA09D72A7B359C51B1254A749DCF0451475D95A99B3E2516F36A", "AF0DD6A2CA9BB39ACB52B0834A75F31B981FDB0D0DB69D820FF93ECBD1FA9B7C", "8A95ED3D61DCB67CB6D4A4A4B8742CE6A663F942F9C7AC5F6539B1F5AF5C1138", "B88D971FA6283FB76D2D13D995B3168DF44069E3E51D9047321A31C3D178F9D1", "504613662C6CBCFCD350067AE781C4C6CBBE50C60398A16DBCFC4828E341CC50", "375E7E0C33C641462BFA36B56BC1D83A51E8DDB636300EFB6A174E80D628848E", "A14E8914189510BB05E687E88D3D1B6A36F5A0D831D1B0289576FE2174FE0A3B", "44090267FCF06177CB6C4A53DA86C74776B42EBC15091A1FC0BC1E981CD05E5E", "176F8706C0F5C0EDDB6B1BF4D9FA4A77227A0797D757EA8DC66821B6B6A2C3B9", "2849B77A914E0753CB9E5542FD5541D0B9A06E2F5915781D42DDFC029E5ED806", "399B06E6C307D41705B91A15779FD2C1179185AD18EFA7EF638704BADEA7AAE5", "B21FC174A17395EF6E547907F5C7F5037A41385A540C74A124734B2EA9AB9F4E", "EA0296D3C1BB494209F5CB654041C90750F32A1EF12E526172341DA88CCD181E", "096C277765027380593657A1DC43F4682CB65B2E38F858916411C9C65D9BFBB4", "080418049DBB99CB8AB773597176BE2F5E44C28334DF8B09340C57E359742ADB", "ACCD20453E3C3E7338BDCD2DB8F91F2FD0FB2DAA3779743A22ACECE064CF05AE", "AFFD33B9E561CC5237C7623DE9A444DDF4313A6EFB50A990D31275D311C868BC", "8C32AE6EFA8292F62A9FADC1BEB2E5674DC405CE27BA85D140A6FB19177A6419", "C4ADF0D537705DE0D182F30FCDA615D6CEC6E4EC3854B480CBF29672B97CD0FD", "345429E00333B14B1009837261F759E29DF35F03215FB63CBE90F5CB0BD99E20", "DF0FB60B77CADDE4424BF97D70660A1C7C0F04EE0692F3EE945065077F10B335", "5A19E55E4DCA7690599F1F98BBD2D78C0364F7114430EF1E4176ED424A79BF68", "9482BEDC0A81EF591C58CE87A3C83F0DC618CC46E39BE8B31DEC1873B4F493D0", "D1D22C378E13EF06D16FDBDA8AA352888733E488895F890B020C50FDC01B0DB8", "3FA67DDDD4889566F8145F3740CC6B22C6ADA063BBE2F8176324035795C30E25", "6C3D0E6B082C4E36816082D6095C7070D3D15675BE8E3905C4A09DCC6E530047", "05C28902FECC8590C9AA6C1C7A1A1CF0ADA708E63A72621489988C1C56F448F9", "676021926359A56078135185D80668A008CF93FC30827C5A10ED0CA5CF409880", "9D6006E3298FE3F5B178F2005B2713CDB7C02C765178772790591EC5DF890BD6", "5B14044CB17305FC093C2D03178D9953C0DB80477ED57095720116BC9D9F3C8D", "6CBBD0C7A9DE8CC0B8027EC685D03152243166ADFC9720051D403F0F0F9C24A6", "9D3E916B36836226DBF9C5688FA16F573E91EF0F001A6C41B14DD09FE2A20EF0", "B1F1148BDF81DE22178DE75A5C5F1B6671C7E61D65F7292C5FD52CFB2371D02E", "D4847147E44756D8F9DD33C41961A6B29D9A1085B6506658718748685E3416EC", "C48FF6CB613E558B97647BCD6C38860AAEABB8C3DD80F2707532A94B50194579", "DCEA0E30130917E4A40D142758094771E03BAEC0383D069D20A641BD92B710FD", "D83B3C26602EF01F005207CF00568778B60938E86B5DEA2E04B787039DCCE5A4", "81E169095FBD1D34C1064B17BD8ECB996F3631ABC5E3A67888C659C29FC67321", "58C3CF9F0702B569FC51745F0AB91CDD08CA33124AB384B28CA008B5F3F91A29", "E7EEF3A8FCB91CAB25FC49449E0195A741E52976DE0E455C4EF62D43C4095A28", "21DA2DE1F9C8563C20C699F7E0F111032D94CEC47DC8CE5F4FD09CFC640C6121", "3879FD5920D3C72D2BB544E32993BAE959A2EB2C87E85BB9ACF942A4651FAC3C", "259765084574A1883514592AB4603B6D58DF9B534A42414C9AEDF3E928CE3A7F", "3869C0A46138A9C3A46E3869C5A4554A72D6A5420339FF3A444F364F64605F25", "0760E356F00CAA002EA7949CD8ACBF0BA69607DBB55CC59BF1D81067979FFD3D", "538B062ED4E08B8328EEB73C03E61A3D9BE515F454968FA655B9B41C84658F02", "DCCA8E3D93C8A742899F13315E506E05FFEF8D1E98868B2FFC56EFDFD9FB3048", "D86148EEDC0F1F6FF441F285175E5887CBA8F16C5CB8B489C0A6E9F4D978BB90", "8CF842EC0E62E5CB5EA764B8B946CB7021B63485F3D023ABA5D3D3DF6A3BD7E4", "EF6CC6B4964E71F8569D2F50EF8E52EFF65BDA374F9F77208BFBA0FD4C986F2F", "A9B0470BCFC517B8B7D8D3F28BBF5DD81AB6B0C9CF1C5BB7060D40E4C9D7CC5F", "41071E5BB63B7D84A8BD5CC6BF318BD892241F7261CC9CC3C54EB12AFFC99C31", "38C1D1386EBC7229E1BD3607B5CC5ABD7F23B7DD86CDE1D9C8948616F4EA34AD", "DBC3917A4B0BF508F833F103ED61B4462CD26211100D7CD2D9808514767E6F20", "5BEF6707B33CD7B183776C8E091139D0D0AE9548CC64074B3C93D9C17B374F08", "D139D070461BE81945E5752E2F58CC9BA6E1F642CC9A7832110E271E1B9FB45C", "8419295037E5E3C8C37660DE656D02A172B17EDDC2F43E1014CF97385DCEE199", "5237CF02549C7CB69E970D0B80978C8C773A0E82FAC1B350B1A1FE1C6CED7FC2", "F3AEBCF3AD139B8EAB9BFE0377FBDD59827AF7F1338F52229510059F6A65FB69", "85B7A8F7B7BE7FB1030BAD72EE62E0E656A7ACE9387D23CCB77AF7154BD7E618", "6E556FEB63262857EEC0FE5A2D5DB55FE7E4B446C04C9F1040BE3B946C7DAFC2", "D30E9A9B486457388A241A3DFCF530F43E6F36D4E52E10F17CF65922AACF06D6", "8983A780255CDB9F95D55027802CDE06A2A23F98C5B58B854A6B3A6EB760E474", "F2C760A648556F34520F4478A763A8F787A43E106D9E7E0ACF0E27F0EF002E3F", "484E5403723070613660BFE79F8FC3F9288F7157E372357F0D4A38AF47288FE6", "1FBC0C8B91BC56F1A6230934E7068798495DE198125F0E6C87A908CC6307BF19", "9BDD82D931EC6090518F64B73DB11D579DD2128EC3219E7C70C9784AEF654E59", "2ED10A7306AD716B4182F9763CD0E4FAC4FCFBF165CA61D41FE4A49EA9F266B4", "9129CE51B46167BD39CA36320439B0A5A266190CAFD76CE454361C828DDEA539", "1A6B802725E932E0A33EBAB50527BA65A92EDE1A382316E0A2AFD7B412596ED9", "AE9B0E496BE0332FE18EADEF1198180B89D32A275F7D065809C8BDF53DA37458", "0F9FDA8F3A2C9AFFE525D4612C39FDA09849E5DFF04FA352EC0A9F3F7C58D5E1", "B6CAC4453C72D00BBE2BBA888CAC034C61057BC3F390A0D81BD081A476EE2173", "EA8DC693E5AEF0BDB8F88090B5A30D8B7DAA86B65D246C094CE2F21314F3ECAA", "C62BE89F7A22597F8CA5DDF3053449169C86CB836D41030B4E55C00DCDAB53B1", "9DC1F6F36AEEEDB2830A1877DF76593630E6CDEBE326DC06EAC29B175437BF0F", "050E5F7C2237D9BBAA9F7306BDAB06B955FD03FB64DE221543B75F512C61AF64", "D6CACB33EFE06E57586E57320BD92B5A9CDB869AEBB8432702BEA5618A4B2766", "ADDD933D14C9CC0106665D1788F72DE9192E7972CF7EC086C2082C2C54A09BE3", "50726B1420A0F2BC7EEF1D0A6E958A83CF954AAF4389EFDC8F8D69B56890FD04", "98E9573783BB47CD630621A7FDAAA23CD3CBA86E2FB67C541BC67D24CF1B146B", "59DE030290F39EE543BA98CB5371F7282CF728190B7B55FB3AE1792AF7D68973", "97DE9B4503BF4BE50A661632951898E6BBBD87E4BF22728B4584DF7B14848A92", "BB4DE15D26C615DC6D4AEF32250C72400E0E2E5BDF4F314ACB87EA26B48AC0D1", "F3A98E718580ADF4162BBC80BD0C3E95F06959A664D6B7C2A0B4E4A987DA6114", "5B205E734343BD9A62267087C8989E0840A391D7913819DDEC3DD99171819B09", "920686751456A102D27F22E92F7C4D84EF4858C5416F84375B071E7C9F00AEFB", "255C99286C78867F0A198CF6438A4BC6D30E72D4D17E5A2DCF55BD86E71C8E15", "C27B6239A922D18EB42B4992B36AC442F699166C8C0AE50EE52E12A3B99A86BA", "451413C9AE570C911C768B5260CA1CB014AA55C27B244BA8D68C7D2143849C8B", "2522AE68C02385030471DE01DFD2896757F87263C078F5E1513228A8FD2A211A", "F12DE18852AB60372963C8EA206B087531E67BD391CD35EB8A0F8A4B888BC635", "85B6633B63F0657BEDD08A5D3CB32908B1F2C47A3CA864147AFFBA0E565C8364", "C54A0430EA74EFCFC237D2621560D667681457B7A5CB9BA3C1BA8145E50A377E", "87801C201508B18F4BA52A6692503BD21A763C70945DA614BC19DE6D0A219CB4", "92A3619502D759BC4E3C6725AB5909FBE73DC0FBC980FC58CFA2667FFD65AEA3", "CC4F9673930E97332C04DBE01D5EABD26B55B07EE512A6BF5CC15D25E766ED9F", "ABE5752A728425B182AF14F165D153B85BFE82AA0623EF8A775570F322EED0BC", "B7DBCFA87C8B35596CEEA0C0B69C4557CEB72388371F341082E1DA650DF661D2", "AEE86AE0218289706CE736E62DBC20631B0C1F44DF7AB9CA9BABF066297D4B20", "A2F46629D8D25F65537A61B177EFAF50705A7316B51E186A6FF2C37CB52C5BC4", "C823B72888ACC1DAFCE2D2F1597625D741CE64885253894A0DCD087013EB55DC", "FBF35680629BDAFE859A3BF42DC5D6CF2D0FB29FF5DD66B9E0DB6A0E7233BD79", "1AF0DED40FAF82D2810E30296C10917F60B9A87EC482676279C1F6CB8ADBD8CB", "99DEBCC1DA88F2CC4208B9750ACB3A25B388BD2CA9B969B8DC067D4B6544CFED", "403D77A3A8E766B2ED3DA30B9FDCF12D55B75C09D4BC185170F72BBD754A2E4F", "33EF882C2F8827F6EA879F256F0A83A055DA05C57256C8F42D4D0CA2D65BC715", "F5FBE2AF7A8B34A027B17E91C65BA8F4DEAE40C572BB123E2D854AA6A075E938", "502693419908A04CC6296AE21BEA27A332797BB432F165EFC8E6DE0E684999C6", "B7FC5B3AA489300DD9A1E5AE417D9C17F4652705BD4AEF525910D4DC2A952F47", "E65D18F466270D9E4923C6F319135AD2BE5B711C8B543703E56532EFED41DF5A", "7D1066AA7D48B18C1DCA844D04F2B04BC503B6204C00D1914C502A2605303896", "E5B8AF0C0DEF2B4740F3D111A1F19E30B2AF2C23FB4AC4F70E36EC2B30DE9B89", "CEDDAC04AAA876198D9C097A87F9111BCCEBF7A92E70753894DEFBC8F8DE0E9F", "4A698383618D9074F4100C6B041956A2A38FBC4186E83C8E9C990CEB111C56A2", "9A97F58C2AAC1B1ED665A386D5A6F1CABDD9714172161212EF18C01FA502D9F6", "A9ECE93E07ECD120994ED03105209E5A5FDA0360A7D58F678F0827CEB1798342", "201A440F16B27EE0040FCBBF8D68BF6E2FD36FF9381003FDE02C73F206E70C8D", "7F9B19CF76C4588A82DE22A5E773089904EEC3C0C431185188D18D08BCA55BDD", "84474BDEE984E0220DA761AF08A020E8186E3BE910B7754776A8620A47B2E6AC", "1A44CFCF979BCD25CE61FAC7BFC731FDCC54EED126B14CB005D9760567862AEF", "D367504F7C77D52EDD91AD17E61C613649AD400BE5DA758162F63E25457A00DC", "01F39EF3D8831BA10791A46484F33E4B37338157831BC47593636E3ACEC1FFE1", "0A7AABB76BBC32E8096B12D4CD09686AFBCFDC0BCD1E3BBDB8F9202853683DFF", "B2828B9A0756D18590D4E60D6E4341C1AB2E6853724B1496254A662D2C3322A1", "F537726FE3FA09FAB69A4014BD4567E7AC6DC9F6020CA9193D977716CC8259E3", "03F361518968DBC9862962CFBA6E480D3598F178389E7776D6ED0AC98C188476", "94DCBD0A6F9D021AE4EE457DA16EF211A32224B04B945E40588108DE154A89AF", "625160C70F0B6CFD9C86FAF13070442261319D8FB48C92DD60E4D6966C342900", "257A446E23EF438BCCB7B745925B622F9D38176904FDD67C901EEF8DF22E9D88", "BA005424D3273F86CB1DB29260B5F7E39D2F5F9DCC9BC14CB34CC71D989904B4", "2CC45A60C649D62EE47895BE850A22FB6D3D1C795DAE166F93E1412379FD03A6", "2CB97F0986AE0A2DE5E6E3F472BDBF353B4159C05D66AF283C89973E00AF9B56", "CD3BD6328EED92B16764CC007700EF48B663A081E010FB573938EB74C4C517A0", "7A9488F705E20199751D78FFA643BC02F724794564DDA7A4CA35EEE7D1418AE3", "05A18D27BC3146F10D958C4E1875F706788E756FBD6BF856DD4E09396A0F952A", "A57035E0CB05F1C25F4F20016FFA511CDE20945E8535D6F74EC557154A3026C8", "552B7072D1D978F7737250E2DE83ACF83E27C795A177570B2CC9E4E6C98DE50A", "FE50403A6E71F27FB84A3C27F1C0452F1EB8E0E924B9CB22D695D111E20D16E7", "589F84DF88CDE12D2505DFF105716BB626287A36CF26E76F8C740039C50CA346", "6B485ECE9098F7114C93908C9756F05D09FFA6405E951C1EF514705B1394814A", "DF33E40BAF9C80735970A91DBF724B4F6E95B1EDB2263F9D2E6630E7A15CF627", "6168689BFC28DB27E8F781C2F80D259335D23C971504C4394DBDF4B4DF804142", "D1137E832E281D16F8B3AF0ED4A0AF6E28A0F4D57D1390FBEA82D0884A6A637A", "EB446CE338BDB1652A4CBFD4D01781702F2415A42D4E26B5C64D1C6EEF34D430", "340DD0375DDA475A9B842169AECB3B55149F8D62A4737118359C58D7D12285A1", "FE637F25561242DD5D16EA6E388E893434A111FA9BFD4F82FE2788FD9F3CD2FF", "2C32AAF3DA3B7C5943C3B16F8663412916BACF5C807E211820F806B19D3B26EF", "B40CD52A2D83EA07B6828ABBD445588B817503AB87BDACF4DC7CF15921E16769", "19F8E6F84F58C89E5178546C8F5C7E404868B6A7C3DC27F89642F10E088F4272", "C77AF8D80EB00B60CEB1D6889671AD39B296C5B2D69C3020DBB2388CED94B35D", "84F8E161E2BEDBA8615C8225633BC3D8AE30C47A6E186B8788C376220E2E6728", "6D194D430F8116200E4003A004A0000681973E002EFBE15E6FF623BD10F210F2", "109E85F02C847D10F641D80F613F8483100E4208C6CE23419F02153025EF930F", "864643C04EE703AC07A03388DB51BCEE60C70EE470745CECBD94033C8E191118", "8E10AE8F4E0CA2BD2ACD41C2C81C447F73F1D920B4DB9D89ED5EFA0046BA2593", "F437342797C539998773722A83CC0922EF388BE3001113406B8E7CCEB196C572", "F61C19BDF364F47E3F8A34F226E18CCCD539C024B3D0320A73C7283C401A99B3", "7372F63CB2AC7EC009CA602CEDED103C0EF024C033002F02BC02B017E0ED4C32", "37F130D6F110C6411807610C8431106A20C47215842A0895102A215440A8183B", "37E218F1F0D9978927929426C63A6A6E72E4C0F5A8B920E9B1F3303A6FCCDC89", "EB075FD2E2255E77AE55BC019C337DE40D2759EF59E4D52D79F349AB511FC02E", "A6F186EDC199EAC077C4D9091A7BF990DB0E044A4113C353EABD812CFFEC042D", "B75AC955ABF085EE020B9D9040CFF5196A39D5CBDEA5094A6FAE8ADDFAB28262", "26B9893D92FDB292B7A21EC87F5919E8287D842814708EF19294DE5FCA9137CD", "8D750A6C88D1702B54DC4A9579859209DF235E225EF19AAE191CD02829022628", "9AC28B14DEBB55856BC46F37B067B5E4E4962B560E74C899EB4BDBF00EB4D7A6", "8431E17295960FBC79418FCAB25A51330E2CAA3EA05BC06D53B1020C0CDE29F8", "881CF37A57812BC729F1DAABD27248CDA2FBC56E5150B45CB02917E22581F76B", "7BC8F5A8182E67D0620BAA1F980D2816D8ADA6E15BDD3E3C97BCDAF839D50776", "DB40B37FDB2473DAAB831C1E2FE2EB971C4BDFD673E5F13E5B8FDD21C43E2F7D", "DB623DD46C046B8AA2C0DF70A0E767EB3F4C3BB9BCDE8D8DE6BC3BD4CD993884", "5969F2F64613FE3C82BA7901646C6CDC12371E2A60FBF33ED8C86E89A0D47FC8", "8D01CF2E4EFD6034A9A1B2747BD4DC0AA5FCA8E5C39A8881AC9B1A98CDE532B7", "693B6EA8CF88AD370B7837291A196F3EC81DDB361984B41F126613AD5CC2F260", "CFDCDFDF7C9CB9A55CBDC6F2D6FD61DC07FAE3CD27B74EF2297E86DDE2740B2D", "27BC266E68DB39F6B2A67E5C96975002991B69E4CC5343E48CF7FEE601F5C38F", "626BD3313BC4C80964E25EC896468A5E4046D1572D340F6CD58432E5CBEAFA9B", "07EA35ECA0A63EC2BA53C20884D171FA838007FCF8083F9A2CCB11E0E7CAB673", "211E4E9C990EC4C1F518716134E4564DDA76729170937BAE1B597D915C8EB45C", "5537FD941C0493BBCAF16E7257B9D9BF13B1E9AD6E9598E11EBC0BAF285BB78B", "5794C9BDA09DD9DBC9E59E537785EA2CC53AD1EEFD62C6CE5C48B6E1075E0245", "13929EEECB0BAE2857F9F2FA5694CBF02EAB581831601B9431D789D78C149EA8", "86BC49DAC0CD3084C910530466B65945BC29C251F41EE8096DD96246B8037304", "FCB6015A732063C836E9389A1A0578B706BF28E374701F707442CCA54E397191", "1234CC78D08BEA667273E5A65630BF64216B959E07FBF9AD2226F32979ABC494", "B09FC8C12A1A46030C231B90315FA2C25853BCAE43DC19E8292122EAA627A8E1", "3DFB0B91082D1642B58135C5A231426C1D6CF3DF4483272264F04C613B2503E3", "14183CF3C1E09921193C2AD1E061F67BA706E21AFF8A3F8D02B10910A3484C01", "8B1AA982C10A74F1447E9CD80633009D50376FC61B0712D7E54AB709E697DF7F", "4A7CF38B5F8AE037E2EDFCC23197C2CAE5D297512CD1F8C28891759CC10B5EBC", "E66DA8E757E2CB8B5CA4B3F514B9FEA43F69B9CA4C8029E1EBBE06BBF34C132E", "4E4665B9C8A80AF8DF1FC3AC2AD433A2DD2CAE6E6F115EE9563F74015F0629F8", "D61E349A8B8205FCBFF0D28B870E75D333F8CE5334B2973A0BEC7CFD97E4CB1A", "2808DEFADE80C9C92FE9138D6D4B07FD136E7130D76B3B65E9F484719DF60281", "E9E57F312008057C0E8F6F407B80C05D3C12883317F532B7037B11FA811C2FA3", "1ABE4DEE748CB6C645B273BE87AC15C90A4C0F3F95D08B21A6FE7260D65CD4C3", "CC06C272203C42B5C031FA4C13BF18859499F5E6E9E496F96A277FFF57D00DD4", "139FC2520ED8F427D130AC473760EF47E806C0E40EF56C9E2251FE164120152B", "918A76F20691147358EFE7A79E44EF45E35E8D93F5F687C0ABE4BAA402E5A91F", "4B2E0BEC294E7EF6E7E2B0E31541AE36C89E8BF432BDE05B32A21F8326315BDF", "43319305FCF257A8F95DE40A24D7C9FFC787C471E905BA518463723F00146253", "A30C5FB82BF8DFBE8D2FF295FCAF49A8E27F49420DFF180963F85612C6F10F60", "98C2DF47925ABE868409FCDD249CCB6F20E17C7E0D0975BC838406FE7612C6F3", "8B4868E22D6F8BF706F428B2FBAD42AD959F4BB2B2792D0973F938122E25528D", "57029424CCE72912AEE6078F60B896EF23E17A9E276129DF434237DF4DC20AFE", "2809ABF90324A4793F09B7F07B48B895DF75446461371EB5F1BFC6DCDD7814C3", "FF8244C965A0ED248A3781F84612C55FA8E16B49947C91F16E124525C3AF27D1", "2731BA8A449FC6E81212C515C36792E8F3183590B6E71787E683CEE722B8E817", "1F02A991D16A4BF8D687C4EFECA88E907B040AA92C4B81850D52E1F93F6361AD", "B28D94552BA12CB9899439F91358563C32DD8750DFE6A842745448A745A2F3EF", "844E8E2654A8C1C2ED5261AB5818132A8CC1C21D52E126B1302E541887858F4B", "8576B1303E54188F854F48857AB1501B2AD462E19352E114B1630952C712B063", "4F4B1DBB7298746CF4F74F9D7ABF5D7AF0FC156CD6B028BCF9B44FA67E419110", "B88067030705C807EFB235821475CAD43B150935E7B87676BFB6F8E0288F1C5F", "1CE225BC4BFBC89E91C685A5CA980550E9C6D412197343542F3DBD9DD7A46685", "31D741E6C4D41239A3012F94DDA788EA658E73F815A41DD7FB8FF5B07E59C7A5", "7DC4C28D6B0D035E80CCE7C000543A75691FFE2214FDCC460E0A90FE11C8ED44", "FA6F02FDFF62DBC3022DC3FC6427A0625D827C8161FC156E9AE3DF07B78736FD", "86509FD83A2155CDAC862EE1AEC6CBC0A39FD03AD5748CB1B52E93B516C82066", "4137119C453E8CF9645D710777001C213CF79977F1DFE99BB86541AE2008581A", "D3D78CAAFD8CA6FD0B0DA4C24C5F93EB8BD7FBD7B1DD427107F0B09F9BC2A94D", "87A01BD04ABCE91CF3114626379EC60DB1F1AFF86939C61C844CFCA652BCFB89", "4A506F7DEFA2456A4E7E1A8D94649FADD7AE171617B81FAF44DB24D62F1E1429", "BDE9581E881DB9641ED5158E5938506D186107C3C46B8960F336FD15D51EDE7C", "209B2D73CACBF49899384629BD5A8F733A455B44EF37335AF5CFFC3EC59B3856", "7681891362F71283CB5BDFDD2CA89BF0F08E1CCAC667721DAC5F8E570FEB4EC0", "BEE4E2B97E2FF38EA39C72F24F9C25FB1B6ADC40ACB41FF3255160B80F902FA9", "02A901666A417918FFE743E496531FACE8BBBA6C3DD86881C44BB96CB875E8F1", "448189B193AFBA9231808D0CD5380AF8754882B39D0A547245F1968F98086E7A", "0BF48AAB8F6B1620918E5D74F0CBC6E337BD0605F22E0DBF2738033D2E5F9E66", "0534652FE0EF198F7E4E1CE1E42F5EB4CA62469B677BC4AF540D6083CF1FC406", "BB7CAE03FCB67760BB383CE621E7210E2E4FF3C94D60BBD52BB94B7AFF57BFBB", "F481FC2D6E0876C38BCFB5E608FA83A98B85CDE174387B26ECD231AE7D8DE40B", "FEF8F5C9096461AA420BF3822F47105766B9C9FD3CCAD1F33029683D1F403932", "391CB8DF122972E39D05E8D2819028251FF8AE281D9044C95C14B3ED7A2E2F86", "B3696E33C5D14AABE52DB0C70EA2993EAF5D668B693B1012B553E85E81ADF38E", "4C12B52174D4046FFD3BDEA203DEA2C3E622EDB0BC691D0E717C41DE8A12C6C8", "9B56923730388E5A2EAA9BD0AF94BE72E953A44802A73C260ADC7EE97832707D", "48C882E3A0D193689411397B87638EA291140F75EDFCCE40C8C8127DB92EDB01", "A40B52D52BB28322A70D899CBAE933287438C46272E84AC60C97C23BE87E7451", "E801462BE85BCC45F1C029AEB5FA78F5232F113B371EA4F7DB55CFE01608BD09", "23BDC9947A937A74B8373D637BB340EA4DCFE8DEF4307150D7CEBFFB45C8C0A4", "AD5DB6C364E9802DF7ED36618A67391CC021A370380211226388E8207D2D253D", "32171DA623D1103CDC0944CD450730D5CBBFDE4924FDCC1A62E876C36C16ED37", "1729611E5BC42B396326154F2E3E1F47BEAFE8C79586EE3BDEB4B2D8B4EAA673", "642C7D7931B0DE3438CFBC308EAC38AFAD1B7AF00E91087B88F1FD92089C4211", "F835EAACA2A0345AAAB7C5D10A7AEBF73A1D05FC7C62BAAA029AD0A05D0EC741", "D30B386660CFCF119853FC6FF0EA0D3A8D742224A1D6C0E7A456976D3FB978C4", "9C2A2012D03D9A0134963B405F0C046E1447CD673B85763374D4CF678D93F4C5", "A58FAE1FB8F4115A987BCC45FBE939057CCB9B78CF679A5867B41E09F5CB5CD4", "8DE3DBCD172326D7E973BDC81B8E4A9AE4FFEA79EA76C7F79FA73EBD929CDD3D", "E910CF53B518EE82BC530094E3479EA722F1BF7F9E8A583F7C9E2AD16021A806", "7003AC07580D6007C805B03AFE51E7A9643404ECF43300BB00F63BFE37CE53E7", "AE1A3E4FEDCEFFC1F3D4F9F9644E1079471AC4D703B4E4FF9DF354C4FE71E7A9", "84EE7FEB3C55A27D0A78E805380BD00F10045040910A60E6AA7FD479AA384626", "F8B402D8014A57FD83CE53C55323723B147F50227DD967D6D798654E9F6DD02E", "C476E3E263827A6650887D075F8DF589DF1BC7F02809F196BD107B18F16CFD7A", "5B9FBECF9B4C0E0E6047C410C9C116EB8E8375E8AEAE865D762158D7D2ADE0DE", "B6C3A007F5072DEDF44C2FE81EE93D9DF825F2334A72B58168A8C039E036979E", "F2C652A0D0D5DC0DAEF2135594E6F577F04C27E68D2D55A1DC6ED8AD5FFF23E4", "B6E4F5885F2E693E85B775570C7FB36432F95A8994CD9FEE4563CAF714A6B80E", "3B7FEC53F48CFDE3D9C1B4DA1B30C3FF29BEC616D1593E51DE5D2E275F3271F0", "0F921309883C85757CD93A95A46E9F3A28D976054EBE11E8BF815F27817833C4", "DD878141277F2F441D4EBE060228A880407815D977F2EB1169F88B264EFE2662", "17A695CBF9E4FF128431F6123927D8257002583549E4C0AAF526501FA6FDF4B9", "F95969D3A61D6C38AD0D6B57643DD8332669EAA18F4CF3C70BEAD7FD6B860560", "A9C35950AE58CD9F3E00DDEDC763DC6EBCFE2B1EE3D29BB9A2533EDB2B30D13D", "38D1797BDAF054D057275C7A7FCED0BCCB5CDF3254E9EC6717D8CE89EA972EC8", "2F5A86BC79831E2B7EA7652DEC43AFE1C52491A8C00487C96A395BAFCC166C2E", "E2E9BF0ED8BE0489ECF6DA8274384C3AD89B83356877A6593A6BE45E2658AE80", "DD6E90D4C6BB538401BC181A24DF01BF01BF64ECCBEB5F61B587B04EE1976E5C", "CF93034267016FDF0B1DDB526A49273F23318E3F009B073708AEAB8ABD7FAE4C", "BD3B62DB84722518B5AE3072781F88E296E7AA772BB2D81EF2A5DB9C40B77AF7", "841CF6F22DDC31B0412FCF631498D6FBD9CBBAAD51EC65F3FD6098EA0272B4F3", "2E0BB40A2FA429B21025F017F6CA2DEB8A99B04BDDD21D2A22FCE511E49B64FD", "76B74283BBA9B2D3768512625F1185947CD1360A8B792BBECFE5F282FCDD2009", "C456F5E32A0A1E18594568321E86BD9DB3C57071DE22BFB77E3F2C178B4DA56E", "AA21E37274859D4BC6ABDC78744B6BD9FAA332669ACF7694180F98154DB2C649", "7BBBB97E3F3D8DBD2AD00AEE62007FA087FFD35F9189BE1C2F7300B7ED0380C1", "4C2B28704806A072C4023D60B944AF866919B13C1FEE1497C3296FD11EB4290B", "1CFC0B1F8F383B53434608FD0DF90D9793C470033A1F33339CE0EE7CF45FC4DD", "E986345A47AF1073702F3142A179FF580ED00465490FE2686D41816452E22F04", "A944BB0DFABA91B381057538508C9D985200CF6804AE0F3AB0C8592EE35DA461", "C004CF270990ECA3D12C5D78EA79987F7B2F5A94F587031AB6DE2FD05160F77B", "657887648FB97E2F3DCEC1FF6E2F71B50E83C1C2E5F5F2CF8105CADFD705860B", "DE2AE46CF805F3C6CB14B9FFA6DC1CC9DD96ABFE83222B90EFE48EB65F511670", "7520845F0D646F9635AC2BA6D5E5612DB66F5A56053B6D43D4EA40548B2DA8F7", "77DABEA1AC3004F7C408F7287C791356D8F1FBD9C0FF477D38C8F1204D61073B", "D47FB04D9863D3882E13791BB6147CFC037872CE44E2258C4BA7F7816D73E934", "D78DA5974A1362E462ECB4FCC41A28FA5E7F6DFC413A0F3DAB7AD51FB25EBE63", "B716F79E1BA37A5BC7D137814E9A239E1798829E08D3A9CD61619F990621D60D", "B14ED37E663C9E531FD31F047515F947FC8EA627ECD20763FDBAD0E3044662C6", "FB99B9C8341E56E88F5FBA20317A81EBE33A805D0D7780EBC4507E2CB018E2F8", "0D6EBCB60238C7CE1C3B79EC8B63DDE30F32FD972E82F9099D038CEC04CDA5CF", "E4C73C132C80B759E9515B00B73672D93C28B83E3F21467F12624A88A92E7D78", "A99BFD90E20E7127C03F85768AC70E886FA1B0A6237485A0348112EFC838B8EE", "F61E7CEB289DF3D0B1AD51E08F9A3EA0DF6E3A48AF900E7F02E3BB0BB88EF64F", "34CEF1DD5CD41BE4D5403B38C06FC1CE7F99BD20E03B82B7F59DEC3E45E3697C", "49C0C4DF40DE159CC040C6281BD1E36A60F617AF5BA3F777700B83A66E3AA5C9", "4F9F379DA26F6AEAA53F6FE73590150B59A7202B02B2DE09FCBC789DC8F3C221", "A807C1376210C440B8E1E9F5DFFE75EE6BCFB5E7FFBE27D74351770054033400", "3C0CF034C02B0007004E01F0008300CA1A8A9A04A0055800900A9003B01AC00D", "500BD002F034C06E80A3003C40184D5171004900568065006B01F087E99B009E", "047805E075804300EF017C06D00FA061282A1E20096021C04A8062806A800700", "9E00F82DC09F000E01F402F40344D5525402404AADD84FD472EC244AF338C0A2", "2A8F6D4B196DF7546D70D5007F9B6A3654795CAE05A51515040FF17362C47518", "4A3BA7C00E2EC54B219E535193037528081D2EDA5952C190F8E251F1AC0AF20B", "F81475B7CB53E9AAD0279106A8117E303C3D756C3BCFC58DA4E7CEA434F3678E", "A42B205E0DE0612AE9B24D2EADCBE3A9F268292A3A8AA2F2972E7738C41C4C52", "8EDB962D1E95A4B297E765DDB66C2467658A2EC91C1D758B96FC970D25D5D515", "651B4AE8B2AACAD07FDB80FF670353535679979676BBB4251BE8B25A97B6D6E5", "A9419CAA8D2437AF6C83A7AAA66A23AD5DB0CC96AF5D29F21565AF7095D4B8B4", "1BAA2A69A827D61F69E0A61A6D0D535D5DE5811257C926ED46E8C326187F6D59", "254437119C058469E4D1843C3295257756B8B47415E094D165251565F7BAB46E", "5749B5D837C433221EF2EDAAAC62EE726B6BAA4B36B808ED8AAACD65A32A12FA", "23F5527EB05E0D5DFA37EA2563BD6A06D8AE2DF3D04C4985762353B9411AC08A", "8A61FE0D3F487F5D55A50BA4F0D6121A032D8D5D1CA69F681EDBEFAA6A57250E", "684D15A44B5DB5651B46E14A63E4DA52EDDA40BB4AC9C88C9E7BC4317E0B6713", "534197D16E8FABA4144668C3DDDFC6FFE171912AE1FF0301E8D151DF11207749", "8DD6E3BA8771D5604338FB92606047689767535925F4590B7D2EABD496809455", "323538809B4BEA16FC23654767FEC13EB82A61D6AA2A37B92A69C0465CD30FE2", "9678EE6210B166986E12E26EACA882E6607954579555D2A42AE494BA4AC5311C", "591ACE32D2BB45F3E60D8FC3D2B23B3D259E3AC48BC2B52865DB700A664545D9", "C5FF4025159636B560C1022A2DF43FAA5496001653797765D5E6CA8CB17A84BD", "71AC1EF9C54D625AFBAD3F373557FAFB76C9F7FDE592FF00E587FF9ABEE76F2C", "46A36CE4EFC73EA3EB3F201BF90BFB917FA1BA387EB230B9223C629C32326ABC", "2A7A825A3371D2E498D82953E3AE9B767DFCF41933B5B366CF49B8E1C69BE6DE", "FC9379F36F5970AB2E31496F484E319ACCA996B4F48C4C6BD6C245D9B69CC5B9", "B72DB97D69DEB2E5F6152B1DF9AB9C05AB0BEF58B3B6A878DDFA923B3794BA36", "DEE52E2BBFBB62536555F53D9E1A9AA9DDBCA5EEDEFBB6D66FBB7F783E3C378F", "9D9F940594E6B66165B6C80331D01B0E1751215995A58EEAB2CA45552018A3F6", "8B4DA994E6BED4B174A22C9406361D692F2B28AB2CADDAECA0C942A0207F558D", "CBB3FCCE72207BDBC80AC9827A50B6B4A486CE227ADD5E55CD54933C312D92A1", "F28062C95DAE85555BB22806088DDEC1B0FD461B3875B6B1FCA8168F4D77403A", "373775D3A654DC6961EF8467BE360F1E2D46EAE0A1F2F26E2D2DBDB58EAC077B", "1E45650164BB36B836DDE9F260DEB2AADAE1F8F20D7415461DAE6A3A9499C5DC", "C5D4C0402D612A088D25A0E730CCAAF69421BB79259E0D6EDCD35D777A1869DD", "2D29A924516807E9235DA489B4900ED2807A754803EB635DAC43394A68C6535A", "4268E478CA482CDFCD786AA4BC025769A54B4AE433622CAFAA92643818292CA1", "B12ED6437CC4431C2CA7FED99FEFEAA0B9FFDB1A6BD49FEC47FE8DD158A3FEC2", "7EE4DF688DF5CFFE7C774EFFB9F6ACFFE9DFDFEB3FFEC550316352A3CB7E7497", "A57E8F4DFFD8FE8EF4FBDB3978B15BDC3F26E6519AD8BC91FDA46E05A5A95F21", "FA61B5CB29CDBDCBC578B61DF61880D1765396F64E66E34697470B7B87077D19", "B44AEF7481155DEAA2451378B3BB6C839BE483FBE761AA43D6AA646DDD541305", "861DB86E60BCD5C08EEA5AA00567C9F5EDFFDEAEA664A3ABA28E18AC65950C38", "655B5C1B1862079754A2995D434781B986FF0BDEB0E95BBA200A7CD931DC8598", "9A155A0559DA1AA00366419DE4E681CB25597ED032ECC67FAB43513FD021ED8F", "EF50D4DFE890F6FB3A04CF2A89BF61CE37969455A08B34AA77385FD73B29CD4C", "00D8EF60DB83DD0F3641D80B614BC49D91ECCDB0DDC2AE0B9B2FECC1B015C38E", "0C1B33ECCFB04DC36E8D9BB6F420BDA1424A137687282763FE6FBCFFE68347FA", "DA7BC49B24A1A76536D824D6EFE2AEBF67249E83670CEBBF9FE63FCBF98A5206", "D6E3A2AA4D9B4048969655BAB2A80C92C3783CE03BE5139FF1B6528AFA18739D", "E231820DECCA97A8D147314FC8245B36ABB4D443CE6636634E5E552953E1CA05", "D21540985A2ECF0F49DEF0194EEAA8D64299F9F2FCE15398EBE50ED1E2254E16", "4595C9168F49AF425C72A25380B1E1331D27A6864F755461B9E05B13342A82C4", "45F25391BAC89F64B4FF27D277D0A562268C29A673CA2A5CF975D52EEA25B1B4", "C44333D568986751F782255A01CBE45B9E00C58CF41F6B2F030F1046E04B0A79", "B08D78B10EDA03BE684D169587F8DF2DA0CEFD408D02EA21794159A96B91BBC4", "935F9587A7020BEB6817B5FCFBE914C0CC937E678377EFA9AAA39424B508A617", "2A51B572A7781A428668BD7C55A59BF4BFD4B6650318ECD021E8048D46FBE3F2", "02E829E913B5386CA9ABA4F63B5DA71EA16CA8AFBE93FF35F15416D9F1DB8210", "5B6ECBC378107317D97138A99A101FD2EC6B08972B5D62F2BAB01FF4BCA84361", "2BE98A55959BC103A266021EB48FC723A407D097BB5CD47D21DA2B1817FA12B9", "614BC1EF975C7A989B49A42D07D0A6A80A22655540DF254E33F57B71E6713051", "1220E7EEB0E151CFAF0A4D05F5EA583C18F7D4B0A58BF28030C9837A96D16928", "FF451861C8EEF21047AF7283288A30D8EF22ADFCB20D774BB269F9EE5A81A5E9", "272DD6D5805B955F06525643A41562545DA8C7808C8A9CA25E1BC125E37DBB6D", "E532DBD2B1279C234FE8FF5C7D0C74056EEE216881F476801DA843407BFF9AE8", "92514A84905BB7A4A4B6645DC9864DEB6017AA5897BDDC310A63DD5D2E1A7230", "6A35FDF7B4FDB5E7DA73EDB9F65C7BAE3DD79E6BCF3FEF53BF8A1ABE73927E13", "A5C95C40FDE01D947531E2990B3E0D517F9B2E1209A728FF78293D1DE20A29FE", "F35171FC3D7BA5147F7854FC9151F11DA3E28F8E8A3F362AFED35171BCE0330E", "600B00B2893EBDCE4569B05C0121FE9C657729A5C1326BA9F843933110E27F6B", "DFBB81D24C82D00FE164081F8710BFF4BF16C2EB203440380DC2E09D94E67A08", "F743180FE19310421FA9C1124A83EDF210E27B806E08EF85F00084F8BBE2FBF1", "4774207CA5441C6799C47328A4BE95FE7BF93F54FEDFC5FFA1F2FF279F4552F8", "63780AF915A31FFCA6E5E8F48E724AB3E741310F7FCDF9C7D25EF4F751FE579E", "FFB7F0210B5390A586BF61BDFE81BA07420797CF7D2C866DCF8A61E3BFF5A0C8", "53D66D0D247C1EF0DB777EB853FB03741B87C4D02A85AFFE48FC2C29DC0DF86F", "FFBAF7D7D3A84F7FCDFF7ACD0FD3DFD646622B4041ADF8B0F8432DB5EEC3F20F", "93BE8B7FA2FBA39ECB1495B84DACA90DFFE975A3CBF18E3D862843532851CF20", "C8A510751CEA0EFC6512FC3512FC6114D43DA89BF0B7F295521829855152D9F8", "516553A4BA18AA25BA1A290FF5D52409307F96949F2CA5B3A4F422296D97EAAC", "94F21D525820D12F94DAAE90F237619F01AA0150C779245E2324FC0689E74629", "7C402A67A5F226890EFEFAF4CD00BF92D26D123FCF48EDFDBB94FF0789BF2352", "F9FB5279DC38712C426B777B19A5690168026800D80AB0058006A8002805580B", "6007C8064803D001CC07980B9000A005880788038801D000A80094000A000A60", "D04D69CE02F4029C728BF8EF407818603FC01E805D00CF003C01F038C00E8026", "806A80528048C5888E41FDF35805A55900F12DA09BECDBFF3EDC2F3DA8CBBE4F", "772FA046E837548BF1BE0BE2FB77BB239FFA9F3CF6ECFF59FD1EE059DB327277", "0E9F6FC767406801B88312F7EB5F00BC0A80DF30B90830113AA4035806B04936", "52279512E5753345EC090AEFA79F00F80A00070A7F92334F86A770FFA32E5C7B", "AE3DD79E6BCFB5E7DAF3FFBF07ACA952D81FC3752E5DAD6E9BEE21DDBFE8FE5D", "F7B2EE635DAFEE9CEEFAC494C48CC4ECC4AD890F24FE34717FE247895F27BA93", "9E4B7A35E958D207491F27F149E793E47ABDDEA65FA2AFD46FD1DFAFFF37FD9F", "F46FEA0FEB8FEB3FD47FAA3FABEFD75FD18F37680CD71BB4865443A3C16BF899", "E15F0D2F1AF61AF6190E1902860B86A02132599B3C3FF997C9FB926F4CB925C5", "93F260CAE329BF4C7939E58F296FA61C4A399ED29DF271CAA7296753BE4AB992", "4219C71955C689C629C6EB8DB38C37187F62BCD5986C4C37AE35DE69DC64AC35", "3E6ADC693C6FFCDA1866BAD16431D59B58D323A6F74D7F310D99AE332F33AF32", "6F343F6EFE95B9C37CD23C25353B7565EA33A9BF4D7D2DF583D4ABA9919638CB", "32CB1ACB6396A72CCF5AFE60D9678949FB224D9EBE283D3F7D6DFA8674777A75", "7A57FA91F453E99FA50BE9E333A666CCC85892F164C6EF33CE650C6544654ECC", "5C98B92C73556673E6C399BB32FF90D999F997CC4F32FB3283996840E38F84CB", "752ADD645DAA2E4767D7ADD6DDA973EBF6E9F489A6C49589AB139549C9494FE8", "7F0F637754FF895E658833DC6E586FB8DFF0A8E129C37F183A0D1F187A0CB264", "4DF2ECE48C645BF2F2E4BAE4E6642EF977C9AF261F49EE49FE2CF97CF250F2CF", "5376A7F8530EA79C480933C6C2F8688DF38D06E3EDC64263B1D16DDC6BFCD0F8", "8DF127268769BBE9B0E91DD349D317A6CB26A579AA79817991F93FCDAF99FDE6", "37CD87CC7F3107CC17CC85A9AED4FAD4C753DB52F7C2E87C9EDA9FAAB0CCB0FC", "C492665962D968612DFF6AF9BDE5354BBBA5DF12917663DAFCB4BC3447DA9D69", "6569D56975693F4F7B21ED3FD3FE98E64F7B2BEDABB409E9F1E937A6EBD3D3D3", "97A43B6024DDE9BF4A7F2EFD77E91DE97F491F488FC898949195B13263634645", "464D4643C64319BE8C9F65FC6BC67319BFCBA07414C583887EA9BBAA93255E9F", "A84DBC1546CB96684FBC3391496C487C30914B7C34F15789AF25B6271E4E3C96", "F841E2C7896712CF272A92C6274D4C9A997443D24F92744919494B92DC497549", "F727ED48BA98F430C8D6DB295AE31A90844A73A339227572EAF4D49B526F4D4D", "4ECD48B5A52E4975A4AE4EE5527F95FA62EAABA97CEA9554CA926D999B6E4D5F", "9CBE1C246135F4A039FD85F483E947D3DF49EF0669E849EF4DE7D3CFA6A764A4", "655833B2337281F33F66BC937132A327A33783CF88CCD467BA322B32AB33E9CC", "2D995B331B329B325B328F6776679ECAECC9ECCD840E5A29AA1782345DBDEE33", "1D951899F81CF4E944E2ED492B92D62555243D96F49BA45D49BB93FE9CF44ED2", "A7496793AE244DD0CFD61BF42BF56BF425FA7BF4B5FA06FD43FA47F43FD33FA5", "DFA9FFADFE15FD6BFA0EFD01587F5FEBA30D330C46C35DC93B927F91FC52726F", "F2B494969487C97AFA3A45674C315A61E5DC657CC9F8AAB1C25C6B6E31FFD4FC", "8CF925F351581F5F9A07CD51A9B1303649B05296A796A4568044B4A45AD272D3", "0AD28AD3DC30D7F7A535A5FD2EED789A3DFDCEF4A6F447D3DF4B673376643C95", "F19B8C97335ECBE8CC389F3103564507AC04743CF107B5E374DB752F412F2FEA", "6C899D89D393B6C0ACFC22E9DF929E497A3EE9C5A47793AE265DA7D7EA13F473", "F5F3F53AE8A3499FA67F50BF5DBF43FFB8FE09FD903ED290609867D0190C0693", "A1D0C01A5E054DE237EC371C301C361C35BC63E836CC4E9E0BDA44976C486E02", "9DF21CAC91DDA0598E2677279F49BE987C35795E4A724A56CAED291B53AA5276", "A5F4805E9962FCA5F105E3CBC60BC65B4D06D32AD326539F69BCF956B3196464", "BF3927F52EE8F54BA93BD2F18E4F36F4E1ACAE4F17973837D10032B823F1C9C4", "A7135F4CDC9578005A701BB7185F34EE32FA8D6926ABC96E5A6F7A32E3E98C17", "337665ECC9D89BB13FE340063AD2314083D66DD1EDD71DD0A9123589E844A3EF", "A2D06974313A9DEEACAE5F17D4291255893189F1890989F3A1A534D0C24B13F3", "13D72696265624D2A0917B92FA92FA938249BB52F6A4EC8575BF3FE500ACFDA3", "29EF80BE3C05FDEA4DE1A16F7D29FD29832941D09B0AA31234A7C618638C33C6", "836E4830CE05FDA0030D6132A6811C641B738D4B8D7663BE7135C8C47A63B591", "366E3536189B8C2DC6EDC61DC6C78D4F189F343E0DFD5B6F2ABDF6AEFDDA73ED", "B9F65C7BAE3DD79E6BCFB5E7FFA3CFFF01504B070808DCFA2BA944000000A000", "00504B010214001400080008000799663608DCFA2BA944000000A000000A0000", "00000000000000000000000000000047434D444C4E2E444C4C504B0506000000", "000100010038000000E14400000000" }; private static final int UNCOMPRESSED_SIZE = 0xA000; } class ExportAppletDialog extends JFileChooser { public ExportAppletDialog(File dir, Program program) { super(dir); setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); setDialogTitle("Export Applet"); String className = program.getClass().getName(); String programName = className.substring(className.lastIndexOf('.') + 1); setSelectedFile(new File(dir, programName)); exportFilesCheckBox = new JCheckBox("Export resource files"); exportFilesCheckBox.setSelected(true); target = program; } protected JDialog createDialog(Component parent) { JDialog dialog = super.createDialog(parent); JPanel panel = new JPanel(); panel.setLayout(new FlowLayout(FlowLayout.LEFT)); panel.add(exportFilesCheckBox); dialog.getContentPane().add(panel, BorderLayout.SOUTH); dialog.validate(); return dialog; } public File chooseOutputDirectory() { int result = showSaveDialog(target); if (result == JFileChooser.CANCEL_OPTION) return null; return getSelectedFile(); } public boolean exportFiles() { return exportFilesCheckBox.isSelected(); } /* Private instance variables */ private JCheckBox exportFilesCheckBox; private Component target; } class ThreadedMenuAction implements Runnable { public ThreadedMenuAction(Program program, String action) { targetProgram = program; actionCommand = action; } public void run() { ProgressBarDialog dialog = new ProgressBarDialog(targetProgram); try { if (actionCommand.equals("Export Applet")) { JTFTools.exportApplet(targetProgram, dialog.getProgressBar()); } else if (actionCommand.equals("Submit Project")) { JTFTools.submitProject(targetProgram, dialog.getProgressBar()); } } catch (Exception ex) { dialog.setVisible(false); IOModel io = targetProgram.getDialog(); if (io == null) io = targetProgram.getConsole(); if (io == null) io = IOConsole.SYSTEM_CONSOLE; String msg = ex.getMessage(); if (!(ex instanceof ErrorException)) { msg = "" + ex; StringWriter wr = new StringWriter(); PrintWriter pwr = new PrintWriter(wr); ex.printStackTrace(pwr); pwr.close(); try { BufferedReader rd = new BufferedReader(new StringReader(wr.toString())); rd.readLine(); msg += rd.readLine(); } catch (IOException ignore) { /* Empty */ } } io.showErrorMessage(msg); } } private Program targetProgram; private String actionCommand; } /* Package class: MailStream */ /** * This class creates a PrintStream subclass that allows the client to send a * message using the standard RFC 2822 message format. Access to this class is obtained * through the static methods in JTFTools. The class is not exported * simply to avoid proliferation of classes in the acm.util package. */ class MailStream extends PrintStream { /* Constructor: MailStream(smtpServer, from, to) */ /** * Creates a PrintStream subclass that allows the client to send a * message. * * Example: MailStream mail = new MailStream(smtpServer, from, to); * @param smtpServer A string indicating the host name of the SMTP server * @param from A string indicating the e-mail address of the sender * @param to A string indicating the e-mail address of this recipient */ public MailStream(String smtpServer, String from, String to) { super(new NullOutputStream()); try { sender = from; recipient = to; socket = new Socket(smtpServer, SMTP_PORT); out = new BufferedOutputStream(socket.getOutputStream()); in = new BufferedInputStream(socket.getInputStream()); verify("220"); println("HELO " + InetAddress.getLocalHost().getHostName()); verify("250"); println("MAIL FROM: " + sender); verify("250"); StringTokenizer tokenizer = new StringTokenizer(to, " ,"); while (tokenizer.hasMoreTokens()) { println("RCPT TO: " + tokenizer.nextToken()); verify("250"); } println("DATA"); verify("354"); } catch (IOException ex) { throw new ErrorException(ex); } } /** Prints a boolean value */ public void print(boolean b) { print("" + b); } /** Prints a char value */ public void print(char c) { print("" + c); } /** Prints a int value */ public void print(int i) { print("" + i); } /** Prints a long value */ public void print(long l) { print("" + l); } /** Prints a float value */ public void print(float f) { print("" + f); } /** Prints a double value */ public void print(double d) { print("" + d); } /** Prints the contents of a character array */ public void print(char[] array) { print(new String(array)); } /** Prints a String value */ public void print(String s) { write(s); } /** Prints any object */ public void print(Object obj) { print("" + obj); } /** Terminates the current line */ public void println() { try { out.write('\n'); out.flush(); } catch (IOException ex) { throw new ErrorException(ex); } } /** Prints a boolean value and terminates the line */ public void println(boolean b) { print(b); println(); } /** Prints a char value and terminates the line */ public void println(char c) { print(c); println(); } /** Prints a int value and terminates the line */ public void println(int i) { print(i); println(); } /** Prints a long value and terminates the line */ public void println(long l) { print(l); println(); } /** Prints a float value and terminates the line */ public void println(float f) { print(f); println(); } /** Prints a double value and terminates the line */ public void println(double d) { print(d); println(); } /** Prints a character array and terminates the line */ public void println(char[] array) { print(array); println(); } /** Prints a String value and terminates the line */ public void println(String s) { print(s); println(); } /** Prints any object and terminates the line */ public void println(Object x) { print(x); println(); } /** Writes a single character to the output stream */ public void write(int c) { try { if (c > 0xFF) { throw new ErrorException("Illegal character in mail stream"); } out.write(c); } catch (IOException ex) { throw new ErrorException(ex); } } /** Writes a segment of a character array to the output stream */ public void write(char[] buffer, int offset, int length) { try { for (int i = 0; i < length; i++) { char c = buffer[offset + i]; if (c > 0xFF) { throw new ErrorException("Illegal character in mail stream"); } out.write(c); } } catch (IOException ex) { throw new ErrorException(ex); } } /** Writes the entire character array to the output stream */ public void write(char[] buffer) { write(buffer, 0, buffer.length); } /** Writes a String to the output stream */ public void write(String s) { try { for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (c > 0xFF) { throw new ErrorException("Illegal character in mail stream"); } out.write(c); } } catch (IOException ex) { throw new ErrorException(ex); } } /** * Checks for errors in the stream. This method always returns false * because all errors are reported using the ErrorException class. */ public boolean checkError() { return false; } /** * Flushes the data in the output stream. */ public void flush() { try { out.flush(); } catch (IOException ex) { throw new ErrorException(ex); } } /** * Closes the output stream and sends the message. */ public void close() { try { println("."); verify("250"); out.close(); socket.close(); } catch (IOException ex) { throw new ErrorException(ex); } } /** * Cancels the current message without sending it. */ public void cancel() { try { socket.close(); out.close(); } catch (IOException ex) { throw new ErrorException(ex); } } /** * Adds the standard "To", "From", "Subject", and "Date" headers to the message. */ public void sendStandardHeaders(String senderName, String subject) { println("To: " + recipient); if (senderName != null && senderName.length() != 0) { boolean requiresQuotes = false; for (int i = 0; i < senderName.length(); i++) { char ch = senderName.charAt(i); if (ch != ' ' && ch != '-' && !Character.isJavaIdentifierPart(ch)) { requiresQuotes = true; break; } } if (requiresQuotes) { sender = '"' + senderName + '"' + " <" + sender + ">"; } else { sender = senderName + " <" + sender + ">"; } } println("From: " + sender); if (subject != null && subject.length() != 0) { println("Subject: " + subject); } println("Date: " + RFC2822_DATE_FORMAT.format(new Date())); } /* * Waits for a response from the server and makes sure it begins with the * specified pattern. */ private void verify(String pattern) { try { String response = ""; while (true) { int c = in.read(); if (c == -1 || c == '\n') break; response += (char) c; } if (pattern != null && !response.startsWith(pattern)) { throw new ErrorException("Unexpected SMTP response: " + response); } } catch (IOException ex) { throw new ErrorException(ex); } } /* Private constants */ private static final int SMTP_PORT = 25; private static SimpleDateFormat RFC2822_DATE_FORMAT = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US); /* Private instance variables */ private Socket socket; private InputStream in; private OutputStream out; private String sender; private String recipient; } /* Package class: HexByteOutputStream */ /** * This class creates an OutputStream subclass that converts data * to hex bytes. The class is not exported simply to avoid proliferation of * classes in the acm.util package. */ class HexByteOutputStream extends OutputStream { /* Constructor: HexByteOutputStream(printStream) */ /** * Creates an OutputStream subclass that converts data to hex bytes. * * Example: HexByteOutputStream out = new HexByteOutputStream(printStream); * @param printStream The underlying PrintStream to which data is written */ public HexByteOutputStream(PrintStream printStream) { out = printStream; out.flush(); columnCount = 0; } /** Writes a single byte to the output stream */ public void write(int b) throws IOException { String hex = Integer.toHexString(0x100 + (b & 0xFF)).toUpperCase(); out.write(hex.charAt(1)); out.write(hex.charAt(2)); columnCount += 2; if (columnCount >= COLUMNS) { columnCount = 0; out.println(); } } /** Flushes data in the output stream */ public void flush() { out.flush(); } /** Closes the output stream */ public void close() { out.close(); } /* Private constants */ private static final int COLUMNS = 76; /* Private instance variables */ private int columnCount; private PrintStream out; } /* Package class: Base64OutputStream */ /** * This class creates an OutputStream subclass that converts data to * its Base64 encoding. This encoding transmits three bytes of binary data as a * series of four characters, each of which supplies six bits of the value. * The class is not exported simply to avoid proliferation of classes in the * acm.util package. */ class Base64OutputStream extends OutputStream { /* Constructor: Base64OutputStream(printStream) */ /** * Creates an OutputStream subclass that converts data to * its Base64 encoding. * * Example: Base64OutputStream out = new Base64OutputStream(printStream); * @param printStream The underlying PrintStream to which data is written */ public Base64OutputStream(PrintStream printStream) { out = printStream; out.flush(); byteCount = 0; columnCount = 0; buffer = 0; } /** Writes a single byte to the output stream */ public void write(int b) throws IOException { buffer = buffer << 8 | (b & 0xFF); byteCount++; if (byteCount == 3) { out.write(BASE64[(buffer >> 18) & 0x3F]); out.write(BASE64[(buffer >> 12) & 0x3F]); out.write(BASE64[(buffer >> 6) & 0x3F]); out.write(BASE64[buffer & 0x3F]); columnCount += 4; if (columnCount >= COLUMNS) { columnCount = 0; out.println(); } byteCount = 0; buffer = 0; } } /** Flushes data in the output stream */ public void flush() { out.flush(); } /** Closes the output stream */ public void close() { pad(); out.close(); } /** Pads the data to ensure that there is a valid Base64 sequence */ public void pad() { switch (byteCount) { case 0: /* Empty */ break; case 1: out.write(BASE64[(buffer >> 2) & 0x3F]); out.write(BASE64[(buffer << 4) & 0x3F]); out.write('='); out.write('='); break; case 2: out.write(BASE64[(buffer >> 10) & 0x3F]); out.write(BASE64[(buffer >> 4) & 0x3F]); out.write(BASE64[(buffer << 2) & 0x3F]); out.write('='); break; } out.println(); out.println(); } /* Private constants */ private static final int COLUMNS = 76; private static final char[] BASE64 = { 'A','B','C','D','E','F','G','H', 'I','J','K','L','M','N','O','P', 'Q','R','S','T','U','V','W','X', 'Y','Z','a','b','c','d','e','f', 'g','h','i','j','k','l','m','n', 'o','p','q','r','s','t','u','v', 'w','x','y','z','0','1','2','3', '4','5','6','7','8','9','+','/', }; /* Private instance variables */ private int buffer; private int columnCount; private int byteCount; private PrintStream out; } /* Package class: NullOutputStream */ /** * This class represents an OutputStream that ignores all data, * much like the device /dev/null on a Unix system. The reason * for including this class is that some older unstuffing programs cannot * read ZIP files that write the sizes and checksum at the end of the entry * data. By writing the entry to a NullOutputStream first, * the system can calculate the correct values before writing them to the * actual ZipOutputStream. Note that this strategy means that * each file in the submission is compressed twice. Caching this result * would save time at the expense of memory, but could easily fail for * large image files, for example. */ class NullOutputStream extends OutputStream { public void write(int b) { } public void write(byte[] b) { } public void write(byte[] b, int off, int len) { } public void flush() { } public void close() { } } /* Package class: SubmitOptions */ /** * This class keeps track of the options used in the "Submit Options" menu. */ class SubmitOptions implements ActionListener, DocumentListener { /* Constructor: SubmitOptions(program) */ /** * Creates a SubmitOptions for the program, filling in * any fields that can be determined using reflection. */ public SubmitOptions(Program program) { parent = program; authorNameField = new JTextField(); authorEMailField = new JTextField(); instructorEMailField = new JTextField(); smtpServerField = new JTextField(); cancelButton = new JButton("Cancel"); submitButton = new JButton("Submit"); authorEMailField.getDocument().addDocumentListener(this); instructorEMailField.getDocument().addDocumentListener(this); smtpServerField.getDocument().addDocumentListener(this); cancelButton.addActionListener(this); submitButton.addActionListener(this); initPreferences(program); } /* Returns the author name */ public String getAuthorName() { return authorNameField.getText().trim(); } /* Returns the author email address */ public String getAuthorEMail() { return authorEMailField.getText().trim(); } /* Returns the submission email address */ public String getSubmissionEMail() { return instructorEMailField.getText().trim(); } /* Returns the SMTP server */ public String getSMTPServer() { return smtpServerField.getText().trim(); } /* Returns true if all the necessary fields are filled in */ public boolean isComplete() { if (getAuthorEMail().indexOf('@') == -1) return false; if (getSubmissionEMail().indexOf('@') == -1) return false; if (getSMTPServer().length() == 0) return false; return true; } /* * Pops up a dialog to request the fields and waits for it to complete. * Returns true if the user activates the dialog by clicking * Submit. */ public boolean popup() { Frame frame = JTFTools.getEnclosingFrame(parent); if (frame == null) return false; dialog = new JDialog(frame, "Submit Project Options", true); Container contentPane = dialog.getContentPane(); contentPane.setLayout(new TableLayout(6, 2, 0, 4)); contentPane.add(new JLabel("Instructor email ", JLabel.RIGHT)); contentPane.add(instructorEMailField, "width=" + FIELD_WIDTH); contentPane.add(new JLabel("Author name ", JLabel.RIGHT)); contentPane.add(authorNameField, "width=" + FIELD_WIDTH); contentPane.add(new JLabel("Author email ", JLabel.RIGHT)); contentPane.add(authorEMailField, "width=" + FIELD_WIDTH); contentPane.add(new JLabel("SMTP server ", JLabel.RIGHT)); contentPane.add(smtpServerField, "width=" + FIELD_WIDTH); JPanel buttonPanel = new JPanel(); buttonPanel.setLayout(new FlowLayout()); buttonPanel.add(cancelButton); buttonPanel.add(submitButton); contentPane.add(new JLabel("")); contentPane.add(buttonPanel, "top=10"); dialog.setSize(DIALOG_WIDTH, DIALOG_HEIGHT); submitFlag = false; submitButton.setEnabled(isComplete()); dialog.setVisible(true); return submitFlag; } /* Responds to an action event */ public void actionPerformed(ActionEvent e) { submitFlag = (e.getSource() == submitButton); dialog.setVisible(false); } /* Responds to any changes in the text fields */ public void changedUpdate(DocumentEvent e) { submitButton.setEnabled(isComplete()); } public void removeUpdate(DocumentEvent e) { submitButton.setEnabled(isComplete()); } public void insertUpdate(DocumentEvent e) { submitButton.setEnabled(isComplete()); } /* Tries to initialize the fields by reflection */ private void initPreferences(Program program) { instructorEMailField.setText(getDefaultField("INSTRUCTOR_EMAIL", program)); authorNameField.setText(getDefaultField("AUTHOR_NAME", program)); String sender = getDefaultField("AUTHOR_EMAIL", program); if (sender.length() == 0) { sender = System.getProperty("user.name"); if (sender == null) { sender = ""; } else { String localHost = JTFTools.getLocalHostName(); if (localHost != null) sender += "@" + localHost; } } authorEMailField.setText(sender); String smtp = getDefaultField("SMTP_SERVER", program); if (smtp.length() == 0) { smtp = System.getProperty("mail.smtp.host"); if (smtp == null) { String localHost = JTFTools.getLocalHostName(); if (localHost == null) { smtp = ""; } else { smtp = "smtp." + localHost.substring(localHost.indexOf('.') + 1); try { new Socket(smtp, SMTP_PORT).close(); } catch (Exception ex) { smtp = ""; } } } } smtpServerField.setText(smtp); } /* Looks up a field by name in the program class */ private String getDefaultField(String name, Program program) { try { Field field = program.getClass().getField(name); String value = (String) field.get(program); if (value != null && value.trim().length() != 0) return value; } catch (Exception ex) { /* Empty */ } return ""; } /* Private constants */ private static final int FIELD_WIDTH = 300; private static final int DIALOG_WIDTH = 500; private static final int DIALOG_HEIGHT = 230; private static final int SMTP_PORT = 25; /* Private instance variables */ private Component parent; private JDialog dialog; private JTextField authorNameField; private JTextField authorEMailField; private JTextField instructorEMailField; private JTextField smtpServerField; private JButton cancelButton; private JButton submitButton; private boolean submitFlag; } /* Package class: ProgressBarDialog */ /** * This class implements the dialog used to track the progress of the * "ExportApplet" and "Submit Program" menu options. */ class ProgressBarDialog extends JDialog implements ActionListener { /* Constructor: ProgressBarDialog(program) */ /** * Creates a dialog containing a progress bar and a Cancel button. */ public ProgressBarDialog(Program program) { super(JTFTools.getEnclosingFrame(program), "Progress", false); Container contentPane = getContentPane(); contentPane.setLayout(new TableLayout(2, 1)); progressBar = new JProgressBar(); contentPane.add(progressBar, "weightx=1 left=5 right=5 height=" + PROGRESS_BAR_HEIGHT); JButton cancelButton = new JButton("Cancel"); cancelButton.addActionListener(this); contentPane.add(cancelButton, "top=10 fill=NONE"); Rectangle programBounds = program.getBounds(); int x = programBounds.x + (programBounds.width - DIALOG_WIDTH) / 2; int y = programBounds.y + (programBounds.height - DIALOG_HEIGHT) / 2; setBounds(x, y, DIALOG_WIDTH, DIALOG_HEIGHT); } /* Returns the progress bar */ public JProgressBar getProgressBar() { return progressBar; } /* Responds to an action event */ public void actionPerformed(ActionEvent e) { progressBar.setString("Cancel"); setVisible(false); } /* Checks to see if a progress bar has been cancelled */ public static boolean hasBeenCancelled(JProgressBar bar) { if (bar == null) return false; String str = bar.getString(); return str != null && str.equals("Cancel"); } /* Pops up the dialog if the progress bar is included inside one */ public static void popup(JProgressBar bar) { Component comp = bar; while (comp != null) { if (comp instanceof ProgressBarDialog) { comp.setVisible(true); comp.repaint(); return; } comp = comp.getParent(); } } /* Dismisses the dialog if the progress bar is included inside one */ public static void dismiss(JProgressBar bar) { Component comp = bar; while (comp != null) { if (comp instanceof ProgressBarDialog) { comp.setVisible(false); return; } comp = comp.getParent(); } } /* Private constants */ private static final int DIALOG_WIDTH = 250; private static final int DIALOG_HEIGHT = 90; private static final int PROGRESS_BAR_HEIGHT = 25; /* Private instance variables */ private JProgressBar progressBar; }