From: ibashir@cat.syr.edu (Imran Bashir)
Newsgroups: comp.windows.interviews
Subject: An InterViews3.1 Beta based demo program
Date: 2 Sep 92 16:27:50 GMT
Organization: CASE Center, Syracuse University


This is a small InterViews 3.1.beta demo program that performs
animation on various predefined objects.  It was written by 
Imran Bashir during his summer internship at the MIT X Consortium
flames can be sent to ibashir@cat.syr.edu :-)

-------- snip ------- snip ----------------------- snip ----------------
#!/bin/sh
# To extract, remove the header and type "sh filename"
#
# This archive contains the following files:
#
#         ./Imakefile
#         ./main.c
#
if `test ! -s ./Imakefile`
then
echo "writing ./Imakefile"
sed 's/^X//' > ./Imakefile << '\End\Of\File\'
XXCOMM
XXCOMM Imran Bashir's animation program.
XXCOMM
X
X#ifdef InObjectCodeDir
X
XUse_libInterViews()
XComplexProgramTarget(animation)
X
XMakeObjectFromSrc(main)
X
X#else
X
XMakeInObjectCodeDir()
X
X#endif
\End\Of\File\
else
  echo "will not over write ./Imakefile"
fi
if `test ! -s ./main.c`
then
echo "writing ./main.c"
sed 's/^X//' > ./main.c << '\End\Of\File\'
X////////////////
X//   demo.c   //
X////////////////
X
X// by Imran Bashir, Syracuse University, Syracuse NY.
X// while working at MIT X Consortium.
X
X// This demo program has three drawings, a rotating palette, 
X// a rotating X logo and a bouncing cube. Each is selectable 
X// from a pull-down menu.
X// The rotation speed of each can be increased and decreased.
X// The animation speed can also be reduced to zero by repeatedly
X// pressing the "Slow down" push button.
X
X//
X// Some code has been borrowed from the "zoomer" example,
X// distributed with the InterViews3.1 Beta.
X// Send any comment/improvements to ibashir@cat.syr.edu
X// 
X
X#include <IV-look/kit.h>
X#include <IV-look/menu.h>
X#include <IV-look/dialogs.h>
X#include <InterViews/bitmap.h>
X#include <InterViews/background.h>
X#include <InterViews/brush.h>
X#include <InterViews/canvas.h>
X#include <InterViews/color.h>
X#include <InterViews/layout.h>
X#include <InterViews/session.h>
X#include <InterViews/window.h>
X#include <InterViews/patch.h>
X#include <InterViews/glyph.h>
X#include <InterViews/monoglyph.h>
X#include <InterViews/tformsetter.h>
X#include <InterViews/transformer.h>
X#include <InterViews/bitmap.h>
X#include <Dispatch/dispatcher.h>
X#include <Dispatch/iocallback.h>
X#include <OS/string.h>
X    
X#include <stdlib.h>
X
Xenum drawingName { Palette, Xlogo, Cube, Undefined };
X
Xclass Drawing : public Glyph {
Xpublic:
X    Drawing(Coord radius, const Color*, const Brush*);
X    virtual ~Drawing();
X
X    virtual void request(Requisition&) const;
X    virtual void allocate(Canvas*, const Allocation&, Extension&);
X    virtual void draw(Canvas*, const Allocation&) const;
X    void setLogo();
X    void setPalette();
X    void setCube();
X    drawingName selectedDrawing();
X
Xprivate:
X    Coord radius_;
X    const Color* color_;
X    const Brush* brush_;
X
X    drawingName currentDrawing;
X    void drawCube(Canvas*, const Allocation&) const;
X    void drawXlogo(Canvas*, const Allocation&) const;
X    void drawPalette(Canvas*, const Allocation&) const;
X};
X
XDrawing::Drawing(Coord r, const Color* c, const Brush* b){
X    radius_ = r;
X    Resource::ref(c);
X    color_ = c;
X    Resource::ref(b);
X    brush_ = b;
X    currentDrawing = Undefined;
X}
X
XDrawing::~Drawing() {
X    Resource::unref(color_);
X    Resource::unref(brush_);
X}
X
Xvoid Drawing::request(Requisition& req) const {
X    Coord diameter = radius_ + radius_;
X    Requirement rx(diameter, 0, 0, 0.5);
X    Requirement ry(diameter, 0, 0, 0.5);
X    req.require(Dimension_X, rx);
X    req.require(Dimension_Y, ry);
X}
X
X
Xvoid Drawing::allocate(Canvas* c, const Allocation& a, Extension& ext) {
X    ext.merge(c, a);
X}
X
Xvoid Drawing::setLogo() {
X    currentDrawing = Xlogo;
X}
X
Xvoid Drawing::setPalette(){
X    currentDrawing = Palette;
X}
X
Xvoid Drawing::setCube(){
X    currentDrawing = Cube;
X}
X
XdrawingName Drawing::selectedDrawing() {
X    return currentDrawing;
X}
X
X
Xvoid Drawing::draw(Canvas* c, const Allocation& a) const {
X    switch(currentDrawing) {
X      case Palette:
X	drawPalette(c,a);
X	break;
X      case Xlogo:
X	drawXlogo(c,a);
X	break;
X      case Cube:
X	drawCube(c,a);
X	break;
X      case Undefined:
X      default:
X	break;
X    }
X}
X
Xvoid Drawing::drawPalette(Canvas* c, const Allocation& a) const{
X
X    const Coord r = radius_, x = a.x(), y = a.y();
X    const Coord p0 = 1.00000000 * r;
X    const Coord p1 = 0.89657547 * r;   // cos 30 * sqrt(1 + tan 15 * tan 15)
X    const Coord p2 = 0.70710678 * r;   // cos 45
X    const Coord p3 = 0.51763809 * r;   // cos 60 * sqrt(1 + tan 15 * tan 15)
X    const Coord p4 = 0.26794919 * r;   // tan 15
X    
X    // draw eight slices, each with a different color, 
X    // to make a complete circle
X
X    // black slice
X    c->new_path();
X    c->line_to(x+p0, y);
X    c->curve_to(x+p2, y+p2, x+p0, y+p4, x+p1, y+p3);
X    c->line_to(x,y);
X    c->close_path();
X    c->fill(new Color(0.0,0.0,0.0));
X    
X    // blue slice
X    c->new_path();
X    c->line_to(x+p2, y+p2);
X    c->curve_to(x, y+p0, x+p3, y+p1, x+p4, y+p0);
X    c->line_to(x,y);
X    c->close_path();
X    c->fill(new Color(0.0,0.0,1.0));
X
X    // green slice
X    c->new_path();
X    c->line_to(x, y+p0);
X    c->curve_to(x-p2, y+p2, x-p4, y+p0, x-p3, y+p1);
X    c->line_to(x,y);
X    c->close_path();
X    c->fill(new Color(0.0,1.0,0.0));
X
X    // cyan slice
X    c->new_path();
X    c->line_to(x-p2, y+p2);
X    c->curve_to(x-p0, y, x-p1, y + p3, x-p0, y+p4);
X    c->line_to(x,y);
X    c->close_path();
X    c->fill(new Color(0.0,1.0,1.0));
X
X    // red slice
X    c->new_path();
X    c->line_to(x-p0, y);
X    c->curve_to(x-p2, y-p2, x-p0, y-p4, x-p1, y-p3);
X    c->line_to(x,y);
X    c->close_path();
X    c->fill(new Color(1.0,0.0,0.0));
X
X    // magenta slice
X    c->new_path();
X    c->line_to(x-p2, y-p2);
X    c->curve_to(x, y-p0, x-p3, y-p1, x-p4, y-p0);
X    c->line_to(x,y);
X    c->close_path();
X    c->fill(new Color(1.0,0.0,1.0));
X
X    // yellow slice
X    c->new_path();
X    c->line_to(x, y-p0);
X    c->curve_to(x+p2, y-p2, x+p4, y-p0, x+p3, y-p1);
X    c->line_to(x,y);
X    c->close_path();
X    c->fill(new Color(1.0,1.0,0.0));
X
X    // white slice
X    c->new_path();
X    c->line_to(x+p2, y-p2);
X    c->curve_to(x+p0, y, x+p1, y-p3, x+p0, y-p4);
X    c->line_to(x,y);
X    c->close_path();
X    c->fill(new Color(1.0,1.0,1.0));
X
X    c->stroke(color_, brush_);
X} 
X
X
Xvoid Drawing::drawXlogo(Canvas* c, const Allocation& a) const {
X    const Coord x = a.x(), y = a.y();
X
X    // draw right half of X logo
X    c->new_path();
X    c->move_to(0.0, 0.0);
X    c->line_to(100.0, 100.0);
X    c->line_to(85.0, 100.0);
X    c->line_to(-26.0, -12.0);
X    c->line_to(65.0, -125.0);
X    c->line_to(100.0, -125.0);
X    c->close_path();
X    c->fill(new Color(0.0,0.0,1.0));
X    
X    // left half of X logo
X    c->new_path();
X    c->move_to(-36.0, 0.0);
X    c->line_to(-136.0, 100.0);
X    c->line_to(-101.0, 100.0);
X    c->line_to(-10.0, 12.0);
X    c->line_to(-125.0, -125.0);
X    c->line_to(-136.0, -125.0);
X    c->close_path();
X    c->fill(new Color(0.0,0.0,1.0));
X
X    c->stroke(color_, brush_);
X}
X
Xvoid Drawing::drawCube(Canvas* c, const Allocation& a) const {
X    const Coord x = a.x(), y = a.y();
X
X    // draw back of cube first
X    c->new_path();
X    c->move_to(80.0, 80.0);
X    c->line_to(-20.0, 80.0);
X    c->line_to(-20.0, -20.0);
X    c->line_to(80.0, -20.0);
X    c->close_path();
X    c->fill(new Color(0.0,1.0,0.0));
X
X    // draw left side of cube
X    c->new_path();
X    c->move_to(-20.0, 80.0);
X    c->line_to(-80.0, 20.0);
X    c->line_to(-80.0, -80.0);
X    c->line_to(-20.0, -20.0);
X    c->close_path();
X    c->fill(new Color(0.0,0.0,1.0));
X
X    // draw right side of cube
X    c->new_path();
X    c->move_to(20.0, 20.0);
X    c->line_to(80.0, 80.0);
X    c->line_to(80.0, -20.0);
X    c->line_to(20.0, -80.0);
X    c->close_path();
X    c->fill(new Color(1.0,0.0,.0));
X 
X    // draw front of cube
X    c->new_path();
X    c->move_to(20.0, 20.0);
X    c->line_to(-80.0, 20.0);
X    c->line_to(-80.0, -80.0);
X    c->line_to(20.0, -80.0);
X    c->close_path();
X    c->fill(new Color(0.0,1.0,1.0));
X
X    // don't draw the top and bottom of the cube.
X
X    c->stroke(color_, brush_);
X}
X
X
Xstruct MenuInfo;
X
Xclass AppArea : public MonoGlyph{
X  public:
X    AppArea(Drawing*);
X    virtual ~AppArea();
X
X    virtual void update_area(Patch*);
X    virtual void draw(Canvas*, const Allocation&) const;
X
X    void run(long, long);
X    void start();
X    void stop();
X
X    void rotPalette();
X    void xlogo();
X    void cube();
X    Menu* menubar();
X
X  private:
X    Drawing* drawing;
X    Coord scale;
X    TransformSetter* xform;
X    Patch* area;
X    Patch* bd;
X    void set_xform();
X    class IOHandler* tick;
X    
X    Menu* make_menu(Menu*, MenuInfo*, int options = 0);
X    MenuItem* make_submenu(MenuItem*, Menu*);
X    MenuItem* make_item(MenuItem*, Action*);
X
X    drawingName selectedDrawing;
X};
X    
XdeclareIOCallback(AppArea)
XimplementIOCallback(AppArea)
X
XdeclareActionCallback(AppArea)
XimplementActionCallback(AppArea)
X
X
Xstruct MenuInfo {
X    const char* str;
X    ActionMemberFunction(AppArea) func;
X    MenuInfo* submenu;
X    int options;
X};
X
XMenuInfo selectionMenu[] = {
X    { "palette", &AppArea::rotPalette },
X    { "xlogo", &AppArea::xlogo },
X    { "cube", &AppArea::cube },
X    { nil }
X};
X
X
X void AppArea::update_area(Patch* p) {
X    area = p;
X }
X
X void AppArea::draw(Canvas* c, const Allocation& a) const {
X     c->push_clipping();
X     c->clip_rect(a.left(), a.bottom(), a.right(), a.top());
X     MonoGlyph::draw(c, a);
X     c->pop_clipping();
X }
X
X void AppArea::run(long /* s */, long /* us */) {
X     int scl = (int)scale;
X     scl++;
X     scl = scl%360;
X     scale = scl;
X     set_xform();
X     bd->redraw();
X     area->reallocate();
X     bd->redraw();
X     Dispatcher::instance().startTimer(0.1, 0.0, tick);
X }
X
X void AppArea::start() {
X     run(0.1, 0.0);
X }
X
X void AppArea::stop() {
X   Dispatcher::instance().stopTimer(tick);
X }
X
X AppArea::AppArea(Drawing* g) : MonoGlyph(nil) {
X     scale = 0.0;
X     drawing = g;
X     xform =  new TransformSetter(g);
X     set_xform();
X     area = nil;
X     bd = new Patch(xform);
X     body(bd);
X     tick = new IOCallback(AppArea)(this, &AppArea::run);
X     WidgetKit* kit_ = WidgetKit::instance();
X     LayoutKit* layout_ = LayoutKit::instance();
X  }
X
X AppArea::~AppArea() {}
X
X
X void AppArea::set_xform() {
X    Transformer t;
X    switch(drawing->selectedDrawing()) {
X      case Palette:
X	t.rotate(3*scale);
X	t.skew(1.0, 1.0);
X	t.rotate(scale);
X	break;
X      case Xlogo:
X	t.rotate(-3*scale);
X	t.skew(-1.0, 1.0);
X	break;
X      case Cube:
X	t.translate(200.0, 200.0);
X	t.rotate(5*scale);
X	break;
X      case Undefined:
X      default:
X	break;
X    }
X    xform->transformer(t);
X}
X
X void AppArea::rotPalette() {
X     drawing->setPalette();
X }
X
X
X void AppArea::xlogo() {
X     drawing->setLogo();
X }
X
Xvoid AppArea::cube() {
X    drawing->setCube();
X}
X
X
XMenu* AppArea::menubar() {
X    WidgetKit* kit_ = WidgetKit::instance();
X    Menu* m = kit_->menubar();
X    Menu* select = make_menu(kit_->pulldown(), selectionMenu);
X    m->append_item(make_submenu(kit_->menubar_item("Application"), select));
X    return m;
X}
X
X
XMenu* AppArea::make_menu(Menu* m, MenuInfo* info, int options) {
X    WidgetKit* kit_ = WidgetKit::instance();
X    LayoutKit* layout_ = LayoutKit::instance();
X    TelltaleGroup* group = nil;
X    for (MenuInfo* i = info; i->str != nil; i++) {
X        if (i->str[0] == '\0') {
X            m->append_item(kit_->menu_item_separator());
X        } else {
X	    Glyph* g = layout_->r_margin(kit_->label(i->str), 0.0, fil, 0.0);
X	    MenuItem* item;
X	    switch (options) {
X	    case 1:
X		item = kit_->check_menu_item(g);
X		break;
X	    case 2:
X		if (group == nil) {
X		    group = new TelltaleGroup;
X		}
X		item = kit_->radio_menu_item(group, g);
X		break;
X	    default:
X		item = kit_->menu_item(g);
X		break;
X	    }
X	    if (i->func == nil) {
X		if (i->submenu != nil) {
X		    make_submenu(
X			item,
X			make_menu(kit_->pullright(), i->submenu, i->options)
X		    );
X		}
X	    } else {
X		make_item(item, new ActionCallback(AppArea)(this, i->func));
X	    }
X	    m->append_item(item);
X        }
X    }
X    return m;
X}
X
X
XMenuItem* AppArea::make_submenu(MenuItem* i, Menu* s) {
X    i->menu(s);
X    return i;
X}
X
XMenuItem* AppArea::make_item(MenuItem* i, Action* a) {
X    i->action(a);
X    return i;
X}
X
X    
Xstatic  OptionDesc options[] = {
X    { nil }
X};
X
Xstatic PropertyData props[] = {
X    { "rotPalette*font", "-*-lucidatypewriter-bold-r-*-*-14-*" },
X    { "rotPalette*title*font", "-*-lucida-bold-r-*-*-14-*" },
X    { nil }
X};
X
X
X#define demo_width 64
X#define demo_height 64
Xstatic char demo_bits[] = {
X   0x3f, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x80, 0x03,
X   0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00,
X   0xf8, 0x01, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x03, 0x70, 0x00,
X   0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00,
X   0xc0, 0x0f, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f, 0x0e, 0x00,
X   0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
X   0x00, 0x3e, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x01, 0x00,
X   0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
X   0x00, 0xcc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xce, 0x07, 0x00,
X   0x00, 0x00, 0x00, 0x00, 0x00, 0xc7, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
X   0x80, 0x83, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x3f, 0x00,
X   0x00, 0xfc, 0xff, 0x07, 0xe0, 0x00, 0x7e, 0x00, 0x00, 0x06, 0x00, 0x06,
X   0x70, 0x00, 0xfc, 0x00, 0x00, 0x05, 0x00, 0x05, 0x38, 0x00, 0xf8, 0x01,
X   0x80, 0x04, 0x80, 0x04, 0x1c, 0x00, 0xf0, 0x03, 0x40, 0x04, 0x40, 0x04,
X   0x0e, 0x00, 0xe0, 0x07, 0xe0, 0xff, 0x3f, 0x04, 0x07, 0x00, 0x00, 0x00,
X   0x20, 0x00, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x20, 0x04,
X   0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00,
X   0x20, 0x00, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x20, 0x04,
X   0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00,
X   0x20, 0x00, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x20, 0x04,
X   0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x20, 0x04, 0x00, 0xf0, 0x1f, 0x00,
X   0x20, 0x00, 0x20, 0x04, 0x00, 0x0c, 0x61, 0x00, 0x20, 0x00, 0x20, 0x04,
X   0x00, 0x03, 0x81, 0x01, 0x20, 0x00, 0x20, 0x02, 0xc0, 0x00, 0x01, 0x06,
X   0x20, 0x00, 0x20, 0x01, 0x20, 0x00, 0x01, 0x08, 0x20, 0x00, 0xa0, 0x00,
X   0x30, 0x00, 0x01, 0x18, 0x20, 0x00, 0x60, 0x00, 0x48, 0x00, 0x01, 0x24,
X   0xe0, 0xff, 0x3f, 0x00, 0x88, 0x00, 0x01, 0x22, 0x00, 0x00, 0x00, 0x00,
X   0x04, 0x01, 0x01, 0x41, 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x81, 0x40,
X   0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x41, 0x80, 0x00, 0x00, 0x00, 0x00,
X   0x02, 0x08, 0x21, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x11, 0x00,
X   0x01, 0x00, 0x00, 0x00, 0x01, 0x20, 0x09, 0x00, 0x01, 0x00, 0x00, 0x00,
X   0x01, 0x40, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x80, 0x03, 0x00,
X   0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
X   0x01, 0x80, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x40, 0x05, 0x00,
X   0x01, 0x00, 0x00, 0x00, 0x01, 0x20, 0x09, 0x00, 0x01, 0x00, 0x00, 0x00,
X   0x01, 0x10, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x08, 0x21, 0x80,
X   0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x41, 0x80, 0x00, 0x00, 0x00, 0x00,
X   0x04, 0x02, 0x81, 0x40, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x01, 0x41,
X   0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x01, 0x22, 0x00, 0x00, 0x00, 0x00,
X   0x48, 0x00, 0x01, 0x24, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x01, 0x18,
X   0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00,
X   0xc0, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x81, 0x01,
X   0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00,
X   0x00, 0xf0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00};
X
X
Xint main(int argc, char** argv) {
X    Session* session = new Session("rotPalette", argc, argv, options, props);
X    WidgetKit& kit = *WidgetKit::instance();
X    const LayoutKit& layout = *LayoutKit::instance();
X    Drawing* drawing = new Drawing(150, kit.foreground(), new Brush(1.0));
X
X    AppArea* aa = new AppArea(drawing);
X    Patch* p = new Patch(
X		layout.vcenter(layout.fixed_span(aa, 10*72.0, 10*72.0), 1.0)
X    );
X    aa->update_area(p);
X
X    Bitmap* bitmap = new Bitmap(demo_bits, demo_width, demo_height);
X
X    ApplicationWindow* AppWin = 
X	new ApplicationWindow(
X	       kit.inset_frame(
X		    layout.vbox(
X			layout.center(aa->menubar(), 1.0),
X			p,
X			layout.vglue(5.0),
X			layout.hbox(      
X			      kit.push_button(
X				   "Start",
X				    new ActionCallback(AppArea)(aa, &AppArea::start)
X			      ),
X			      layout.hglue(5.0),
X			      kit.push_button(
X				   "Speed Up",
X				    new ActionCallback(AppArea)(aa, &AppArea::start)
X			      ),
X			      layout.hglue(5.0),
X			      kit.push_button(
X				   "Slow Down",
X				    new ActionCallback(AppArea)(aa, &AppArea::stop)
X			      ),
X			      layout.hglue(5.0),
X			      kit.push_button(
X				   "Quit",
X				    kit.quit()
X			      )
X	                )
X		    )
X	       )
X	);
X
X    AppWin->icon_bitmap(bitmap);
X    return session->run_window(AppWin);
X
X
X}
\End\Of\File\
else
  echo "will not over write ./main.c"
fi
echo "Finished archive 1 of 1"
exit
Newsgroups: comp.windows.interviews