Java is the programming language designed by Sun Microsystems for distributing applications throughout a network. Basically put, Java allows Web pages to have executable content or actually contain an application (see the sidebar below titled
"Executable Content"). Hot Java is the prototype Web browser developed by Sun Microsystems to display the capabilities of the Java language. Netscape has licensed Java from Sun Microsystems and made Navigator 2.0 Java-aware. Microsoft also
recently announced that they are licensing Java technology to make the Microsoft Internet Explorer Java-aware. Additionally, IBM and Adobe have licensed Java. With the backing of Sun Microsystems, Netscape, IBM, Abobe, Microsoft, and other major players in
the Internet industry, Java seems to have a very secure future on the Web.
We cannot hope to teach you to become an accomplished Java programmer in only one chapter. What we can do is show you the basics of Java, introduce you to the Java SDK (Software Development Kit), and show even nonprogrammers how to create Java-aware Web
pages. At the end of this chapter we show you how to create a ready-to-run scrolling LED sign for your Web page.
Most of the excitement about Java is about its ability to create dynamic multimedia Web pages. While this is the leading use of Java today, soon you will see more advanced implementations, such as complete interactive Web page applications. Imagine
going to a Web page that was a spreadsheet or a full-featured graphics application (such as CAD/CAM, perhaps).
Most skeptics say Java applications take up too much Internet bandwidth. While a given Java application can take up a lot of bandwidth, the available bandwidth throughout the Internet is also continuing to grow (partly due to new network technologies,
for example).
Until Java-aware browsers are more widespread, Webmasters must take care to ensure that Java-designed Web pages still look good to non-Java browsers. Fortunately, most browsers safely ignore the Java applet tags.
Anyone who can write a Web page will be able to take advantage of Java. You don't have to know a programming language. All you need to do is know the Java HTML tag and drop in the appropriate Java applet.
Applet is a term that has been used in the past to describe small programs that come free with an operating system. For example, WordPad and HyperTerminal are Windows 95 applets. A Java applet is of course written in Java language and then attached to a
Web page using a new HTML tag recognized by Java browsers. When the browser sees the tag that refers to the Java applet, it downloads the applet from the server to the client (if the client doesn't already have it cached), and then executes the applet
inside the browser.
For more information about the basics of Java applets, see
http://java.sun.com/applets/index.html
For examples of cool applets written by Sun Microsystems, try
http://java.sun.com/applets/applets.html
The Java SDK included on the CD-ROM with this book is distributed freely by Sun Microsystems and is designed to assist you in developing Java applications. The Java SDK (also called JDK) provides you with the following:
The Java API consists of the following packages and libraries that have been designed and developed for the benefit of Java application programmers: java.lang, java.util, java.io, java.net, java.awt, java.awt.peer, java.awt.image, and java.applet. If
you get into Java programming, you should avail yourself of the capabilities of this predefined code as much as possible.
If you haven't yet done so, now is a good time to install the Java SDK from the CD-ROM to your HTML document directory. Just copy it to your \temp directory, unzip it, and run the setup program.
With the following few steps you can easily add an applet to an HTML page. The example uses one of the most common original Java applets: the Animator applet. With the Animator applet you can create pages with embedded audio and animation.
<HTML> <HEAD> <TITLE> A Cool Java Applet </TITLE> </HEAD> <BODY> Here is a cool Java applet: <APPLET code=Animator.class width=200 height=200> <param name=imagesource value="/java/images/Duke"> <param name=endimage value=10> <param name=soundsource value="audio"> <param name=soundtrack value=spacemusic.au> <param name=sounds value="1.au|2.au|3.au|4.au|5.au|6.au|7.au|8.au|9.au|0.au"> <param name=pause value=200> </APPLET> </BODY> </HTML>
Continuation of numbered list this item not numbered
The LED Sign Java applet was written by Darrick Brown of Hope College in Holland, Michigan. In addition to the information you'll find in this chapter, you can visit his Web site at http://www.cs.hope.edu/~dbrown/ for more information. See Figure 24.1
for an example of how the LED Sign application looks on the Web.
Figure 24.1. The LED Sign is written in Java.
LED Sign is one of the best implementations of Java animation that we have seen on the Web. We have included the entire LED Sign distribution on the CD-ROM. To install LED Sign, use WinZIP and select "All files" from the "List Files of
Type" drop down box. Select the LED Sign *.gz archive. When prompted to decompress to a temporary directory, select Yes. Select the Extract button and choose your HTML document directory. The archive creates the following directory structure:
LED Sign comes pre-compiled, so you have everything you need to display the LED Sign demo. To display the demo, choose Open URL with your favorite Java enabled Web browser and type in a URL such as
http://your ip address/ledsign/www/led.html.
This assumes you fill in your own domain name or IP address and that you have installed the LEDSign application in the suggested directories. You must use Open URL as opposed to opening a local file.
The LED Sign applet is highly configurable through a script file. If you like, you can even change the fonts by editing the font data file.
The syntax for the LED script is extremely simple. Each command must be on one line; the commands cannot be split onto multiple lines. Again, only one command can be on a line. A line that starts with a "!!" is a comment. Here is an example of
a script.
!! Just a simple script Do !! Move "Hello" up onto the sign ScrollUp delay=30 center=true text=Hello Sleep delay=1000 !! Scroll "This is a test" left onto the sign ScrollLeft delay=30 startspace=20 endspace=80 text=This is a test Sleep delay=300 !! Repeat infinitely Repeat times=-1
The different options for each function/transition are as follows:
The different functions/transitions available in LED Sign are as follows:
The following list shows the script commands for LEDSign:
You can make the "on" LEDs six different colors: Red (default), Orange, Yellow, Green, Blue, and Purple.
The way you specify a color is with a '\' followed by 'r', 'o', 'y', 'g', 'b' or 'p'. Everything after a color specification will be that color until another color is specified or the end of the message is reached. The text specified as
text=This \ois \ya \gtest
will appear on the sign as "This is a test" but with "Test" being red, "is" being orange, "a" being yellow and "test" being green.
LEDSign also has the capability of displaying the current time/date. The tags are specified in the text just like the colors. Here are the time/date tags:
tt - time dd - day abbreviated (eg Fri) DD - day (eg Friday) dn - day number 1-31 mm - month abbreviated (eg Aug) MM - month (eg August) mn - month number 1-12 yy - last two digits of the year (eg 95) YY - the year (eg 1995)
The time/date tags are preceded with a backslash ('\') and enclosed in brackets ({}). Here is an example:
ScrollLeft text=The current time is \{tt}. Today is \{dd} \{mm} \{dn}, \{YY}.
The preceding line in a script would print something like "The current time is 6:19pm. Today is Sun Oct 29, 1995." on the sign.
You can specify a URL to go to if the user clicks on LED Sign while it is displaying a certain message. To do this you only need to specify the URL on the function line in the script. Here's an example:
ScrollLeft URL=http://java.sun.com text=Java is cool! ScrollLeft URL=http://java.sun.com endspace=40 text=Click on this sign now to go to Sun!
The URL tag is also valid for the "Sleep" function. So you can be displaying a message and sleeping, and the user can still click on the sign and have it take them to the URL. Example:
Appear center=true URL=http://www.sun.com text=Sun MicroSystems Sleep URL=http://www.sun.com delay=4000 !! Wait a long time to give them a chance to click!
The "text" parameter must be the last parameter, because the string after the "test=" is your message. This makes it easy to parse (that is, no nested quote problem) and easy for the user. What you see is what you get!
If the "clear=true" parameter is given to one of the transitions, it causes the sign to clear (turn off the LEDs) in the manner of the transition. For example, "ScrollDown clear=true" would clear the sign by scrolling whatever is on
the sign down off the sign.
If the "center=true" option is set, the messageif it fits on the signis centered. It doesn't make sense to center a message if it is longer than the sign. So, if your message isn't centering, it's probably too long. The
"startspace" and "endspace" parameters are ignored when the "center=true" parameter is given.
The script is much like HTML in how it handles function tags and parameters. It ignores anything it doesn't recognize. There are, however, some ways to stop the applet. For example, "delay=fifty" is incorrect because "delay" requires
an integer and would thus cause the applet to stop. There is some script error output. If you are having trouble with LED Sign running your script, check your .hotjava/weblog; any error output is printed there.
Here is a sample of an applet tag that will add the LED Sign to your Web page.
<applet codebase="classes" code="LED.class" width=540 height=70> <param name="script" value="../scripts/Demo.led"> <param name="font" value="../fonts/default.font"> <param name="border" value="3"> <param name="bordercolor" value="100,130,130"> <param name="spacewidth" value="3"> <param name="wth" value="100"> <blockquote> <hr> If you were using a Java-enabled browser, you would see a scrolling text sign instead of this paragraph. <hr> </blockquote> </applet>
The LED Source Code
Included in the LED Sign distribution is all the well-commented Java source code. Listing 24.2 shows the main file appLED.java. If you are a C++ programmer, just by looking through this file you will find that Java should be an easy programming language
migration.
/////////////////////////////////////////////////////////////// // appLED.java -- LED Sign V2.0beta // // The main for the LED Sign applet. This applet mimics // an LED sign that you typically see displaying messages // at airport terminals and the such. // // Revisions: // V2.0beta: Modified V1.0 to comply with Pre-Beta java. // A problem with delay causes a jerky display. // Modified Oct 20 - 29, 1995 // // V1.0: Written July 10 - August 6, 1995 // // By Darrick Brown // dbrown@cs.hope.edu // http://www.cs.hope.edu/~dbrown/ // // © Copyright 1995 /////////////////////////////////////////////////////////////// import java.awt.*; import java.io.*; import java.net.*; import FuncInfo; import Script; import Letters; import LEDMessage; // Just a small struct // used in randomizing the pixels in the "Pixel" function class Pixelize { int x; int y; } ///////////////////////////////////////////////////////////////// // The java.applet.Applet!! ///////////////////////////////////////////////////////////////// public class LED extends java.applet.Applet implements Runnable { // my #defines int WIDTH = 400; int HEIGHT = 30; Color highlight; Script com; // The class that takes care of the script FuncInfo fi; // All the info for any funtion/transition Letters let; // The class that contains all the letters Color colors[]; // The array of possible colors // The class that takes care of the message to be displayed LEDMessage msg; Color bhilite; // The highlight color of the border Color bcolor; // The color of the border Color bshadow; // The shadow of the border Thread led = null; String scrpt,endspace,fnt; // "command line" arguments String text; // the current message int place; // The place where we are in each transition. How we know when we are done. int border; // The border width int offset; // The offset for the sign from the upper left int w,h; // Width & Height in LEDs int swidth; // The width of the space character. Settable in the HTML command line. boolean beginning; // make sure we init certain stuff only once boolean suspended; int delay = 40; // The global delay variable boolean delayed = true; // Just to make sure the "delay" in run() works Image pixmapimg,offimg,tmpimg; // The pixmaps!! -- These are what make this program possible Graphics pixmap,offmap,tmpmap; // Graphics for the pixmaps Pixelize pix[] = new Pixelize[1]; // Just so it loads this class NOW!! ////////////////////////////////////////////////////////////////// // get the "command line" arguments from the HTML private void getAttrs() { String s; int r,g,b; if(getParameter("script") != null) { scrpt = new String(getParameter("script")); } else System.out.println("NO SCRIPT SPECIFIED OR BAD URL"); if(getParameter("font") != null) { fnt = new String(getParameter("font")); } else System.out.println("NO FONTS FOUND!!!! WHERE'D THEY GO?!?!?!?"); if(getParameter("spacewidth") != null) { swidth = (new Integer(new String(getParameter("spacewidth")))).intValue(); } else swidth = 5; if(getParameter("wth") != null) { WIDTH = 5*(new Integer(new String(getParameter("Wth")))).intValue(); } else WIDTH = 60*5; if(getParameter("border") != null) { border = new Integer(new String(getParameter("border"))).intValue(); } else border = 0; if(getParameter("bordercolor") != null) { // User specified border color!! s = new String(getParameter("bordercolor")); s = s.trim(); r = new Integer(s.substring(0,s.indexOf(","))).intValue(); s = s.substring(s.indexOf(",")+1); g = new Integer(s.substring(0,s.indexOf(","))).intValue(); s = s.substring(s.indexOf(",")+1); b = new Integer(s).intValue(); // Forgive the "if" syntax, I didn't want to bother typing the // "normal" ifs for this small part. :) bhilite = new Color(r+40<256?r+40:255, g+40<256?g+40:255, b+40<256?b+40:255); bcolor = new Color(r,g,b); bshadow = new Color(r-40>=0?r-40:0, g-40>=0?g-40:0, b-40>=0?b-40:0); } else { // The default gray bhilite = Color.white; bcolor = Color.lightGray; bshadow = Color.darkGray; } } // end getAttrs() ///////////////////////////////////////////////////////////// // Initialize the java.applet.Applet public void init() { // Set up the different colors for the sign highlight = new Color(100,100,100); colors = new Color[7]; colors[0] = new Color(80,80,80); // off color colors[1] = new Color(255,0,0); // Default red colors[2] = new Color(130,255,0); // green colors[3] = new Color(0,100,255); // blue colors[4] = new Color(255,255,0); // yellow colors[5] = new Color(255,160,0); // orange colors[6] = new Color(255,0,255); // purple // The the attributes from the HTML doc getAttrs(); let = new Letters(getDocumentBase(),fnt,swidth); HEIGHT = let.height(); h = HEIGHT/5; // height in LEDs w = WIDTH/5; // width in LEDs msg = new LEDMessage(h,w,let); // Set up the script com = new Script(getDocumentBase(),scrpt); fi = new FuncInfo(); nextFunc(); offset = 3*border; resize(WIDTH+2*(offset),HEIGHT+2*(offset)); // Set the applet size beginning = true; } // End Init ////////////////////////////////////////////////////////// // Start the applet running and fork the thread public void start() { if(led == null) { led = new Thread(this); // Start the applet running led.start(); } } ////////////////////////////////////////////////////////// public void stop() { led.stop(); // Stop the applet led = null; } ////////////////////////////////////////////////////////// public void run() { while(led != null) { // The following "if" is to make sure that the delay // function actually has an effect. I found that it // tends to get skipped if the function takes too // much time (i.e. Pixel with certain delay settings) if(!delayed) delayed = true; try { led.sleep(fi.delay); // Slow it down a bit and save TONS of CPU } catch (InterruptedException e) { break; } repaint(); if((fi.func == 1 && delayed) || fi.func >= 97 || fi.func < 0) nextFunc(); } led = null; } ////////////////////////////////////////////////////////// // Trap for a mouse click on the applet public boolean mouseDown(java.awt.Event evt, int x, int y) { if (fi.url != null) { getAppletContext().showDocument(fi.url); } return true; } ////////////////////////////////////////////////////////// // set the next function // This function is only called when the previous // function/transition has finished. void nextFunc() { int i,j; Pixelize temp; int rand; // get the next function fi = com.nextFunc(); // Parse the text line to expand any time/date tags fi = com.parseLine(fi); // Create the message in LED format (boolean) msg.setmsg(fi); // Set up some initial stuff for each of the transitions switch(fi.func) { case 0: place = 0; break; case 1: place = 0; delayed = false; break; case 2: place = 0; break; case 3: place = msg.length()-1; break; case 4: place = 0; break; case 5: place = h-1; break; case 6: place = 0; // This randomizes the "LEDs" for the // Pixel function. pix = new Pixelize[w*h]; for(i=0;i<w;i++) { for(j=0;j<h;j++) { pix[h*i+j] = new Pixelize(); pix[h*i+j].x = i; pix[h*i+j].y = j; } } // Randomly sort all the LED's so all we have to do // is draw them in "order" and they come out all pixelly for(i=0;i<WIDTH/5*h;i++) { rand = (int)(Math.random()*(double)(WIDTH/5)*(double)h); temp = pix[i]; pix[i] = pix[rand]; pix[rand] = temp; } break; case 7: place = fi.times*2; // on AND off break; case 8: place = 0; break; case 9: place = 0; break; case 10: place = 0; break; case 11: place = w; break; case 12: place = h-1; break; case 13: place = 0; break; } } ////////////////////////////////////////////////////////// // Draw a pretty little LED private void drawLED(int x, int y, boolean on, int col, Graphics gr) { if(on) { gr.setColor(colors[col]); gr.fillRect(x+1,y,2,4); gr.fillRect(x,y+1,4,2); } else // its off { gr.setColor(colors[0]); gr.fillRect(x+1,y,2,4); gr.fillRect(x,y+1,4,2); gr.setColor(highlight); gr.fillRect(x+1,y+1,1,1); // the cool little highlight } } ///////////////////////////////////////////////////////////// // My version of paint3DRect (variable width) void draw3DRect(Graphics gr, int x, int y, int lx, int ly, int width, boolean raised) { int i; for(i=0; i<width; i++) { if(raised) gr.setColor(bhilite); else gr.setColor(bshadow); gr.drawLine(x+i,y+i,lx-i,y+i); gr.drawLine(x+i,y+i,x+i,ly-i); if(raised) gr.setColor(bshadow); else gr.setColor(bhilite); gr.drawLine(lx-i,y+i,lx-i,ly-i); gr.drawLine(x+i,ly-i,lx-i,ly-i); } } ///////////////////////////////////////////////////////////// public void paint(Graphics gr) { int i,j; int p,p2; // don't do any of this if the thread is null if(led != null) { if(border > 0) { draw3DRect(gr,0,0,WIDTH+2*offset-1,HEIGHT+2*offset-1,border,true); gr.setColor(bcolor); gr.fillRect(border,border,WIDTH+4*border,HEIGHT+4*border); draw3DRect(gr,2*border,2*border,WIDTH+4*border-1,HEIGHT+4*border-1,border,false); } // If the applet has just start, set up the pixmap // and draw all the LEDs off if(beginning) { // Set up some pixmaps! pixmapimg = createImage(WIDTH, HEIGHT); offimg = createImage(WIDTH, HEIGHT); // A copy of the sign with all the LEDs off tmpimg = createImage(WIDTH, HEIGHT); pixmap = pixmapimg.getGraphics(); offmap = offimg.getGraphics(); tmpmap = tmpimg.getGraphics(); pixmap.setColor(Color.black); pixmap.fillRect(0,0,WIDTH,HEIGHT); offmap.setColor(Color.black); offmap.fillRect(0,0,WIDTH,HEIGHT); for(i=0;i<HEIGHT;i+=5) for(j=0;j<WIDTH;j+=5) { drawLED(j,i,false,1,pixmap); drawLED(j,i,false,1,offmap); } gr.drawImage(pixmapimg,offset,offset, this); beginning = false; } else { gr.drawImage(pixmapimg,offset,offset, this); } } } ///////////////////////////////////////////////////////////// // This procedure contains all the different transitions // Each transition does one iteration and returns to the // "run" procedure to use its delay. This also allows // the applet to be redrawn (if needed) more quickly. public void update(Graphics gr) { int i,j; int count; // if we have not initialized our applet, don't do anything here. if( (led != null) && (pixmap != null) && (offmap != null) && (tmpmap != null)) { switch(fi.func) { case 0: // Appear if(fi.text == null) { gr.drawImage(offimg,offset,offset, this); // Turn all the LEDs off } else { for(i=0;i<w;i++) for(j=0;j<h;j++) drawLED(i*5,j*5,msg.getLED(i,j), msg.getColor(i), pixmap); gr.drawImage(pixmapimg,offset,offset, this); } nextFunc(); break; case 2: // ScrollLeft pixmap.copyArea(5,0,WIDTH-5,HEIGHT,-5,0); for(i=0;i<HEIGHT;i+=5) drawLED(WIDTH-5,i,msg.getLED(place,i/5), msg.getColor(place),pixmap); gr.drawImage(pixmapimg,offset,offset, this); place++; if(!msg.inRange(place)) nextFunc(); delayed = false; break; case 3: // ScrollRight pixmap.copyArea(0,0,WIDTH-5,HEIGHT,5,0); for(i=0;i<HEIGHT;i+=5) drawLED(0,i,msg.getLED(place,i/5),msg.getColor(place),pixmap); gr.drawImage(pixmapimg,offset,offset, this); place--; if(place < 0) nextFunc(); break; case 4: // ScrollUp pixmap.copyArea(0,5,WIDTH,HEIGHT-5,0,-5); for(i=0;i<WIDTH;i+=5) if(msg.inRange(i/5)) drawLED(i,HEIGHT-5,msg.getLED(i/5,place), msg.getColor(i/5),pixmap); else drawLED(i,HEIGHT-5,false,1,pixmap); gr.drawImage(pixmapimg,offset,offset, this); place++; if(place >= h) nextFunc(); break; case 5: // ScrollDown pixmap.copyArea(0,0,WIDTH,HEIGHT-5,0,5); for(i=0;i<WIDTH;i+=5) if(msg.inRange(i/5)) { drawLED(i,0,msg.getLED(i/5,place),msg.getColor(i/5),pixmap); } else { drawLED(i,0,false,1,pixmap); } gr.drawImage(pixmapimg,offset,offset, this); place--; if(place < 0) nextFunc(); break; case 6: // Pixel i = place + fi.times; while(place < WIDTH/5*h && place < i) { if(msg.inRange(pix[place].x)) { drawLED(pix[place].x*5,pix[place].y*5,msg.getLED(pix[place].x,pix[place].y),msg.getColor(pix[place].x),pixmap); } else { drawLED(pix[place].x*5,pix[place].y*5,false,1,pixmap); } place++; } gr.drawImage(pixmapimg,offset,offset, this); if(place >= w*h) nextFunc(); break; case 7: // Blink if(place%2 == 0) gr.drawImage(offimg,offset,offset, this); else gr.drawImage(pixmapimg,offset,offset, this); place--; if(place == 0) nextFunc(); break; case 8: // OverRight if(msg.inRange(place)) for(i=0;i<h;i++) drawLED(place*5,i*5,msg.getLED(place,i),msg.getColor(place),pixmap); else for(i=0;i<h;i++) drawLED(place*5,i*5,false,1,pixmap); gr.drawImage(pixmapimg,offset,offset, this); place++; if(place >= w) nextFunc(); break; case 9: // ScrollCenter // The right side if(w >= place*2) { pixmap.copyArea(WIDTH/2,0,WIDTH/2-5,HEIGHT,5,0); for(i=0;i<h;i++) if(msg.inRange(w-place)) drawLED(WIDTH/2,i*5,msg.getLED(w-place,i),msg.getColor(w-place),pixmap); else drawLED(WIDTH/2,i*5,false,1,pixmap); } if(place < w/2) { pixmap.copyArea(5,0,WIDTH/2-5,HEIGHT,-5,0); for(i=0;i<h;i++) if(msg.inRange(place)) drawLED(WIDTH/2-5,i*5,msg.getLED(place,i),msg.getColor(place),pixmap); else drawLED(WIDTH/2-5,i*5,false,1,pixmap); } gr.drawImage(pixmapimg,offset,offset, this); place++; if(place >= w/2 && place*2 > w) nextFunc(); break; case 10: // OverCenter // The right side if(w >= place+w/2) { for(i=0;i<h;i++) if(msg.inRange(w/2+place+1)) drawLED(WIDTH/2+place*5+5,i*5,msg.getLED(w/2+place+1,i),msg.getColor(w/2+place+1),pixmap); else drawLED(WIDTH/2+place*5+5,i*5,false,1,pixmap); } if(place < w/2) { for(i=0;i<h;i++) if(msg.inRange(w/2-place)) drawLED(WIDTH/2-place*5,i*5,msg.getLED(w/2-place,i),msg.getColor(w/2-place),pixmap); else drawLED(WIDTH/2-place*5,i*5,false,1,pixmap); } gr.drawImage(pixmapimg,offset,offset, this); place++; if(w < w/2+place && place >= w/2) nextFunc(); break; case 11: // OverLeft if(msg.inRange(place)) for(i=0;i<h;i++) drawLED(place*5,i*5,msg.getLED(place,i),msg.getColor(place),pixmap); else for(i=0;i<h;i++) drawLED(place*5,i*5,false,1,pixmap); gr.drawImage(pixmapimg,offset,offset, this); place--; if(place == 0) nextFunc(); break; case 12: // OverUp for(i=0;i<w;i++) { if(msg.inRange(i)) drawLED(i*5,place*5,msg.getLED(i,place),msg.getColor(i),pixmap); else drawLED(i*5,place*5,false,1,pixmap); } gr.drawImage(pixmapimg,offset,offset, this); place--; if(place < 0) nextFunc(); break; case 13: // OverDown for(i=0;i<w;i++) { if(msg.inRange(i)) drawLED(i*5,place*5,msg.getLED(i,place),msg.getColor(i),pixmap); else drawLED(i*5,place*5,false,1,pixmap); } gr.drawImage(pixmapimg,offset,offset, this); place++; if(place >= h) nextFunc(); break; } // End switch() statement } // End if(led != null) } // End update() } // End LED class
Symantec Corporation just recently announced support of Sun's Java Developer's Kit Beta 2 with a product they call Symantec Espresso. Espresso is offered as a free update to Symantec's C++ 7.2 development environment. This update allows Java developers
to use the Graphical User Interface to develop Java applications. Symantec Espresso contains Sun's Java Development Kit Beta 2, including new bug fixes and improvements such as increased security, a more robust and improved API, improved error handling,
and support for compressed classes that load from ZIP files.
For more information see http://www.Symantec.com/lit/dev/javaindex.html.
This just about wraps up our complete Windows 95 Internet server project. Now the question is, "Where is the Web going?" We outline the future of the Web with several miscellaneous topics in the next chapter.